| | |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.beans.BeanUtils; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.beans.factory.annotation.Value; |
| | | import org.springframework.data.redis.core.RedisTemplate; |
| | | import org.springframework.scheduling.annotation.Scheduled; |
| | | import org.springframework.stereotype.Service; |
| | |
| | | private IcbcPaymentClient icbcPaymentClient; |
| | | @Resource |
| | | private TChargingOrderShareRecordMapper chargingOrderShareRecordMapper; |
| | | @Value("${icbc.share.online-enabled:false}") |
| | | private boolean icbcOnlineShareEnabled; |
| | | @Resource |
| | | private ChargingOrderSettlementExecutor chargingOrderSettlementExecutor; |
| | | @Resource |
| | |
| | | public R<PageInfo<TChargingOrderRefund>> getRefundList(ChargingRefundDto chargingRefundDto) { |
| | | PageInfo<TChargingOrderRefund> pageInfo = new PageInfo<>(chargingRefundDto.getPageCurr(), chargingRefundDto.getPageSize()); |
| | | List<TChargingOrderRefund> list = this.baseMapper.getRefundList(pageInfo, chargingRefundDto); |
| | | for (TChargingOrderRefund refund : list) { |
| | | refund.setUid(refund.getType() + "-" + refund.getId()); |
| | | } |
| | | pageInfo.setRecords(list); |
| | | |
| | | return R.ok(pageInfo); |
| | |
| | | |
| | | @Override |
| | | public Map<String, Object> countAll(List<Integer> siteIds, Boolean partnerView) { |
| | | return this.baseMapper.countAll(siteIds, partnerView); |
| | | Map<String, Object> result = this.baseMapper.countAll(siteIds, partnerView); |
| | | if (!Boolean.TRUE.equals(partnerView) && result != null) { |
| | | result.put("commission_amount", this.baseMapper.sumSuccessfulShareAmount(siteIds)); |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | /** |
| | |
| | | PageInfo<ChargingOrderListVO> pageInfo = new PageInfo<>(dto.getPageCurr(), dto.getPageSize()); |
| | | |
| | | List<ChargingOrderListVO> list = new ArrayList<>(); |
| | | Map<Integer, BigDecimal> siteServiceShareRatioMap = loadSiteServiceShareRatioMap(); |
| | | List<Map<String, Object>> maps = this.baseMapper.chargingList1(pageInfo, dto, startTime1, startTime2, endTime1, endTime2); |
| | | Map<Integer, Site> siteMap = loadChargingPeriodSites(maps); |
| | | Map<Integer, TChargingPile> pileMap = loadChargingPeriodPiles(maps); |
| | |
| | | chargingOrderListVO.setSharingAmount(BigDecimal.ZERO); |
| | | } |
| | | chargingOrderListVO.setElectrovalence(null == map.get("electrovalence") ? BigDecimal.ZERO : new BigDecimal(map.get("electrovalence").toString())); |
| | | fillChargingPeriodIncome(chargingOrderListVO, siteServiceShareRatioMap); |
| | | if(null != map.get("tripartitePlatformName")){ |
| | | chargingOrderListVO.setTripartitePlatformName(map.get("tripartitePlatformName").toString()); |
| | | } |
| | |
| | | } |
| | | list.add(chargingOrderListVO); |
| | | } |
| | | fillChargingPeriodShareIncome(list); |
| | | |
| | | |
| | | |
| | |
| | | chargingOrderTimeVO.setPaymentAmount(paymentAmount.setScale(2, BigDecimal.ROUND_HALF_EVEN)); |
| | | chargingOrderTimeVO.setElectrovalence(electrovalence.setScale(2, BigDecimal.ROUND_HALF_EVEN)); |
| | | chargingOrderTimeVO.setServiceCharge(serviceCharge.setScale(2, BigDecimal.ROUND_HALF_EVEN)); |
| | | BigDecimal platformIncome = BigDecimal.ZERO; |
| | | BigDecimal partnerIncome = BigDecimal.ZERO; |
| | | for (Map<String, Object> sumMap : list1) { |
| | | if (sumMap == null) { |
| | | continue; |
| | | } |
| | | ChargingOrderListVO item = new ChargingOrderListVO(); |
| | | item.setSiteId(getSummaryLong(sumMap, "siteId").intValue()); |
| | | item.setOrderSource(getSummaryLong(sumMap, "orderSource").intValue()); |
| | | item.setPaymentAmount(getSummaryDecimal(sumMap, "paymentAmount")); |
| | | item.setServiceCharge(getSummaryDecimal(sumMap, "serviceCharge")); |
| | | fillChargingPeriodIncome(item, siteServiceShareRatioMap); |
| | | platformIncome = platformIncome.add(nullToZero(item.getPlatformIncome())); |
| | | partnerIncome = partnerIncome.add(nullToZero(item.getPartnerIncome())); |
| | | } |
| | | chargingOrderTimeVO.setPlatformIncome(platformIncome.setScale(2, RoundingMode.HALF_UP)); |
| | | chargingOrderTimeVO.setPartnerIncome(partnerIncome.setScale(2, RoundingMode.HALF_UP)); |
| | | List<Long> summaryOrderIds = list1.stream() |
| | | .filter(Objects::nonNull) |
| | | .map(sumMap -> getSummaryLong(sumMap, "id")) |
| | | .filter(Objects::nonNull) |
| | | .distinct() |
| | | .collect(Collectors.toList()); |
| | | Map<String, Object> shareIncomeMap = getChargingOrderShareIncomeSummary(summaryOrderIds); |
| | | chargingOrderTimeVO.setPlatformIncome(getSummaryDecimal(shareIncomeMap, "platformIncomeTotal")); |
| | | chargingOrderTimeVO.setPartnerIncome(getSummaryDecimal(shareIncomeMap, "partnerIncomeTotal")); |
| | | // 计算尖峰平谷充电到账占比 |
| | | BigDecimal add = jianElectronic.add(fengElectronic).add(pingElectronic).add(guElectronic); |
| | | // 计算尖峰平谷服务费占比 |
| | |
| | | dto.setSiteIds(siteIds); |
| | | List<ChargingOrderListVO> list1 = this.baseMapper.chargingList(dto, startTime1, startTime2, endTime1, endTime2); |
| | | fillChargingPeriodExportBalanceIncome(list1); |
| | | fillChargingPeriodIncome(list1); |
| | | fillChargingPeriodShareIncome(list1); |
| | | return list1; |
| | | } |
| | | |
| | | private void fillChargingPeriodIncome(List<ChargingOrderListVO> list) { |
| | | private void fillChargingPeriodShareIncome(List<ChargingOrderListVO> list) { |
| | | if (list == null || list.isEmpty()) { |
| | | return; |
| | | } |
| | | Map<Integer, BigDecimal> siteServiceShareRatioMap = loadSiteServiceShareRatioMap(); |
| | | List<Long> orderIds = list.stream() |
| | | .map(ChargingOrderListVO::getId) |
| | | .filter(Objects::nonNull) |
| | | .distinct() |
| | | .collect(Collectors.toList()); |
| | | Map<Long, Map<String, Object>> incomeMap = new HashMap<>(); |
| | | int batchSize = 500; |
| | | for (int i = 0; i < orderIds.size(); i += batchSize) { |
| | | List<Long> batchIds = orderIds.subList(i, Math.min(i + batchSize, orderIds.size())); |
| | | List<Map<String, Object>> rows = this.baseMapper.chargingOrderShareIncomeByOrderIds(batchIds); |
| | | if (rows == null) { |
| | | continue; |
| | | } |
| | | for (Map<String, Object> row : rows) { |
| | | Long orderId = getSummaryLong(row, "orderId"); |
| | | if (orderId != null) { |
| | | incomeMap.put(orderId, row); |
| | | } |
| | | } |
| | | } |
| | | for (ChargingOrderListVO item : list) { |
| | | fillChargingPeriodIncome(item, siteServiceShareRatioMap); |
| | | applyChargingPeriodShareIncome(item, incomeMap.get(item.getId())); |
| | | } |
| | | } |
| | | |
| | | private void fillChargingPeriodIncome(ChargingOrderListVO item, Map<Integer, BigDecimal> siteServiceShareRatioMap) { |
| | | void applyChargingPeriodShareIncome(ChargingOrderListVO item, Map<String, Object> row) { |
| | | if (item == null) { |
| | | return; |
| | | } |
| | | BigDecimal paymentAmount = nullToZero(item.getPaymentAmount()); |
| | | BigDecimal partnerIncome = BigDecimal.ZERO; |
| | | if (!Integer.valueOf(2).equals(item.getOrderSource())) { |
| | | BigDecimal serviceShareRatio = siteServiceShareRatioMap.get(item.getSiteId()); |
| | | if (serviceShareRatio != null && serviceShareRatio.compareTo(BigDecimal.ZERO) > 0) { |
| | | partnerIncome = nullToZero(item.getServiceCharge()) |
| | | .multiply(serviceShareRatio) |
| | | .divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP); |
| | | } |
| | | } |
| | | item.setPartnerIncome(partnerIncome); |
| | | item.setPlatformIncome(paymentAmount.subtract(partnerIncome).max(BigDecimal.ZERO).setScale(2, RoundingMode.HALF_UP)); |
| | | } |
| | | |
| | | private Map<Integer, BigDecimal> loadSiteServiceShareRatioMap() { |
| | | Map<Integer, BigDecimal> ratioMap = new HashMap<>(); |
| | | R<List<Site>> siteResult = siteClient.getSiteAll(); |
| | | R<List<Partner>> partnerResult = siteClient.getAllPartner(); |
| | | List<Site> sites = siteResult == null ? Collections.emptyList() : siteResult.getData(); |
| | | List<Partner> partners = partnerResult == null ? Collections.emptyList() : partnerResult.getData(); |
| | | if (sites == null || sites.isEmpty() || partners == null || partners.isEmpty()) { |
| | | return ratioMap; |
| | | } |
| | | Map<Integer, Partner> partnerMap = partners.stream() |
| | | .filter(partner -> partner != null && partner.getId() != null) |
| | | .collect(Collectors.toMap(Partner::getId, partner -> partner, (left, right) -> left)); |
| | | 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; |
| | | item.setPlatformIncome(getSummaryDecimal(row, "platformIncome")); |
| | | item.setPartnerIncome(getSummaryDecimal(row, "partnerIncome")); |
| | | } |
| | | |
| | | /** |
| | |
| | | this.updateById(chargingOrder); |
| | | triggerChargingOrderShare(chargingOrder); |
| | | } else { |
| | | //构建退款明细 |
| | | TChargingOrderRefund chargingOrderRefund = new TChargingOrderRefund(); |
| | | chargingOrderRefund.setChargingOrderId(chargingOrder.getId()); |
| | | SimpleDateFormat sdf1 = new SimpleDateFormat("yyyyMMddHHmmssSSS"); |
| | | chargingOrderRefund.setRefundCode("CDF" + sdf1.format(new Date()) + (Double.valueOf(Math.random() * 1000).intValue())); |
| | | chargingOrderRefund.setRefundAmount(refundAmount); |
| | | chargingOrderRefund.setBalanceRefundAmount(balanceRefundAmount); |
| | | chargingOrderRefund.setThirdRefundAmount(thirdRefundAmount); |
| | | chargingOrderRefund.setRefundStatus(2); |
| | | chargingOrderRefund.setPayType(rechargePaymentType); |
| | | chargingOrderRefund.setCode(chargingOrder.getCode()); |
| | | chargingOrderRefund.setRefundTitle("充电完成退款"); |
| | | chargingOrderRefund.setRefundContent("充电完成退款"); |
| | | chargingOrderRefund.setRefundReason("充电完成退款"); |
| | | chargingOrderRefund.setRefundRemark("实际充电消费金额:" + chargingOrder.getPaymentAmount()); |
| | | chargingOrderRefund.setRefundTotalAmount(refundAmount); |
| | | chargingOrderRefund.setPayAmount(rechargeAmount); |
| | | chargingOrderRefund.setRefundTime(LocalDateTime.now()); |
| | | chargingOrderRefundService.save(chargingOrderRefund); |
| | | if (balanceRefundAmount.compareTo(BigDecimal.ZERO) > 0) { |
| | | changeUserBalance(chargingOrder.getAppUserId(), balanceRefundAmount); |
| | | recordBalanceRefund(chargingOrder, balanceRefundAmount, chargingOrderRefund.getRefundCode()); |
| | | } |
| | | |
| | | chargingOrder.setRefundStatus(2); |
| | | chargingOrder.setRefundTime(LocalDateTime.now()); |
| | | this.updateById(chargingOrder); |
| | | // 无可退金额时正常结算,不生成金额为 0 的退款记录。 |
| | | triggerChargingOrderShare(chargingOrder); |
| | | } |
| | | } |
| | |
| | | shoppingOrderRefund.setRefundContent("后台退款"); |
| | | shoppingOrderRefund.setRefundReason("后台退款"); |
| | | shoppingOrderRefund.setRefundRemark(payOrderQueryDto.getRemark()); |
| | | shoppingOrderRefund.setRefundTotalAmount(shoppingOrder.getRefundAmount().add(payOrderQueryDto.getRefundAmount())); |
| | | shoppingOrderRefund.setRefundTotalAmount(money(shoppingOrder.getRefundAmount()).add(payOrderQueryDto.getRefundAmount())); |
| | | shoppingOrderRefund.setPayAmount(shoppingOrder.getPaymentAmount()); |
| | | |
| | | if (1 == shoppingOrder.getPaymentType()) { |
| | |
| | | shoppingOrderRefundService.save(shoppingOrderRefund); |
| | | } |
| | | } |
| | | if (3 == shoppingOrder.getPaymentType()) { |
| | | IcbcRefundReq refundReq = new IcbcRefundReq(); |
| | | refundReq.setOutTradeNo(shoppingOrder.getCode()); |
| | | refundReq.setOrderId(shoppingOrder.getSerialNumber()); |
| | | refundReq.setOutRefundNo(shoppingOrderRefund.getRefundCode()); |
| | | refundReq.setRefundAmount(payOrderQueryDto.getRefundAmount()); |
| | | refundReq.setTotalAmount(shoppingOrder.getPaymentAmount()); |
| | | refundReq.setReason("后台商城订单退款"); |
| | | R<IcbcRefundResp> refundResult = icbcPaymentClient.refund(refundReq); |
| | | IcbcRefundResp refundResp = refundResult == null ? null : refundResult.getData(); |
| | | if (refundResult == null || refundResult.getCode() != 200 || refundResp == null || !"SUCCESS".equals(refundResp.getStatus())) { |
| | | return R.fail(refundResult == null ? "工行退款服务无响应" |
| | | : firstNotBlank(refundResp == null ? null : refundResp.getRawResponse(), refundResult.getMsg(), "工行退款失败")); |
| | | } |
| | | shoppingOrder.setRefundStatus(2); |
| | | shoppingOrder.setRefundAmount(money(shoppingOrder.getRefundAmount()).add(payOrderQueryDto.getRefundAmount())); |
| | | shoppingOrder.setRefundSerialNumber(refundResp.getRefundId()); |
| | | shoppingOrder.setRefundTime(LocalDateTime.now()); |
| | | shoppingOrderService.updateById(shoppingOrder); |
| | | shoppingOrderRefund.setRefundStatus(2); |
| | | shoppingOrderRefund.setRefundSerialNumber(refundResp.getRefundId()); |
| | | shoppingOrderRefundService.save(shoppingOrderRefund); |
| | | } |
| | | // if(3 == tChargingOrder.getPaymentType()){ |
| | | // RefundReq dto = new RefundReq(); |
| | | // dto.setOutTradeNo(tChargingOrder.getCode()); |
| | |
| | | vipOrderRefund.setRefundContent("后台退款"); |
| | | vipOrderRefund.setRefundReason("后台退款"); |
| | | vipOrderRefund.setRefundRemark(payOrderQueryDto.getRemark()); |
| | | vipOrderRefund.setRefundTotalAmount(vipOrder.getRefundAmount().add(payOrderQueryDto.getRefundAmount())); |
| | | vipOrderRefund.setRefundTotalAmount(money(vipOrder.getRefundAmount()).add(payOrderQueryDto.getRefundAmount())); |
| | | vipOrderRefund.setPayAmount(vipOrder.getPaymentAmount()); |
| | | |
| | | if (1 == vipOrder.getPaymentType()) { |
| | |
| | | vipOrderService.updateById(vipOrder); |
| | | vipOrderRefundService.save(vipOrderRefund); |
| | | } |
| | | } |
| | | if (3 == vipOrder.getPaymentType()) { |
| | | IcbcRefundReq refundReq = new IcbcRefundReq(); |
| | | refundReq.setOutTradeNo(vipOrder.getCode()); |
| | | refundReq.setOrderId(vipOrder.getSerialNumber()); |
| | | refundReq.setOutRefundNo(vipOrderRefund.getRefundCode()); |
| | | refundReq.setRefundAmount(payOrderQueryDto.getRefundAmount()); |
| | | refundReq.setTotalAmount(vipOrder.getPaymentAmount()); |
| | | refundReq.setReason("后台会员订单退款"); |
| | | R<IcbcRefundResp> refundResult = icbcPaymentClient.refund(refundReq); |
| | | IcbcRefundResp refundResp = refundResult == null ? null : refundResult.getData(); |
| | | if (refundResult == null || refundResult.getCode() != 200 || refundResp == null || !"SUCCESS".equals(refundResp.getStatus())) { |
| | | return R.fail(refundResult == null ? "工行退款服务无响应" |
| | | : firstNotBlank(refundResp == null ? null : refundResp.getRawResponse(), refundResult.getMsg(), "工行退款失败")); |
| | | } |
| | | vipOrder.setRefundStatus(2); |
| | | vipOrder.setRefundAmount(money(vipOrder.getRefundAmount()).add(payOrderQueryDto.getRefundAmount())); |
| | | vipOrderService.updateById(vipOrder); |
| | | vipOrderRefund.setRefundStatus(2); |
| | | vipOrderRefund.setRefundSerialNumber(refundResp.getRefundId()); |
| | | vipOrderRefundService.save(vipOrderRefund); |
| | | } |
| | | // if(3 == tChargingOrder.getPaymentType()){ |
| | | // RefundReq dto = new RefundReq(); |
| | |
| | | record.setSubMerId(partner.getIcbcSubMerId()); |
| | | record.setSubMerPrtclNo(partner.getIcbcSubMerPrtclNo()); |
| | | } |
| | | boolean needOnlineShare = shouldProcessIcbcOnlineShare(payChannel, record.getShareAmount(), partner); |
| | | boolean needOnlineShare = shouldProcessIcbcOnlineShare(icbcOnlineShareEnabled, payChannel, record.getShareAmount(), partner); |
| | | record.setNeedOnlineShare(needOnlineShare); |
| | | record.setOnlineShareStatus(needOnlineShare ? "INIT" : "RECORDED"); |
| | | if ("ICBC".equals(payChannel) && record.getShareAmount().compareTo(BigDecimal.ZERO) > 0 && !needOnlineShare) { |
| | | record.setFailReason("未配置完整工行二级商户参数,仅记录本地分账"); |
| | | record.setFailReason(icbcOnlineShareEnabled |
| | | ? "未配置完整工行二级商户参数,仅记录本地分账" |
| | | : "工行线上分账已关闭,仅记录本地分账"); |
| | | } |
| | | record.setRetryCount(0); |
| | | record.setDelFlag(false); |
| | |
| | | } |
| | | |
| | | static boolean shouldProcessIcbcOnlineShare(String payChannel, BigDecimal shareAmount, Partner partner) { |
| | | return "ICBC".equals(payChannel) |
| | | return shouldProcessIcbcOnlineShare(true, payChannel, shareAmount, partner); |
| | | } |
| | | |
| | | static boolean shouldProcessIcbcOnlineShare(boolean onlineShareEnabled, String payChannel, BigDecimal shareAmount, Partner partner) { |
| | | return onlineShareEnabled |
| | | && "ICBC".equals(payChannel) |
| | | && shareAmount != null |
| | | && shareAmount.compareTo(BigDecimal.ZERO) > 0 |
| | | && partner != null |