From 1f80d4e479dda938b9e712888082691e437db59b Mon Sep 17 00:00:00 2001 From: "autumn.g@foxmail.com" Date: Wed, 30 Aug 2023 09:54:39 +0800 Subject: [PATCH] update --- .../orderlogic/AbstractOrderLogic.java | 353 +++++++++++++++++- .../orderlogic/DelayMerchantOrderLogic.java | 299 +++++++++++++-- 2 files changed, 624 insertions(+), 28 deletions(-) diff --git a/jsowell-pile/src/main/java/com/jsowell/pile/service/orderlogic/AbstractOrderLogic.java b/jsowell-pile/src/main/java/com/jsowell/pile/service/orderlogic/AbstractOrderLogic.java index a92472d8e..b99489d98 100644 --- a/jsowell-pile/src/main/java/com/jsowell/pile/service/orderlogic/AbstractOrderLogic.java +++ b/jsowell-pile/src/main/java/com/jsowell/pile/service/orderlogic/AbstractOrderLogic.java @@ -1,14 +1,36 @@ package com.jsowell.pile.service.orderlogic; +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONObject; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.jsowell.adapay.service.AdapayService; +import com.jsowell.common.constant.CacheConstants; +import com.jsowell.common.core.domain.ykc.RealTimeMonitorData; import com.jsowell.common.core.domain.ykc.TransactionRecordsData; +import com.jsowell.common.core.redis.RedisCache; +import com.jsowell.common.enums.ykc.OrderPayModeEnum; +import com.jsowell.common.enums.ykc.OrderStatusEnum; +import com.jsowell.common.util.DateUtils; +import com.jsowell.common.util.StringUtils; import com.jsowell.pile.domain.OrderBasicInfo; +import com.jsowell.pile.domain.OrderDetail; +import com.jsowell.pile.domain.OrderMonitorData; +import com.jsowell.pile.domain.OrderPayRecord; import com.jsowell.pile.dto.PayOrderDTO; import com.jsowell.pile.dto.PayOrderSuccessCallbackDTO; -import com.jsowell.pile.service.IOrderBasicInfoService; +import com.jsowell.pile.service.*; +import com.jsowell.pile.transaction.service.TransactionService; import com.jsowell.pile.vo.web.BalanceDeductionAmountVO; +import com.jsowell.wxpay.service.WxAppletRemoteService; +import org.apache.commons.collections4.CollectionUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import javax.annotation.Resource; import java.math.BigDecimal; +import java.math.RoundingMode; import java.util.List; import java.util.Map; @@ -16,8 +38,52 @@ import java.util.Map; * 描述订单逻辑 */ public abstract class AbstractOrderLogic { + protected Logger logger = LoggerFactory.getLogger(this.getClass()); + @Resource - private IOrderBasicInfoService orderBasicInfoService; + protected IOrderBasicInfoService orderBasicInfoService; + + @Autowired + protected IMemberBasicInfoService memberBasicInfoService; + + @Autowired + protected MemberAdapayRecordService memberAdapayRecordService; + + @Autowired + protected OrderPayRecordService orderPayRecordService; + + @Autowired + protected IMemberTransactionRecordService memberTransactionRecordService; + + @Autowired + protected AdapayService adapayService; + + @Autowired + protected IAdapayMemberAccountService adapayMemberAccountService; + + @Autowired + protected IPileMerchantInfoService pileMerchantInfoService; + + @Autowired + protected TransactionService transactionService; + + @Autowired + protected AdapayCallbackRecordService adapayCallbackRecordService; + + @Autowired + protected IPileAuthCardService pileAuthCardService; + + @Autowired + protected IMemberPlateNumberRelationService memberPlateNumberRelationService; + + @Autowired + protected WxAppletRemoteService wxAppletRemoteService; + + @Autowired + protected OrderMonitorDataService orderMonitorDataService; + + @Autowired + protected RedisCache redisCache; /** * 余额支付订单 @@ -42,7 +108,7 @@ public abstract class AbstractOrderLogic { /** * 余额支付订单退款 */ - public abstract void balancePayOrderRefund(OrderBasicInfo orderBasicInfo); + public abstract void balancePaymentOrderRefund(OrderBasicInfo orderBasicInfo); /** * 在线支付订单退款 @@ -62,4 +128,285 @@ public abstract class AbstractOrderLogic { protected List calculateTheBalanceDeductionAmount(String memberId, BigDecimal amount) { return orderBasicInfoService.calculateTheBalanceDeductionAmount(memberId, amount); } + + /** + * 返回更新后的OrderBasicInfo对象 + * 专用方法,其他地方如果要用请仔细检查 + * 【公共方法】 + */ + protected void returnUpdateOrderBasicInfo(OrderBasicInfo orderBasicInfo, TransactionRecordsData data) { + // 订单编号 + String orderCode = orderBasicInfo.getOrderCode(); + // 消费金额就是订单总金额/交易记录传过来的消费金额 + BigDecimal orderAmount = new BigDecimal(data.getConsumptionAmount()); + // 付款金额 - 实际消费金额,如果有剩余,需要走退款操作 当使用余额支付时payAmount = principalPay + giftPay + BigDecimal payAmount = orderBasicInfo.getPayAmount(); + + // 有时候充电桩到达金额停止充电会多出一点金额,比如实际需要充50元的电,充电桩传来的消费金额为50.01元,在后台记录的时候需要舍去 + if (orderAmount.compareTo(payAmount) > 0) { + logger.info("结算订单:【{}】充电桩传来的消费金额:【{}】大于付款金额:【{}】, 消费金额设置为付款金额相等数据", orderCode, orderAmount, payAmount); + orderAmount = payAmount; + } + orderBasicInfo.setOrderAmount(orderAmount); // 订单总金额 + + // 虚拟金额 指订单消费中不参与结算的部分 + BigDecimal virtualAmount = BigDecimal.ZERO; + if (OrderPayModeEnum.PAYMENT_OF_WHITELIST.getValue().equals(orderBasicInfo.getPayMode())) { + // 白名单支付所消费的金额,都属于虚拟金额,不参与结算对账 + virtualAmount = new BigDecimal(orderAmount.toString()); + } + + // 剩余需要退回的金额 residue + BigDecimal residue = payAmount.subtract(orderAmount); + + // 把交易记录中的用电量,金额等信息 更新到orderBasicInfo和orderDetail + orderBasicInfo.setVirtualAmount(virtualAmount); // 虚拟金额 + orderBasicInfo.setSettleAmount(orderAmount.subtract(virtualAmount)); // 结算金额 + orderBasicInfo.setOrderStatus(OrderStatusEnum.ORDER_COMPLETE.getValue()); + orderBasicInfo.setReason(data.getStopReasonMsg()); // 充电停止原因 + orderBasicInfo.setSettlementTime(DateUtils.getNowDate()); // 结算时间 + orderBasicInfo.setRefundAmount(residue); // 结算退款金额 + } + + /** + * 获取更新数据后的orderDetail对象 + * 专用方法,其他地方如果要用请仔细检查 + * 【公共方法】 + * @return 查询并更新过数据的orderDetail + */ + protected OrderDetail returnUpdateOrderDetail(OrderBasicInfo orderBasicInfo, TransactionRecordsData data) { + String orderCode = orderBasicInfo.getOrderCode(); + BigDecimal orderAmount = orderBasicInfo.getOrderAmount(); + // 更新订单详情 查询订单详情 修改订单数据 + OrderDetail orderDetail = orderBasicInfoService.getOrderDetailByOrderCode(orderCode); + try { + // 总电费金额 + BigDecimal totalElectricityAmount = BigDecimal.ZERO; + + // 尖时段用电量 + String sharpUsedElectricity = data.getSharpUsedElectricity(); + if (sharpUsedElectricity != null) { + orderDetail.setSharpUsedElectricity(new BigDecimal(sharpUsedElectricity)); + if (data.getSharpPrice() != null) { + orderDetail.setSharpPrice(new BigDecimal(data.getSharpPrice())); + } + if (data.getSharpAmount() != null) { + orderDetail.setSharpAmount(new BigDecimal(data.getSharpAmount())); + } + // 计算该时段电费 + BigDecimal multiply = orderDetail.getSharpElectricityPrice() + .multiply(new BigDecimal(sharpUsedElectricity)) + .setScale(2, RoundingMode.DOWN); + totalElectricityAmount = totalElectricityAmount.add(multiply); + } + + // 峰时段用电量 + String peakUsedElectricity = data.getPeakUsedElectricity(); + if (peakUsedElectricity != null) { + orderDetail.setPeakUsedElectricity(new BigDecimal(peakUsedElectricity)); + if (data.getPeakPrice() != null) { + orderDetail.setPeakPrice(new BigDecimal(data.getPeakPrice())); + } + if (data.getPeakAmount() != null) { + orderDetail.setPeakAmount(new BigDecimal(data.getPeakAmount())); + } + // 计算该时段电费 + BigDecimal multiply = orderDetail.getPeakElectricityPrice() + .multiply(new BigDecimal(peakUsedElectricity)) + .setScale(2, RoundingMode.DOWN); + totalElectricityAmount = totalElectricityAmount.add(multiply); + } + + // 平时段用电量 + String flatUsedElectricity = data.getFlatUsedElectricity(); + if (flatUsedElectricity != null) { + orderDetail.setFlatUsedElectricity(new BigDecimal(flatUsedElectricity)); + if (data.getFlatPrice() != null) { + orderDetail.setFlatPrice(new BigDecimal(data.getFlatPrice())); + } + if (data.getFlatAmount() != null) { + orderDetail.setFlatAmount(new BigDecimal(data.getFlatAmount())); + } + // 计算该时段电费 + BigDecimal multiply = orderDetail.getFlatElectricityPrice() + .multiply(new BigDecimal(flatUsedElectricity)) + .setScale(2, RoundingMode.DOWN); + totalElectricityAmount = totalElectricityAmount.add(multiply); + } + + // 谷时段用电量 + String valleyUsedElectricity = data.getValleyUsedElectricity(); + if (valleyUsedElectricity != null) { + orderDetail.setValleyUsedElectricity(new BigDecimal(valleyUsedElectricity)); + if (data.getValleyPrice() != null) { + orderDetail.setValleyPrice(new BigDecimal(data.getValleyPrice())); + } + if (data.getValleyAmount() != null) { + orderDetail.setValleyAmount(new BigDecimal(data.getValleyAmount())); + } + // 计算该时段电费 + BigDecimal multiply = orderDetail.getValleyElectricityPrice() + .multiply(new BigDecimal(valleyUsedElectricity)) + .setScale(2, RoundingMode.DOWN); + totalElectricityAmount = totalElectricityAmount.add(multiply); + } + + // 如果算出来的电费金额大于总消费金额,则电费金额等于总消费金额 + if (totalElectricityAmount.compareTo(orderAmount) > 0) { + totalElectricityAmount = orderAmount; + } + orderDetail.setTotalElectricityAmount(totalElectricityAmount); + orderDetail.setTotalServiceAmount(orderAmount.subtract(totalElectricityAmount)); + orderDetail.setTotalUsedElectricity(new BigDecimal(data.getTotalElectricity())); // 总用电量 + orderDetail.setTotalOrderAmount(orderAmount); // 订单总金额 + } catch (Exception e) { + logger.error("设置订单详情参数发生异常", e); + } + return orderDetail; + } + + /** + * 余额支付 计算需要退回的金额 + * 【公共方法】 + * @param principalPay 本金支付金额 + * @param giftPay 赠送金额支付的金额 + * @param orderAmount 订单消费金额 + * @return + */ + protected Map calculateReturnAmount(BigDecimal principalPay, BigDecimal giftPay, BigDecimal orderAmount) { + Map resultMap = Maps.newHashMap(); + + // 消费金额优先使用本金 + BigDecimal returnPrincipal = null; // 退回本金金额 + BigDecimal returnGift = null; // 退回赠送金额 + + // 余额支付 有3种情况 + if (principalPay != null && giftPay == null) { + // 只有本金支付 + BigDecimal subtract = principalPay.subtract(orderAmount); + if (subtract.compareTo(BigDecimal.ZERO) > 0) { + returnPrincipal = subtract; + } + } + if (principalPay == null && giftPay != null) { + // 只有赠送金额支付 + BigDecimal subtract = giftPay.subtract(orderAmount); + if (subtract.compareTo(BigDecimal.ZERO) > 0) { + returnGift = subtract; + } + } + if (principalPay != null && giftPay != null) { + // 本金+赠送支付 + BigDecimal subtract = principalPay.subtract(orderAmount); + if (subtract.compareTo(BigDecimal.ZERO) > 0) { + // 本金减掉订单金额后还有剩余,那就把剩余的退回,赠送原封不动退回 + returnPrincipal = subtract; + returnGift = giftPay; + } else if (subtract.compareTo(BigDecimal.ZERO) == 0) { + // 本金刚好够,那赠送金额支付的原封不动退回 + returnGift = giftPay; + } else { + returnGift = giftPay.subtract(subtract.negate()); + } + } + + resultMap.put("returnPrincipal", returnPrincipal); + resultMap.put("returnGift", returnGift); + return resultMap; + } + + /** + * 计算解冻金额 + * @param orderAmount 订单消费金额 + * @param payRecordList 订单支付记录 + */ + protected List> calculateUnfreezeAmount(BigDecimal orderAmount, List payRecordList) { + List> resultList = Lists.newArrayList(); + + BigDecimal tempAmount = new BigDecimal(orderAmount.toString()); // 临时金额 + for (OrderPayRecord record : payRecordList) { + JSONObject jsonObject = JSON.parseObject(record.getDeductionRecord()); + String paymentId = jsonObject.getString("paymentId"); + BigDecimal payAmount = record.getPayAmount(); // 此交易单支付的金额 + // 该笔支付扣除金额 + BigDecimal deductionAmount; + // 该笔支付解冻金额 + BigDecimal unfreezeAmount = null; + // 临时消费金额 = 临时消费金额 - 该笔交易的剩余金额 + tempAmount = tempAmount.subtract(payAmount); + if (tempAmount.compareTo(BigDecimal.ZERO) >= 0) { + // 计算以后,大于等于0,说明这笔支付剩余金额需要扣完,还要继续扣下一笔 + deductionAmount = payAmount; + unfreezeAmount = payAmount.subtract(deductionAmount); // 支付金额 - 扣除金额 = 需要退回的金额 + Map map = Maps.newHashMap(); + map.put("paymentId", paymentId); + map.put("unfreezeAmount", unfreezeAmount); + resultList.add(map); + } else { + // 如果小于0,则说明该笔交易的剩余金额用不完,扣除金额等于临时消费金额,并结束循环 + deductionAmount = payAmount.add(tempAmount); // 该笔交易的剩余金额加上一个负数临时消费金额,就是该笔交易扣除金额 + unfreezeAmount = payAmount.subtract(deductionAmount); // 支付金额 - 扣除金额 = 需要退回的金额 + Map map = Maps.newHashMap(); + map.put("paymentId", paymentId); + map.put("unfreezeAmount", unfreezeAmount); + resultList.add(map); + break; + } + } + return resultList; + } + + /** + * 从redis中取出实时记录保存到表中j + * 当订单完成的时候调用 + * 【公共方法】 + */ + protected void realTimeMonitorDataRedis2DB(String transactionCode, String orderCode) { + try { + if (StringUtils.isBlank(transactionCode) || StringUtils.isBlank(orderCode)) { + return; + } + // 校验有没有保存过 + OrderMonitorData orderMonitorData = orderMonitorDataService.selectByOrderCode(orderCode); + if (orderMonitorData != null) { + return; + } + List chargingRealTimeData = orderBasicInfoService.getChargingRealTimeData(transactionCode); + if (CollectionUtils.isEmpty(chargingRealTimeData)) { + return; + } + List list = Lists.newArrayList(); + for (RealTimeMonitorData data : chargingRealTimeData) { + RealTimeMonitorData build = RealTimeMonitorData.builder() + .outputCurrent(data.getOutputCurrent()) + .outputCurrent(data.getOutputCurrent()) // 电流 + .outputVoltage(data.getOutputVoltage()) // 电压 + .outputPower(data.getOutputPower()) // 功率 + .SOC(data.getSOC()) // soc + .dateTime(data.getDateTime()) // 时间 + .batteryMaxTemperature(data.getBatteryMaxTemperature()) + .chargingAmount(data.getChargingAmount()) + .chargingDegree(data.getChargingDegree()) + .sumChargingTime(data.getSumChargingTime()) + .timeRemaining(data.getTimeRemaining()) + .gunLineTemperature(data.getGunLineTemperature()) + .build(); + list.add(build); + } + + OrderMonitorData record = new OrderMonitorData(); + record.setOrderCode(orderCode); + record.setTransactionCode(transactionCode); + record.setMonitorData(JSONObject.toJSONString(list)); + int insert = orderMonitorDataService.insertSelective(record); + if (insert > 0) { + // 删除redis中缓存 + String pileConnectorCode = transactionCode.substring(0, 16); + String redisKey = CacheConstants.PILE_REAL_TIME_MONITOR_DATA + pileConnectorCode + "_" + transactionCode; + redisCache.deleteObject(redisKey); + } + } catch (Exception e) { + logger.info("redis中取出实时记录保存到表发生异常", e); + } + } } diff --git a/jsowell-pile/src/main/java/com/jsowell/pile/service/orderlogic/DelayMerchantOrderLogic.java b/jsowell-pile/src/main/java/com/jsowell/pile/service/orderlogic/DelayMerchantOrderLogic.java index 539745e51..cdbb70ccf 100644 --- a/jsowell-pile/src/main/java/com/jsowell/pile/service/orderlogic/DelayMerchantOrderLogic.java +++ b/jsowell-pile/src/main/java/com/jsowell/pile/service/orderlogic/DelayMerchantOrderLogic.java @@ -3,31 +3,34 @@ package com.jsowell.pile.service.orderlogic; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONObject; import com.google.common.collect.Lists; -import com.jsowell.adapay.service.AdapayService; +import com.jsowell.adapay.operation.PaymentReverseOperation; +import com.jsowell.adapay.response.PaymentReverseResponse; +import com.jsowell.adapay.vo.OrderSettleResult; +import com.jsowell.common.constant.Constants; import com.jsowell.common.core.domain.ykc.TransactionRecordsData; import com.jsowell.common.enums.AcquirerEnum; import com.jsowell.common.enums.MemberWalletEnum; import com.jsowell.common.enums.ykc.*; import com.jsowell.common.exception.BusinessException; -import com.jsowell.pile.domain.MemberTransactionRecord; -import com.jsowell.pile.domain.OrderBasicInfo; -import com.jsowell.pile.domain.OrderPayRecord; +import com.jsowell.common.util.StringUtils; +import com.jsowell.pile.domain.*; +import com.jsowell.pile.dto.ApplyRefundDTO; import com.jsowell.pile.dto.PayOrderDTO; import com.jsowell.pile.dto.PayOrderSuccessCallbackDTO; -import com.jsowell.pile.service.IMemberBasicInfoService; -import com.jsowell.pile.service.IMemberTransactionRecordService; -import com.jsowell.pile.service.MemberAdapayRecordService; -import com.jsowell.pile.service.OrderPayRecordService; +import com.jsowell.pile.transaction.dto.OrderTransactionDTO; import com.jsowell.pile.vo.uniapp.MemberVO; import com.jsowell.pile.vo.web.BalanceDeductionAmountVO; import com.jsowell.pile.vo.web.UpdateMemberBalanceDTO; +import com.jsowell.wxpay.dto.WechatSendMsgDTO; import org.apache.commons.collections4.CollectionUtils; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.math.BigDecimal; import java.util.List; import java.util.Map; +import java.util.Objects; +import java.util.function.Function; +import java.util.stream.Collectors; /** * 设置延时分账的运营商订单逻辑 @@ -35,21 +38,6 @@ import java.util.Map; @Service public class DelayMerchantOrderLogic extends AbstractOrderLogic { - @Autowired - private IMemberBasicInfoService memberBasicInfoService; - - @Autowired - private MemberAdapayRecordService memberAdapayRecordService; - - @Autowired - private OrderPayRecordService orderPayRecordService; - - @Autowired - private IMemberTransactionRecordService memberTransactionRecordService; - - @Autowired - private AdapayService adapayService; - /** * 余额支付订单 */ @@ -150,7 +138,19 @@ public class DelayMerchantOrderLogic extends AbstractOrderLogic { */ @Override public void whitelistPaymentOrder(PayOrderDTO dto) { + String orderCode = dto.getOrderCode(); + BigDecimal payAmount = dto.getPayAmount(); + String payMode = dto.getPayMode(); + // 白名单直接算支付成功 + PayOrderSuccessCallbackDTO callbackDTO = PayOrderSuccessCallbackDTO.builder() + .orderCode(orderCode) + .payAmount(payAmount) + .payMode(payMode) + .startMode(dto.getStartMode()) + .acquirer(AcquirerEnum.LOCAL.getValue()) + .build(); + payOrderSuccessCallback(callbackDTO); } /** @@ -158,15 +158,179 @@ public class DelayMerchantOrderLogic extends AbstractOrderLogic { */ @Override public void orderSettle(TransactionRecordsData data, OrderBasicInfo orderBasicInfo) { + logger.info("结算订单start data:{}, orderBasicInfo:{}", data.toString(), orderBasicInfo.toString()); + // 判断订单状态 + if (StringUtils.equals(orderBasicInfo.getOrderStatus(), OrderStatusEnum.ORDER_COMPLETE.getValue())) { + logger.info("结算订单:{}, 是订单完成状态", orderBasicInfo.getOrderCode()); + return; + } + // 获取更新数据后的orderBasicInfo对象 + returnUpdateOrderBasicInfo(orderBasicInfo, data); + // 获取更新数据后的orderDetail对象/更新订单详情 查询订单详情 修改订单数据 + OrderDetail orderDetail = returnUpdateOrderDetail(orderBasicInfo, data); + // 更新数据库 + OrderTransactionDTO dto = new OrderTransactionDTO(); + dto.setOrderBasicInfo(orderBasicInfo); + dto.setOrderDetail(orderDetail); + transactionService.doUpdateOrder(dto); + // 订单支付结算and退款, delay商户部分解冻并退款, 非delay商户全部解冻并退款 + orderPaymentSettlementAndRefund(orderBasicInfo); + + // 将卡/vin状态解锁 + if (!StringUtils.equals("0000000000000000", data.getLogicCard())) { + cardStatusUnlocked(orderBasicInfo.getLogicCard()); + } + + // 如果是vin启动,将启动锁定状态改为正常 + if (StringUtils.equals(data.getTransactionIdentifier(), "05")) { + vinStatusUnlocked(data.getVinCode()); + } + + // 发送停止充电订阅消息 + sendMsg(orderBasicInfo); + + // 从redis中取出实时记录保存到表中 + realTimeMonitorDataRedis2DB(orderBasicInfo.getTransactionCode(), orderBasicInfo.getOrderCode()); + + // TODO 如果该站点的停车场优惠券信息配置不为空,则需绑定一张优惠券 + + logger.info("结算订单end:{} OrderTransactionDTO:{}", orderBasicInfo.getOrderCode(), JSONObject.toJSONString(dto)); + } + + /** + * 卡状态解锁 + */ + private void cardStatusUnlocked(String logicCard) { + try { + // 根据物理卡号查出当前为锁定状态的卡 + PileAuthCard cardInfo = pileAuthCardService.selectSomeStatusCardInfo(CardStatusEnum.START_LOCK.getCode(), logicCard); + if (cardInfo != null) { + // 将此卡状态改为正常 + cardInfo.setStatus(CardStatusEnum.NORMAL.getCode()); + pileAuthCardService.updatePileAuthCard(cardInfo); + } + } catch (Exception e) { + logger.error("解锁卡状态 error,", e); + } + } + + /** + * 解锁vin状态 + * + * @param vinCode + */ + private void vinStatusUnlocked(String vinCode) { + try { + MemberPlateNumberRelation plateInfo = memberPlateNumberRelationService.getMemberPlateInfoByVinCode(vinCode); + if (plateInfo != null && (StringUtils.equals(plateInfo.getVinStatus(), "2"))) { + plateInfo.setVinStatus("1"); + memberPlateNumberRelationService.updateMemberPlateNumberRelation(plateInfo); + } + } catch (Exception e) { + logger.error("解锁vin状态 error,", e); + } + } + + // uniApp 发送停止充电订阅消息 + private void sendMsg(OrderBasicInfo orderBasicInfo) { + try { + WechatSendMsgDTO wechatSendMsgDTO = new WechatSendMsgDTO(); + wechatSendMsgDTO.setOrderCode(orderBasicInfo.getOrderCode()); + Map resultMap = wxAppletRemoteService.stopChargingSendMsg(wechatSendMsgDTO); + logger.info("小程序发送充电停止推送消息 result:{}", JSON.toJSONString(resultMap)); + } catch (Exception e) { + logger.error("小程序发送充电停止推送消息 error", e); + } + } + + /** + * 订单分账逻辑 + * 订单结算完成,就执行清分and退款 + */ + private OrderSettleResult orderPaymentSettlementAndRefund(OrderBasicInfo orderBasicInfo) { + String merchantId = orderBasicInfo.getMerchantId(); + String orderCode = orderBasicInfo.getOrderCode(); + // 获取一级运营商信息 + PileMerchantInfo merchantInfo = pileMerchantInfoService.getFirstLevelMerchantByMerchantId(merchantId); + if (merchantInfo == null) { + logger.info("订单分账逻辑-订单:{}, 查不到一级运营商信息", orderCode); + return null; + } + + // 获取结算账户信息 + AdapayMemberAccount adapayMemberAccount = adapayMemberAccountService.selectByMerchantId(merchantId); + if (adapayMemberAccount == null) { + logger.info("订单分账逻辑-订单:{}, 运营商id:{}, 没有配置结算账户信息", orderCode, merchantId); + return null; + } + + try { + String payMode = orderBasicInfo.getPayMode(); + if (StringUtils.equals(payMode, OrderPayModeEnum.PAYMENT_OF_BALANCE.getValue())) { + // 余额支付 + balancePaymentOrderRefund(orderBasicInfo); + } else if (StringUtils.equals(payMode, OrderPayModeEnum.PAYMENT_OF_WECHATPAY.getValue())) { + // 微信支付 + onlinePaymentOrderRefund(orderBasicInfo); + } else { + // 白名单支付 + logger.info("订单:{}使用白名单支付,不进行退款处理", orderBasicInfo.getOrderCode()); + } + } catch (Exception e) { + logger.error("订单退款逻辑异常orderCode:{}", orderBasicInfo.getOrderCode(), e); + } + return null; } /** * 余额支付订单退款 */ @Override - public void balancePayOrderRefund(OrderBasicInfo orderBasicInfo) { + public void balancePaymentOrderRefund(OrderBasicInfo orderBasicInfo) { + // 订单编号 + String orderCode = orderBasicInfo.getOrderCode(); + // 订单消费金额 + BigDecimal orderAmount = orderBasicInfo.getOrderAmount(); + // 查支付记录 + List payRecordList = orderPayRecordService.getOrderPayRecordList(orderCode); + Map payRecordMap = payRecordList.stream() + .collect(Collectors.toMap(OrderPayRecord::getPayMode, Function.identity(), (k1, k2) -> k1)); + // 取出本金支付金额 + BigDecimal principalPay = null; + + // 获取本金支付的记录 + OrderPayRecord principalPayRecord = payRecordMap.get(Constants.ONE); + if (principalPayRecord != null) { + principalPay = principalPayRecord.getPayAmount(); + } + + // 计算需要退回的金额 + Map returnAmountMap = calculateReturnAmount(principalPay, null, orderAmount); + logger.info("结算订单:{}, 剩余金额退回余额, 订单消费金额:{}, 本金支付金额:{}, 赠送支付金额:{}, 退回金额map:{}", + orderCode, orderAmount, principalPay, null, JSONObject.toJSONString(returnAmountMap)); + + // 需要退回本金的金额 + BigDecimal returnPrincipal = returnAmountMap.get("returnPrincipal"); + + // 更新会员钱包/余额退回到钱包 + UpdateMemberBalanceDTO updateMemberBalanceDTO = UpdateMemberBalanceDTO.builder() + .memberId(orderBasicInfo.getMemberId()) + .type(MemberWalletEnum.TYPE_IN.getValue()) // 进账 + .subType(MemberWalletEnum.SUBTYPE_ORDER_SETTLEMENT_REFUND.getValue()) // 订单结算退款 + .updatePrincipalBalance(returnPrincipal) + .relatedOrderCode(orderCode) + .build(); + memberBasicInfoService.updateMemberBalance(updateMemberBalanceDTO); + + // 更新order_pay_record, 解冻部分 + List> list = calculateUnfreezeAmount(orderAmount, payRecordList); + for (Map map : list) { + String paymentId = (String) map.get("paymentId"); + String unfreezeAmount = (String) map.get("unfreezeAmount"); + memberAdapayRecordService.unfreezeAmount(paymentId, new BigDecimal(unfreezeAmount)); + } } /** @@ -174,6 +338,91 @@ public class DelayMerchantOrderLogic extends AbstractOrderLogic { */ @Override public void onlinePaymentOrderRefund(OrderBasicInfo orderBasicInfo) { + // 订单编号 + String orderCode = orderBasicInfo.getOrderCode(); + // 需要退款的金额 + BigDecimal refundAmount = orderBasicInfo.getRefundAmount(); + + // 微信退款逻辑 + ApplyRefundDTO applyRefundDTO = new ApplyRefundDTO(); + applyRefundDTO.setOrderCode(orderCode); + applyRefundDTO.setRefundType(Constants.ONE); + applyRefundDTO.setRefundAmount(refundAmount); + + // 汇付退款需要一级运营商的小程序appId, 否则会退款失败 + String wechatAppId = pileMerchantInfoService.queryAppIdByMerchantId(orderBasicInfo.getMerchantId()); + if (StringUtils.isNotBlank(wechatAppId)) { + applyRefundDTO.setWechatAppId(wechatAppId); + } + this.refundOrderWithAdapay(applyRefundDTO); + } + + /** + * 汇付支付-订单退款处理逻辑 + * 汇付支付订单退款 + * + * @param dto + */ + public void refundOrderWithAdapay(ApplyRefundDTO dto) { + logger.info("汇付支付订单:{}, 执行退款逻辑 param:{}", dto.getOrderCode(), JSON.toJSONString(dto)); + // 查出来原来的支付信息 + AdapayCallbackRecord callbackRecord = adapayCallbackRecordService.selectByOrderCode(dto.getOrderCode()); + if (Objects.isNull(callbackRecord)) { + logger.error("汇付支付orderCode:{}, 订单退款处理逻辑, 查询订单微信支付记录为空!", dto.getOrderCode()); + throw new BusinessException(ReturnCodeEnum.CODE_REFUND_ORDER_CALLBACK_RECORD_ERROR); + } + + String paymentId = callbackRecord.getPaymentId(); + // 判断支付金额和退款金额 + BigDecimal refundAmount = dto.getRefundAmount(); + BigDecimal payAmt = callbackRecord.getPayAmt(); + if (refundAmount.compareTo(payAmt) > 0) { + logger.error("汇付支付订单号:{}, 退款金额:{}(元),大于付款金额{}(元), 抛出异常", dto.getOrderCode(), refundAmount, payAmt); + throw new BusinessException(ReturnCodeEnum.CODE_REFUND_ORDER_AMOUNT_ERROR); + } + + BigDecimal refundAmt = null; // 交易退款金额 + // 延迟分账未确认调撤销调撤销接口退款 + PaymentReverseOperation operation = new PaymentReverseOperation(); + operation.setPaymentId(paymentId); + operation.setReverseAmt(refundAmount); + operation.setMerchantKey(dto.getWechatAppId()); + operation.setMemberId(dto.getMemberId()); + operation.setScenarioType(ScenarioEnum.ORDER.getValue()); + operation.setOrderCode(dto.getOrderCode()); + PaymentReverseResponse response = adapayService.createPaymentReverseRequest(operation); + if (response != null && response.isNotFailed()) { + refundAmt = new BigDecimal(response.getReverse_amt()); + memberAdapayRecordService.updateRefundAmountFromFreezeAmount(paymentId, refundAmt); + } + + // 获取延时分账模式 延时分账的使用撤销方法退款,实时分账的使用退款方法 + // String expend = callbackRecord.getExpend(); + // JSONObject expendJsonObject = JSON.parseObject(expend); + // String payMode = expendJsonObject.getString("payMode"); + // if (StringUtils.equalsIgnoreCase(payMode, Constants.ADAPAY_PAY_MODE_DELAY)) { + // // 延迟分账未确认调撤销调撤销接口退款 + // PaymentReverseOperation operation = new PaymentReverseOperation(); + // operation.setPaymentId(paymentId); + // operation.setReverseAmt(refundAmount); + // operation.setMerchantKey(dto.getWechatAppId()); + // operation.setMemberId(dto.getMemberId()); + // operation.setScenarioType(ScenarioEnum.ORDER.getValue()); + // operation.setOrderCode(dto.getOrderCode()); + // PaymentReverseResponse response = adapayService.createPaymentReverseRequest(operation); + // if (response != null && response.isNotFailed()) { + // refundAmt = new BigDecimal(response.getReverse_amt()); + // memberAdapayRecordService.updateRefundAmountFromFreezeAmount(paymentId, refundAmt); + // } + // } else { + // // // 实时分账的调退款接口 + // RefundResponse refundRequest = adapayService.createRefundRequest(paymentId, refundAmount, + // dto.getWechatAppId(), dto.getMemberId(), ScenarioEnum.ORDER.getValue(), dto.getOrderCode()); + // if (refundRequest != null && refundRequest.isNotFailed()) { + // refundAmt = new BigDecimal(refundRequest.getRefund_amt()); + // memberAdapayRecordService.unfreezeAmountAndUpdateSpendAmount(paymentId, payAmt, refundAmt); + // } + // } } }