MessageService.java 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. package com.ywt.alipaympapi.service;
  2. import com.alibaba.fastjson.JSON;
  3. import com.alibaba.fastjson.JSONArray;
  4. import com.alibaba.fastjson.JSONObject;
  5. import com.alipay.api.AlipayApiException;
  6. import com.alipay.api.domain.CommerceAppUploadRequestContent;
  7. import com.alipay.api.request.AlipayCommerceAppAuthUploadRequest;
  8. import com.alipay.api.response.AlipayCommerceAppAuthUploadResponse;
  9. import com.alipay.easysdk.base.oauth.models.AlipaySystemOauthTokenResponse;
  10. import com.alipay.easysdk.factory.Factory;
  11. import com.ywt.alipaympapi.core.utils.CheckUtil;
  12. import com.ywt.alipaympapi.core.utils.DateUtil;
  13. import com.ywt.alipaympapi.face.impl.AlipayService;
  14. import com.ywt.alipaympapi.models.Constants;
  15. import com.ywt.core.exception.AppMessageException;
  16. import lombok.extern.slf4j.Slf4j;
  17. import org.apache.tomcat.util.bcel.Const;
  18. import org.springframework.beans.factory.annotation.Autowired;
  19. import org.springframework.stereotype.Service;
  20. import redis.clients.jedis.JedisCommands;
  21. import java.io.UnsupportedEncodingException;
  22. import java.net.URLEncoder;
  23. import java.util.Date;
  24. /**
  25. * 支付宝“智能”消息服务
  26. * 参考文档 <a href="https://opendocs.alipay.com/pre-open/01odaz">医疗小程序智能消息推送接入方案</a>
  27. *
  28. * @author Walker
  29. * Created on 2022/9/28
  30. */
  31. @Slf4j
  32. @Service
  33. public class MessageService {
  34. @Autowired
  35. AlipayService alipayService;
  36. @Autowired
  37. JedisCommands jedisCommands;
  38. /**
  39. * 小程序用 authCode 换取 accessToken
  40. */
  41. public String getAccessToken(String authCode) {
  42. String accessToken = "";
  43. try {
  44. AlipaySystemOauthTokenResponse response = Factory.Base.OAuth().getToken(authCode);
  45. log.info("MessageService#getAccessToken(authCode={} ):\n {}", authCode, JSON.toJSONString(response));
  46. accessToken = response.getAccessToken();
  47. } catch (Exception e) {
  48. log.error("MessageService#getAccessToken(authCode={} ):\n {}", authCode, e.getMessage(), e);
  49. }
  50. return accessToken;
  51. }
  52. /**
  53. * 发送“智能”消息
  54. *
  55. * @param appId 小程序 appId
  56. * @param alipayUid 支付宝用户 id
  57. * @param jsonBody 业务参数,具体根据业务类型按照文档拼接
  58. */
  59. public void sendIntelliMsg(String appId, String alipayUid, JSONObject jsonBody, String hospitalPid, String tenantAppId) {
  60. try {
  61. String rk = String.format(Constants.RK_ACCESS_TOKEN, appId, alipayUid);
  62. String accessToken = jedisCommands.get(rk);
  63. CheckUtil.ensureNotEmpty(accessToken, rk + " 无法获取 accessToken");
  64. AlipayCommerceAppAuthUploadRequest request = new AlipayCommerceAppAuthUploadRequest();
  65. request.setServiceName("alipay.commerce.app.data");//应用服务名称 固定值 String(256) 不可空
  66. request.setTargetId(hospitalPid); //目标用户 String(64) 签约商家 PID 不可空
  67. CommerceAppUploadRequestContent content = new CommerceAppUploadRequestContent(); //服务数据参数
  68. content.setTenantAppId(tenantAppId); //租户应 用ID String(64) 支付宝分配 不可空
  69. content.setActivityId("upload_hospital_order"); //业务流程ID String(64) 不可空 此处固定为“upload_hospital_order”
  70. content.setBody(JSONObject.toJSONString(jsonBody));
  71. request.setContent(content);
  72. log.info("MessageService#sendIntelliMsg(appId={}, accessToken={} ): 入参:{}", appId, accessToken, JSON.toJSONString(request));
  73. AlipayCommerceAppAuthUploadResponse response = alipayService.getAlipayClient(appId).execute(request, accessToken);
  74. log.info("MessageService#sendIntelliMsg(appId={}, accessToken={} ): 响应:{}", appId, accessToken, JSON.toJSONString(response));
  75. } catch (AppMessageException e) {
  76. log.error("MessageService#sendIntelliMsg(): 业务异常:{}", e.getMessage());
  77. } catch (Exception e) {
  78. log.error("MessageService#sendIntelliMsg(appId={} , jsonBody={} , alipayUid={} ):\n {}", appId, jsonBody, alipayUid, e.getMessage(), e);
  79. }
  80. }
  81. /**
  82. * 发送预约挂号单消息
  83. */
  84. public void sendRegMsg(int orderId, String orderNo, String alipayUid, String orderCreateTime, String orderAmountStr,
  85. String tradeNo, String hospitalName, String deptName, String doctorName, String doctorId,
  86. String patientName, String regDate, String deptLoc, String appId, String merchantOrderStatus,
  87. String isvPid, String hospitalPid, String tenantAppId, String hospitalRegId) throws AppMessageException {
  88. CheckUtil.ensureNotEmpty(deptLoc, "科室位置不能为空");
  89. // 小程序跳转路径
  90. String pathParam = "";
  91. try {
  92. pathParam = URLEncoder.encode(String.format("?header=show&orderId=%d&pageType=appointment-result&title=挂号详情", orderId), "utf-8");
  93. } catch (UnsupportedEncodingException e) {
  94. log.error("MessageService#sendRegMsg UnsupportedEncodingException: {}", e.getMessage(), e);
  95. }
  96. String mpPath = String.format("alipays://platformapi/startapp?appId=%s&page=antbuilder/industry/hospitalV2/pages/page-no-pull/index%s", appId, pathParam);
  97. JSONObject jsonBody = new JSONObject(); //业务流程参数 String(6000) 业务流程请求参数说明
  98. jsonBody.put("out_biz_no", orderNo);//医院预约单订单号 唯一不重复(同一 家 ISV 接入的所有 医院的挂号单、检 查号、医药单都不 可重复) String(128)
  99. jsonBody.put("partner_id", isvPid); //ISV的PID,支付宝id(2088 开头)。同一家ISV 请保持一致!
  100. jsonBody.put("buyer_id", alipayUid);//就诊人 id,授权 人id 就诊人在支付宝平 台的 2088 开头 16 位id
  101. jsonBody.put("tiny_app_id", appId);//医院在支付宝的小 程序id
  102. jsonBody.put("order_create_time", orderCreateTime);//订单创建时间
  103. jsonBody.put("order_modified_time", DateUtil.formatDate(new Date(), ""));//订单修改时间
  104. jsonBody.put("amount", orderAmountStr);//订单金额
  105. jsonBody.put("pay_amount", orderAmountStr);//支付金额
  106. jsonBody.put("trade_no", tradeNo);//支付宝交易号
  107. jsonBody.put("order_type", "HOSPITAL_ORDER"); // 固定为 HOSPITAL_ORDER
  108. jsonBody.put("out_biz_type", "HOSPITAL_APPOINTMENT"); // 固定值 HOSPITAL_APPOINTMENT
  109. // 状态文档:https://gw.alipayobjects.com/os/bmw-prod/05064ae2-e3c7-4e6c-93ed-ad4740b66000.pdf
  110. // MERCHANT PREORDER SUCCESS 预约成功
  111. // MERCHANT NUM TAKEN 己取号
  112. // MERCHANT WAIT CHECK IN 待签到
  113. // MERCHANT CALL NUM 叫号中
  114. // MERCHANT NUM ARRIVED 己到号
  115. // MERCHANT NUM PASSED 已过号
  116. // MERCHANT FINISHED 已完成
  117. // MERCHANT CLOSED 已取消
  118. // MERCHANT REFUNDED 已退款
  119. jsonBody.put("merchant_order_status", merchantOrderStatus); //状态 String(64) 枚举详见文档
  120. JSONArray itemOrderList = new JSONArray();
  121. JSONObject itemOrder = new JSONObject();
  122. itemOrder.put("item_name", "预约挂号");//商品名称
  123. itemOrder.put("quantity", "1");//商品数量
  124. itemOrder.put("sku_id", "1"); //商品 skuId
  125. itemOrder.put("unit_price", orderAmountStr);//商品单价
  126. itemOrderList.add(itemOrder);
  127. jsonBody.put("item_order_list", itemOrderList);
  128. JSONObject extInfo = new JSONObject();
  129. extInfo.put("hospital", hospitalName);//医院名称
  130. extInfo.put("hospital_register_id", hospitalRegId);//医院登记号
  131. extInfo.put("department", deptName);//就诊科室
  132. extInfo.put("dept_num", "");//诊室编号
  133. extInfo.put("dept_loc", deptLoc);//科室位置
  134. extInfo.put("navigation", "");//导航地址
  135. extInfo.put("doctor", doctorName);//医生名称
  136. extInfo.put("doctor_rank", "");//医生职级
  137. extInfo.put("doctor_id", doctorId);//医生 id
  138. extInfo.put("doctor_avatar", "");//医生头像 url
  139. extInfo.put("patient", patientName);//就诊人 必须与 buy_id 对 应的姓名一致
  140. extInfo.put("scheduled_time", regDate);//预约时间
  141. extInfo.put("take_num_url", "");//取号入口
  142. extInfo.put("take_num_password", "");//取号密码
  143. extInfo.put("call_num_url", "");//叫号进度入口
  144. extInfo.put("medical_order_id", "");//就诊单id
  145. extInfo.put("medical_num", "");//就诊/检 查序号
  146. extInfo.put("merchant_order_link_page", mpPath);//订单链接
  147. jsonBody.put("ext_info", extInfo);
  148. sendIntelliMsg(appId, alipayUid, jsonBody, hospitalPid, tenantAppId);
  149. }
  150. }