VipCardLogServiceImpl.java 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487
  1. package beilv.vipCardLog.service.impl;
  2. import beilv.admissionticket.domain.AdmissionTicket;
  3. import beilv.admissionticket.mapper.AdmissionTicketMapper;
  4. import beilv.admissionticket.service.IAdmissionTicketService;
  5. import beilv.carinformation.domain.CarInformation;
  6. import beilv.carinformation.service.ICarInformationService;
  7. import beilv.common.core.domain.AjaxResult;
  8. import beilv.common.core.text.Convert;
  9. import beilv.common.utils.DateUtils;
  10. import beilv.common.utils.DictUtils;
  11. import beilv.common.utils.StringUtils;
  12. import beilv.common.utils.uuid.IdUtils;
  13. import beilv.competition.domain.Competition;
  14. import beilv.competition.service.ICompetitionService;
  15. import beilv.system.service.ISysConfigService;
  16. import beilv.usermembershipcard.domain.UserMembershipCard;
  17. import beilv.usermembershipcard.service.IUserMembershipCardService;
  18. import beilv.vipCard.domain.VipCard;
  19. import beilv.vipCard.service.IVipCardService;
  20. import beilv.vipCardAmountLog.domain.VipCardAmountLog;
  21. import beilv.vipCardAmountLog.mapper.VipCardAmountLogMapper;
  22. import beilv.vipCardLog.domain.VipCardLog;
  23. import beilv.vipCardLog.mapper.VipCardLogMapper;
  24. import beilv.vipCardLog.service.IVipCardLogService;
  25. import beilv.voucher.domain.BeilvVoucherMember;
  26. import beilv.voucher.mapper.BeilvVoucherMemberMapper;
  27. import org.apache.commons.collections4.MapUtils;
  28. import org.checkerframework.checker.units.qual.A;
  29. import org.springframework.beans.factory.annotation.Autowired;
  30. import org.springframework.data.redis.core.StringRedisTemplate;
  31. import org.springframework.stereotype.Service;
  32. import javax.annotation.Resource;
  33. import java.math.BigDecimal;
  34. import java.math.RoundingMode;
  35. import java.text.SimpleDateFormat;
  36. import java.time.LocalDateTime;
  37. import java.time.format.DateTimeFormatter;
  38. import java.time.temporal.ChronoUnit;
  39. import java.util.List;
  40. import java.util.Map;
  41. import static beilv.competition.domain.Constant.ORDER_QUEUE;
  42. /**
  43. * 充值记录Service业务层处理
  44. *
  45. * @author LG
  46. * @date 2025-11-12
  47. */
  48. @Service
  49. public class VipCardLogServiceImpl implements IVipCardLogService {
  50. @Resource
  51. private VipCardLogMapper vipCardLogMapper;
  52. @Autowired
  53. private IVipCardService vipCardService;
  54. @Autowired
  55. private ICompetitionService competitionService;
  56. @Autowired
  57. private IUserMembershipCardService userMembershipCardService;
  58. @Autowired
  59. private ICarInformationService carInformationService;
  60. @Autowired
  61. private IAdmissionTicketService ticketService;
  62. @Autowired
  63. private ISysConfigService configService;
  64. @Resource
  65. private VipCardAmountLogMapper amountLogMapper;
  66. @Autowired
  67. private StringRedisTemplate stringRedisTemplate;
  68. @Autowired
  69. private BeilvVoucherMemberMapper beilvVoucherMemberMapper;
  70. /**
  71. * 查询充值记录
  72. *
  73. * @param id 充值记录主键
  74. * @return 充值记录
  75. */
  76. @Override
  77. public VipCardLog selectVipCardLogById(String id) {
  78. return vipCardLogMapper.selectVipCardLogById(id);
  79. }
  80. /**
  81. * 查询充值记录列表
  82. *
  83. * @param vipCardLog 充值记录
  84. * @return 充值记录
  85. */
  86. @Override
  87. public List<VipCardLog> selectVipCardLogList(VipCardLog vipCardLog) {
  88. List<VipCardLog> list = vipCardLogMapper.selectVipCardLogList(vipCardLog);
  89. Map<String, String> orderType = DictUtils.getDictCacheToMap("order_type");
  90. Map<String, String> paymentStatus = DictUtils.getDictCacheToMap("payment_status");
  91. Map<String, String> paymentType = DictUtils.getDictCacheToMap("payment_type");
  92. for (VipCardLog var : list) {
  93. var.setOrderTypeText(MapUtils.getString(orderType, var.getOrderType()));
  94. var.setPaymentStatusText(MapUtils.getString(paymentStatus, var.getPaymentStatus()));
  95. var.setPaymentTypeText(MapUtils.getString(paymentType, var.getPaymentType()));
  96. }
  97. return list;
  98. }
  99. /**
  100. * 新增充值记录
  101. *
  102. * @param vipCardLog 充值记录
  103. * @return 结果
  104. */
  105. @Override
  106. public int insertVipCardLog(VipCardLog vipCardLog) {
  107. return vipCardLogMapper.insertVipCardLog(vipCardLog);
  108. }
  109. /**
  110. * 修改充值记录
  111. *
  112. * @param vipCardLog 充值记录
  113. * @return 结果
  114. */
  115. @Override
  116. public int updateVipCardLog(VipCardLog vipCardLog) {
  117. return vipCardLogMapper.updateVipCardLog(vipCardLog);
  118. }
  119. /**
  120. * 批量删除充值记录
  121. *
  122. * @param ids 需要删除的充值记录主键
  123. * @return 结果
  124. */
  125. @Override
  126. public int deleteVipCardLogByIds(String ids) {
  127. return vipCardLogMapper.deleteVipCardLogByIds(Convert.toStrArray(ids));
  128. }
  129. /**
  130. * 删除充值记录信息
  131. *
  132. * @param id 充值记录主键
  133. * @return 结果
  134. */
  135. @Override
  136. public int deleteVipCardLogById(String id) {
  137. return vipCardLogMapper.deleteVipCardLogById(id);
  138. }
  139. @Override
  140. public int updateVipCardLogByOrderId(VipCardLog vipCardLog) {
  141. //验证订单编号是否为空
  142. if (StringUtils.isEmpty(vipCardLog.getId())) {
  143. return 0;
  144. }
  145. //拉去订单信息
  146. VipCardLog orderInfo = vipCardLogMapper.selectVipCardLogById(vipCardLog.getId());
  147. //充值订单和其他订单处理方式不同
  148. if ("chongzhi".equals(orderInfo.getOrderType())) {
  149. charging(vipCardLog, orderInfo);
  150. } else {
  151. other(vipCardLog, orderInfo);
  152. }
  153. //更新订单状态
  154. return vipCardLogMapper.updateVipCardLog(vipCardLog);
  155. }
  156. /**
  157. * 充值回调
  158. *
  159. * @param vipCardLog 订单请求信息
  160. * @param orderInfo 原订单信息
  161. * @return
  162. */
  163. private void charging(VipCardLog vipCardLog, VipCardLog orderInfo) {
  164. if ("payment_status_have_paid".equals(vipCardLog.getPaymentStatus())) {
  165. //拉取订单信息
  166. // VipCardLog orderInfo = vipCardLogMapper.selectVipCardLogById(vipCardLog.getId());
  167. //获取会员卡信息
  168. VipCard vipCard = vipCardService.selectVipCardByUserId(orderInfo.getUserId());
  169. //获取当前余额
  170. BigDecimal balance = BigDecimal.ZERO;
  171. String vipCardId;
  172. if (null == vipCard) {
  173. //true 没有会员卡; 新增会员卡, 并且设置本次充值金额
  174. vipCardId = vipCardService.insertVipCard(new VipCard(Long.parseLong(orderInfo.getUserId()), orderInfo.getOriginalPrice(), BigDecimal.ZERO));
  175. } else {
  176. balance = vipCard.getBalance();
  177. vipCardId = vipCard.getId();
  178. //false 有会员卡,
  179. vipCardService.updateVipCard(new VipCard(Long.parseLong(orderInfo.getUserId()), orderInfo.getOriginalPrice().add(vipCard.getBalance()).setScale(2, RoundingMode.HALF_UP), vipCard.getScore()));
  180. }
  181. //设定支付时间
  182. vipCardLog.setPaymentTime(DateUtils.getNowDate());
  183. //写入会员卡流水
  184. insertAmountLog(new VipCardAmountLog(orderInfo.getUserId(), vipCardId, orderInfo.getId(), balance, orderInfo.getOriginalPrice(), "1"));
  185. //支付成功移除定时任务
  186. stringRedisTemplate.delete(ORDER_QUEUE + orderInfo.getId());
  187. } else if ("payment_status_cancelled".equals(vipCardLog.getPaymentStatus())) {
  188. //如果是取消, 设置支付状态为取消支付
  189. vipCardLog.setCancellationTime(DateUtils.getNowDate());
  190. }
  191. }
  192. /**
  193. * 其他支付回调
  194. *
  195. * @param vipCardLog
  196. * @return
  197. */
  198. private void other(VipCardLog vipCardLog, VipCardLog orderInfo) {
  199. //拉取订单信息
  200. // VipCardLog orderInfo = vipCardLogMapper.selectVipCardLogById(vipCardLog.getId());
  201. if ("payment_status_have_paid".equals(vipCardLog.getPaymentStatus())) {
  202. //支付成功流程
  203. //设置支付时间
  204. vipCardLog.setPaymentTime(DateUtils.getNowDate());
  205. //获取订单类型
  206. String orderType = orderInfo.getOrderType();
  207. if ("gouka".equals(orderType)) {
  208. //如果是购买次卡订单, 拉去卡种信息
  209. CarInformation carInformation = carInformationService.selectCarInformationById(Long.valueOf(orderInfo.getBusId()));
  210. //购卡订单, 支付成功, 生成卡片写入到次卡表
  211. userMembershipCardService.insertUserMembershipCard(new UserMembershipCard(orderInfo.getUserId(), vipCardLog.getId(), carInformation.getTotalNumber(), "0", "3", DateUtils.getNowDate(), orderInfo.getBusId()));
  212. }
  213. if ("yueqiu".equals(orderType)) {
  214. //如果是约球订单
  215. AdmissionTicket admissionTicket = new AdmissionTicket();
  216. admissionTicket.setId(orderInfo.getBusId());
  217. //创建场次定时任务, 到时间自动核销
  218. ticketService.createTask(admissionTicket);
  219. }
  220. } else if ("payment_status_cancelled".equals(vipCardLog.getPaymentStatus())) {
  221. //如果是取消订单,设置支付状态为取消支付
  222. vipCardLog.setCancellationTime(DateUtils.getNowDate());
  223. if ("yueqiu".equals(orderInfo.getOrderType())) {
  224. //如果是约球订单, 修改球场信息
  225. AdmissionTicket admissionTicket = new AdmissionTicket();
  226. admissionTicket.setId(orderInfo.getBusId());
  227. admissionTicket.setAdmissionTicketStatus("0");
  228. ticketService.updateBeilvAdmissionTicket(admissionTicket);
  229. }
  230. }
  231. }
  232. @Override
  233. public int getRegistrantsNumber(VipCardLog vipCardLog) {
  234. return vipCardLogMapper.getRegistrantsNumber(vipCardLog);
  235. }
  236. @Override
  237. public AjaxResult refundById(VipCardLog vipCardLog, boolean isOnline, boolean executeUpdate) {
  238. if (StringUtils.isEmpty(vipCardLog.getId())) {
  239. return AjaxResult.error("订单编号不能为空!");
  240. }
  241. //拉去订单信息
  242. VipCardLog orderInfo = vipCardLogMapper.selectVipCardLogById(vipCardLog.getId());
  243. if ("payment_status_to_be_paid".equals(orderInfo.getPaymentStatus())) {
  244. return AjaxResult.error("订单未支付, 无需退款!");
  245. }
  246. if ("payment_status_cancelled".equals(orderInfo.getPaymentStatus())) {
  247. return AjaxResult.error("订单已取消, 无需退款!");
  248. }
  249. if ("payment_status_refunded".equals(orderInfo.getPaymentStatus())) {
  250. return AjaxResult.error("订单已退款, 无需重复操作!");
  251. }
  252. if ("payment_status_verification".equals(orderInfo.getPaymentStatus())) {
  253. return AjaxResult.error("订单已核销, 无法退款!");
  254. }
  255. //退款金额
  256. BigDecimal refundPrice = BigDecimal.valueOf(0);
  257. int refundSum = 0;
  258. if ("yueqiu".equals(orderInfo.getOrderType())) {
  259. if (isOnline) {
  260. // 获取设定的取消时间范围(分钟)
  261. long cancelMinutes = Long.parseLong(configService.selectConfigByKey("cancel.minutes"));
  262. // 根据订单获取约场的开始时间
  263. AdmissionTicket admissionTicket = ticketService.selectBeilvAdmissionTicketById(orderInfo.getBusId());
  264. String format = new SimpleDateFormat("yyyy-MM-dd").format(admissionTicket.getTicketDate());
  265. String startTime = admissionTicket.getSession().split("-")[0]; // 10:00
  266. // 当前时间
  267. LocalDateTime now = LocalDateTime.now();
  268. // 定义日期时间格式器
  269. DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
  270. if (startTime.length() == 4) {
  271. startTime = "0" + startTime; // 将 8:00 补充成 08:00
  272. }
  273. // 将 startTime 转换为 LocalDateTime
  274. LocalDateTime startDateTime = LocalDateTime.parse(format + " " + startTime, formatter);
  275. // 计算 startTime 减去 cancelMinutes 后的时间
  276. LocalDateTime cancelTime = startDateTime.minus(cancelMinutes, ChronoUnit.MINUTES);
  277. // 判断当前时间是否可以退款
  278. if (cancelTime.isBefore(now)) {
  279. return AjaxResult.error("距离开场不足" + cancelMinutes + "分钟, 不允许线上退款!如需退款请线下联系工作人员!");
  280. }
  281. }
  282. if ("numCard".equals(orderInfo.getPaymentType())) {
  283. refundSum++;
  284. } else {
  285. refundPrice = refundPrice.add(orderInfo.getPracticalMoney());
  286. }
  287. } else if ("gouka".equals(orderInfo.getOrderType())) {
  288. //根据订单id查询会员卡, 用会员卡id验证是否存在未核销的订单, 如果存在不允许退卡.
  289. if(vipCardLogMapper.hasOrderHavePaid(orderInfo.getId())){
  290. return AjaxResult.error("次卡存在未核销订单, 无法退款!");
  291. }
  292. //拿到次卡信息, 得到剩余使用次数
  293. UserMembershipCard userMembershipCard = userMembershipCardService.selectUserMembershipCardRecordId(orderInfo.getId());
  294. //获取原价信息
  295. CarInformation carInformation = carInformationService.selectCarInformationById(Long.valueOf(orderInfo.getBusId()));
  296. //计算已使用次数
  297. BigDecimal useSum = BigDecimal.valueOf(carInformation.getTotalNumber() - userMembershipCard.getRemainingNumber());
  298. //计算需要支付的金额 = 原价 / 总次数(直接截断,不进行四舍五入) * 已使用次数
  299. BigDecimal userPrice = carInformation.getOriginalPrice().divide(BigDecimal.valueOf(carInformation.getTotalNumber()), 2, RoundingMode.DOWN).multiply(useSum);
  300. //实际支付的金额 - 需要支付的金额 = 退款金额
  301. BigDecimal refundMoner = orderInfo.getPracticalMoney().subtract(userPrice);
  302. //判断如果退款金额 不大于0, 则设置退款金额为0
  303. refundMoner = refundMoner.compareTo(BigDecimal.ZERO) > 0 ? refundMoner : BigDecimal.ZERO;
  304. //计算退款金额
  305. refundPrice = refundPrice.add(refundMoner);
  306. userMembershipCard.setState("2");
  307. userMembershipCardService.updateUserMembershipCard(userMembershipCard);
  308. } else if ("cansai".equals(orderInfo.getOrderType()) || "menpiao".equals(orderInfo.getOrderType())) {
  309. //验证赛事状态, 已经开始/已经结束/已经关闭 无法退款
  310. Competition competition = competitionService.selectCompetitionById(Integer.valueOf(orderInfo.getBusId()));
  311. if ("competiton_state_5".equals(competition.getCompetitionState())) {
  312. return AjaxResult.error("赛事已开始, 无法退票!");
  313. }
  314. if ("competiton_state_6".equals(competition.getCompetitionState())) {
  315. return AjaxResult.error("赛事已结束, 无法退票!");
  316. }
  317. if ("competiton_state_3".equals(competition.getCompetitionState())) {
  318. return AjaxResult.error("报名已结束, 无法退票!");
  319. }
  320. if ("competiton_state_4".equals(competition.getCompetitionState())) {
  321. return AjaxResult.error("赛事已关闭, 无法退票!");
  322. }
  323. //计算退款金额
  324. refundPrice = refundPrice.add(orderInfo.getPracticalMoney());
  325. } else if ("chongzhi".equals(orderInfo.getOrderType())) {
  326. refundPrice = orderInfo.getPracticalMoney();
  327. }
  328. vipCardLog.setRefundPrice(refundPrice);
  329. orderInfo.setRefundPrice(refundPrice);
  330. //使用钱包支付的订单, 不走我微信退款
  331. if (!"weChart".equals(orderInfo.getPaymentType())) {
  332. executeUpdate = true;
  333. }
  334. // executeUpdate=true 时才执行更新操作(包括订单状态、会员卡余额、次卡次数等)
  335. if (executeUpdate) {
  336. if ("vipCard".equals(orderInfo.getPaymentType())) {
  337. //查询会员卡信息
  338. VipCard vipCard = vipCardService.selectVipCardById(orderInfo.getPaymentId());
  339. //写入会员卡流水
  340. VipCardAmountLog vipCardAmountLog = new VipCardAmountLog(orderInfo.getUserId(), orderInfo.getPaymentId(), orderInfo.getId(), vipCard.getBalance(), refundPrice, "1");
  341. amountLogMapper.insertVipCardAmountLog(vipCardAmountLog);
  342. vipCard.setBalance(vipCardAmountLog.getRemainingAmount());
  343. vipCardService.updateVipCard(vipCard);
  344. } else if ("numCard".equals(orderInfo.getPaymentType())) {
  345. //查询次卡信息
  346. UserMembershipCard userMembershipCard = userMembershipCardService.selectUserMembershipCardById(Long.valueOf(orderInfo.getPaymentId()));
  347. //剩余使用次数+1
  348. userMembershipCard.setRemainingNumber(userMembershipCard.getRemainingNumber() + refundSum);
  349. //更新次卡信息
  350. userMembershipCardService.updateUserMembershipCard(userMembershipCard);
  351. } else if ("chongzhi".equals(orderInfo.getOrderType())) {
  352. VipCard vipCard = vipCardService.selectVipCardByUserId(orderInfo.getUserId());
  353. // 检查余额是否足够退款
  354. if (vipCard.getBalance().compareTo(orderInfo.getOriginalPrice()) < 0) {
  355. return AjaxResult.error("会员卡余额不足,无法完成退款,请前往柜台联系客服!");
  356. }
  357. vipCard.setBalance(vipCard.getBalance().subtract(orderInfo.getOriginalPrice()));
  358. vipCardService.updateVipCard(vipCard);
  359. }
  360. vipCardLog.setRefundTime(DateUtils.getNowDate());
  361. vipCardLog.setPaymentStatus("payment_status_refunded");
  362. vipCardLogMapper.updateVipCardLog(vipCardLog);
  363. // 如果是约球订单,更新场次状态
  364. if ("yueqiu".equals(orderInfo.getOrderType())) {
  365. AdmissionTicket admissionTicket = new AdmissionTicket();
  366. admissionTicket.setId(orderInfo.getBusId());
  367. admissionTicket.setAdmissionTicketStatus("0");
  368. ticketService.updateBeilvAdmissionTicket(admissionTicket);
  369. }
  370. //如果使用了优惠券,释放优惠券
  371. if (StringUtils.isNotEmpty(orderInfo.getVoucherId())) {
  372. beilvVoucherMemberMapper.updateBeilvVoucherMember(new BeilvVoucherMember(Long.parseLong(orderInfo.getVoucherId()), "1"));
  373. }
  374. return AjaxResult.success("退款成功!");
  375. }
  376. // executeUpdate=false 时只返回计算结果,不更新任何状态
  377. return AjaxResult.success(orderInfo);
  378. }
  379. @Override
  380. public List<Map<String, Object>> selectYueQiuList(VipCardLog vipCardLog) {
  381. vipCardLog.setOrderType("yueqiu");
  382. Map<String, String> orderType = DictUtils.getDictCacheToMap("order_type");
  383. Map<String, String> paymentStatus = DictUtils.getDictCacheToMap("payment_status");
  384. Map<String, String> paymentType = DictUtils.getDictCacheToMap("payment_type");
  385. List<Map<String, Object>> maps = vipCardLogMapper.selectYueQiuList(vipCardLog);
  386. maps.forEach(map -> {
  387. map.put("orderTypeLabel", MapUtils.getString(orderType, MapUtils.getString(map, "orderType")));
  388. map.put("paymentStatusLabel", MapUtils.getString(paymentStatus, MapUtils.getString(map, "paymentStatus")));
  389. map.put("paymentTypeLabel", MapUtils.getString(paymentType, MapUtils.getString(map, "paymentType")));
  390. map.put("createTime", MapUtils.getString(map, "createTime").replace("T", " "));
  391. map.put("paymentTime", MapUtils.getString(map, "paymentTime").replace("T", " "));
  392. });
  393. return maps;
  394. }
  395. @Override
  396. public List<Map<String, Object>> selectCanSaiList(VipCardLog vipCardLog) {
  397. List<Map<String, Object>> maps = vipCardLogMapper.selectCanSaiList(vipCardLog);
  398. Map<String, String> orderType = DictUtils.getDictCacheToMap("order_type");
  399. Map<String, String> paymentType = DictUtils.getDictCacheToMap("payment_type");
  400. Map<String, String> competitionState = DictUtils.getDictCacheToMap("competition_state");
  401. Map<String, String> paymentStatus = DictUtils.getDictCacheToMap("payment_status");
  402. maps.forEach(map -> {
  403. map.put("orderTypeLabel", MapUtils.getString(orderType, MapUtils.getString(map, "orderType")));
  404. map.put("paymentTypeLabel", MapUtils.getString(paymentType, MapUtils.getString(map, "paymentType")));
  405. map.put("competitionStateLabel", MapUtils.getString(competitionState, MapUtils.getString(map, "competitionState")));
  406. map.put("paymentStatusLabel", MapUtils.getString(paymentStatus, MapUtils.getString(map, "paymentStatus")));
  407. map.put("publishTime", MapUtils.getString(map, "publishTime").replace("T", " "));
  408. map.put("applyEndTime", MapUtils.getString(map, "applyEndTime").replace("T", " "));
  409. map.put("applyStartTime", MapUtils.getString(map, "applyStartTime").replace("T", " "));
  410. map.put("createTime", MapUtils.getString(map, "createTime").replace("T", " "));
  411. map.put("paymentTime", MapUtils.getString(map, "paymentTime").replace("T", " "));
  412. });
  413. return maps;
  414. }
  415. public void insertAmountLog(VipCardAmountLog vipCardAmountLog) {
  416. amountLogMapper.insertVipCardAmountLog(vipCardAmountLog);
  417. }
  418. }