OrderNotificationServiceImpl.java 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. package com.ylx.massage.service.impl;
  2. import cn.hutool.json.JSONUtil;
  3. import com.alibaba.fastjson.JSONObject;
  4. import com.ylx.common.config.WechatAccountConfig;
  5. import com.ylx.massage.domain.TJs;
  6. import com.ylx.massage.domain.TOrder;
  7. import com.ylx.massage.domain.TXiangmu;
  8. import com.ylx.massage.service.OrderNotificationService;
  9. import com.ylx.massage.service.TJsService;
  10. import com.ylx.massage.utils.DateTimeUtils;
  11. import com.ylx.massage.utils.WeChatUtil;
  12. import lombok.extern.slf4j.Slf4j;
  13. import org.springframework.stereotype.Service;
  14. import javax.annotation.Resource;
  15. import java.time.LocalDateTime;
  16. import java.time.ZoneId;
  17. import java.util.Date;
  18. import java.util.List;
  19. /**
  20. * 订单消息通知服务实现类
  21. * <p>
  22. * 负责处理订单生命周期中各阶段的消息通知功能。
  23. * 所有通知通过微信公众号模板消息推送给用户。
  24. * </p>
  25. *
  26. * @author ylx
  27. * @version 1.0
  28. * @since 2024
  29. */
  30. @Service
  31. @Slf4j
  32. public class OrderNotificationServiceImpl implements OrderNotificationService {
  33. @Resource
  34. private WeChatUtil weChatUtil;
  35. @Resource
  36. private WechatAccountConfig wxPayProperties;
  37. @Resource
  38. private TJsService jsService;
  39. /**
  40. * 订单待接单提醒(技师侧)
  41. *
  42. * @param order 订单信息
  43. */
  44. @Override
  45. public void sendPendingRemindNotification(TOrder order) {
  46. try {
  47. log.info("订单待接单提醒(技师侧)");
  48. cn.hutool.json.JSONObject param = buildPendingRemindParams(order);
  49. //获取技师openid
  50. TJs js = jsService.getById(order.getcJsId());
  51. weChatUtil.notification(js.getcOpenId(), wxPayProperties.getTechTemplate1(), param);
  52. log.info("订单待接单提醒发送成功,订单号:{}", order.getOrderNo());
  53. } catch (Exception e) {
  54. log.error("订单待接单提醒发送失败,订单号:{}", order.getOrderNo(), e);
  55. }
  56. }
  57. /**
  58. * 订单已接单通知(用户侧)
  59. *
  60. * @param order 订单信息
  61. */
  62. @Override
  63. public void sendReceivedNotification(TOrder order) {
  64. try {
  65. cn.hutool.json.JSONObject param = buildReceivedNotificationParams(order);
  66. weChatUtil.notification(order.getcOpenId(), wxPayProperties.getUserTemplate1(), param);
  67. log.info("订单已接单通知发送成功,订单号:{}", order.getOrderNo());
  68. } catch (Exception e) {
  69. e.printStackTrace();
  70. log.error("订单已接单通知发送失败,订单号:{}", order.getOrderNo(), e);
  71. }
  72. }
  73. /**
  74. * 订单完成通知(用户侧)
  75. *
  76. * @param order 订单信息
  77. */
  78. @Override
  79. public void sendCompletedNotification(TOrder order) {
  80. try {
  81. cn.hutool.json.JSONObject param = buildCompletedNotificationParams(order);
  82. weChatUtil.notification(order.getcOpenId(), wxPayProperties.getUserTemplate2(), param);
  83. log.info("订单完成通知发送成功,订单号:{}", order.getOrderNo());
  84. } catch (Exception e) {
  85. log.error("订单完成通知发送失败,订单号:{}", order.getOrderNo(), e);
  86. }
  87. }
  88. /**
  89. * 订单取消通知(用户侧)
  90. *
  91. * @param order 订单信息
  92. */
  93. @Override
  94. public void sendCancelledNotification(TOrder order) {
  95. try {
  96. cn.hutool.json.JSONObject param = buildCancelledNotificationParams(order);
  97. weChatUtil.notification(order.getcOpenId(), wxPayProperties.getUserTemplate3(), param);
  98. log.info("订单取消通知发送成功,订单号:{}", order.getOrderNo());
  99. } catch (Exception e) {
  100. log.error("订单取消通知发送失败,订单号:{}", order.getOrderNo(), e);
  101. }
  102. }
  103. /**
  104. * 构建待接单提醒消息参数(技师侧)
  105. *
  106. * @param order 订单信息
  107. * @return JSONObject 消息参数
  108. */
  109. private cn.hutool.json.JSONObject buildPendingRemindParams(TOrder order) {
  110. cn.hutool.json.JSONObject param = JSONUtil.createObj();
  111. // 订单号
  112. param.set("character_string9", JSONUtil.createObj().set("value", order.getOrderNo()));
  113. // 用户电话
  114. param.set("phone_number3", JSONUtil.createObj().set("value", order.getcPhone()));
  115. // 项目
  116. String projectNames = getProjectNames(order);
  117. param.set("thing10", JSONUtil.createObj().set("value", projectNames));
  118. // 下单地址
  119. param.set("thing13", JSONUtil.createObj().set("value", order.getAddress()));
  120. // 预约时间
  121. LocalDateTime startTime = order.getStartTime();
  122. if(startTime==null){
  123. // 预约时间为空,设置默认值
  124. startTime = LocalDateTime.now();
  125. }
  126. Date date = Date.from(startTime.atZone(ZoneId.systemDefault()).toInstant());
  127. param.set("time6", JSONUtil.createObj().set("value", DateTimeUtils.formatDate(date, "yyyy-MM-dd HH:mm")));
  128. return param;
  129. }
  130. /**
  131. * 构建已接单通知消息参数
  132. *
  133. * @param order 订单信息
  134. * @return JSONObject 消息参数
  135. */
  136. private cn.hutool.json.JSONObject buildReceivedNotificationParams(TOrder order) {
  137. cn.hutool.json.JSONObject param = JSONUtil.createObj();
  138. // 订单号
  139. param.set("character_string1", JSONUtil.createObj().set("value", order.getOrderNo()));
  140. // 项目名称
  141. String projectNames = getProjectNames(order);
  142. param.set("thing4", JSONUtil.createObj().set("value", projectNames));
  143. //根据技师ID查询技师姓名
  144. TJs js = jsService.getById(order.getcJsId());
  145. String jsName = js.getcName();
  146. // 商家名称
  147. param.set("thing9", JSONUtil.createObj().set("value", jsName));
  148. // 联系电话
  149. param.set("phone_number5", JSONUtil.createObj().set("value", js.getcPhone()));
  150. return param;
  151. }
  152. /**
  153. * 构建完成通知消息参数(用户侧)
  154. *
  155. * @param order 订单信息
  156. * @return JSONObject 消息参数
  157. */
  158. private cn.hutool.json.JSONObject buildCompletedNotificationParams(TOrder order) {
  159. cn.hutool.json.JSONObject param = JSONUtil.createObj();
  160. // 订单号
  161. param.set("character_string8", JSONUtil.createObj().set("value", order.getOrderNo()));
  162. // 项目名称
  163. String projectNames = getProjectNames(order);
  164. param.set("thing19", JSONUtil.createObj().set("value", projectNames));
  165. // 完成时间
  166. LocalDateTime completeTime = order.getEndTime();
  167. Date date = Date.from(completeTime.atZone(ZoneId.systemDefault()).toInstant());
  168. param.set("time18", JSONUtil.createObj().set("value", DateTimeUtils.formatDate(date, "yyyy-MM-dd HH:mm")));
  169. return param;
  170. }
  171. /**
  172. * 构建取消通知消息参数
  173. *
  174. * @param order 订单信息
  175. * @return JSONObject 消息参数
  176. */
  177. private cn.hutool.json.JSONObject buildCancelledNotificationParams(TOrder order) {
  178. cn.hutool.json.JSONObject param = JSONUtil.createObj();
  179. // 订单号
  180. param.set("character_string2", JSONUtil.createObj().set("value", order.getOrderNo()));
  181. // 取消原因
  182. param.set("thing5", JSONUtil.createObj().set("value", "用户个人原因"));
  183. // 项目名称
  184. String projectNames = getProjectNames(order);
  185. param.set("thing25", JSONUtil.createObj().set("value", projectNames));
  186. //订单金额
  187. param.set("amount23", JSONUtil.createObj().set("value", order.getTotalPrice().toString()));
  188. return param;
  189. }
  190. /**
  191. * 从订单明细中提取项目名称
  192. * <p>
  193. * 解析订单的商品列表,将多个项目名称用逗号连接
  194. * </p>
  195. *
  196. * @param order 订单信息
  197. * @return String 项目名称字符串,多个项目用逗号分隔
  198. */
  199. private String getProjectNames(TOrder order) {
  200. List<TXiangmu> list = JSONObject.parseArray(order.getcGoods().toJSONString(), TXiangmu.class);
  201. StringBuilder sb = new StringBuilder();
  202. for (TXiangmu xiangmu : list) {
  203. sb.append(xiangmu.getcTitle()).append(",");
  204. }
  205. // 移除最后一个逗号
  206. if (sb.length() > 0) {
  207. sb.setLength(sb.length() - 1);
  208. }
  209. return sb.toString();
  210. }
  211. /**
  212. * 订单已接单通知(技师侧)
  213. *
  214. * @param order 订单信息
  215. */
  216. @Override
  217. public void sendTechnicianReceivedNotification(TOrder order) {
  218. try {
  219. // 获取技师信息
  220. String jsOpenId = getTechnicianOpenId(order);
  221. log.info("技师的openId:{}", jsOpenId);
  222. if (jsOpenId == null) {
  223. log.warn("技师信息不存在,无法发送已接单通知,订单号:{}", order.getOrderNo());
  224. return;
  225. }
  226. cn.hutool.json.JSONObject param = buildTechnicianReceivedNotificationParams(order);
  227. weChatUtil.notification(jsOpenId, wxPayProperties.getTechTemplate2(), param);
  228. log.info("技师侧已接单通知发送成功,订单号:{}", order.getOrderNo());
  229. } catch (Exception e) {
  230. log.error("技师侧已接单通知发送失败,订单号:{}", order.getOrderNo(), e);
  231. }
  232. }
  233. /**
  234. * 订单取消通知(技师侧)
  235. *
  236. * @param order 订单信息
  237. */
  238. @Override
  239. public void sendTechnicianCancelledNotification(TOrder order) {
  240. try {
  241. // 获取技师的openId
  242. String jsOpenId = getTechnicianOpenId(order);
  243. log.info("技师的openId:{}", jsOpenId);
  244. if (jsOpenId == null) {
  245. log.warn("技师信息不存在,无法发送取消通知,订单号:{}", order.getOrderNo());
  246. return;
  247. }
  248. cn.hutool.json.JSONObject param = buildTechnicianCancelledNotificationParams(order);
  249. weChatUtil.notification(jsOpenId, wxPayProperties.getTechTemplate3(), param);
  250. log.info("技师侧取消订单通知发送成功,订单号:{}", order.getOrderNo());
  251. } catch (Exception e) {
  252. log.error("技师侧取消订单通知发送失败,订单号:{}", order.getOrderNo(), e);
  253. }
  254. }
  255. /**
  256. * 构建技师侧已接单通知消息参数
  257. *
  258. * @param order 订单信息
  259. * @return JSONObject 消息参数
  260. */
  261. private cn.hutool.json.JSONObject buildTechnicianReceivedNotificationParams(TOrder order) {
  262. cn.hutool.json.JSONObject param = JSONUtil.createObj();
  263. // 订单编号
  264. param.set("character_string1", JSONUtil.createObj().set("value", order.getOrderNo()));
  265. // 联系电话
  266. param.set("phone_number5", JSONUtil.createObj().set("value", order.getcPhone()));
  267. // 项目名称
  268. String projectNames = getProjectNames(order);
  269. param.set("thing4", JSONUtil.createObj().set("value", projectNames));
  270. // 预约地址
  271. param.set("thing14", JSONUtil.createObj().set("value", order.getAddress()));
  272. // 预约时间
  273. LocalDateTime dtCreateTime = order.getDtCreateTime();
  274. Date createTime = Date.from(dtCreateTime.atZone(ZoneId.systemDefault()).toInstant());
  275. param.set("time3", JSONUtil.createObj().set("value", DateTimeUtils.formatDate(createTime, "yyyy-MM-dd HH:mm")));
  276. return param;
  277. }
  278. /**
  279. * 构建技师侧取消通知消息参数
  280. *
  281. * @param order 订单信息
  282. * @return JSONObject 消息参数
  283. */
  284. private cn.hutool.json.JSONObject buildTechnicianCancelledNotificationParams(TOrder order) {
  285. cn.hutool.json.JSONObject param = JSONUtil.createObj();
  286. // 订单号
  287. param.set("character_string2", JSONUtil.createObj().set("value", order.getOrderNo()));
  288. // 取消原因
  289. param.set("thing5", JSONUtil.createObj().set("value", getCancelReason(order)));
  290. // 订单金额
  291. param.set("amount23", JSONUtil.createObj().set("value", order.getTotalPrice().toString()));
  292. return param;
  293. }
  294. /**
  295. * 获取技师的 OpenId
  296. *
  297. * @param order 订单信息
  298. * @return String 技师 OpenId,如果技师不存在则返回 null
  299. */
  300. private String getTechnicianOpenId(TOrder order) {
  301. if (order.getcJsId() == null) {
  302. return null;
  303. }
  304. try {
  305. return jsService.getById(order.getcJsId()).getcOpenId();
  306. } catch (Exception e) {
  307. log.error("获取技师信息失败,技师ID:{}", order.getcJsId(), e);
  308. return null;
  309. }
  310. }
  311. /**
  312. * 获取订单取消原因
  313. *
  314. * @param order 订单信息
  315. * @return String 取消原因描述
  316. */
  317. private String getCancelReason(TOrder order) {
  318. // 如果订单中有具体的取消原因,使用订单中的原因
  319. if (order.getReasonRefusal() != null && !order.getReasonRefusal().trim().isEmpty()) {
  320. return order.getReasonRefusal();
  321. }
  322. // 默认取消原因
  323. return "用户取消订单";
  324. }
  325. }