package com.ruoyi.order.util.task; import com.alibaba.fastjson.JSON; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import com.baomidou.mybatisplus.extension.conditions.update.UpdateChainWrapper; import com.ruoyi.account.api.feignClient.AppCouponClient; import com.ruoyi.account.api.feignClient.AppUserClient; import com.ruoyi.account.api.feignClient.AppUserIntegralChangeClient; import com.ruoyi.account.api.model.TAppCoupon; import com.ruoyi.account.api.model.TAppUser; import com.ruoyi.account.api.model.TAppUserIntegralChange; import com.ruoyi.chargingPile.api.dto.TBillingTemplateDTO; import com.ruoyi.chargingPile.api.feignClient.ChargingGunClient; import com.ruoyi.chargingPile.api.feignClient.SiteClient; import com.ruoyi.chargingPile.api.model.Partner; import com.ruoyi.chargingPile.api.model.Site; import com.ruoyi.chargingPile.api.model.TBillingTemplateDetail; import com.ruoyi.chargingPile.api.model.TChargingGun; import com.ruoyi.common.core.domain.R; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.integration.api.feignClient.ChargingMessageClient; import com.ruoyi.integration.api.feignClient.ChengDuJianGuanClient; import com.ruoyi.integration.api.feignClient.TCECClient; import com.ruoyi.integration.api.model.TransactionRecord; import com.ruoyi.integration.api.model.UploadRealTimeMonitoringData; import com.ruoyi.integration.api.vo.ChargingOrderVo; import com.ruoyi.integration.api.vo.NotificationConnectorChargeStatusVo; import com.ruoyi.order.api.model.*; import com.ruoyi.order.api.vo.TransactionRecordMessageVO; import com.ruoyi.order.service.*; import com.ruoyi.order.service.impl.ChargingCouponSupport; import com.ruoyi.order.support.ChargeAccountSupport; import com.ruoyi.order.util.mongodb.service.TransactionRecordService; import com.ruoyi.order.util.mongodb.service.UploadRealTimeMonitoringDataService; import com.ruoyi.other.api.domain.TCoupon; import com.ruoyi.other.api.domain.TIntegralRule; import com.ruoyi.other.api.domain.TVip; import com.ruoyi.other.api.dto.CompanyPreferentialDTO; import com.ruoyi.other.api.dto.ExchangeCodeConsumeDTO; import com.ruoyi.other.api.feignClient.IntegralRuleClient; import com.ruoyi.other.api.feignClient.OtherClient; import com.ruoyi.other.api.feignClient.VipClient; import com.ruoyi.other.api.vo.ExchangeCodeConsumeResultVO; import com.ruoyi.payment.api.feignClient.AliPaymentClient; import com.ruoyi.payment.api.feignClient.H5AliPaymentClient; import com.ruoyi.payment.api.feignClient.IcbcPaymentClient; import com.ruoyi.payment.api.feignClient.WxPaymentClient; import com.ruoyi.payment.api.model.RefundReq; import com.ruoyi.payment.api.model.RefundResp; import com.ruoyi.payment.api.model.WxPaymentRefundModel; import com.ruoyi.payment.api.vo.IcbcRefundReq; import com.ruoyi.payment.api.vo.IcbcRefundResp; import lombok.extern.slf4j.Slf4j; import org.redisson.api.RLock; import org.redisson.api.RedissonClient; import org.springframework.beans.BeanUtils; import org.springframework.boot.web.context.WebServerInitializedEvent; import org.springframework.context.ApplicationListener; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; import java.math.BigDecimal; import java.math.MathContext; import java.math.RoundingMode; import java.text.SimpleDateFormat; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; import java.time.temporal.TemporalAdjusters; import java.util.*; import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; /** * @author zhibing.pu * @date 2023/7/11 8:39 */ @Slf4j @Component public class TaskUtil implements ApplicationListener { private static final int WHITELIST_BENEFIT_ALL_FREE = 1; @Resource private TChargingBillService chargingBillService; @Resource private ITChargingSettlementBillService chargingSettlementBillService; @Resource private ITAccountSettlementStatementService accountSettlementStatementService; @Resource private SiteClient siteClient; @Resource private TChargingOrderService chargingOrderService; @Resource private TCardChargingOrderService cardChargingOrderService; @Resource private TVinChargingOrderService vinChargingOrderService; @Resource private TChargingOrderRefundService chargingOrderRefundService; @Resource private UploadRealTimeMonitoringDataService uploadRealTimeMonitoringDataService; @Resource private TransactionRecordService transactionRecordService; @Resource private ChargingMessageClient chargingMessageClient; private Integer port = null; @Resource private AccountingStrategyDetailOrderService accountingStrategyDetailOrderService; @Resource private TChargingOrderAccountingStrategyService chargingOrderAccountingStrategyService; @Resource private AppCouponClient appCouponClient; @Resource private TCECClient tcecClient; @Resource private VipClient vipClient; @Resource private ChargingGunClient chargingGunClient; @Resource private IntegralRuleClient integralRuleClient; @Resource private AppUserClient appUserClient; @Resource private AppUserIntegralChangeClient appUserIntegralChangeClient; @Resource private OtherClient otherClient; @Resource private WxPaymentClient wxPaymentClient; @Resource private IcbcPaymentClient icbcPaymentClient; @Resource private AliPaymentClient aliPaymentClient; @Resource private H5AliPaymentClient h5AliPaymentClient; @Resource private ITChargingOrderSummaryDataService chargingOrderSummaryDataService; @Resource private ChengDuJianGuanClient chengDuJianGuanClient; @Resource private RedissonClient redissonClient; @Resource private ChargeAccountSupport chargeAccountSupport; /** * 判断订单是否使用余额或余额组合支付 * * @param payMethod 支付方式 * @return true=余额相关支付方式 */ private boolean isBalancePayMode(Integer payMethod) { return payMethod != null && (payMethod == 1 || payMethod == 2); } /** * 将金额空值统一转换为两位小数,避免补偿结算金额计算出现空指针 * * @param amount 原始金额 * @return 非空两位小数金额 */ private BigDecimal money(BigDecimal amount) { return amount == null ? BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP) : amount.setScale(2, RoundingMode.HALF_UP); } /** * 获取第三方实付金额,兼容早期未写入third_pay_amount的纯第三方支付订单。 * * @param order 充电订单 * @return 第三方可退款本金 */ private BigDecimal getRefundableThirdPayAmount(TChargingOrder order) { if (order == null || isWhitelistAllFreeOrder(order)) { return BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP); } BigDecimal thirdPayAmount = money(order.getThirdPayAmount()); if (thirdPayAmount.compareTo(BigDecimal.ZERO) > 0) { return thirdPayAmount; } if ("ICBC".equalsIgnoreCase(order.getSourceName())) { return money(order.getRechargeAmount()) .subtract(money(order.getBalancePayAmount())) .max(BigDecimal.ZERO) .setScale(2, RoundingMode.HALF_UP); } if (Integer.valueOf(3).equals(order.getPayMethod())) { return money(order.getRechargeAmount()); } return thirdPayAmount; } /** * 判断订单是否为白名单订单 * * @param order 充电订单 * @return true=白名单订单 */ private boolean isWhitelistOrder(TChargingOrder order) { return order != null && Integer.valueOf(1).equals(order.getIsWhitelist()); } /** * 判断订单是否为白名单全部免费权益 * * @param order 充电订单 * @return true=全部免费白名单订单 */ private boolean isWhitelistAllFreeOrder(TChargingOrder order) { return isWhitelistOrder(order) && Integer.valueOf(WHITELIST_BENEFIT_ALL_FREE).equals(order.getWhitelistBenefitType()); } /** * 按白名单权益拆分补偿结算的电费和服务费减免金额,确保任务补偿与正常结算口径一致 * * @param order 充电订单 * @param electrovalence 原始电费 * @param serviceCharge 原始服务费 * @return 数组下标0=电费减免,下标1=服务费减免 */ private BigDecimal[] calculateWhitelistRefundSplit(TChargingOrder order, BigDecimal electrovalence, BigDecimal serviceCharge) { return ChargingCouponSupport.calculateWhitelistRefundSplitByBenefitType( isWhitelistOrder(order), order == null ? null : order.getWhitelistBenefitType(), electrovalence, serviceCharge); } /** * 记录兑换码余额退款流水 * * @param order 充电订单 * @param refundAmount 退款金额 * @param refundNo 退款单号 */ private void recordBalanceRefund(TChargingOrder order, BigDecimal refundAmount, String refundNo) { if (order == null || order.getAppUserId() == null || order.getId() == null || refundAmount == null || refundAmount.compareTo(BigDecimal.ZERO) <= 0) { return; } ExchangeCodeConsumeDTO refundDTO = new ExchangeCodeConsumeDTO(); refundDTO.setUserId(order.getAppUserId()); refundDTO.setOrderId(order.getId()); refundDTO.setAmount(refundAmount); refundDTO.setRefundNo(refundNo); R result = otherClient.refundExchangeCodeBalance(refundDTO); if (result == null || result.getCode() != 200) { throw new RuntimeException("退还兑换码余额失败"); } } @Scheduled(fixedRate = 1000 * 60) public void taskOneMinutes() { if (isScheduledTaskPort(port)) { List upStatusChargingOrder = chargingOrderService.findUpStatusChargingOrder(); log.info("定时任务执行,查询需要手动修改状态的订单数量:{}", upStatusChargingOrder.size()); for (TChargingOrder order : upStatusChargingOrder) { if(2 == order.getStatus()){ order.setStatus(-1); }else{ order.setStatus(5); } chargingOrderService.updateById(order); } } } /** 实时监控静默阈值:超过该时间仍无交易记录时按异常断电补偿 */ private static final long MONITORING_SILENT_MILLIS = TimeUnit.MINUTES.toMillis(10); /** 无任何设备数据时的最长保护时间,避免 Mongo 短暂延迟造成误关单 */ private static final long NO_DEVICE_DATA_TIMEOUT_MILLIS = TimeUnit.HOURS.toMillis(24); /** * 刷卡/VIN 订单补偿(10分钟一轮):真实交易记录优先统一结算;启动中有实时数据则恢复充电中; * 仅在设备数据缺失或静默达到保护阈值后执行关单/累计电量兜底结算。 */ @Scheduled(fixedRate = 1000 * 60 * 10, initialDelay = 1000 * 60) public void cardVinOrderCompensationTask() { if (isScheduledTaskPort(port)) { compensateCardOrders(); compensateVinOrders(); } } /** * VIN 结算失败重试(1分钟一轮,结算失败主触发):处理账户结算失败回退的状态4订单, * 与10分钟补偿任务(DB兜底扫描)互补;重试幂等由账户侧消费流水保证,不会重复扣款。 */ @Scheduled(fixedRate = 1000 * 60, initialDelay = 1000 * 30) public void vinSettleRetryTask() { if (isScheduledTaskPort(port)) { try { vinChargingOrderService.retryPendingVinSettle(); } catch (Exception e) { log.error("[VD结算重试] 定时任务异常", e); } } } private void compensateCardOrders() { try { int recovered = cardChargingOrderService.recoverFinishedOrdersWithoutDeduct(); if (recovered > 0) { log.warn("[SD扣款补偿] 本轮回退未扣款已结束订单数量:{}", recovered); } } catch (Exception e) { log.error("[SD扣款补偿] 已结束未扣款扫描异常", e); } try { for (TCardChargingOrder order : cardChargingOrderService.listTimeoutStartingOrders()) { compensateCardStartingOrder(order); } } catch (Exception e) { log.error("[SD补偿] 启动超时扫描异常", e); } try { for (TCardChargingOrder order : cardChargingOrderService.listTimeoutChargingOrders()) { compensateCardActiveOrder(order); } } catch (Exception e) { log.error("[SD补偿] 活动订单扫描异常", e); } } private void compensateCardStartingOrder(TCardChargingOrder order) { try { TransactionRecord record = findCompleteTransactionRecord(order.getCode()); if (record != null) { cardChargingOrderService.cardEndChargeBillingCharge(toTransactionRecordVO(record)); return; } UploadRealTimeMonitoringData latest = uploadRealTimeMonitoringDataService.getLastDataById(order.getCode()); if (latest != null && (latest.getCreate_time() == null || System.currentTimeMillis() - latest.getCreate_time().getTime() <= MONITORING_SILENT_MILLIS)) { cardChargingOrderService.handleHandshakeVin(order.getCode(), null); log.info("[SD补偿] 启动应答缺失但存在活跃实时数据,恢复充电中 code={}", order.getCode()); return; } cardChargingOrderService.closeTimeoutStartingOrder(order); } catch (Exception ex) { log.error("[SD补偿] 启动订单处理异常,保留原状态待下轮重试 code={}", order.getCode(), ex); } } private void compensateCardActiveOrder(TCardChargingOrder order) { try { TransactionRecord record = findCompleteTransactionRecord(order.getCode()); if (record != null) { cardChargingOrderService.cardEndChargeBillingCharge(toTransactionRecordVO(record)); return; } UploadRealTimeMonitoringData latest = uploadRealTimeMonitoringDataService.getLastDataById(order.getCode()); if (shouldFallbackSettle(latest, order.getCreateTime(), false)) { cardChargingOrderService.compensationSettle(order); } } catch (Exception ex) { log.error("[SD补偿] 活动订单处理异常,保留原状态待下轮重试 code={}", order.getCode(), ex); } } private void compensateVinOrders() { try { for (TVinChargingOrder order : vinChargingOrderService.listTimeoutStartingOrders()) { compensateVinStartingOrder(order); } } catch (Exception e) { log.error("[VD补偿] 启动超时扫描异常", e); } try { for (TVinChargingOrder order : vinChargingOrderService.listTimeoutChargingOrders()) { compensateVinActiveOrder(order); } } catch (Exception e) { log.error("[VD补偿] 活动订单扫描异常", e); } } private void compensateVinStartingOrder(TVinChargingOrder order) { try { TransactionRecord record = findCompleteTransactionRecord(order.getCode()); if (record != null) { vinChargingOrderService.vinEndChargeBillingCharge(toTransactionRecordVO(record)); return; } UploadRealTimeMonitoringData latest = uploadRealTimeMonitoringDataService.getLastDataById(order.getCode()); if (latest != null && (latest.getCreate_time() == null || System.currentTimeMillis() - latest.getCreate_time().getTime() <= MONITORING_SILENT_MILLIS)) { vinChargingOrderService.handleHandshakeVin(order.getCode(), null); log.info("[VD补偿] 启动应答缺失但存在活跃实时数据,恢复充电中 code={}", order.getCode()); return; } vinChargingOrderService.closeTimeoutStartingOrder(order); } catch (Exception ex) { log.error("[VD补偿] 启动订单处理异常,保留原状态待下轮重试 code={}", order.getCode(), ex); } } private void compensateVinActiveOrder(TVinChargingOrder order) { try { TransactionRecord record = findCompleteTransactionRecord(order.getCode()); if (record != null) { vinChargingOrderService.vinEndChargeBillingCharge(toTransactionRecordVO(record)); return; } UploadRealTimeMonitoringData latest = uploadRealTimeMonitoringDataService.getLastDataById(order.getCode()); boolean stopping = Integer.valueOf(4).equals(order.getStatus()); if (shouldFallbackSettle(latest, order.getCreateTime(), stopping)) { vinChargingOrderService.compensationSettle(order); } } catch (Exception ex) { log.error("[VD补偿] 活动订单处理异常,保留原状态待下轮重试 code={}", order.getCode(), ex); } } private TransactionRecord findCompleteTransactionRecord(String code) { TransactionRecord record = transactionRecordService.findOne(code); return record != null && StringUtils.isNotEmpty(record.getResult()) ? record : null; } private TransactionRecordMessageVO toTransactionRecordVO(TransactionRecord record) { TransactionRecordMessageVO vo = new TransactionRecordMessageVO(); BeanUtils.copyProperties(record, vo); return vo; } static boolean shouldFallbackSettle(UploadRealTimeMonitoringData latest, LocalDateTime createTime, boolean stopping) { if (latest != null && latest.getCreate_time() != null) { return stopping || System.currentTimeMillis() - latest.getCreate_time().getTime() > MONITORING_SILENT_MILLIS; } if (stopping) { return true; } return createTime != null && ChronoUnit.MILLIS.between(createTime, LocalDateTime.now()) > NO_DEVICE_DATA_TIMEOUT_MILLIS; } //十分钟循环执行的定时任务 @Scheduled(fixedRate = 1000 * 60 * 10) public void taskTenMinutes() { if (isScheduledTaskPort(port)) { List failedStartupOrder = chargingOrderService.findFailedStartupOrder(); log.info("定时任务执行,查询到启动失败的订单数量:{}", failedStartupOrder.size()); for (TChargingOrder order : failedStartupOrder) { log.info("定时任务执行,查询到启动失败的订单:{}", order.getCode()); //查询是否有充电信息 List dataByOrderCode = uploadRealTimeMonitoringDataService.getDataByOrderCode(order.getCode()); log.info("充电实时数据:{}", dataByOrderCode.size()); //没有充电数据,则执行退款 if(null == dataByOrderCode || dataByOrderCode.isEmpty()){ log.info("定时任务执行,查询到启动失败的订单,执行退款:{}", order.getCode()); if(1 == order.getOrderSource()){ chargingOrderService.refund(order.getCode()); int num = 0; while (true){ TChargingOrderRefund one = chargingOrderRefundService.getOne(new LambdaQueryWrapper().eq(TChargingOrderRefund::getChargingOrderId, order.getId())); if(null != one && 2 == one.getRefundStatus()){ order.setStatus(-1); chargingOrderService.updateById(order); break; } try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } num++; if(num > 30){ break; } } }else{ order.setStatus(-1); chargingOrderService.updateById(order); } } } //处理退款中的数据 List stoppedOrder = chargingOrderService.findStoppedOrder(); log.info("定时任务执行,查询到停止中的订单数量:{}", stoppedOrder.size()); for (TChargingOrder order : stoppedOrder) { log.info("定时任务执行,查询到停止中的订单:{}", order.getCode()); TransactionRecord one = transactionRecordService.findOne(order.getCode()); if(null != one){ log.info("定时任务执行,查询到停止中的订单账单数据:{}", JSON.toJSONString(one)); if(null == order.getStartTime()){ List dataList = uploadRealTimeMonitoringDataService.getDataByOrderCode(order.getCode()); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); if(dataList.isEmpty()){ order.setStartTime(LocalDateTime.parse(one.getStart_time(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SS").withZone(ZoneId.systemDefault()))); }else{ order.setStartTime(LocalDateTime.parse(sdf.format(dataList.get(dataList.size() - 1).getCreate_time()), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(ZoneId.systemDefault()))); } } if(null == order.getEndTime()){ order.setEndTime(LocalDateTime.parse(one.getEnd_time(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SS").withZone(ZoneId.systemDefault()))); } chargingOrderService.updateById(order); TransactionRecordMessageVO vo = new TransactionRecordMessageVO(); BeanUtils.copyProperties(one, vo); R r = chargingOrderService.endChargeBillingCharge(vo); log.info("定时任务执行,停止中的订单处理结果:{}", JSON.toJSONString(r)); }else{ endOrder(order); } } //处理状态为充电中,但硬件已完成的订单 List chargingOrder = chargingOrderService.findChargingOrder(); log.info("定时任务执行,查询到充电中的订单数量:{}", chargingOrder.size()); for (TChargingOrder order : chargingOrder) { log.info("定时任务执行,查询到充电中的订单:{}", order.getCode()); TransactionRecord one = transactionRecordService.findOne(order.getCode()); if(null != one && StringUtils.isNotEmpty(one.getResult())){ log.info("定时任务执行,查询到充电中的订单账单数据:{}", JSON.toJSONString(one)); if(null == order.getStartTime()){ List dataList = uploadRealTimeMonitoringDataService.getDataByOrderCode(order.getCode()); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); if(dataList.isEmpty()){ order.setStartTime(LocalDateTime.parse(one.getStart_time(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SS").withZone(ZoneId.systemDefault()))); }else{ order.setStartTime(LocalDateTime.parse(sdf.format(dataList.get(dataList.size() - 1).getCreate_time()), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(ZoneId.systemDefault()))); } } if(null == order.getEndTime()){ order.setEndTime(LocalDateTime.parse(one.getEnd_time(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SS").withZone(ZoneId.systemDefault()))); } chargingOrderService.updateById(order); TransactionRecordMessageVO vo = new TransactionRecordMessageVO(); BeanUtils.copyProperties(one, vo); R r = chargingOrderService.endChargeBillingCharge(vo); log.info("定时任务执行,充电中的订单处理结果:{}", JSON.toJSONString(r)); }else{ //判断充电流水超过10分钟没有更新,则判定为充电结束 List dataList = uploadRealTimeMonitoringDataService.getDataByOrderCode(order.getCode()); if(!dataList.isEmpty()){ UploadRealTimeMonitoringData uploadRealTimeMonitoringData = dataList.get(0); Date createTime = uploadRealTimeMonitoringData.getCreate_time(); if(System.currentTimeMillis() - createTime.getTime() - (8 * 60 * 60 * 1000) > 1000 * 60 * 10){ endOrder(order); } } } } //处理还未退款,但是订单状态已结束的数据 List endChargingOrder = chargingOrderService.findEndChargingOrder(); log.info("定时任务执行,查询到已结束未退款的订单数量:{}", endChargingOrder.size()); for (TChargingOrder order : endChargingOrder) { if(-1 == order.getStatus()){ order.setStatus(2); } if(5 == order.getStatus()){ order.setStatus(4); } chargingOrderService.updateById(order); } } } //定时任务添加结算账单汇总数据 @Scheduled(cron = "0 30 0 * * ?") public void taskMonth() { if (isScheduledTaskPort(port)) { //推送三方引流平台数据 pushOrderDrainagePlatform(); //添加充电算账单汇总数据 addChargingSettlementBill(); //添加账户结算账单数据 addAccountSettlementStatement(); } } // 每个月最后一天23点执行的定时任务 @Scheduled(cron = "0 0 23 * * ?") public void taskLastDay() { if (isScheduledTaskPort(port)) { try { int dayOfMonth = LocalDate.now().getDayOfMonth(); int lastDayOfMonth = LocalDate.now().with(TemporalAdjusters.lastDayOfMonth()).getDayOfMonth(); //当月最后一天 if(dayOfMonth == lastDayOfMonth){ //修改充电结算账单为已出账 chargingSettlementBillService.update(new UpdateWrapper().set("status", 2).set("create_time", LocalDateTime.now()).eq("status", 1)); //修改账户结算账单为已出账 accountSettlementStatementService.update(new UpdateWrapper().set("status", 2).set("create_time", LocalDateTime.now()).eq("status", 1)); } } catch (Exception e) { e.printStackTrace(); } } } @Override public void onApplicationEvent(WebServerInitializedEvent event) { port = event.getWebServer().getPort(); System.out.println("端口号:" + port); } static boolean isScheduledTaskPort(Integer serverPort) { return Integer.valueOf(5400).equals(serverPort) || Integer.valueOf(9400).equals(serverPort); } @Transactional public void endOrder(TChargingOrder order){ RLock lock = redissonClient.getLock("endOrder:" + order.getCode()); try { boolean tryLock = lock.tryLock(60, 60, TimeUnit.SECONDS); if(tryLock){ List dataList = uploadRealTimeMonitoringDataService.getDataByOrderCode(order.getCode()); if(!dataList.isEmpty()){ //获取当前订单的计费规则,然后分段计算总的度数和充电金额 List detailOrders = accountingStrategyDetailOrderService.list(new LambdaQueryWrapper() .eq(AccountingStrategyDetailOrder::getChargingOrderId, order.getId()).last(" order by start_time")); detailOrders.get(detailOrders.size() - 1).setEndTime("23:59"); SimpleDateFormat sdf = new SimpleDateFormat("HH:mm"); //开始解析每个时段的充电度数 BigDecimal decimal = BigDecimal.ZERO; //如果使用优惠券需要判断优惠券是否满足使用条件 //退款金额=优惠券金额+剩余充电金额 BigDecimal periodElectricPrice_total = BigDecimal.ZERO; BigDecimal periodServicePrice_total = BigDecimal.ZERO; BigDecimal vipDiscountAmount_total = BigDecimal.ZERO; BigDecimal serviceCharge_total = BigDecimal.ZERO; BigDecimal total = BigDecimal.ZERO; //判断实时数据是否跨天 SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd"); Date end_time = dataList.get(0).getCreate_time(); String end = sdf2.format(end_time); Date start_time = dataList.get(dataList.size() - 1).getCreate_time(); String start = sdf2.format(start_time); if(!end.equals(start)){ List list = detailOrders.stream().map(s->{ AccountingStrategyDetailOrder accountingStrategyDetailOrder = new AccountingStrategyDetailOrder(); BeanUtils.copyProperties(s, accountingStrategyDetailOrder); return accountingStrategyDetailOrder; }).collect(Collectors.toList()); for (AccountingStrategyDetailOrder detailOrder : detailOrders) { detailOrder.setStartTime(start + " " + detailOrder.getStartTime()); detailOrder.setEndTime(start + " " + detailOrder.getEndTime()); } for (AccountingStrategyDetailOrder detailOrder : list) { detailOrder.setStartTime(end + " " + detailOrder.getStartTime()); detailOrder.setEndTime(end + " " + detailOrder.getEndTime()); } detailOrders.addAll(list); }else{ for (AccountingStrategyDetailOrder detailOrder : detailOrders) { detailOrder.setStartTime(start + " " + detailOrder.getStartTime()); detailOrder.setEndTime(start + " " + detailOrder.getEndTime()); } } //企业账户流程:白名单企业账户订单按企业优惠结算(方式2=服务费比例优惠,方式3=按计费模板同阶段单价) boolean enterpriseSettlement = chargingOrderService.isWhitelistEnterpriseOrder(order); CompanyPreferentialDTO enterprisePreferential = enterpriseSettlement ? chargeAccountSupport.loadCompanyPreferential(order.getCompanyId()) : null; Integer enterprisePreferentialType = null == enterprisePreferential ? null : enterprisePreferential.getPreferentialType(); TBillingTemplateDTO enterpriseTemplate = enterpriseSettlement ? chargeAccountSupport.loadBillingTemplate(enterprisePreferential) : null; BigDecimal enterpriseElectricDiscount = BigDecimal.ZERO; BigDecimal enterpriseServiceDiscount = BigDecimal.ZERO; SimpleDateFormat sdf1 = new SimpleDateFormat("yyyyMMddHHmm"); List list = new ArrayList<>(); for (AccountingStrategyDetailOrder detailOrder : detailOrders) { long startTime = Long.parseLong(detailOrder.getStartTime().replaceAll("-", "").replaceAll(" ", "").replaceAll(":", "")); long endTime = Long.parseLong(detailOrder.getEndTime().replaceAll("-", "").replaceAll(" ", "").replaceAll(":", "")); List collect = dataList.stream().filter(s -> Long.parseLong(sdf1.format(s.getCreate_time())) > startTime && Long.parseLong(sdf1.format(s.getCreate_time())) <= endTime).collect(Collectors.toList()); if(!collect.isEmpty()){ //升序排序 collect.sort(new Comparator(){ @Override public int compare(UploadRealTimeMonitoringData o1, UploadRealTimeMonitoringData o2) { return o1.getCharging_degree().compareTo(o2.getCharging_degree()); } }); UploadRealTimeMonitoringData uploadRealTimeMonitoringData = collect.get(collect.size() - 1); BigDecimal chargingDegree = uploadRealTimeMonitoringData.getCharging_degree(); BigDecimal subtract = chargingDegree.subtract(decimal); decimal = chargingDegree; if(subtract.compareTo(BigDecimal.ZERO) > 0){ //组装充电明细数据 TChargingOrderAccountingStrategy chargingOrderAccountingStrategy = new TChargingOrderAccountingStrategy(); chargingOrderAccountingStrategy.setChargingOrderId(order.getId()); chargingOrderAccountingStrategy.setAccountingStrategyDetailId(detailOrder.getId()); chargingOrderAccountingStrategy.setType(detailOrder.getType()); chargingOrderAccountingStrategy.setElectrovalence(detailOrder.getElectrovalence()); chargingOrderAccountingStrategy.setServiceCharge(detailOrder.getServiceCharge()); chargingOrderAccountingStrategy.setCostServiceCharge(detailOrder.getCostServiceCharge()); chargingOrderAccountingStrategy.setChargingCapacity(subtract); chargingOrderAccountingStrategy.setCreateTime(LocalDateTime.now()); if (list.size() == 0) { String time = sdf.format(collect.get(0).getCreate_time()); chargingOrderAccountingStrategy.setStartTime(time); } else { chargingOrderAccountingStrategy.setStartTime(detailOrder.getStartTime().split(" ")[1]); } chargingOrderAccountingStrategy.setEndTime(detailOrder.getEndTime().split(" ")[1]); //已充电总度数 BigDecimal finalElectricPrice = detailOrder.getElectrovalence(); BigDecimal finalServicePrice = detailOrder.getServiceCharge(); //企业账户流程:按企业优惠计算最终用电单价 if (enterpriseSettlement) { if (Integer.valueOf(ChargeAccountSupport.PREFERENTIAL_TYPE_RATE).equals(enterprisePreferentialType)) { //方式2:服务费按比例优惠 finalServicePrice = ChargeAccountSupport.applyServiceDiscountRate(finalServicePrice, enterprisePreferential.getServiceDiscountRate()); } else if (Integer.valueOf(ChargeAccountSupport.PREFERENTIAL_TYPE_TEMPLATE).equals(enterprisePreferentialType)) { //方式3:按计费模板同电价阶段单价 TBillingTemplateDetail templateDetail = ChargeAccountSupport.findTemplateDetail(enterpriseTemplate, detailOrder.getType()); if (null == templateDetail) { log.error("[CD补偿结算] 计费模板缺少对应电价阶段,该阶段按原价结算 code={} type={}", order.getCode(), detailOrder.getType()); } else { if (null != templateDetail.getElectrovalence()) { finalElectricPrice = templateDetail.getElectrovalence(); } if (null != templateDetail.getServiceCharge()) { finalServicePrice = templateDetail.getServiceCharge(); } } } } BigDecimal electrovalenc = finalElectricPrice.multiply(subtract); BigDecimal originalServicePrice = detailOrder.getServiceCharge().multiply(subtract); BigDecimal serviceCharge = finalServicePrice.multiply(subtract); BigDecimal vipDiscountAmount = BigDecimal.ZERO; //计算优惠金额;企业账户流程按企业优惠结算,其余订单中余额支付(含组合支付)不参与会员折扣 if (enterpriseSettlement) { //企业优惠金额(原价-优惠价),用于订单优惠统计与 whitelist_* 快照 enterpriseElectricDiscount = enterpriseElectricDiscount.add(detailOrder.getElectrovalence().multiply(subtract).subtract(electrovalenc)); enterpriseServiceDiscount = enterpriseServiceDiscount.add(originalServicePrice.subtract(serviceCharge)); } else if (!isWhitelistOrder(order) && !isBalancePayMode(order.getPayMethod()) && null != order.getVipDiscount()) { //0.58折 vipDiscountAmount = serviceCharge.multiply(new BigDecimal(1).subtract(order.getVipDiscount())); serviceCharge = serviceCharge.multiply(order.getVipDiscount()); } //企业账户流程:明细单价记录优惠后单价,金额与单价口径一致 if (enterpriseSettlement) { chargingOrderAccountingStrategy.setElectrovalence(finalElectricPrice); chargingOrderAccountingStrategy.setServiceCharge(finalServicePrice); } chargingOrderAccountingStrategy.setPeriodElectricPrice(electrovalenc.setScale(4, RoundingMode.HALF_EVEN)); chargingOrderAccountingStrategy.setPeriodServicePrice(serviceCharge.setScale(4, RoundingMode.HALF_EVEN)); chargingOrderAccountingStrategy.setPeriodOriginalServicePrice(originalServicePrice.setScale(4, RoundingMode.HALF_EVEN)); chargingOrderAccountingStrategy.setVipDiscountAmount(vipDiscountAmount.setScale(4, RoundingMode.HALF_EVEN)); chargingOrderAccountingStrategy.setCreateTime(LocalDateTime.now()); list.add(chargingOrderAccountingStrategy); //电费 periodElectricPrice_total = periodElectricPrice_total.add(electrovalenc); //服务费(含折扣) serviceCharge_total = serviceCharge_total.add(serviceCharge); //服务费(不含折扣) periodServicePrice_total = periodServicePrice_total.add(originalServicePrice); //会员折扣优惠金额 vipDiscountAmount_total = vipDiscountAmount_total.add(vipDiscountAmount); //原始总金额(不含折扣) total = total.add(electrovalenc.add(originalServicePrice)); } } } list.get(list.size() - 1).setEndTime(sdf.format(dataList.get(0).getCreate_time())); chargingOrderAccountingStrategyService.saveBatch(list); BigDecimal orderAmount = BigDecimal.valueOf(total.doubleValue()); //原金额 BigDecimal rechargeAmount = order.getRechargeAmount(); //支付金额 BigDecimal payAmount = periodElectricPrice_total.add(serviceCharge_total); //退款金额=充值金额-实际支付金额 BigDecimal refundAmount = rechargeAmount.subtract(payAmount); UploadRealTimeMonitoringData uploadRealTimeMonitoringData = uploadRealTimeMonitoringDataService.getLastDataById(order.getCode()); if (null != uploadRealTimeMonitoringData && null == order.getEndMode()) { Integer soc = uploadRealTimeMonitoringData.getSoc(); if (soc >= 98) { order.setEndMode(2); } else if (null != order.getResidualAmount() && order.getResidualAmount().compareTo(new BigDecimal(1)) <= 0) { order.setEndMode(3); } else { order.setEndMode(1); } } order.setResidualAmount(rechargeAmount.subtract(total).setScale(2, RoundingMode.HALF_EVEN)); order.setStartTime(list.get(0).getCreateTime()); order.setEndTime(list.get(list.size() - 1).getCreateTime()); order.setStatus(5); order.setOrderAmount(orderAmount.setScale(2, RoundingMode.HALF_EVEN)); order.setElectrovalence(periodElectricPrice_total.setScale(2, RoundingMode.HALF_EVEN)); order.setChargingCapacity(list.get(list.size() - 1).getChargingCapacity()); order.setElectricity(list.get(list.size() - 1).getChargingCapacity()); order.setVipDiscountAmount(vipDiscountAmount_total); if (vipDiscountAmount_total.compareTo(BigDecimal.ZERO) == 0) { order.setVipDiscount(BigDecimal.valueOf(1)); } //计算优惠券 BigDecimal couponDiscount = BigDecimal.ZERO; if (!isWhitelistOrder(order) && null != order.getAppCouponId()) { //判断实际充电金额是否满足优惠券使用条件,如果不满足则不适用优惠券。 TAppCoupon appCoupon = appCouponClient.getAppCouponById(order.getAppCouponId()).getData(); String couponJson = appCoupon.getCouponJson(); TCoupon tCoupon = com.alibaba.fastjson2.JSON.parseObject(couponJson, TCoupon.class); Integer preferentialMode = tCoupon.getPreferentialMode(); if (1 == preferentialMode) { //满减 if (payAmount.compareTo(tCoupon.getMeetTheConditions()) >= 0) { BigDecimal couponDiscountAmount = tCoupon.getDiscountAmount(); //如果优惠金额大于服务费金额,以服务费作为最大限制 if (serviceCharge_total.compareTo(couponDiscountAmount) < 0) { couponDiscount = serviceCharge_total; serviceCharge_total = BigDecimal.ZERO; } else { couponDiscount = couponDiscountAmount; } appCoupon.setStatus(2); appCouponClient.updateAppCoupon(appCoupon); } else { appCouponClient.refund(order.getAppCouponId().toString()); order.setAppCouponId(null); order.setCouponDiscountAmount(BigDecimal.ZERO); } } if (2 == preferentialMode) { //抵扣 if (payAmount.compareTo(tCoupon.getMeetTheConditions()) >= 0) { //折扣金额 BigDecimal divide = payAmount.multiply(new BigDecimal(10).subtract(tCoupon.getDiscount())).divide(new BigDecimal(10)); divide = divide.compareTo(tCoupon.getMaximumDiscountAmount()) > 0 ? tCoupon.getMaximumDiscountAmount() : divide; //如果优惠金额大于服务费金额,以服务费作为最大限制 if (serviceCharge_total.compareTo(divide) < 0) { couponDiscount = serviceCharge_total; serviceCharge_total = BigDecimal.ZERO; } else { couponDiscount = divide; } appCoupon.setStatus(2); appCouponClient.updateAppCoupon(appCoupon); } else { order.setAppCouponId(null); order.setCouponDiscountAmount(BigDecimal.ZERO); appCouponClient.refund(order.getAppCouponId().toString()); } } } BigDecimal[] whitelistRefundSplit = calculateWhitelistRefundSplit(order, periodElectricPrice_total, serviceCharge_total); BigDecimal electricDiscount = whitelistRefundSplit[0]; BigDecimal serviceDiscount = whitelistRefundSplit[1]; BigDecimal whitelistDiscount = electricDiscount.add(serviceDiscount).setScale(4, RoundingMode.HALF_EVEN); if (enterpriseSettlement) { // 企业账户流程:企业优惠已在明细阶段计入金额,这里只做统计快照(金额口径与实时结算一致) electricDiscount = enterpriseElectricDiscount.max(BigDecimal.ZERO).setScale(4, RoundingMode.HALF_EVEN); serviceDiscount = enterpriseServiceDiscount.max(BigDecimal.ZERO).setScale(4, RoundingMode.HALF_EVEN); whitelistDiscount = electricDiscount.add(serviceDiscount); } else if (whitelistDiscount.compareTo(BigDecimal.ZERO) > 0) { // 补偿任务需与实时结算使用同一拆分口径,避免财务导出金额不一致。 periodElectricPrice_total = periodElectricPrice_total.subtract(electricDiscount).max(BigDecimal.ZERO); serviceCharge_total = serviceCharge_total.subtract(serviceDiscount).max(BigDecimal.ZERO); refundAmount = refundAmount.add(whitelistDiscount); payAmount = payAmount.subtract(whitelistDiscount).max(BigDecimal.ZERO); } //优惠券优惠金额 couponDiscount = couponDiscount.setScale(4, RoundingMode.HALF_EVEN); //退款金额+优惠券 refundAmount = refundAmount.add(couponDiscount); //实际支付金额-优惠券 payAmount = payAmount.subtract(couponDiscount); if (serviceCharge_total.compareTo(BigDecimal.ZERO) > 0) { serviceCharge_total = serviceCharge_total.subtract(couponDiscount); } order.setCouponDiscountAmount(couponDiscount.setScale(2, RoundingMode.HALF_EVEN)); //企业账户流程:企业优惠金额与 whitelist_* 三列快照双写(订单优惠统计沿用 whitelist_* 口径) if (enterpriseSettlement) { order.setDiscountElectrovalence(electricDiscount.setScale(2, RoundingMode.HALF_EVEN)); order.setDiscountServiceCharge(serviceDiscount.setScale(2, RoundingMode.HALF_EVEN)); order.setWhitelistElectricRefundAmount(electricDiscount.setScale(2, RoundingMode.HALF_EVEN)); order.setWhitelistServiceRefundAmount(serviceDiscount.setScale(2, RoundingMode.HALF_EVEN)); order.setWhitelistDiscountAmount(whitelistDiscount.setScale(2, RoundingMode.HALF_EVEN)); } else { order.setWhitelistDiscountAmount(whitelistDiscount.setScale(2, RoundingMode.HALF_EVEN)); order.setWhitelistElectricRefundAmount(electricDiscount.setScale(2, RoundingMode.HALF_EVEN)); order.setWhitelistServiceRefundAmount(serviceDiscount.setScale(2, RoundingMode.HALF_EVEN)); } order.setElectrovalence(periodElectricPrice_total.setScale(2, RoundingMode.HALF_EVEN)); order.setServiceCharge(serviceCharge_total.setScale(2, RoundingMode.HALF_EVEN)); if (enterpriseSettlement) { // 企业账户流程:资金来自企业账户额度(差额结算时退回企业账户),订单无用户侧退款,实付金额=实际消费金额 order.setBalancePayAmount(payAmount.setScale(2, RoundingMode.HALF_EVEN)); order.setPaymentAmount(payAmount.setScale(2, RoundingMode.HALF_EVEN)); order.setRefundAmount(BigDecimal.ZERO.setScale(2, RoundingMode.HALF_EVEN)); order.setRefundStatus(2); refundAmount = BigDecimal.ZERO.setScale(2, RoundingMode.HALF_EVEN); } else { order.setPaymentAmount(payAmount.setScale(2, RoundingMode.HALF_EVEN)); order.setRefundAmount(refundAmount.setScale(2, RoundingMode.HALF_EVEN)); order.setRefundStatus(1); } UploadRealTimeMonitoringData asc = uploadRealTimeMonitoringDataService.getDataByOrderCode(order.getCode(), "asc"); UploadRealTimeMonitoringData desc = uploadRealTimeMonitoringDataService.getDataByOrderCode(order.getCode(), "desc"); if(null != asc){ order.setStartSoc(new BigDecimal(asc.getSoc())); } if(null != desc){ order.setEndSoc(new BigDecimal(desc.getSoc())); } chargingOrderService.updateById(order); //企业账户流程:结算企业额度(按实际消费扣减锁定额度、差额退回企业账户)并写消费流水 if (enterpriseSettlement && !chargingOrderService.settleWhitelistEnterpriseAccount(order, payAmount)) { // 结算失败回退为停止中,交由补偿任务下一轮重新结算,避免企业额度长期冻结 order.setStatus(4); chargingOrderService.updateById(order); log.error("[CD补偿结算] 企业账户额度结算失败,订单回退停止中等待重试 code={}", order.getCode()); return; } order = chargingOrderService.getById(order.getId()); Site site = siteClient.getSiteByIds(Arrays.asList(order.getSiteId())).getData().get(0); //推送三方平台 if (2 == order.getOrderSource() && 1 == site.getIsOpenSynchronization()) { TChargingOrder finalChargingOrder = order; new Thread(new Runnable() { @Override public void run() { tcecClient.notificationEquipChargeStatus(finalChargingOrder.getStartChargeSeq(), finalChargingOrder.getOperatorId()); tcecClient.notificationStopChargeResult(finalChargingOrder.getStartChargeSeq(), finalChargingOrder.getChargingGunId().toString(), finalChargingOrder.getOperatorId()); tcecClient.notificationChargeOrderInfo(finalChargingOrder.getStartChargeSeq(), finalChargingOrder.getOperatorId()); } }).start(); } //开始将优惠券优惠的金额添加到明细中 BigDecimal couponDiscountAmount = order.getCouponDiscountAmount(); if (null != couponDiscountAmount && couponDiscountAmount.compareTo(BigDecimal.ZERO) > 0) { List list1 = chargingOrderAccountingStrategyService.list(new LambdaQueryWrapper().eq(TChargingOrderAccountingStrategy::getChargingOrderId, order.getId())); BigDecimal reduce = list1.stream().map(TChargingOrderAccountingStrategy::getPeriodServicePrice).reduce(BigDecimal.ZERO, BigDecimal::add); for (TChargingOrderAccountingStrategy chargingOrderAccountingStrategy : list1) { BigDecimal periodServicePrice = chargingOrderAccountingStrategy.getPeriodServicePrice(); BigDecimal multiply = couponDiscountAmount.multiply(periodServicePrice.divide(reduce, new MathContext(4, RoundingMode.HALF_EVEN))); periodServicePrice = periodServicePrice.subtract(multiply); chargingOrderAccountingStrategy.setPeriodServicePrice(periodServicePrice.setScale(2, RoundingMode.HALF_EVEN)); chargingOrderAccountingStrategy.setCouponDiscountAmount(multiply.setScale(2, RoundingMode.HALF_EVEN)); } chargingOrderAccountingStrategyService.updateBatchById(list1); } // 将枪状态重置为空闲 TChargingGun chargingGun = new TChargingGun(); chargingGun.setId(order.getChargingGunId()); chargingGun.setStatus(2); chargingGun.setChargingPower(BigDecimal.ZERO); chargingGunClient.updateChargingGunById(chargingGun); chargingGun = chargingGunClient.getChargingGunById(order.getChargingGunId()).getData(); //推送状态给三方平台 if (2 == order.getOrderSource() && 1 == site.getIsOpenSynchronization()) { tcecClient.pushChargingGunStatus(chargingGun.getFullNumber(), 2); } ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.SECONDS, new LinkedBlockingDeque<>()); TChargingOrder finalOrder = order; threadPoolExecutor.execute(()->{ //推送成都监管 NotificationConnectorChargeStatusVo statusVo = new NotificationConnectorChargeStatusVo(); statusVo.setOrderCode(finalOrder.getCode()); statusVo.setChargingGunId(finalOrder.getChargingGunId()); chengDuJianGuanClient.notificationConnectorChargeStatus(statusVo); chengDuJianGuanClient.notificationOrderInfo(statusVo); }); //添加积分 if (1 == order.getOrderSource()) { TIntegralRule integralRule = integralRuleClient.getSet().getData(); if (null != integralRule) { TAppUser appUser = appUserClient.getUserById(order.getAppUserId()).getData(); Integer num1 = com.alibaba.fastjson2.JSON.parseObject(integralRule.getChargeCredit()).getInteger("num1"); Integer integral = order.getServiceCharge().intValue() * num1; if (null != appUser.getVipId()) { TVip vip = vipClient.getInfo1(appUser.getVipId()).getData(); Integer doubleIntegration = vip.getDoubleIntegration(); //双倍积分 if (1 == doubleIntegration) { integral *= 2; } } if (integral > 0) { TAppUserIntegralChange appUserIntegralChange = new TAppUserIntegralChange(); appUserIntegralChange.setAppUserId(appUser.getId()); appUserIntegralChange.setChangeType(2); appUserIntegralChange.setHistoricalIntegral(appUser.getPoints()); appUser.setPoints(appUser.getPoints() + integral); appUserIntegralChange.setCurrentIntegral(appUser.getPoints()); appUserIntegralChange.setCreateTime(LocalDateTime.now()); appUserIntegralChange.setOrderCode(order.getCode()); appUserIntegralChange.setExtension(order.getId().toString()); appUserClient.updateAppUser(appUser); appUserIntegralChangeClient.addAppUserIntegralChange(appUserIntegralChange); } } //计算用户标签 chargingOrderService.editUserTag(order); //用户推荐奖励 chargingOrderService.referralReward(order); //开始构建退款费用 refundAmount = refundAmount.setScale(2, RoundingMode.HALF_EVEN); BigDecimal refundableThirdPayAmount = getRefundableThirdPayAmount(order); BigDecimal remainingThirdAmount = refundableThirdPayAmount .subtract(money(order.getThirdRefundAmount())).max(BigDecimal.ZERO); BigDecimal remainingBalanceAmount = money(order.getBalancePayAmount()) .subtract(money(order.getBalanceRefundAmount())).max(BigDecimal.ZERO); BigDecimal refundableAmount = remainingThirdAmount.add(remainingBalanceAmount).setScale(2, RoundingMode.HALF_UP); // 白名单全部免费只记录预估预充金额,实际渠道退款金额保持0,防止补偿任务重复发起退款。 BigDecimal recordedRefundAmount = isWhitelistAllFreeOrder(order) ? money(order.getRechargeAmount()) : refundAmount; BigDecimal channelRefundAmount = isWhitelistAllFreeOrder(order) ? BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP) : refundAmount.min(refundableAmount).setScale(2, RoundingMode.HALF_UP); Integer rechargePaymentType = order.getRechargePaymentType(); BigDecimal thirdRefundAmount = channelRefundAmount.min(remainingThirdAmount).setScale(2, RoundingMode.HALF_UP); BigDecimal balanceRefundAmount = channelRefundAmount.subtract(thirdRefundAmount) .min(remainingBalanceAmount).setScale(2, RoundingMode.HALF_UP); if (channelRefundAmount.compareTo(BigDecimal.ZERO) > 0) { refundAmount = thirdRefundAmount.add(balanceRefundAmount).setScale(2, RoundingMode.HALF_UP); order.setThirdRefundAmount(money(order.getThirdRefundAmount()).add(thirdRefundAmount)); order.setBalanceRefundAmount(money(order.getBalanceRefundAmount()).add(balanceRefundAmount)); order.setRefundAmount(recordedRefundAmount); order.setRefundStatus(refundAmount.compareTo(BigDecimal.ZERO) > 0 ? 1 : 2); chargingOrderService.updateById(order); //构建退款明细 TChargingOrderRefund chargingOrderRefund = new TChargingOrderRefund(); chargingOrderRefund.setChargingOrderId(order.getId()); SimpleDateFormat sdfaa = new SimpleDateFormat("yyyyMMddHHmmssSSS"); chargingOrderRefund.setRefundCode("CDF" + sdfaa.format(new Date()) + (Double.valueOf(Math.random() * 1000).intValue())); chargingOrderRefund.setRefundAmount(refundAmount); chargingOrderRefund.setRefundStatus(1); chargingOrderRefund.setPayType(rechargePaymentType); chargingOrderRefund.setCode(order.getCode()); chargingOrderRefund.setRefundTitle("充电完成退款"); chargingOrderRefund.setRefundContent("充电完成退款"); chargingOrderRefund.setRefundReason("充电完成退款"); chargingOrderRefund.setRefundRemark("实际充电消费金额:" + order.getPaymentAmount()); chargingOrderRefund.setRefundTotalAmount(refundAmount); chargingOrderRefund.setPayAmount(rechargeAmount); if (thirdRefundAmount.compareTo(BigDecimal.ZERO) == 0) { chargingOrderRefund.setRefundStatus(2); chargingOrderRefund.setRefundSerialNumber("BALANCE"); chargingOrderRefund.setRefundTime(LocalDateTime.now()); chargingOrderRefundService.save(chargingOrderRefund); if (balanceRefundAmount.compareTo(BigDecimal.ZERO) > 0) { recordBalanceRefund(order, balanceRefundAmount, chargingOrderRefund.getRefundCode()); } order.setRefundStatus(2); order.setRefundTime(LocalDateTime.now()); chargingOrderService.updateById(order); } else if ("ICBC".equalsIgnoreCase(order.getSourceName())) { IcbcRefundReq req = new IcbcRefundReq(); req.setOutTradeNo(order.getCode()); req.setOrderId(order.getRechargeSerialNumber()); req.setOutRefundNo(chargingOrderRefund.getRefundCode()); req.setRefundAmount(thirdRefundAmount); req.setTotalAmount(getRefundableThirdPayAmount(order)); req.setReason("充电完成退款"); R result = icbcPaymentClient.refund(req); IcbcRefundResp resp = result == null ? null : result.getData(); if (result != null && result.getCode() == 200 && resp != null && "SUCCESS".equals(resp.getStatus())) { chargingOrderRefundService.save(chargingOrderRefund); String refundId = StringUtils.isNotEmpty(resp.getRefundId()) ? resp.getRefundId() : resp.getOutRefundNo(); chargingOrderService.chargingOrderStartupFailureWxRefund( chargingOrderRefund.getRefundCode(), refundId, "SUCCESS", resp.getRefundTime()); } else { log.error("工行充电完成退款失败,订单号:{},退款单号:{},返回:{}", order.getCode(), chargingOrderRefund.getRefundCode(), result == null ? null : result.getMsg()); } } else if (1 == rechargePaymentType) { WxPaymentRefundModel model = new WxPaymentRefundModel(); model.setOut_trade_no(order.getCode()); model.setOut_refund_no(chargingOrderRefund.getRefundCode()); model.setReason("充电完成退款"); model.setNotify_url("/payment/wx/refund/notify"); WxPaymentRefundModel.RefundAmount amount = new WxPaymentRefundModel.RefundAmount(); amount.setRefund(thirdRefundAmount.multiply(new BigDecimal(100)).intValue()); amount.setTotal(getRefundableThirdPayAmount(order).multiply(new BigDecimal(100)).intValue()); amount.setCurrency("CNY"); model.setAmount(amount); R> result = wxPaymentClient.refundOrderR(model); if (200 == result.getCode()) { chargingOrderRefundService.save(chargingOrderRefund); //??? Map amount1 = (Map) result.getData().get("amount"); Object refund_fee1 = amount1.get("refund_fee"); BigDecimal refund_fee = new BigDecimal(null == refund_fee1 ? "0" : refund_fee1.toString()).divide(new BigDecimal(100)); chargingOrderRefund.setRefundFee(refund_fee); chargingOrderRefundService.updateById(chargingOrderRefund); } } else if (2 == rechargePaymentType) { RefundReq dto = new RefundReq(); dto.setOutTradeNo(order.getCode()); dto.setOutRequestNo(chargingOrderRefund.getRefundCode()); dto.setRefundAmount(thirdRefundAmount.toString()); dto.setRefundReason("充电完成退款"); RefundResp resp = aliPaymentClient.refund(dto).getData(); if (null != resp) { chargingOrderRefundService.save(chargingOrderRefund); chargingOrderService.chargingOrderStartupFailureWxRefund(chargingOrderRefund.getRefundCode(), resp.getTradeNo(), "SUCCESS", null); } } else if (3 == rechargePaymentType) { RefundReq dto = new RefundReq(); dto.setOutTradeNo(order.getRechargeSerialNumber()); dto.setOutRequestNo(chargingOrderRefund.getRefundCode()); dto.setRefundAmount(thirdRefundAmount.toString()); dto.setRefundReason("充电完成退款"); RefundResp resp = h5AliPaymentClient.refund(dto).getData(); if (null != resp && "10000".equals(resp.getCode())) { chargingOrderRefundService.save(chargingOrderRefund); chargingOrderService.chargingOrderStartupFailureWxRefund(chargingOrderRefund.getRefundCode(), resp.getTradeNo(), "SUCCESS", null); } } } else if (recordedRefundAmount.compareTo(BigDecimal.ZERO) > 0) { order.setThirdRefundAmount(thirdRefundAmount); order.setBalanceRefundAmount(balanceRefundAmount); order.setRefundAmount(recordedRefundAmount); order.setRefundStatus(2); chargingOrderService.updateById(order); TChargingOrderRefund chargingOrderRefund = new TChargingOrderRefund(); chargingOrderRefund.setChargingOrderId(order.getId()); SimpleDateFormat sdfaa = new SimpleDateFormat("yyyyMMddHHmmssSSS"); chargingOrderRefund.setRefundCode("CDF" + sdfaa.format(new Date()) + (Double.valueOf(Math.random() * 1000).intValue())); chargingOrderRefund.setRefundAmount(recordedRefundAmount); chargingOrderRefund.setBalanceRefundAmount(balanceRefundAmount); chargingOrderRefund.setThirdRefundAmount(thirdRefundAmount); chargingOrderRefund.setRefundStatus(2); chargingOrderRefund.setRefundSerialNumber("WHITELIST"); chargingOrderRefund.setRefundTime(LocalDateTime.now()); chargingOrderRefund.setPayType(rechargePaymentType); chargingOrderRefund.setCode(order.getCode()); chargingOrderRefund.setRefundTitle("充电完成退款"); chargingOrderRefund.setRefundContent("充电完成退款"); chargingOrderRefund.setRefundReason("充电完成退款"); chargingOrderRefund.setRefundRemark("白名单全部免费,记录预估退款金额"); chargingOrderRefund.setRefundTotalAmount(recordedRefundAmount); chargingOrderRefund.setPayAmount(rechargeAmount); chargingOrderRefundService.save(chargingOrderRefund); } } //添加汇总统计数据 List list4 = chargingOrderAccountingStrategyService.list(new QueryWrapper().eq("charging_order_id", order.getId())); BigDecimal electronic_reduce = list4.stream().map(TChargingOrderAccountingStrategy::getPeriodElectricPrice).reduce(BigDecimal.ZERO, BigDecimal::add); BigDecimal service_reduce = list4.stream().map(TChargingOrderAccountingStrategy::getPeriodServicePrice).reduce(BigDecimal.ZERO, BigDecimal::add); BigDecimal chargingCapacity = list4.stream().map(TChargingOrderAccountingStrategy::getChargingCapacity).reduce(BigDecimal.ZERO, BigDecimal::add); BigDecimal serviceMoney = BigDecimal.ZERO; BigDecimal paymentMoney = BigDecimal.ZERO; long time = 0; if (!order.getOrderSource().equals(2)) { serviceMoney = serviceMoney.add(service_reduce); paymentMoney = paymentMoney.add(electronic_reduce).add(service_reduce); } else { serviceMoney = serviceMoney.add(service_reduce.multiply(new BigDecimal("0.8"))); paymentMoney = paymentMoney.add(electronic_reduce).add(service_reduce.multiply(new BigDecimal("0.8"))); } if (order.getStartTime() != null && order.getEndTime() != null) { time = ChronoUnit.SECONDS.between(order.getStartTime(), order.getEndTime()); } TChargingOrderSummaryData summaryData = new TChargingOrderSummaryData(); summaryData.setChargingOrderId(order.getId()); summaryData.setChargingCapacity(chargingCapacity.setScale(6, RoundingMode.HALF_EVEN)); summaryData.setChargingDuration(time); summaryData.setIncome(paymentMoney.setScale(2, BigDecimal.ROUND_HALF_EVEN)); summaryData.setElectricPrice(electronic_reduce.setScale(2, BigDecimal.ROUND_HALF_EVEN)); summaryData.setServicePrice(serviceMoney.setScale(2, BigDecimal.ROUND_HALF_EVEN)); chargingOrderSummaryDataService.save(summaryData); //推送监管平台订单状态和订单详情 ChargingOrderVo chargingOrderVo = new ChargingOrderVo(); BeanUtils.copyProperties(order, chargingOrderVo); chargingMessageClient.pushOrderInfo(chargingOrderVo); chargingMessageClient.pushOrderStatus(chargingOrderVo); } } }catch (Exception e){ e.printStackTrace(); }finally { lock.unlock(); } } /** * 添加充电算账单汇总数据 * 生成上个月账单,避免月末最后一天 00:30 之后结算的订单漏统计(与账户结算账单 addAccountSettlementStatement 保持一致)。 */ public void addChargingSettlementBill(){ int day = LocalDate.now().getDayOfMonth(); int lastDay = LocalDate.now().with(TemporalAdjusters.lastDayOfMonth()).getDayOfMonth(); if (2 <= day && day <= lastDay) { refreshChargingSettlementBill(LocalDate.now().minusMonths(1)); } } /** * 主动刷新指定月份的充电结算账单。重建该月全部数据(含已出账),并保持已出账月份状态不回退。 */ public synchronized void refreshChargingSettlementBill(LocalDate billingMonth){ try { if (billingMonth == null) { throw new IllegalArgumentException("账单月份不能为空"); } LocalDate firstDayOfBillingMonth = billingMonth.withDayOfMonth(2); String string = firstDayOfBillingMonth.toString(); // 将-替换为空字符串 string = string.replace("-", ""); String targetMonth = billingMonth.format(DateTimeFormatter.ofPattern("yyyy-MM")); //统计数据的开始时间 String startTime = targetMonth + "-01 00:00:00"; //统计数据的结束时间 int lastDay = billingMonth.with(TemporalAdjusters.lastDayOfMonth()).getDayOfMonth(); String endTime = targetMonth + "-" + String.format("%02d", lastDay) + " 23:59:59"; LocalDateTime createTime = LocalDateTime.now(); //删除之前生成的汇总数据,在添加最新的汇总数据 //重建时删除该月全部记录(含已出账),避免重建已冻结月份时旧数据残留造成重复;并保留已出账状态 String format = firstDayOfBillingMonth.format(DateTimeFormatter.ofPattern("yyyy-MM")); boolean targetFrozen = chargingSettlementBillService.count(new QueryWrapper() .eq("status", 2) .last(" and DATE_FORMAT(billing_cycle, '%Y-%m') = '" + format + "'")) > 0; chargingSettlementBillService.remove(new QueryWrapper().last(" and DATE_FORMAT(billing_cycle, '%Y-%m') = '" + format + "'")); int targetStatus = targetFrozen ? 2 : 1; //循环生成按照开始时间和结束时间分别统计的汇总数据 for (int i = 1; i < 3; i++) { TChargingSettlementBill chargingSettlementBill = new TChargingSettlementBill(); // 订单生成规则JSD+20231201(账单所属月份)+1131304205(随机10位数)+001(当月账单序号,每月重置) Random random = new Random(); String randomDigits = random.ints(10, 0, 10) // 生成10个随机数字,范围在0-9 .mapToObj(String::valueOf) .collect(Collectors.joining()); // 将其连接成一个字符串 chargingSettlementBill.setSiteId(0); chargingSettlementBill.setStatisticalDateType(i); chargingSettlementBill.setBillingCycle(firstDayOfBillingMonth); chargingSettlementBill.setStatus(targetStatus); chargingSettlementBill.setCode("JSD"+string+randomDigits); //根据业务订单查询汇总数据 List> mapList = chargingOrderService.getChargingSettlementBill(startTime, endTime, i); Long chargingDuration = 0L; Integer orderNumber = 0; BigDecimal totalAmount = BigDecimal.ZERO; BigDecimal platformFee = BigDecimal.ZERO; BigDecimal tripartiteCommission = BigDecimal.ZERO; BigDecimal fundsReceived = BigDecimal.ZERO; BigDecimal totalElectricity = BigDecimal.ZERO; BigDecimal totalElectricityCharge = BigDecimal.ZERO; BigDecimal totalServiceFee = BigDecimal.ZERO; BigDecimal couponDeduction = BigDecimal.ZERO; List list = new ArrayList<>(); for (Map map : mapList) { Long charging_duration = null == map.get("chargingDuration") ? 0L : Long.valueOf(map.get("chargingDuration").toString()); Integer order_number = null == map.get("orderNum") ? 0 : Integer.valueOf(map.get("orderNum").toString()); BigDecimal total_amount = null == map.get("totalAmount") ? BigDecimal.ZERO : new BigDecimal(map.get("totalAmount").toString()); BigDecimal platform_fee = null == map.get("platformFee") ? BigDecimal.ZERO : new BigDecimal(map.get("platformFee").toString()); BigDecimal tripartite_commission = null == map.get("tripartiteCommission") ? BigDecimal.ZERO : new BigDecimal(map.get("tripartiteCommission").toString()); BigDecimal funds_received = total_amount.subtract(platform_fee).subtract(tripartite_commission); BigDecimal total_electricity = null == map.get("totalElectricity") ? BigDecimal.ZERO : new BigDecimal(map.get("totalElectricity").toString()); BigDecimal total_electricity_charge = null == map.get("totalElectricityCharge") ? BigDecimal.ZERO : new BigDecimal(map.get("totalElectricityCharge").toString()); BigDecimal total_service_fee = null == map.get("totalServiceFee") ? BigDecimal.ZERO : new BigDecimal(map.get("totalServiceFee").toString()); BigDecimal coupon_deduction = null == map.get("couponDeduction") ? BigDecimal.ZERO : new BigDecimal(map.get("couponDeduction").toString()); //构建每个站点的汇总数据 TChargingSettlementBill chargingSettlementBill1 = new TChargingSettlementBill(); String randomDigits1 = random.ints(10, 0, 10) // 生成10个随机数字,范围在0-9 .mapToObj(String::valueOf) .collect(Collectors.joining()); // 将其连接成一个字符串 chargingSettlementBill1.setSiteId(Integer.valueOf(map.get("siteId").toString())); chargingSettlementBill1.setStatisticalDateType(i); chargingSettlementBill1.setBillingCycle(firstDayOfBillingMonth); chargingSettlementBill1.setStatus(targetStatus); chargingSettlementBill1.setCode("JSD"+string+randomDigits1); chargingSettlementBill1.setChargingDuration(charging_duration); chargingSettlementBill1.setOrderNumber(order_number); chargingSettlementBill1.setTotalAmount(total_amount.setScale(2, RoundingMode.HALF_EVEN)); chargingSettlementBill1.setCouponDeduction(coupon_deduction.setScale(2, RoundingMode.HALF_EVEN)); chargingSettlementBill1.setPlatformFee(platform_fee.setScale(2, RoundingMode.HALF_EVEN)); chargingSettlementBill1.setTripartiteCommission(tripartite_commission.setScale(2, RoundingMode.HALF_EVEN)); chargingSettlementBill1.setFundsReceived(funds_received.setScale(2, RoundingMode.HALF_EVEN)); chargingSettlementBill1.setTotalElectricity(total_electricity.setScale(4, RoundingMode.HALF_EVEN)); chargingSettlementBill1.setTotalElectricityCharge(total_electricity_charge.setScale(2, RoundingMode.HALF_EVEN)); chargingSettlementBill1.setTotalServiceFee(total_service_fee.setScale(2, RoundingMode.HALF_EVEN)); chargingSettlementBill1.setCreateTime(createTime); list.add(chargingSettlementBill1); //计算全站汇总数据 chargingDuration = chargingDuration + charging_duration; orderNumber = orderNumber + order_number; totalAmount = totalAmount.add(total_amount); platformFee = platformFee.add(platform_fee); tripartiteCommission = tripartiteCommission.add(tripartite_commission); fundsReceived = fundsReceived.add(funds_received); totalElectricity = totalElectricity.add(total_electricity); totalElectricityCharge = totalElectricityCharge.add(total_electricity_charge); totalServiceFee = totalServiceFee.add(total_service_fee); couponDeduction = couponDeduction.add(coupon_deduction); } chargingSettlementBill.setChargingDuration(chargingDuration); chargingSettlementBill.setOrderNumber(orderNumber); chargingSettlementBill.setTotalAmount(totalAmount.setScale(2, RoundingMode.HALF_EVEN)); chargingSettlementBill.setCouponDeduction(couponDeduction.setScale(2, RoundingMode.HALF_EVEN)); chargingSettlementBill.setPlatformFee(platformFee.setScale(2, RoundingMode.HALF_EVEN)); chargingSettlementBill.setTripartiteCommission(tripartiteCommission.setScale(2, RoundingMode.HALF_EVEN)); chargingSettlementBill.setFundsReceived(fundsReceived.setScale(2, RoundingMode.HALF_EVEN)); chargingSettlementBill.setTotalElectricity(totalElectricity.setScale(4, RoundingMode.HALF_EVEN)); chargingSettlementBill.setTotalElectricityCharge(totalElectricityCharge.setScale(2, RoundingMode.HALF_EVEN)); chargingSettlementBill.setTotalServiceFee(totalServiceFee.setScale(2, RoundingMode.HALF_EVEN)); chargingSettlementBill.setCreateTime(createTime); chargingSettlementBillService.save(chargingSettlementBill); chargingSettlementBillService.saveBatch(list); } } catch (Exception e) { log.error("生成{}充电结算账单失败", billingMonth, e); throw new RuntimeException("生成充电结算账单失败", e); } } /** * 添加账户结算账单数据 */ public void addAccountSettlementStatement(){ int day = LocalDate.now().getDayOfMonth(); int lastDay = LocalDate.now().with(TemporalAdjusters.lastDayOfMonth()).getDayOfMonth(); //时间在当月的2号到当月的最后一天才执行汇总数据和生成新的汇总数据(中间有修改数据的情况) if (2 <= day && day <= lastDay) { refreshAccountSettlementStatement(LocalDate.now().minusMonths(1)); } } /** * 主动刷新指定月份的账户结算账单。只重建该月未出账数据,已出账数据不受影响。 */ public synchronized void refreshAccountSettlementStatement(LocalDate billingMonth) { try { if (billingMonth == null) { throw new IllegalArgumentException("账单月份不能为空"); } LocalDate firstDayOfBillingMonth = billingMonth.withDayOfMonth(2); String string = firstDayOfBillingMonth.toString(); // 将-替换为空字符串 string = string.replace("-", ""); String targetMonth = billingMonth.format(DateTimeFormatter.ofPattern("yyyy-MM")); //统计数据的开始时间 String startTime = targetMonth + "-01 00:00:00"; //统计数据的结束时间 int targetLastDay = billingMonth.with(TemporalAdjusters.lastDayOfMonth()).getDayOfMonth(); String endTime = targetMonth + "-" + String.format("%02d", targetLastDay) + " 23:59:59"; LocalDateTime createTime = LocalDateTime.now(); //删除之前生成的汇总数据,在添加最新的汇总数据 String format = firstDayOfBillingMonth.format(DateTimeFormatter.ofPattern("yyyy-MM")); accountSettlementStatementService.remove(new QueryWrapper().eq("status", 1).last(" and DATE_FORMAT(billing_cycle, '%Y-%m') = '" + format + "'")); Map siteServiceShareRatioMap = loadSiteServiceShareRatioMap(); // V2.0 账户类型统一为工商银行商户,只生成明星充电小程序订单账单。 for (int i = 3; i < 4; i++) { TAccountSettlementStatement accountSettlementStatement = new TAccountSettlementStatement(); // 订单生成规则JSD+20231201(账单所属月份)+1131304205(随机10位数)+001(当月账单序号,每月重置) Random random = new Random(); String randomDigits = random.ints(10, 0, 10) // 生成10个随机数字,范围在0-9 .mapToObj(String::valueOf) .collect(Collectors.joining()); // 将其连接成一个字符串 accountSettlementStatement.setSiteId(0); accountSettlementStatement.setAccountType(i); accountSettlementStatement.setBillingCycle(firstDayOfBillingMonth); accountSettlementStatement.setStatus(1); accountSettlementStatement.setCode("JSD"+string+randomDigits); //根据业务订单查询汇总数据 List> mapList = chargingOrderService.getAccountSettlementStatement(startTime, endTime); BigDecimal rechargeAmount = BigDecimal.ZERO; BigDecimal refundAmount = BigDecimal.ZERO; BigDecimal platformFee = BigDecimal.ZERO; BigDecimal tripartiteCommission = BigDecimal.ZERO; BigDecimal recordedAmount = BigDecimal.ZERO; BigDecimal platformIncome = BigDecimal.ZERO; BigDecimal partnerIncome = BigDecimal.ZERO; List list = new ArrayList<>(); for (Map map : mapList) { Integer siteId = Integer.valueOf(map.get("siteId").toString()); BigDecimal recharge_amount = null == map.get("rechargeAmount") ? BigDecimal.ZERO : new BigDecimal(map.get("rechargeAmount").toString()); BigDecimal refund_amount = null == map.get("refundAmount") ? BigDecimal.ZERO : new BigDecimal(map.get("refundAmount").toString()); BigDecimal service_amount = null == map.get("serviceAmount") ? BigDecimal.ZERO : new BigDecimal(map.get("serviceAmount").toString()); BigDecimal partner_income = calculateAccountPartnerIncome( service_amount, siteServiceShareRatioMap.get(siteId), false); BigDecimal platform_income = calculateAccountPlatformIncome(recharge_amount, partner_income); BigDecimal recorded_amount = recharge_amount.subtract(refund_amount); //构建每个站点的汇总数据 TAccountSettlementStatement accountSettlementStatement1 = new TAccountSettlementStatement(); String randomDigits1 = random.ints(10, 0, 10) // 生成10个随机数字,范围在0-9 .mapToObj(String::valueOf) .collect(Collectors.joining()); // 将其连接成一个字符串 accountSettlementStatement1.setSiteId(siteId); accountSettlementStatement1.setAccountType(i); accountSettlementStatement1.setBillingCycle(firstDayOfBillingMonth); accountSettlementStatement1.setStatus(1); accountSettlementStatement1.setCode("JSD"+string+randomDigits1); accountSettlementStatement1.setRechargeAmount(recharge_amount.setScale(2, RoundingMode.HALF_EVEN)); accountSettlementStatement1.setRefundAmount(refund_amount.setScale(2, RoundingMode.HALF_EVEN)); accountSettlementStatement1.setPlatformFee(BigDecimal.ZERO.setScale(2, RoundingMode.HALF_EVEN)); accountSettlementStatement1.setTripartiteCommission(BigDecimal.ZERO.setScale(2, RoundingMode.HALF_EVEN)); accountSettlementStatement1.setRecordedAmount(recorded_amount.setScale(2, RoundingMode.HALF_EVEN)); accountSettlementStatement1.setPlatformIncome(platform_income.setScale(2, RoundingMode.HALF_UP)); accountSettlementStatement1.setPartnerIncome(partner_income.setScale(2, RoundingMode.HALF_UP)); accountSettlementStatement1.setCreateTime(createTime); list.add(accountSettlementStatement1); //计算全站汇总数据 rechargeAmount = rechargeAmount.add(recharge_amount); refundAmount = refundAmount.add(refund_amount); recordedAmount = recordedAmount.add(recorded_amount); platformIncome = platformIncome.add(platform_income); partnerIncome = partnerIncome.add(partner_income); } accountSettlementStatement.setRechargeAmount(rechargeAmount.setScale(2, RoundingMode.HALF_EVEN)); accountSettlementStatement.setRefundAmount(refundAmount.setScale(2, RoundingMode.HALF_EVEN)); accountSettlementStatement.setPlatformFee(platformFee.setScale(2, RoundingMode.HALF_EVEN)); accountSettlementStatement.setTripartiteCommission(tripartiteCommission.setScale(2, RoundingMode.HALF_EVEN)); accountSettlementStatement.setRecordedAmount(recordedAmount.setScale(2, RoundingMode.HALF_EVEN)); accountSettlementStatement.setPlatformIncome(platformIncome.setScale(2, RoundingMode.HALF_UP)); accountSettlementStatement.setPartnerIncome(partnerIncome.setScale(2, RoundingMode.HALF_UP)); accountSettlementStatement.setCreateTime(createTime); accountSettlementStatementService.save(accountSettlementStatement); accountSettlementStatementService.saveBatch(list); } } catch (Exception e) { log.error("生成{}账户结算账单失败", billingMonth, e); throw new RuntimeException("生成账户结算账单失败", e); } } static BigDecimal calculateAccountPartnerIncome(BigDecimal paidServiceAmount, BigDecimal serviceShareRatio, boolean thirdPartyOrder) { if (thirdPartyOrder || paidServiceAmount == null || serviceShareRatio == null || serviceShareRatio.compareTo(BigDecimal.ZERO) <= 0) { return BigDecimal.ZERO; } return paidServiceAmount.multiply(serviceShareRatio) .divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP); } static BigDecimal calculateAccountPlatformIncome(BigDecimal paymentAmount, BigDecimal partnerIncome) { BigDecimal paid = paymentAmount == null ? BigDecimal.ZERO : paymentAmount; BigDecimal partner = partnerIncome == null ? BigDecimal.ZERO : partnerIncome; return paid.subtract(partner).setScale(2, RoundingMode.HALF_UP); } private Map loadSiteServiceShareRatioMap() { List sites = Optional.ofNullable(siteClient.getSiteAll()) .map(R::getData).orElse(Collections.emptyList()); List partners = Optional.ofNullable(siteClient.getAllPartner()) .map(R::getData).orElse(Collections.emptyList()); Map partnerMap = partners.stream() .filter(partner -> partner != null && partner.getId() != null) .collect(Collectors.toMap(Partner::getId, partner -> partner, (left, right) -> left)); Map ratioMap = new HashMap<>(); for (Site site : sites) { if (site == null || site.getId() == null || site.getPartnerId() == null) { continue; } Partner partner = partnerMap.get(site.getPartnerId()); if (partner != null && partner.getServiceShareRatio() != null) { ratioMap.put(site.getId(), partner.getServiceShareRatio()); } } return ratioMap; } /** * 推送三方引流平台充电数据 */ public void pushOrderDrainagePlatform(){ String format = LocalDateTime.now().minusDays(1).format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); List list = chargingOrderService.list(new LambdaQueryWrapper().eq(TChargingOrder::getStatus, 5) .eq(TChargingOrder::getOrderSource, 2).eq(TChargingOrder::getDelFlag, 0) .isNotNull(TChargingOrder::getStartChargeSeq).isNotNull(TChargingOrder::getOperatorId) .last(" and DATE_FORMAT(end_time, '%Y-%m-%d') = '" + format + "'")); for (TChargingOrder tChargingOrder : list) { String code = tChargingOrder.getCode(); chargingOrderService.pushOrderInfo(code); } } }