|
|
@@ -1,22 +1,14 @@
|
|
|
package com.kym.service.awoara.event.handle;
|
|
|
|
|
|
-import com.kym.entity.*;
|
|
|
+import com.kym.entity.WashOrder;
|
|
|
import com.kym.entity.awoara.MessageBody;
|
|
|
import com.kym.entity.awoara.OrderInfoObject;
|
|
|
-import com.kym.service.*;
|
|
|
-import com.kym.service.cache.KymCache;
|
|
|
-import com.kym.service.factory.DiscountStrategyFactory;
|
|
|
+import com.kym.service.OrderSettlementService;
|
|
|
+import com.kym.service.WashOrderService;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import org.springframework.stereotype.Component;
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
|
|
|
-import java.math.BigDecimal;
|
|
|
-import java.math.RoundingMode;
|
|
|
-import java.time.Duration;
|
|
|
-import java.time.LocalDateTime;
|
|
|
-import java.util.List;
|
|
|
-import java.util.UUID;
|
|
|
-
|
|
|
/**
|
|
|
* 关闭订单事件(订单结算)
|
|
|
*
|
|
|
@@ -25,187 +17,34 @@ import java.util.UUID;
|
|
|
@Slf4j
|
|
|
@Component
|
|
|
public class OrderCloseEventHandler implements AwoaraEventHandler<OrderInfoObject> {
|
|
|
- private String DOMAIN;
|
|
|
- private final WashOrderService washOrderService;
|
|
|
- private final WalletDetailService walletDetailService;
|
|
|
- private final AccountService accountService;
|
|
|
- private final SplitRecordService splitRecordService;
|
|
|
-
|
|
|
- private final MpMsgTemplateService mpMsgTemplateService;
|
|
|
|
|
|
+ private final WashOrderService washOrderService;
|
|
|
+ private final OrderSettlementService orderSettlementService;
|
|
|
|
|
|
- public OrderCloseEventHandler(WashOrderService washOrderService, WalletDetailService walletDetailService,
|
|
|
- AccountService accountService, SplitRecordService splitRecordService,
|
|
|
- MpMsgTemplateService mpMsgTemplateService,String domain) {
|
|
|
- DOMAIN = domain;
|
|
|
+ public OrderCloseEventHandler(WashOrderService washOrderService,
|
|
|
+ OrderSettlementService orderSettlementService) {
|
|
|
this.washOrderService = washOrderService;
|
|
|
- this.walletDetailService = walletDetailService;
|
|
|
- this.accountService = accountService;
|
|
|
- this.splitRecordService = splitRecordService;
|
|
|
- this.mpMsgTemplateService = mpMsgTemplateService;
|
|
|
+ this.orderSettlementService = orderSettlementService;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
@Override
|
|
|
@Transactional
|
|
|
public void handle(MessageBody<OrderInfoObject> message) {
|
|
|
log.info("收到订单关闭事件");
|
|
|
|
|
|
- // 订单结算
|
|
|
var orderInfo = message.getPayload().getData().getOrder_info();
|
|
|
log.info("订单:{},结算信息:{}", orderInfo.getOrder_id(), orderInfo);
|
|
|
|
|
|
- // 订单状态、支付状态
|
|
|
var washOrder = washOrderService.lambdaQuery().eq(WashOrder::getOrderId, orderInfo.getOrder_id()).one();
|
|
|
if (washOrder == null) {
|
|
|
log.error("订单不存在,订单号:{}", orderInfo.getOrder_id());
|
|
|
return;
|
|
|
}
|
|
|
- // 幂等保护:已结算订单不再重复处理
|
|
|
if (Integer.valueOf(WashOrder.PAY_STATUS_已支付).equals(washOrder.getPayStatus())) {
|
|
|
log.warn("订单:{},已结算,跳过重复关闭事件", orderInfo.getOrder_id());
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- int rechargePayment;
|
|
|
- int grantsPayment = 0;
|
|
|
- var account = accountService.lambdaQuery().eq(Account::getUserId, washOrder.getUserId()).last("FOR UPDATE").one();
|
|
|
- // 以实收金额扣款(优先扣减充值款,不够则扣除赠款)
|
|
|
- int amountReceived = orderInfo.getAmount_received();
|
|
|
- if (account.getRechargeBalance() >= amountReceived) {
|
|
|
- rechargePayment = amountReceived;
|
|
|
- accountService.lambdaUpdate()
|
|
|
- .setSql("balance = balance - {0}, recharge_balance = recharge_balance - {1}",
|
|
|
- amountReceived, rechargePayment)
|
|
|
- .eq(Account::getUserId, washOrder.getUserId())
|
|
|
- .update();
|
|
|
- } else {
|
|
|
- // 充值款余额不足以支付订单,则扣赠款
|
|
|
- rechargePayment = account.getRechargeBalance();
|
|
|
- grantsPayment = amountReceived - account.getRechargeBalance();
|
|
|
- accountService.lambdaUpdate()
|
|
|
- .setSql("balance = balance - {0}, recharge_balance = 0, grants_balance = grants_balance - {1}",
|
|
|
- amountReceived, grantsPayment)
|
|
|
- .eq(Account::getUserId, washOrder.getUserId())
|
|
|
- .update();
|
|
|
- }
|
|
|
-
|
|
|
- washOrder
|
|
|
- .setCloseType(orderInfo.getClose_type())
|
|
|
- .setAmount(orderInfo.getAmount())
|
|
|
- .setAmountReceivable(orderInfo.getAmount_receivable())
|
|
|
- .setAmountReceived(amountReceived)
|
|
|
- .setDiscountMoney(orderInfo.getDiscount_money())
|
|
|
- .setDetail(orderInfo.getDetail())
|
|
|
- .setEndTime(LocalDateTime.now())
|
|
|
- .setTotalSeconds(Duration.between(washOrder.getStartTime(), LocalDateTime.now()).toSecondsPart())
|
|
|
- .setRechargePayment(rechargePayment)
|
|
|
- .setGrantsPayment(grantsPayment)
|
|
|
- .setPayStatus(WashOrder.PAY_STATUS_已支付)
|
|
|
- .setOrderStatus(WashOrder.ORDER_STATUS_成功);
|
|
|
-
|
|
|
- washOrderService.updateById(washOrder);
|
|
|
-
|
|
|
- // 订单金额为0的订单不处理
|
|
|
- if (orderInfo.getAmount() == 0) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- // 需要判断是否跨网点,分开处理;跨网点结算比例是消费站点分充值款实收的70%,充值站点保留30%
|
|
|
- if (washOrder.getIsCross()) {
|
|
|
- doCrossSplit(washOrder, KymCache.INSTANCE.getUserStationId(washOrder.getUserId()));
|
|
|
- } else {
|
|
|
- doLocalSplit(washOrder);
|
|
|
- }
|
|
|
-
|
|
|
- // 记录资金流水(含赠款明细)
|
|
|
- var walletDetail = new WalletDetail();
|
|
|
- walletDetail.setUserId(washOrder.getUserId());
|
|
|
- walletDetail.setType(WalletDetail.TYPE_消费);
|
|
|
- walletDetail.setOrderNo(washOrder.getOrderId());
|
|
|
- walletDetail.setAmount(amountReceived);
|
|
|
- walletDetail.setGrantsAmount(grantsPayment);
|
|
|
- walletDetail.setBeforeBalance(account.getBalance());
|
|
|
- walletDetail.setAfterBalance(account.getBalance() - amountReceived);
|
|
|
- walletDetail.setBeforeGrantsBalance(account.getGrantsBalance());
|
|
|
- walletDetail.setAfterGrantsBalance(account.getGrantsBalance() - grantsPayment);
|
|
|
- walletDetail.setTransactionId(washOrder.getId().toString());
|
|
|
- walletDetail.setTransactionTime(LocalDateTime.now());
|
|
|
- walletDetail.setStatus(WalletDetail.STATUS_已确认);
|
|
|
- walletDetailService.save(walletDetail);
|
|
|
-
|
|
|
- // 处理充值权益优惠逻辑/优惠券优惠逻辑/账户优惠金额记录处理逻辑(涉及退款扣减优惠,在NoDiscountHandle中处理)
|
|
|
- DiscountStrategyFactory.getDiscountStrategy(washOrder.getDiscountType()).computeDiscount(washOrder, account);
|
|
|
-
|
|
|
- // 更新订单优惠金额
|
|
|
- washOrderService.updateById(washOrder);
|
|
|
-
|
|
|
- // 判断消费金额是否达标,达标发送领取停车优惠券消息
|
|
|
- if (orderInfo.getAmount() >= WashOrder.PARKING_COUPON_MIN_AMOUNT) {
|
|
|
- var parkingCouponUrl = KymCache.INSTANCE.getParkingQrCodeUrlByStationId(washOrder.getStationId());
|
|
|
- // 二维码链接做转换防止重复使用,有效期2小时
|
|
|
- var code = UUID.randomUUID().toString();
|
|
|
- KymCache.INSTANCE.setParkingCouponCode(code, parkingCouponUrl, 3600*2L);
|
|
|
- var url = DOMAIN + "/api/parking-coupon?code=" + code;
|
|
|
- mpMsgTemplateService.sendParkingCouponMsg(washOrder, url);
|
|
|
- } else {
|
|
|
- // 发送公众号消息(订单完成)
|
|
|
- mpMsgTemplateService.sendOrderCompletedMsg(washOrder, account.getBalance());
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 本店消费分账 — V2 结算方案
|
|
|
- * 同店消费不产生分账记录,资金不跨站,在周期结算时统一处理
|
|
|
- *
|
|
|
- * @param washOrder
|
|
|
- */
|
|
|
- @Transactional
|
|
|
- protected void doLocalSplit(WashOrder washOrder) {
|
|
|
- log.info("订单:{},本店消费,V2方案无需分账", washOrder.getOrderId());
|
|
|
- // V2: 同店消费资金不出站,结算日统一计算
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 跨店消费分账 — V2 结算方案
|
|
|
- * 以订单实收总额(充值余额 + 赠款余额)的 70% 为跨店转账基数
|
|
|
- * 平台服务费由结算日统一计算,70:30 拉新奖励比例在此体现
|
|
|
- * 赠款为归属站点自行发起的营销成本,参与跨店分账,由归属站承担
|
|
|
- *
|
|
|
- * @param washOrder 洗车订单
|
|
|
- * @param userStationId 用户归属站点(充值方)
|
|
|
- */
|
|
|
- @Transactional
|
|
|
- protected void doCrossSplit(WashOrder washOrder, String userStationId) {
|
|
|
- int rechargePayment = washOrder.getRechargePayment();
|
|
|
- int grantsPayment = washOrder.getGrantsPayment();
|
|
|
- int totalPayment = rechargePayment + grantsPayment;
|
|
|
- if (totalPayment == 0) {
|
|
|
- log.info("订单:{},支付金额为0,不产生跨店转账", washOrder.getOrderId());
|
|
|
- return;
|
|
|
- }
|
|
|
- BigDecimal crossRate = new BigDecimal("0.7");
|
|
|
- int crossAmount = crossRate.multiply(BigDecimal.valueOf(totalPayment)).setScale(0, RoundingMode.DOWN).intValue();
|
|
|
- log.info("订单:{},执行跨店分账,归属站:{},消费站:{},充值款实收:{},赠款实收:{},转账金额:{}",
|
|
|
- washOrder.getOrderId(), userStationId, washOrder.getStationId(), rechargePayment, grantsPayment, crossAmount);
|
|
|
-
|
|
|
- // 归属站点跨店支出
|
|
|
- var crossExpend = new SplitRecord()
|
|
|
- .setFromStationId(userStationId)
|
|
|
- .setToStationId(washOrder.getStationId())
|
|
|
- .setTradeNo(washOrder.getOrderId())
|
|
|
- .setAmount(crossAmount)
|
|
|
- .setType(SplitRecord.TYPE_CROSS_EXPEND);
|
|
|
-
|
|
|
- // 消费站点跨店收入
|
|
|
- var crossIncome = new SplitRecord()
|
|
|
- .setFromStationId(userStationId)
|
|
|
- .setToStationId(washOrder.getStationId())
|
|
|
- .setTradeNo(washOrder.getOrderId())
|
|
|
- .setAmount(crossAmount)
|
|
|
- .setType(SplitRecord.TYPE_CROSS_INCOME);
|
|
|
-
|
|
|
- splitRecordService.saveBatch(List.of(crossExpend, crossIncome));
|
|
|
- log.info("订单:{},跨店分账完成", washOrder.getOrderId());
|
|
|
+ orderSettlementService.settleOrder(washOrder, orderInfo);
|
|
|
}
|
|
|
}
|