GitBucket
4.23.0
Toggle navigation
Sign in
Files
Branches
1
Releases
Issues
Pull requests
Labels
Priorities
Milestones
Wiki
Forks
yn-bftl-byx
/
thirdparty
Browse code
修改分账bug
master
1 parent
c6e1a79
commit
73973bf73072d3ad89961d119f6c9b2c4cfe6cc3
steven
authored
on 7 Oct
Patch
Showing
1 changed file
src/main/java/com/yn/bftl/thirdparty/modules/business/service/impl/SubaccountServiceImpl.java
Ignore Space
Show notes
View
src/main/java/com/yn/bftl/thirdparty/modules/business/service/impl/SubaccountServiceImpl.java
package com.yn.bftl.thirdparty.modules.business.service.impl; import cn.hutool.core.util.ObjectUtil; import com.alibaba.fastjson.JSONObject; import com.yn.bftl.common.common.exception.YnceError; import com.yn.bftl.common.common.util.ByxRouteUtil; import com.yn.bftl.common.common.util.RouteUtil; import com.yn.bftl.common.modules.account.entity.Payment; import com.yn.bftl.common.modules.account.enums.AccountChangeType; import com.yn.bftl.common.modules.account.enums.ChangeDirection; import com.yn.bftl.common.modules.account.enums.PaymentType; import com.yn.bftl.common.modules.account.vo.BalanceAcctsVO; import com.yn.bftl.common.modules.company.entity.Brand; import com.yn.bftl.common.modules.company.entity.Company; import com.yn.bftl.common.modules.order.entity.*; import com.yn.bftl.common.modules.order.enums.*; import com.yn.bftl.common.modules.relation.entity.BusinessRelations; import com.yn.bftl.common.modules.subaccount.entity.*; import com.yn.bftl.common.modules.subaccount.enums.StatementState; import com.yn.bftl.common.modules.subaccount.enums.StatementType; import com.yn.bftl.common.modules.subaccount.enums.SubaccountState; import com.yn.bftl.common.modules.subaccount.enums.SubaccountType; import com.yn.bftl.thirdparty.common.exception.YnceErrorException; import com.yn.bftl.thirdparty.common.repository.*; import com.yn.bftl.thirdparty.common.service.ByxTradeWayService; import com.yn.bftl.thirdparty.common.util.DateTimeUtils; import com.yn.bftl.thirdparty.common.util.SequenceUtil; import com.yn.bftl.thirdparty.modules.business.abstracts.AbstractBusinessService; import com.yn.bftl.thirdparty.modules.business.dto.AccountChangeCreateDTO; import com.yn.bftl.thirdparty.modules.business.dto.CreatePaymentDTO; import com.yn.bftl.thirdparty.modules.business.dto.OrderRefundItemDTO; import com.yn.bftl.thirdparty.modules.business.repository.ChinaumsPaymentRepository; import com.yn.bftl.thirdparty.modules.business.repository.ChinaumsRefundRepository; import com.yn.bftl.thirdparty.modules.business.service.AccountService; import com.yn.bftl.thirdparty.modules.business.service.PaymentService; import com.yn.bftl.thirdparty.modules.business.service.SubaccountService; import com.yn.bftl.thirdparty.modules.chinaums.dto.BrandAuthFeeDTO; import com.yn.bftl.thirdparty.modules.chinaums.dto.byx.ByxChinaumsGuaranteePayConfirmsDTO; import com.yn.bftl.thirdparty.modules.chinaums.dto.byx.ByxChinaumsGuaranteePayConfirmsDetailDTO; import com.yn.bftl.thirdparty.modules.chinaums.dto.chinaums.ChinaumsAllocationsDTO; import com.yn.bftl.thirdparty.modules.chinaums.dto.chinaums.ChinaumsGuaranteePayConfirmsDTO; import com.yn.bftl.thirdparty.modules.chinaums.dto.chinaums.ChinaumsGuaranteePayExtraDTO; import com.yn.bftl.thirdparty.modules.chinaums.dto.chinaums.ChinaumsTransferParamsDTO; import com.yn.bftl.thirdparty.modules.chinaums.repository.ChinaumsAuthInfoRepository; import com.yn.bftl.thirdparty.modules.chinaums.service.WalletService; import com.yn.bftl.thirdparty.modules.chinaums.util.ByxChinaumsUtil; import com.yn.bftl.thirdparty.modules.chinaums.util.ChinaumsUtil; import com.yn.bftl.thirdparty.modules.chinaums.vo.chinaums.ChinaumsAllocationsVO; import com.yn.bftl.thirdparty.modules.chinaums.vo.chinaums.ChinaumsGuaranteePayConfirmsVO; import com.yn.bftl.thirdparty.modules.chinaums.vo.chinaums.ChinaumsTransferResultsVO; import com.yn.bftl.thirdparty.modules.unionpay.enums.UnionpayAppOrderType; import com.yn.bftl.thirdparty.modules.unionpay.repository.OrderFeeRatioRepository; import com.yn.bftl.thirdparty.modules.unionpay.vo.callback.ProfitSharingCallbackVO; import com.yn.bftl.thirdparty.modules.unionpay.vo.callback.SettlementCallbackVO; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; import java.math.BigDecimal; import java.math.RoundingMode; import java.text.SimpleDateFormat; import java.time.LocalDateTime; import java.util.*; import java.util.stream.Collectors; /** * 分账服务实现 * * @author huabiao * @create 2022/9/14 17:25 **/ @Service public class SubaccountServiceImpl extends AbstractBusinessService implements SubaccountService { private static final Log log = LogFactory.getLog(SubaccountServiceImpl.class); @Resource private AfterSaleRepository afterSaleRepository; @Resource private OrderRepository orderRepository; @Resource private SubaccountRepository subaccountRepository; @Resource private StatementRepository statementRepository; @Resource private SequenceUtil sequenceUtil; @Resource private PaymentRepository paymentRepository; @Resource private ShippingRepository shippingRepository; @Resource private TemporaryStatementRepository temporaryStatementRepository; @Resource private OrderFeeRatioRepository orderFeeRatioRepository; @Resource private StatementLineRepository statementLineRepository; @Resource private WalletService walletService; @Resource private ChinaumsUtil chinaumsUtil; @Resource private OrderItemRepository orderItemRepository; @Resource private ChinaumsPaymentRepository chinaumsPaymentRepository; @Resource private CompanyRepository companyRepository; @Resource private AccountService accountService; @Resource private ChinaumsRefundRepository chinaumsRefundRepository; @Resource private BrandRepository brandRepository; @Resource private RefundRepository refundRepository; @Resource private PaymentService paymentService; @Resource private ChinaumsAuthInfoRepository chinaumsAuthInfoRepository; @Resource private ByxTradeWayService byxTradeWayService; @Resource private ByxChinaumsUtil byxChinaumsUtil; @Resource private BusinessRelationsRepository businessRelationsRepository; @Override public void generateTemporaryStatement(Long orderId) { log.error("开始生成临时结算单"); // 查询订单 Order order = orderRepository.findById(orderId).orElse(null); if (order == null) { writeCommissionLog("[临时服务费][普通订单]订单ID:" + orderId + ",未查到"); return; } if (CollectionUtils.isEmpty(order.getReceipt())) { writeCommissionLog(String.format("[临时服务费][普通订单][%s],收款单不存在", order.getSn())); return; } // 授信支付 if (PaymentMethod.CREDIT_PAY.equals(order.getReceipt().get(0).getPaymentMethod())) { // 判断是否已支付 if (PaymentStatus.UN_PAID.equals(order.getPaymentStatus())) { writeCommissionLog(String.format("[临时服务费][普通订单][%s],订单未付款", order.getSn())); } } // 其他支付方式 else { // 查看付款单是否支付 Payment payment = paymentRepository.findFirstByOrderIdAndPayStatusOrderByIdDesc(orderId.toString(), PayStatus.SUCC); if (payment == null) { writeCommissionLog(String.format("[临时服务费][普通订单][%s],支付单未付款", order.getSn())); return; } } // 判断订单是否已创建服务单据 TemporaryStatement temporaryStatement = temporaryStatementRepository.findFirstByOrdersId(orderId); if (temporaryStatement != null) { writeCommissionLog(String.format("[临时服务费][普通订单][%s],订单已创建过临时服务费单据", order.getSn())); return; } List<TemporaryStatement> temporaryStatementList = new ArrayList<>(); // 总临时结算单数量 Integer totalNumber = 0; // 生成货款临时结算单 if (order.getGoodsPayment().compareTo(BigDecimal.ZERO) == 1) { temporaryStatementList.add(generateTemporaryStatementByType(SubaccountType.GOODS_COST, order, order.getSellerCompany())); totalNumber++; } // 生成品牌临时结算单 if (order.getBrandCost().compareTo(BigDecimal.ZERO) == 1) { temporaryStatementList.add(generateTemporaryStatementByType(SubaccountType.BRAND_FEE, order, order.getBrandCompany())); totalNumber++; } // 生成策划临时结算单 if (order.getDeviseCost().compareTo(BigDecimal.ZERO) == 1) { temporaryStatementList.add(generateTemporaryStatementByType(SubaccountType.DEVISE_FEE, order, order.getDeviseCompany())); totalNumber++; } if (totalNumber != temporaryStatementList.size()) { return; } temporaryStatementRepository.saveAll(temporaryStatementList); writeCommissionLog(String.format("[临时服务费][普通订单][%s],订单临时服务费单据已创建完成", order.getSn())); log.error("生成临时结算单结束"); } /** * 临时结算单-根据分账类型生成 * * @param order:订单 * @param subaccountType:分账类型 * @param company:分账企业 * @return 临时结算单 * @author huabiao * @create 2022/9/19 11:24 */ private TemporaryStatement generateTemporaryStatementByType(SubaccountType subaccountType, Order order, Company company) { TemporaryStatement temporaryStatement = new TemporaryStatement(); temporaryStatement.setOrderNo(sequenceUtil.getNextSequenceNumber("TFEE")); temporaryStatement.setOrders(order); temporaryStatement.setCompany(order.getSellerCompany()); temporaryStatement.setSubaccountType(subaccountType); // 通过商品明细计算对应单据 List<TemporaryStatementLine> temporaryStatementLineList = new ArrayList<>(); // 获取订单费用比例 OrderFeeRatio orderFeeRatio = orderFeeRatioRepository.findByOrdersId(order.getId()); // 计算总结算金额 BigDecimal statementAmount = BigDecimal.ZERO; for (OrderItem orderItem : order.getOrderItems()) { TemporaryStatementLine temporaryStatementLine = new TemporaryStatementLine(); if (subaccountType.equals(SubaccountType.GOODS_COST)) { temporaryStatementLine.setStatementAmount(orderItem.getGoodsPayment()); temporaryStatementLine.setSubaccountRatio(BigDecimal.ONE.subtract(orderFeeRatio.getBrandCostRatio()).subtract(orderFeeRatio.getDeviseCostRatio())); temporaryStatementLine.setCompany(order.getSellerCompany()); } else if (subaccountType.equals(SubaccountType.BRAND_FEE)) { temporaryStatementLine.setStatementAmount(orderItem.getBrandCost()); temporaryStatementLine.setCompany(order.getBrandCompany()); temporaryStatementLine.setSubaccountRatio(orderFeeRatio != null ? orderFeeRatio.getBrandCostRatio() : null); } else if (subaccountType.equals(SubaccountType.DEVISE_FEE)) { temporaryStatementLine.setStatementAmount(orderItem.getDeviseCost()); temporaryStatementLine.setCompany(order.getDeviseCompany()); temporaryStatementLine.setSubaccountRatio(orderFeeRatio != null ? orderFeeRatio.getDeviseCostRatio() : null); } temporaryStatementLine.setTemporaryStatement(temporaryStatement); temporaryStatementLine.setOrderItem(orderItem); temporaryStatementLineList.add(temporaryStatementLine); statementAmount = statementAmount.add(temporaryStatementLine.getStatementAmount()); } temporaryStatement.setTemporaryStatementLines(temporaryStatementLineList); temporaryStatement.setStatementAmount(statementAmount); temporaryStatement.setCompany(company); // 判断订单项结算金额和订单结算金额是否一致 if (subaccountType.equals(SubaccountType.GOODS_COST) && order.getGoodsPayment().compareTo(statementAmount) != 0) { writeCommissionLog(String.format("[临时服务费][普通订单][%s],订单的货款与订单行不一致", order.getSn())); return null; } else if (subaccountType.equals(SubaccountType.BRAND_FEE) && order.getBrandCost().compareTo(statementAmount) != 0) { writeCommissionLog(String.format("[临时服务费][普通订单][%s],订单的品牌费与订单行不一致", order.getSn())); return null; } else if (subaccountType.equals(SubaccountType.DEVISE_FEE) && order.getDeviseCost().compareTo(statementAmount) != 0) { writeCommissionLog(String.format("[临时服务费][普通订单][%s],订单的策划费与订单行不一致", order.getSn())); return null; } return temporaryStatement; } @Override public void generateStatementByOrder(Long orderId) { Order order = orderRepository.findById(orderId).orElse(null); if (order == null) { writeCommissionLog("[服务费][普通订单]订单ID:" + orderId + ",订单不存在"); } // 判断是否已存在对应的结算单 if (statementRepository.existsByOrdersIdAndStatementType(orderId, StatementType.NORMALORDER)) { writeCommissionLog(String.format("[服务费][普通订单][%s],订单已创建过服务费单据", order.getSn())); } // 临时结算单 List<TemporaryStatement> temporaryStatementList = new ArrayList<>(); // 结算单 List<Statement> statementList = new ArrayList<>(); // 生成货款结算单 if (order.getGoodsPayment().compareTo(BigDecimal.ZERO) == 1) { // 获取货款临时结算单 TemporaryStatement temporaryStatement = temporaryStatementRepository.findFirstByOrdersIdAndSubaccountType(orderId, SubaccountType.GOODS_COST); if (temporaryStatement == null) { writeCommissionLog(String.format("[服务费][普通订单][%s],订单的货款临时服务费单据不存在", order.getSn())); return; } statementList.add(createStatementByTemporaryStatement(temporaryStatement, null, order, true)); temporaryStatement.setIsStatement(true); temporaryStatementList.add(temporaryStatement); } // 生成品牌结算单 if (order.getBrandCost().compareTo(BigDecimal.ZERO) == 1) { // 获取品牌临时结算单 TemporaryStatement temporaryStatement = temporaryStatementRepository.findFirstByOrdersIdAndSubaccountType(orderId, SubaccountType.BRAND_FEE); if (temporaryStatement == null) { writeCommissionLog(String.format("[服务费][普通订单][%s],订单的品牌临时服务费单据不存在", order.getSn())); return; } statementList.add(createStatementByTemporaryStatement(temporaryStatement, null, order, true)); temporaryStatement.setIsStatement(true); temporaryStatementList.add(temporaryStatement); } // 生成策划结算单 if (order.getDeviseCost().compareTo(BigDecimal.ZERO) == 1) { // 获取品牌临时结算单 TemporaryStatement temporaryStatement = temporaryStatementRepository.findFirstByOrdersIdAndSubaccountType(orderId, SubaccountType.DEVISE_FEE); if (temporaryStatement == null) { writeCommissionLog(String.format("[服务费][普通订单][%s],订单的策划临时服务费单据不存在", order.getSn())); return; } statementList.add(createStatementByTemporaryStatement(temporaryStatement, null, order, true)); temporaryStatement.setIsStatement(true); temporaryStatementList.add(temporaryStatement); } if (temporaryStatementList.size() != statementList.size()) { return; } statementRepository.saveAll(statementList); // 修改临时结算单状态 temporaryStatementRepository.saveAll(temporaryStatementList); writeCommissionLog(String.format("[服务费][普通订单][%s],订单服务费单据已创建完成", order.getSn())); } @Override public void generateStatementByShipping(Long shippingId) { // 获取发货单 Shipping shipping = shippingRepository.findById(shippingId).orElse(null); if (shipping == null) { writeCommissionLog("[服务费][普通订单]发货单ID:" + shippingId + ",发货单的不存在"); return; } // 判断发货单是否已创建结算单 Statement statementRow = statementRepository.findFirstByShippingId(shippingId); if (statementRow != null) { writeCommissionLog(String.format("[服务费][普通订单][%s][发货单][%s],发货单已创建过服务费单据", shipping.getOrders().getSn(), shipping.getShippingSn())); return; } // 获取订单数据 Order order = shipping.getOrders(); Long orderId = shipping.getOrders().getId(); // 临时结算单 List<TemporaryStatement> temporaryStatementList = new ArrayList<>(); // 结算单 List<Statement> statementList = new ArrayList<>(); // 生成货款结算单 if (order.getGoodsPayment().compareTo(BigDecimal.ZERO) == 1) { // 获取货款临时结算单 TemporaryStatement temporaryStatement = temporaryStatementRepository.findFirstByOrdersIdAndSubaccountType(orderId, SubaccountType.GOODS_COST); if (temporaryStatement == null) { writeCommissionLog(String.format("[服务费][普通订单][%s][发货单][%s],订单的货款临时服务费单据不存在", shipping.getOrders().getSn(), shipping.getShippingSn())); return; } statementList.add(createStatementByTemporaryStatement(temporaryStatement, shipping, order, false)); temporaryStatementList.add(temporaryStatement); } // 生成品牌结算单 if (order.getBrandCost().compareTo(BigDecimal.ZERO) == 1) { // 获取品牌临时结算单 TemporaryStatement temporaryStatement = temporaryStatementRepository.findFirstByOrdersIdAndSubaccountType(orderId, SubaccountType.BRAND_FEE); if (temporaryStatement == null) { writeCommissionLog(String.format("[服务费][普通订单][%s][发货单][%s],订单的品牌临时服务费单据不存在", shipping.getOrders().getSn(), shipping.getShippingSn())); return; } statementList.add(createStatementByTemporaryStatement(temporaryStatement, shipping, order, false)); temporaryStatementList.add(temporaryStatement); } // 生成策划结算单 if (order.getDeviseCost().compareTo(BigDecimal.ZERO) == 1) { // 获取品牌临时结算单 TemporaryStatement temporaryStatement = temporaryStatementRepository.findFirstByOrdersIdAndSubaccountType(orderId, SubaccountType.DEVISE_FEE); if (temporaryStatement == null) { writeCommissionLog(String.format("[服务费][普通订单][%s][发货单][%s],订单的策划临时服务费单据不存在", shipping.getOrders().getSn(), shipping.getShippingSn())); return; } statementList.add(createStatementByTemporaryStatement(temporaryStatement, shipping, order, false)); temporaryStatementList.add(temporaryStatement); } if (temporaryStatementList.size() != statementList.size()) { return; } statementRepository.saveAll(statementList); // 获取已结算单据 List<Statement> allStatementList = statementRepository.findAllByOrdersId(orderId); // 计算总结算金额 BigDecimal totalStatementAmount = allStatementList.stream().map(Statement::getStatementAmount).reduce(BigDecimal.ZERO, BigDecimal::add); // 判断该临时结算是否结算完毕 if (totalStatementAmount.compareTo(order.getPayAmount()) == 0) { for (TemporaryStatement temporaryStatement : temporaryStatementList) { temporaryStatement.setIsStatement(true); } temporaryStatementRepository.saveAll(temporaryStatementList); } writeCommissionLog(String.format("[服务费][普通订单][%s][发货单][%s],发货单服务费单据已创建完成", shipping.getOrders().getSn(), shipping.getShippingSn())); } /** * 结算单-根据临时结算单生成 * <p>若是直接结算则不需要传发货单</p> * * @param temporaryStatement 临时结算单 * @param shipping 发货单 * @param order 订单 * @param isDirectSettlement 是否直接结算 * @return 结算单 * @description * @author huabiao * @create 2022/9/2 16:15 */ private Statement createStatementByTemporaryStatement(TemporaryStatement temporaryStatement, Shipping shipping, Order order, Boolean isDirectSettlement) { // 获取订单相关数据 Long orderId = order.getId(); // 获取订单费用比例 OrderFeeRatio orderFeeRatio = orderFeeRatioRepository.findByOrdersId(orderId); // 结算单构建 Statement statement = new Statement(); statement.setOrders(order); statement.setStatementNo(sequenceUtil.getNextSequenceNumber("FEE")); statement.setStatementType(StatementType.NORMALORDER); statement.setSubaccountType(temporaryStatement.getSubaccountType()); statement.setStatementState(StatementState.NOTRECORDED); statement.setShipping(shipping); statement.setCompany(temporaryStatement.getCompany()); // 结算单项 List<StatementLine> statementLineList = new ArrayList<>(); // 结算金额 BigDecimal subaccountAmount = BigDecimal.ZERO; if (isDirectSettlement) { for (OrderItem orderItem : order.getOrderItems()) { StatementLine statementLine = new StatementLine(); statementLine.setStatement(statement); if (statement.getSubaccountType().equals(SubaccountType.GOODS_COST)) { statementLine.setSubaccountAmount(orderItem.getGoodsPayment()); statementLine.setSubaccountRatio(BigDecimal.ONE.subtract(orderFeeRatio.getBrandCostRatio()).subtract(orderFeeRatio.getDeviseCostRatio())); statementLine.setCompany(temporaryStatement.getCompany()); // 计算品牌授权费 if (CollectionUtils.isNotEmpty(orderFeeRatio.getOrderItemFeeRatio())) { OrderItemFeeRatio orderItemFeeRatio = orderFeeRatio.getOrderItemFeeRatio().stream().filter(filterOrderItemFeeRatio -> filterOrderItemFeeRatio.getOrderItem().getId().equals(orderItem.getId())).findFirst().orElse(null); if (orderItemFeeRatio != null) { statementLine.setBrandAuthFee(orderItem.getGoodsPayment().multiply(orderItemFeeRatio.getBrandAuthCostRatio()).setScale(2, BigDecimal.ROUND_HALF_UP)); } } } else if (statement.getSubaccountType().equals(SubaccountType.BRAND_FEE)) { statementLine.setSubaccountAmount(orderItem.getBrandCost()); statementLine.setCompany(temporaryStatement.getCompany()); statementLine.setSubaccountRatio(orderFeeRatio != null ? orderFeeRatio.getBrandCostRatio() : null); } else if (statement.getSubaccountType().equals(SubaccountType.DEVISE_FEE)) { statementLine.setSubaccountAmount(orderItem.getDeviseCost()); statementLine.setCompany(temporaryStatement.getCompany()); statementLine.setSubaccountRatio(orderFeeRatio != null ? orderFeeRatio.getDeviseCostRatio() : null); } statementLine.setOrderItem(orderItem); statementLine.setQuantity(orderItem.getQuantity()); subaccountAmount = subaccountAmount.add(statementLine.getSubaccountAmount()); statementLineList.add(statementLine); } // 判断订单项分账金额和订单分账金额是否一致 if (temporaryStatement.getSubaccountType().equals(SubaccountType.GOODS_COST) && order.getGoodsPayment().compareTo(subaccountAmount) != 0) { writeCommissionLog(String.format("[服务费][普通订单][%s],订单的货款与订单行不一致", order.getSn())); return null; } else if (temporaryStatement.getSubaccountType().equals(SubaccountType.BRAND_FEE) && order.getBrandCost().compareTo(subaccountAmount) != 0) { writeCommissionLog(String.format("[服务费][普通订单][%s],订单的品牌费与订单行不一致", order.getSn())); return null; } else if (temporaryStatement.getSubaccountType().equals(SubaccountType.DEVISE_FEE) && order.getDeviseCost().compareTo(subaccountAmount) != 0) { writeCommissionLog(String.format("[服务费][普通订单][%s],订单的策划费与订单行不一致", order.getSn())); return null; } } else { for (ShippingItem shippingItem : shipping.getShippingItem()) { StatementLine statementLine = new StatementLine(); List<OrderItem> orderItemList = order.getOrderItems().stream().filter(filterOrderItem -> filterOrderItem.getId().equals(Long.valueOf(shippingItem.getOrderItemId()))).collect(Collectors.toList()); if (CollectionUtils.isEmpty(orderItemList)) { writeCommissionLog(String.format("[服务费][普通订单][%s][发货单][%s],发货单的订单明细[SKU_ID:%s]不存在", shipping.getOrders().getSn(), shipping.getShippingSn(), shippingItem.getSkuId())); return null; } if (orderItemList.size() > 1) { writeCommissionLog(String.format("[服务费][普通订单][%s][发货单][%s],发货单的订单明细[SKU_ID:%s]存在多条", shipping.getOrders().getSn(), shipping.getShippingSn(), shippingItem.getSkuId())); return null; } OrderItem orderItem = orderItemList.get(0); // 获取临时结算单项 TemporaryStatementLine temporaryStatementLine = temporaryStatement.getTemporaryStatementLines().stream().filter(filterTemporaryStatementLine -> filterTemporaryStatementLine.getOrderItem().equals(orderItem)).findFirst().orElse(null); if (temporaryStatementLine == null) { writeCommissionLog(String.format("[服务费][普通订单][%s][发货单][%s],发货单的临时结算明细[SKU_ID:%s]不存在", shipping.getOrders().getSn(), shipping.getShippingSn(), shippingItem.getSkuId())); return null; } BigDecimal subaccountLineAmount; // 判断是否部分发货 if (shippingItem.getShippingQuantity().equals(orderItem.getQuantity())) { // 一次性全部发完 subaccountLineAmount = temporaryStatementLine.getStatementAmount(); } else { // 获取已结算数量 BigDecimal statementQuantity = statementLineRepository.calculateSubaccountQuantity(orderItem.getId()); // 判断是否最后一次结算 if (orderItem.getQuantity().equals(shippingItem.getShippingQuantity() + statementQuantity.intValue())) { // 最后一次发货 总的减去之前计算的 BigDecimal subaccountAmountSum = statementLineRepository.calculateSubaccountAmount(orderItem.getId()); subaccountLineAmount = temporaryStatementLine.getStatementAmount().subtract(subaccountAmountSum); } else { // 部分发货 // 计算比例 总分账*(当前发货数量/总购买数量) subaccountLineAmount = temporaryStatementLine.getStatementAmount() .multiply(new BigDecimal(shippingItem.getShippingQuantity())) .divide(new BigDecimal(orderItem.getQuantity()), 2, BigDecimal.ROUND_HALF_UP); } } statementLine.setCompany(temporaryStatementLine.getCompany()); statementLine.setSubaccountAmount(subaccountLineAmount); statementLine.setOrderItem(orderItem); statementLine.setShippingItem(shippingItem); statementLine.setSubaccountRatio(temporaryStatementLine.getSubaccountRatio()); statementLine.setStatement(statement); // 计算品牌授权费 if (statement.getSubaccountType().equals(SubaccountType.GOODS_COST) && CollectionUtils.isNotEmpty(orderFeeRatio.getOrderItemFeeRatio())) { OrderItemFeeRatio orderItemFeeRatio = orderFeeRatio.getOrderItemFeeRatio().stream().filter(filterOrderItemFeeRatio -> filterOrderItemFeeRatio.getOrderItem().getId().equals(Long.valueOf(shippingItem.getOrderItemId()))).findFirst().orElse(null); if (orderItemFeeRatio != null) { statementLine.setBrandAuthFee(subaccountLineAmount.multiply(orderItemFeeRatio.getBrandAuthCostRatio()).setScale(2, BigDecimal.ROUND_HALF_UP)); } } statementLine.setQuantity(shippingItem.getShippingQuantity()); subaccountAmount = subaccountAmount.add(subaccountLineAmount); statementLineList.add(statementLine); } } statement.setStatementLine(statementLineList); statement.setStatementAmount(subaccountAmount); return statement; } @Override public void generateStatementByAfterSale(Long afterSaleId) { AfterSale afterSale = afterSaleRepository.findById(afterSaleId).orElse(null); if (afterSale == null) { writeCommissionLog("[服务费][普通订单]售后单ID:" + afterSaleId + ",售后单不存在"); return; } // 判断是否已存在对应的结算单 if (statementRepository.existsByAfterSaleId(afterSaleId)) { writeCommissionLog(String.format("[服务费][普通订单][%s][售后单][%s],售后单已创建过服务费单据", afterSale.getOrders().getSn(), afterSale.getAfterSaleSn())); return; } List<Statement> refundStatementList = new ArrayList<>(); /** * 先算品牌和策划的退款金额,而剩下的则是货款的金额 */ // 生成品牌结算单 Order order = afterSale.getOrders(); List<Statement> statementList = statementRepository.findAllByOrdersIdAndStatementType(order.getId(), StatementType.NORMALORDER); if (CollectionUtils.isEmpty(statementList)) { writeCommissionLog(String.format("[服务费][普通订单][%s][售后单][%s],结算单不存在", afterSale.getOrders().getSn(), afterSale.getAfterSaleSn())); return; } if (order.getBrandCost().compareTo(BigDecimal.ZERO) == 1) { // 获取对应订单结算单 Statement statement = statementList.stream().filter(filterStatement -> filterStatement.getSubaccountType().equals(SubaccountType.BRAND_FEE)).findFirst().orElse(null); if (statement == null) { writeCommissionLog(String.format("[服务费][普通订单][%s][售后单][%s],对应的品牌费结算单不存在", afterSale.getOrders().getSn(), afterSale.getAfterSaleSn())); return; } Statement refundStatement = createRefundStatement(statement, afterSale); refundStatementList.add(refundStatement); } // 生成策划结算单 if (order.getDeviseCost().compareTo(BigDecimal.ZERO) == 1) { Statement statement = statementList.stream().filter(filterStatement -> filterStatement.getSubaccountType().equals(SubaccountType.DEVISE_FEE)).findFirst().orElse(null); if (statement == null) { writeCommissionLog(String.format("[服务费][普通订单][%s][售后单][%s],对应的策划费结算单不存在", afterSale.getOrders().getSn(), afterSale.getAfterSaleSn())); return; } refundStatementList.add(createRefundStatement(statement, afterSale)); } // 生成货款结算单 if (order.getGoodsPayment().compareTo(BigDecimal.ZERO) == 1) { Statement statement = statementList.stream().filter(filterStatement -> filterStatement.getSubaccountType().equals(SubaccountType.GOODS_COST)).findFirst().orElse(null); if (statement == null) { writeCommissionLog(String.format("[服务费][普通订单][%s][售后单][%s],对应的货款结算单不存在", afterSale.getOrders().getSn(), afterSale.getAfterSaleSn())); return; } // 货款退款金额 = 退款金额 - 品牌费退款金额 - 策划费退款金额 refundStatementList.add(createRefundStatement(statement, afterSale)); } // 判断退款结算单和售后单的退款金额是否一致 BigDecimal totalRefundAmount = refundStatementList.stream().map(statement -> statement.getStatementAmount()).reduce(BigDecimal.ZERO, BigDecimal::add); if (totalRefundAmount.add(afterSale.getAmount()).compareTo(BigDecimal.ZERO) != 0) { writeCommissionLog(String.format("[服务费][普通订单][%s][售后单][%s],订单对冲服务费单据金额不一致", afterSale.getOrders().getSn(), afterSale.getAfterSaleSn())); return; } statementRepository.saveAll(refundStatementList); writeCommissionLog(String.format("[服务费][普通订单][%s][售后单][%s],订单对冲服务费单据已创建完成", afterSale.getOrders().getSn(), afterSale.getAfterSaleSn())); } /** * 退款结算单-生成 * * @param statement:结算单 * @param afterSale:售后单 * @return 结算单 * @description * @author huabiao * @create 2022/9/2 16:15 */ private Statement createRefundStatement(Statement statement, AfterSale afterSale) { Long afterSaleId = afterSale.getId(); Long orderId = afterSale.getOrders().getId(); // 拼接退款结算单 Statement refundStatement = new Statement(); refundStatement.setOrders(afterSale.getOrders()); refundStatement.setStatementNo(sequenceUtil.getNextSequenceNumber("FEE")); refundStatement.setStatementType(StatementType.AFTERSALES); refundStatement.setSubaccountType(statement.getSubaccountType()); refundStatement.setStatementState(StatementState.NOTRECORDED); // 拼接退款结算单行 List<StatementLine> refundStatementLineList = new ArrayList<>(); // 退款金额 BigDecimal subaccountAmount = BigDecimal.ZERO; for (AfterSaleItem afterSaleItem : afterSale.getAfterSaleItems()) { StatementLine refundStatementLine = new StatementLine(); refundStatementLine.setStatement(refundStatement); // 退款时不会有发货单 if (afterSale.getAfterSaleType().equals(AfterSaleType.RETURN_REFUND)) { // 查找对应发货单项 List<ShippingItem> shippingItemList = afterSale.getShipping().getShippingItem().stream().filter(filterShippingItem -> filterShippingItem.getSkuId().equals(afterSaleItem.getSkuId())).collect(Collectors.toList()); if (CollectionUtils.isEmpty(shippingItemList)) { writeCommissionLog(String.format("[服务费][普通订单][%s][售后单][%s],发货单项明细[SKU_ID:[%s]不存在", afterSale.getOrders().getSn(), afterSale.getAfterSaleSn(), afterSaleItem.getSkuId())); return null; } if (shippingItemList.size() > 1) { writeCommissionLog(String.format("[服务费][普通订单][%s][售后单][%s],发货单项明细[SKU_ID:[%s]存在多条", afterSale.getOrders().getSn(), afterSale.getAfterSaleSn(), afterSaleItem.getSkuId())); return null; } ShippingItem shippingItem = shippingItemList.get(0); refundStatementLine.setShippingItem(shippingItem); } // 获取订单结算单的结算单行 List<StatementLine> statementLineList = statement.getStatementLine().stream().filter(filterStatementLine -> filterStatementLine.getOrderItem().getSkuId().equals(afterSaleItem.getSkuId())).collect(Collectors.toList()); if (CollectionUtils.isEmpty(statementLineList)) { writeCommissionLog(String.format("[服务费][普通订单][%s][售后单][%s],售后单的订单明细[SKU_ID:[%s]不存在", afterSale.getOrders().getSn(), afterSale.getAfterSaleSn(), afterSaleItem.getSkuId())); return null; } if (statementLineList.size() > 1) { writeCommissionLog(String.format("[服务费][普通订单][%s][售后单][%s],售后单的订单明细[SKU_ID:[%s]存在多条", afterSale.getOrders().getSn(), afterSale.getAfterSaleSn(), afterSaleItem.getSkuId())); return null; } StatementLine statementLine = statementLineList.get(0); // 获取订单费用比例 OrderFeeRatio orderFeeRatio = orderFeeRatioRepository.findByOrdersId(orderId); refundStatementLine.setCompany(statementLine.getCompany()); refundStatementLine.setOrderItem(statementLine.getOrderItem()); // 计算每个售后项的退款金额 BigDecimal subaccountLineAmount = BigDecimal.ZERO; switch (statement.getSubaccountType()) { case GOODS_COST: subaccountLineAmount = afterSaleItem.getAmount().multiply(BigDecimal.ONE.subtract(orderFeeRatio.getBrandCostRatio()).subtract(orderFeeRatio.getDeviseCostRatio())).setScale(2, BigDecimal.ROUND_HALF_UP); break; case BRAND_FEE: refundStatementLine.setSubaccountRatio(orderFeeRatio.getBrandCostRatio()); subaccountLineAmount = afterSaleItem.getAmount().multiply(orderFeeRatio.getBrandCostRatio()).setScale(2, BigDecimal.ROUND_HALF_UP); break; case DEVISE_FEE: refundStatementLine.setSubaccountRatio(orderFeeRatio.getDeviseCostRatio()); subaccountLineAmount = afterSaleItem.getAmount().multiply(orderFeeRatio.getDeviseCostRatio()).setScale(2, BigDecimal.ROUND_HALF_UP); break; } subaccountAmount = subaccountAmount.add(subaccountLineAmount); refundStatementLine.setSubaccountAmount(subaccountLineAmount.negate()); // 计算品牌授权费 if (statement.getSubaccountType().equals(SubaccountType.GOODS_COST) && CollectionUtils.isNotEmpty(orderFeeRatio.getOrderItemFeeRatio())) { OrderItemFeeRatio orderItemFeeRatio = orderFeeRatio.getOrderItemFeeRatio().stream().filter(filterOrderItemFeeRatio -> filterOrderItemFeeRatio.getOrderItem().getId().equals(afterSaleItem.getOrderItem().getId())).findFirst().orElse(null); if (orderItemFeeRatio != null) { refundStatementLine.setBrandAuthFee(subaccountLineAmount.multiply(orderItemFeeRatio.getBrandAuthCostRatio()).setScale(2, BigDecimal.ROUND_HALF_UP)); } } refundStatementLine.setQuantity(afterSaleItem.getQuantity()); refundStatementLineList.add(refundStatementLine); } refundStatement.setStatementLine(refundStatementLineList); refundStatement.setShipping(afterSale.getShipping()); refundStatement.setAfterSale(afterSale); refundStatement.setCompany(statement.getCompany()); refundStatement.setStatementAmount(subaccountAmount.negate()); return refundStatement; } @Override public void generateSubaccountByOrder(Long orderId) { Order order = getOrderAndCheck(orderId); if (order == null) { return; } // 获取所有的退款单并判断退款结算单是否都生成 if (checkRefundList(orderId, order)) { return; } // 根据支付方式进行分账 Receipt receipt = order.getReceipt().get(0); // 电子账簿支付 if (receipt.getPaymentMethod().equals(PaymentMethod.DEPOSIT)) { confirmsCombinedGuaranteeByOrder(order); } // POS、微信、支付宝、云闪付支付 if (receipt.getPaymentMethod().equals(PaymentMethod.WECHAT) || receipt.getPaymentMethod().equals(PaymentMethod.ALIPAY) || receipt.getPaymentMethod().equals(PaymentMethod.CHINA_UNIONPAY_QUICK_PASS) || receipt.getPaymentMethod().equals(PaymentMethod.POS) || receipt.getPaymentMethod().equals(PaymentMethod.CREDIT_PAY)) { createSubaccountByOrder(order, receipt.getPaymentMethod()); } } private boolean checkRefundList(Long orderId, Order order) { List<Refund> refundList = refundRepository.findAllByOrdersId(orderId); if (CollectionUtils.isNotEmpty(refundList)) { BigDecimal refundAmount = refundList.stream().map(Refund::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add); // 获取退款结算单 List<Statement> statementList = statementRepository.findAllByOrdersIdAndStatementType(orderId, StatementType.AFTERSALES); BigDecimal refundStatementAmount = statementList.stream().map(Statement::getStatementAmount).reduce(BigDecimal.ZERO, BigDecimal::add); if (refundAmount.add(refundStatementAmount).compareTo(BigDecimal.ZERO) != 0) { writeSeparateLog(String.format("[分账][生成][普通订单][%s],退款单金额与退款结算单金额不一致,分账失败。", order.getSn())); return true; } // 判断所有退款单状态是否都为已退款 if(refundList.stream().filter(refund -> !RefundStatus.REFUNDED.equals(refund.getRefundStatus())).findAny().isPresent()){ writeSeparateLog(String.format("[分账][生成][普通订单][%s],存在未完成退款的退款单,分账失败。", order.getSn())); return true; } } return false; } private Order getOrderAndCheck(Long orderId) { Order order = orderRepository.findById(orderId).orElse(null); if (order == null) { throw new YnceErrorException(YnceError.YNCE_204003); } // 判断订单是否在申请售后中 if (order.getIsReturnRefund() || order.getIsRefund()) { writeSeparateLog(String.format("[分账][生成][普通订单][%s],订单在售后中。", order.getSn())); return null; } // 判断是否当前订单所有的商品是否全部退货 Optional<OrderItem> orderItemOptional = order.getOrderItems().stream().filter(orderItem -> orderItem.getQuantity() > (orderItem.getReturnCount() + orderItem.getCloseCount())).findAny(); if (BooleanUtils.isFalse(orderItemOptional.isPresent())) { // 此订单下面的所有商品已全部退退货,不执行分账 stopOrderSubaccount(order.getId()); writeSeparateLog(String.format("[分账][生成][普通订单][%s],订单已退货,不执行分账。", order.getSn())); return null; } // 判断当前订单是否已经退款 if (order.getPaymentStatus().equals(PaymentStatus.REFUNDED)) { stopOrderSubaccount(order.getId()); writeSeparateLog(String.format("[分账][生成][普通订单][%s],订单已退款,不执行分账。", order.getSn())); return null; } return order; } @Override public void handleSubaccount(SettlementCallbackVO settlementCallbackVO) { // 获取分账单 List<Subaccount> subaccountList = subaccountRepository.findAllByExternalId(settlementCallbackVO.getSettOrderNo()); Boolean isSeparate = false; // 存在订单结算和发货单结算 Long orderId = null; Long shippingId = null; for (Subaccount subaccount : subaccountList) { orderId = subaccount.getOrders().getId(); if (subaccount.getShipping() != null) { shippingId = subaccount.getShipping().getId(); } ProfitSharingCallbackVO profitSharingCallbackVO = settlementCallbackVO.getProfitSharingList().stream().filter(filterProfitSharingCallbackVO -> filterProfitSharingCallbackVO.getProfitSharingWalletId().equals(subaccount.getCompany().getWalletId())).findFirst().orElse(null); if (profitSharingCallbackVO != null) { // 分账成功 if (profitSharingCallbackVO.getProfitSharingStatus().equals("02")) { subaccount.setSeparateTime(LocalDateTime.now()); subaccount.setSubaccountState(SubaccountState.SEPARATE_SUCC); subaccountRepository.save(subaccount); } // 分账失败 else if (profitSharingCallbackVO.getProfitSharingStatus().equals("03")) { subaccount.setSubaccountState(SubaccountState.SEPARATE_FAIL); subaccountRepository.save(subaccount); } } } if (isSeparate) { if (shippingId != null) { // 更新发货单已分账 shippingRepository.updateIsSeparateAccountsById(orderId); } else if (orderId != null) { // 更新订单已分账 orderRepository.updateIsSeparateAccountsById(orderId); } } } @Override public void handleBrandAuthFee(String subaccountNo) { // 获取所有品牌授权费 Subaccount subaccount = subaccountRepository.findBySubaccountNo(subaccountNo); if (ObjectUtil.isNull(subaccount)) { throw new YnceErrorException("分帐单不存在"); } if (!subaccount.getSubaccountType().equals(SubaccountType.BRAND_AUTH_FEE)) { throw new YnceErrorException("分帐单类型不是品牌授权费"); } if (subaccount.getOrders().getIsSeparateAccounts()) { throw new YnceErrorException("对应订单已分账"); } // 查询订单 Order order = orderRepository.findById(subaccount.getOrders().getId()).orElse(null); if (ObjectUtil.isNull(order)) { throw new YnceErrorException(YnceError.YNCE_211004); } // 区分预存款和其他支付方式 Receipt receipt = order.getReceipt().get(0); // 获取货款数据,可获得品牌授权费 Subaccount goodsCostSubaccount = subaccountRepository.findByOrdersIdAndSubaccountType(order.getId(), SubaccountType.GOODS_COST); // 预存款支付 if (receipt.getPaymentMethod().equals(PaymentMethod.DEPOSIT)) { // 品牌授权费差额 = 银联支付单金额-已分账金额 ChinaumsPayment chinaumsPayment = chinaumsPaymentRepository.findFirstByOrdersIdAndSubaccountType(order.getId(), SubaccountType.BRAND_AUTH_FEE); BigDecimal balance = chinaumsPayment.getAmount().subtract(subaccount.getSubaccountAmount()); // 调用分账确认接口 // 拼接扩展字段:商品信息 ChinaumsGuaranteePayExtraDTO chinaumsGuaranteePayExtraDTO = new ChinaumsGuaranteePayExtraDTO(); chinaumsGuaranteePayExtraDTO.setProductInfos(this.handleProductInfoByOrder(order.getOrderItems(), order.getSn(), order.getAmount(), balance)); // 拼接分账确认请求参数 ChinaumsGuaranteePayConfirmsDTO chinaumsGuaranteePayConfirmsDTO = ChinaumsGuaranteePayConfirmsDTO .builder() .outOrderNo(subaccount.getSubaccountNo() + "-BALANCE") .guaranteePaymentId(chinaumsPayment.getGuaranteePaymentId()) .sentAt(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX").format(new Date())) .amount(balance.multiply(new BigDecimal(100)).intValue()) .extra(chinaumsGuaranteePayExtraDTO) .build(); ChinaumsGuaranteePayConfirmsVO chinaumsGuaranteePayConfirmsVO; try { chinaumsGuaranteePayConfirmsVO = walletService.paySettlement(chinaumsGuaranteePayConfirmsDTO); } catch (Exception exception) { throw new YnceErrorException("分账确认失败"); } // 当为处理中时需要调用接口查询 if (chinaumsGuaranteePayConfirmsVO.getStatus().equals("processing")) { try { long currentTimeMillis = System.currentTimeMillis(); while (true) { JSONObject jsonObject = new JSONObject(); jsonObject.put("combinedGuaranteeConfirmId", chinaumsGuaranteePayConfirmsVO.getCombinedGuaranteeConfirmId()); chinaumsGuaranteePayConfirmsVO = chinaumsUtil.execute(RouteUtil.ROUTE_WALLET_COMBINED_GUARANTEE_PAYMENTS_CONFIRMS_BY_SYS_NO, jsonObject, ChinaumsGuaranteePayConfirmsVO.class); // 当请求成功或者时间超时时,结束循环 if (!chinaumsGuaranteePayConfirmsVO.getStatus().equals("processing") || System.currentTimeMillis() - currentTimeMillis > 5000) { break; } } } catch (Exception exception) { log.error(exception.getMessage()); throw new YnceErrorException("循环查询合并消费担保确认失败"); } } subaccount.setExternalId(subaccount.getExternalId() + "," + chinaumsGuaranteePayConfirmsVO.getCombinedGuaranteeConfirmId()); writeSeparateLog(String.format("[分账][生成][普通订单][%s],生成差额分账单成功,银联结算单号[%s]。", order.getSn(), chinaumsGuaranteePayConfirmsVO.getCombinedGuaranteeConfirmId())); // 修改分账总金额 subaccount.setSubaccountTotalAmount(goodsCostSubaccount.getBrandAuthFee()); // 修改分账净额 subaccount.setSubaccountAmount(chinaumsPayment.getAmount()); // 修改服务费比例 OrderFeeRatio orderFeeRatio = orderFeeRatioRepository.findByOrdersId(order.getId()); if (CollectionUtils.isNotEmpty(orderFeeRatio.getOrderItemFeeRatio())) { subaccount.setPlatformServiceCostRatio(orderFeeRatio.getOrderItemFeeRatio().get(0).getBrandAuthCostServiceCostRatio()); } // 修改平台服务费:平台服务费 = 分账总额 - 分账净额 subaccount.setPlatformServiceFee(subaccount.getSubaccountTotalAmount().subtract(subaccount.getSubaccountAmount())); subaccountRepository.save(subaccount); // 处理预存款账户 AccountChangeCreateDTO accountChangeCreateDTO = AccountChangeCreateDTO .builder() .company(subaccount.getCompany()) .direction(ChangeDirection.ADD) .type(AccountChangeType.valueOf(SubaccountType.BRAND_AUTH_FEE.getValue())) .amount(balance) .sourceNo(chinaumsGuaranteePayConfirmsDTO.getOutOrderNo()) .sourceCompanyId(subaccount.getSourceCompany().getId()) .build(); accountService.intoAccount(accountChangeCreateDTO); // 修改已确认金额 chinaumsPayment.setConfirmedAmount(chinaumsPayment.getConfirmedAmount().add(balance)); chinaumsPaymentRepository.saveAndFlush(chinaumsPayment); } else { // 其他支付方式所生成的分帐单金额是正确的,但是分帐单有问题 // 修改分账总金额 subaccount.setSubaccountTotalAmount(goodsCostSubaccount.getBrandAuthFee()); // 修改服务费比例 OrderFeeRatio orderFeeRatio = orderFeeRatioRepository.findByOrdersId(order.getId()); if (CollectionUtils.isNotEmpty(orderFeeRatio.getOrderItemFeeRatio())) { subaccount.setPlatformServiceCostRatio(orderFeeRatio.getOrderItemFeeRatio().get(0).getBrandAuthCostServiceCostRatio()); } // 修改平台服务费:平台服务费 = 分账总额 - 分账净额 subaccount.setPlatformServiceFee(subaccount.getSubaccountTotalAmount().subtract(subaccount.getSubaccountAmount())); subaccountRepository.save(subaccount); } } @Override @Transactional(rollbackFor = Exception.class) public void generateStatementByOrderRefund(Long orderId) { Order order = orderRepository.findById(orderId).orElse(null); if (order == null) { throw new YnceErrorException(YnceError.YNCE_204003); } // 获取所有退款单 List<Refund> refundList = refundRepository.findAllByOrdersId(orderId); if (CollectionUtils.isNotEmpty(refundList)) { List<OrderRefundItemDTO> orderRefundItemDTOList = new ArrayList<>(); // 拼接订单退款项DTO for (OrderItem orderItem : order.getOrderItems()) { if (orderItem.getCloseCount() > 0) { OrderRefundItemDTO orderRefundItemDTO = new OrderRefundItemDTO(); orderRefundItemDTO.setOrderItem(orderItem); orderRefundItemDTO.setRefundAmount(orderItem.getRefundAmount()); orderRefundItemDTO.setRefundQuantity(orderItem.getCloseCount()); orderRefundItemDTOList.add(orderRefundItemDTO); } } if (CollectionUtils.isEmpty(orderRefundItemDTOList)) { return; } // 总退款金额 BigDecimal totalCloseAmount = refundList.stream().map(Refund::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add); List<Statement> refundStatementList = new ArrayList<>(); // 生成品牌结算单 if (order.getBrandCost().compareTo(BigDecimal.ZERO) == 1) { refundStatementList.add(createRefundStatement(SubaccountType.BRAND_FEE, order, orderRefundItemDTOList, order.getBrandCompany())); } // 生成策划结算单 if (order.getDeviseCost().compareTo(BigDecimal.ZERO) == 1) { refundStatementList.add(createRefundStatement(SubaccountType.DEVISE_FEE, order, orderRefundItemDTOList, order.getDeviseCompany())); } // 生成货款结算单 if (order.getGoodsPayment().compareTo(BigDecimal.ZERO) == 1) { // 货款退款金额 = 退款金额 - 品牌费退款金额 - 策划费退款金额 refundStatementList.add(createRefundStatement(SubaccountType.GOODS_COST, order, orderRefundItemDTOList, order.getSellerCompany())); } // 判断金额是否一致 BigDecimal totalRefundAmount = refundStatementList.stream().map(Statement::getStatementAmount).reduce(BigDecimal.ZERO, BigDecimal::add); if (totalRefundAmount.add(totalCloseAmount).compareTo(BigDecimal.ZERO) != 0) { log.error("订单关闭生成退款结算单失败:退款金额不一致"); return; } statementRepository.saveAll(refundStatementList); } } @Override public void handleGoodsCost(String subaccountNo, List<Long> orderItemIdList) { // 获取货款分帐单 Subaccount subaccount = subaccountRepository.findBySubaccountNo(subaccountNo); if (subaccount == null) { throw new YnceErrorException("分帐单不存在"); } if (!subaccount.getSubaccountType().equals(SubaccountType.GOODS_COST)) { throw new YnceErrorException("分帐单类型不是货款"); } if (subaccount.getOrders().getIsSeparateAccounts()) { throw new YnceErrorException("对应订单已分账"); } // 查询订单 Order order = orderRepository.findById(subaccount.getOrders().getId()).orElse(null); if (order == null) { throw new YnceErrorException(YnceError.YNCE_211004); } // 区分预存款和其他支付方式 Receipt receipt = order.getReceipt().get(0); // 预存款支付 if (receipt.getPaymentMethod().equals(PaymentMethod.DEPOSIT)) { // 货款差额 = 银联支付单金额-银联退款单金额-已分账金额 // 获取银联支付单 ChinaumsPayment chinaumsPayment = chinaumsPaymentRepository.findFirstByOrdersIdAndSubaccountType(order.getId(), SubaccountType.GOODS_COST); // 获取银联退款单 List<ChinaumsRefund> chinaumsRefundList = chinaumsRefundRepository.findAllByOrigTradeId(chinaumsPayment.getGuaranteePaymentId()); BigDecimal chinaumsRefundAmount = CollectionUtils.isNotEmpty(chinaumsRefundList) ? chinaumsRefundList.stream().map(ChinaumsRefund::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add) : BigDecimal.ZERO; BigDecimal balance = chinaumsPayment.getAmount().subtract(chinaumsRefundAmount).subtract(subaccount.getSubaccountAmount()); if (balance.compareTo(BigDecimal.ZERO) == 0) { throw new YnceErrorException("货款差额为0,无需补充"); } // 拼接扩展字段:商品信息 ChinaumsGuaranteePayExtraDTO chinaumsGuaranteePayExtraDTO = new ChinaumsGuaranteePayExtraDTO(); List<OrderItem> orderItemList = new ArrayList<>(); BigDecimal orderAmount = BigDecimal.ZERO; if (CollectionUtils.isNotEmpty(orderItemIdList)) { for (OrderItem orderItem : order.getOrderItems()) { if (orderItemIdList.contains(orderItem.getId())) { orderItemList.add(orderItem); orderAmount = orderAmount.add(orderItem.getAmount()); } } } else { orderItemList = order.getOrderItems(); orderAmount = order.getAmount(); } chinaumsGuaranteePayExtraDTO.setProductInfos(this.handleProductInfoByOrder(orderItemList, order.getSn(), orderAmount, balance)); // 拼接分账确认请求参数 ChinaumsGuaranteePayConfirmsDTO chinaumsGuaranteePayConfirmsDTO = ChinaumsGuaranteePayConfirmsDTO .builder() .outOrderNo(subaccount.getSubaccountNo() + "-BALANCE") .guaranteePaymentId(chinaumsPayment.getGuaranteePaymentId()) .sentAt(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX").format(new Date())) .amount(balance.multiply(new BigDecimal(100)).intValue()) .extra(chinaumsGuaranteePayExtraDTO) .build(); ChinaumsGuaranteePayConfirmsVO chinaumsGuaranteePayConfirmsVO; try { chinaumsGuaranteePayConfirmsVO = walletService.paySettlement(chinaumsGuaranteePayConfirmsDTO); } catch (Exception exception) { throw new YnceErrorException("分账确认失败"); } // 当为处理中时需要调用接口查询 if (chinaumsGuaranteePayConfirmsVO.getStatus().equals("processing")) { try { long currentTimeMillis = System.currentTimeMillis(); while (true) { JSONObject jsonObject = new JSONObject(); jsonObject.put("combinedGuaranteeConfirmId", chinaumsGuaranteePayConfirmsVO.getCombinedGuaranteeConfirmId()); chinaumsGuaranteePayConfirmsVO = chinaumsUtil.execute(RouteUtil.ROUTE_WALLET_COMBINED_GUARANTEE_PAYMENTS_CONFIRMS_BY_SYS_NO, jsonObject, ChinaumsGuaranteePayConfirmsVO.class); // 当请求成功或者时间超时时,结束循环 if (!chinaumsGuaranteePayConfirmsVO.getStatus().equals("processing") || System.currentTimeMillis() - currentTimeMillis > 5000) { break; } } } catch (Exception exception) { log.error(exception.getMessage()); throw new YnceErrorException("循环查询合并消费担保确认失败"); } } subaccount.setExternalId(subaccount.getExternalId() + "," + chinaumsGuaranteePayConfirmsVO.getCombinedGuaranteeConfirmId()); writeSeparateLog(String.format("[分账][生成][普通订单][%s],生成差额分账单成功,银联结算单号[%s]。", order.getSn(), chinaumsGuaranteePayConfirmsVO.getCombinedGuaranteeConfirmId())); // 修改分账净额 subaccount.setSubaccountAmount(subaccount.getSubaccountAmount().add(balance)); subaccountRepository.save(subaccount); // 处理预存款账户 AccountChangeCreateDTO accountChangeCreateDTO = AccountChangeCreateDTO .builder() .company(subaccount.getCompany()) .direction(ChangeDirection.ADD) .type(AccountChangeType.valueOf(SubaccountType.BRAND_AUTH_FEE.getValue())) .amount(balance) .sourceNo(chinaumsGuaranteePayConfirmsDTO.getOutOrderNo()) .sourceCompanyId(subaccount.getSourceCompany().getId()) .build(); accountService.intoAccount(accountChangeCreateDTO); // 修改已确认金额 chinaumsPayment.setConfirmedAmount(chinaumsPayment.getConfirmedAmount().add(balance)); chinaumsPaymentRepository.saveAndFlush(chinaumsPayment); } } @Override @Transactional(rollbackFor = Exception.class) public void generateRefundSubaccount(SubaccountRefund subaccountRefund) { Subaccount subaccount = new Subaccount(); subaccount.setSubaccountNo(sequenceUtil.getNextSequenceNumber("FZ")); subaccount.setCompany(subaccountRefund.getRefundCompany()); subaccount.setSubaccountCostRatio(subaccountRefund.getSubaccountCostRatio()); subaccount.setSubaccountAmount(subaccountRefund.getAmount().negate()); subaccount.setSubaccountTotalAmount(subaccountRefund.getAmount().negate()); subaccount.setSubaccountType(subaccountRefund.getSubaccountType()); subaccount.setOrders(subaccountRefund.getOrders()); subaccount.setSubaccountState(SubaccountState.SEPARATE_SUCC); subaccount.setSeparateTime(subaccountRefund.getRefundTime()); subaccount.setExternalId(subaccountRefund.getExternalId()); subaccount.setExternalTime(subaccountRefund.getRefundTime()); subaccount.setSourceCompany(subaccountRefund.getRefundCompany()); subaccount.setExternalTime(subaccountRefund.getRefundTime()); subaccountRepository.saveAndFlush(subaccount); // 对供应商流水进行处理 AccountChangeCreateDTO supplierAccountChangeCreateDTO = AccountChangeCreateDTO .builder() .company(subaccount.getCompany()) .direction(ChangeDirection.REDUCE) .type(AccountChangeType.REFUND) .amount(subaccountRefund.getAmount()) .sourceCompanyId(subaccountRefund.getReceiptCompany().getId()) .sourceNo(subaccountRefund.getRefundSn()) .build(); accountService.intoAccount(supplierAccountChangeCreateDTO); // 对经销商流水进行处理 AccountChangeCreateDTO dealerAccountChangeCreateDTO = AccountChangeCreateDTO .builder() .company(subaccountRefund.getReceiptCompany()) .direction(ChangeDirection.ADD) .type(AccountChangeType.REFUND) .amount(subaccountRefund.getAmount()) .sourceCompanyId(subaccountRefund.getRefundCompany().getId()) .sourceNo(subaccountRefund.getRefundSn()) .build(); accountService.intoAccount(dealerAccountChangeCreateDTO); } @Override public void generateSubaccountByShipping(Long shippingId) { Shipping shipping = shippingRepository.findById(shippingId).orElse(null); if (shipping == null) { throw new YnceErrorException(YnceError.YNCE_204010); } // 判断发货单是否售后中 AfterSale afterSale = afterSaleRepository.findFirstByShippingIdAndAfterSaleStatus(shipping.getId(), AfterSaleStatus.CREATED); if (afterSale != null) { writeSeparateLog(String.format("[分账][生成][普通订单][%s][发货单][%s],发货单在售后中。", shipping.getOrders().getSn(), shipping.getShippingSn())); return; } // 判断当前发货单是否已全部退货,若是则不参与分账 Optional<ShippingItem> shippingItemOptional = shipping.getShippingItem().stream().filter(shippingItem -> !shippingItem.getReturnQuantity().equals(shippingItem.getShippingQuantity())).findAny(); if (BooleanUtils.isFalse(shippingItemOptional.isPresent())) { // 此发货单下面的所有商品已全部退退货,不执行分账 updateIsSeparateAccountsByShipping(shipping); writeSeparateLog(String.format("[分账][生成][普通订单][%s][发货单][%s],不执行分账。", shipping.getOrders().getSn(), shipping.getShippingSn())); return; } // 根据支付方式进行分账 Receipt receipt = shipping.getOrders().getReceipt().get(0); // 电子账簿支付 if (receipt.getPaymentMethod().equals(PaymentMethod.DEPOSIT)) { confirmsCombinedGuaranteeByShipping(shipping); } // POS、微信、支付宝、云闪付支付 if (receipt.getPaymentMethod().equals(PaymentMethod.WECHAT) || receipt.getPaymentMethod().equals(PaymentMethod.ALIPAY) || receipt.getPaymentMethod().equals(PaymentMethod.CHINA_UNIONPAY_QUICK_PASS) || receipt.getPaymentMethod().equals(PaymentMethod.POS) || receipt.getPaymentMethod().equals(PaymentMethod.CREDIT_PAY)) { // 判断支付时间是否超过T+1 createSubaccountByShipping(shipping, receipt.getPaymentMethod()); } } /** * 生成平台服务费分账单 * * @param subaccountCostRatio :分账比例 * @param subaccountAmount :分账金额 * @param order :订单 * @param shipping :发货单 * @param sourceCompany :来源企业 * @return 分账单 * @author huabiao * @create 2022/9/17 16:51 */ private Subaccount generatePlatformSubaccount(BigDecimal subaccountCostRatio, BigDecimal subaccountAmount, Order order, Shipping shipping, Company sourceCompany) { Subaccount subaccount = new Subaccount(); subaccount.setSubaccountNo(sequenceUtil.getNextSequenceNumber("FZ")); subaccount.setSubaccountCostRatio(subaccountCostRatio); subaccount.setSubaccountAmount(subaccountAmount); subaccount.setSubaccountTotalAmount(subaccountAmount); subaccount.setSubaccountType(SubaccountType.SERVICE_FEE); subaccount.setOrders(order); subaccount.setShipping(shipping); subaccount.setSubaccountState(SubaccountState.SEPARATE_NOT); subaccount.setSourceCompany(sourceCompany); return subaccount; } @Override public String createPayment(Order order, PaymentType paymentType, UnionpayAppOrderType unionpayAppOrderType, String unionpaySn, PosPaymentType posType, String hardwareSn) { if (!PaymentStatus.UN_PAID.equals(order.getPaymentStatus())) { throw new YnceErrorException(YnceError.YNCE_204004); } if (paymentType == null) { paymentType = PaymentType.ORDER; } // 校验订单支付单状态 if (!PaymentType.RECHARGE.equals(paymentType)) { paymentService.checkPaymentStatus(order); } // 拼接支付单参数 CreatePaymentDTO createPaymentDTO = new CreatePaymentDTO(); createPaymentDTO.setPaymentMethod(PaymentMethod.valueOf(unionpayAppOrderType.getValue())); createPaymentDTO.setPayerId(order.getBuyerCompany().getId().toString()); createPaymentDTO.setPayerName(order.getBuyerCompany().getName()); createPaymentDTO.setPayeeId(order.getSellerCompany().getId().toString()); createPaymentDTO.setPayeeName(order.getSellerCompany().getName()); createPaymentDTO.setAmount(order.getAmount().subtract(order.getPayAmount())); createPaymentDTO.setPaymentType(paymentType); if (paymentType.equals(PaymentType.RECHARGE)) { createPaymentDTO.setTopUpOrderId(order.getId()); } else { createPaymentDTO.setOrderId(order.getId().toString()); } createPaymentDTO.setErpAccountSet(order.getErpAccountSet()); if (UnionpayAppOrderType.POS.equals(unionpayAppOrderType)) { createPaymentDTO.setPosPaymentType(posType); } createPaymentDTO.setExternalId(unionpaySn); createPaymentDTO.setUnionpaySn(unionpaySn); createPaymentDTO.setHardwareSn(hardwareSn); return createPayment(createPaymentDTO); } /*** * 支付单-创建 * * @param createPaymentDTO:创建支付单DTO * @return 银联订单号/支付单号 * @description * @author huabiao * @create 2022/9/1 16:46 */ @Transactional(rollbackFor = Exception.class) public String createPayment(CreatePaymentDTO createPaymentDTO) { Payment payment = new Payment(); payment.setSn(sequenceUtil.getNextSequenceNumber("ZF")); payment.setPayStatus(PayStatus.READY); BeanUtils.copyProperties(createPaymentDTO, payment); paymentRepository.saveAndFlush(payment); return payment.getSn(); } /** * 处理商品数据 * * @param orderItemList:订单项 * @param sn:订单号 * @param orderAmount:订单金额 * @param amount:分摊金额 * @return 处理完的银联JSON数据 * @author huabiao * @create 2022/12/15 14:08 */ private List<JSONObject> handleProductInfoByOrder(List<OrderItem> orderItemList, String sn, BigDecimal orderAmount, BigDecimal amount) { // 循环订单项 List<JSONObject> productInfos = new ArrayList<>(); BigDecimal allocatedAmount = BigDecimal.ZERO; for (int i = 0; i < orderItemList.size(); i++) { OrderItem orderItem = orderItemList.get(i); JSONObject jsonObject = new JSONObject(); jsonObject.put("orderNo", sn + "-" + orderItem.getId()); // 按比例计算,最后一项直接减完 if (i == (orderItemList.size() - 1)) { jsonObject.put("orderAmount", amount.subtract(allocatedAmount).multiply(new BigDecimal(100)).intValue()); } else { BigDecimal orderItemPlatformServiceFee = amount.multiply(orderItem.getAmount()).divide(orderAmount, 2, BigDecimal.ROUND_DOWN); // 当计算结果不大于0时,赋值0.01 if (orderItemPlatformServiceFee.compareTo(BigDecimal.ZERO) != 1) { orderItemPlatformServiceFee = new BigDecimal("0.01"); } jsonObject.put("orderAmount", orderItemPlatformServiceFee.multiply(new BigDecimal(100)).intValue()); allocatedAmount = allocatedAmount.add(orderItemPlatformServiceFee); } jsonObject.put("productName", orderItem.getGoodsName() + orderItem.getSkuName()); jsonObject.put("productCount", orderItem.getQuantity()); productInfos.add(jsonObject); } return productInfos; } /** * 处理商品数据 * * @param shippingItems:订单项 * @param sn:订单号 * @param shippingAmount:发货金额 * @param amount:分摊金额 * @return 处理完的银联JSON数据 * @author huabiao * @create 2022/12/15 14:08 */ private List<JSONObject> handleProductInfoByShipping(List<ShippingItem> shippingItems, String sn, BigDecimal shippingAmount, BigDecimal amount) { // 循环订单项 List<JSONObject> productInfos = new ArrayList<>(); BigDecimal allocatedAmount = BigDecimal.ZERO; for (int i = 0; i < shippingItems.size(); i++) { ShippingItem shippingItem = shippingItems.get(i); JSONObject jsonObject = new JSONObject(); // 找到对应的订单项 OrderItem orderItem = orderItemRepository.findById(Long.valueOf(shippingItem.getOrderItemId())).orElse(null); jsonObject.put("orderNo", sn + "-" + orderItem.getId()); // 按比例计算,最后一项直接减完 if (i == (shippingItems.size() - 1)) { jsonObject.put("orderAmount", amount.subtract(allocatedAmount).multiply(new BigDecimal(100)).intValue()); } else { BigDecimal orderItemPlatformServiceFee = amount.multiply(shippingItem.getAmount()).divide(shippingAmount, 2, BigDecimal.ROUND_DOWN); jsonObject.put("orderAmount", orderItemPlatformServiceFee.multiply(new BigDecimal(100)).intValue()); allocatedAmount = allocatedAmount.add(orderItemPlatformServiceFee); } jsonObject.put("productName", shippingItem.getGoodsName() + shippingItem.getSkuName()); jsonObject.put("productCount", shippingItem.getShippingQuantity()); productInfos.add(jsonObject); } return productInfos; } /** * 判断是否分账 * * @param subaccountList:分账记录数组 * @param chinaumsPaymentList:银联支付单数组 * @param isNoPlatformSubaccount:是否无平台分账 * @return true:已分账;false:未分账; * @description * @author huabiao * @create 2022/12/16 17:55 */ private Boolean checkIsSubaccount(List<Subaccount> subaccountList, List<ChinaumsPayment> chinaumsPaymentList, Boolean isNoPlatformSubaccount) { // 判断分帐单是否已经生成: // 1.判断是否存在分账记录; // 2.判断分账记录跟银联支付单数量是否一致 // 3.分账记录必须为成功 if (subaccountList.stream().filter(subaccount -> !subaccount.getSubaccountState().equals(SubaccountState.SEPARATE_SUCC)).count() > 0) { return false; } if (CollectionUtils.isNotEmpty(subaccountList) && CollectionUtils.isNotEmpty(chinaumsPaymentList)) { // 非平台分账记录数量 Integer noPlatformSubaccountSize = Math.toIntExact(subaccountList.stream().filter(subaccount -> subaccount.getCompany() != null).count()); // 平台分账记录数量:由于是一张银联支付单分成多张分账记录,所以这里只需要判断是否存在即可 Integer platformSubaccountSize = subaccountList.stream().filter(subaccount -> subaccount.getCompany() == null).findFirst().isPresent() ? 1 : (isNoPlatformSubaccount ? 1 : 0); if ((noPlatformSubaccountSize + platformSubaccountSize) == chinaumsPaymentList.size()) { return true; } } return false; } /** * 校验是否分账 * * @param subaccountList 分账记录 * @return true:已分账;false:未分账; * @description 只需判断已分账的金额之和是否和订单金额是否一致 * @author huabiao * @create 2023/2/11 14:49 */ private Boolean checkIsSubaccountOrder(List<Subaccount> subaccountList) { if (CollectionUtils.isEmpty(subaccountList)) { return false; } Order order = subaccountList.get(0).getOrders(); BigDecimal totalSubaccountAmount = subaccountList.stream().filter(subaccount -> subaccount.getSubaccountState().equals(SubaccountState.SEPARATE_SUCC)) .collect(Collectors.toList()).stream().map(Subaccount::getSubaccountAmount) .reduce(BigDecimal.ZERO, BigDecimal::add); if (totalSubaccountAmount.compareTo(order.getPayAmount().subtract(order.getRefundAmount())) == 0) { return true; } else { return false; } } /** * 校验是否分账 * * @param subaccountList 分账记录 * @return true:已分账;false:未分账; * @description 只需判断已分账的金额之和是否和发货单金额是否一致 * @author huabiao * @create 2023/2/11 14:49 */ private Boolean checkIsSubaccountByShipping(List<Subaccount> subaccountList) { if (CollectionUtils.isEmpty(subaccountList)) { return false; } Shipping shipping = subaccountList.get(0).getShipping(); BigDecimal totalSubaccountAmount = subaccountList.stream().filter(subaccount -> subaccount.getSubaccountState().equals(SubaccountState.SEPARATE_SUCC)) .collect(Collectors.toList()).stream().map(Subaccount::getSubaccountAmount) .reduce(BigDecimal.ZERO, BigDecimal::add); if (totalSubaccountAmount.compareTo(shipping.getPayAmount()) == 0) { return true; } else { return false; } } /** * 处理分账状态 * * @param subaccount 分账记录 * @param isOnlinePayment 是否线上支付(区分不同分账形式) * @author huabiao * @description 线上支付为POS支付和B2C支付,非线上支付为电子账簿支付 * @create 2022/12/21 14:46 */ @Transactional(rollbackFor = Exception.class) public void handleSubaccountStatus(Subaccount subaccount, Boolean isOnlinePayment) { // 分账状态 String subaccountStatus; // 分账时间 String finishedAt; // 当分账成功则返回 if (subaccount.getSubaccountState().equals(SubaccountState.SEPARATE_SUCC)) { return; } if (isOnlinePayment) { try { JSONObject jsonObject = new JSONObject(); jsonObject.put("transferId", subaccount.getExternalId()); ChinaumsGuaranteePayConfirmsVO chinaumsGuaranteePayConfirmsVO = chinaumsUtil.execute(RouteUtil.ROUTE_WALLET_UPAPI_ALLOCATIONS_TRANSFERS_BY_SYS_NO, jsonObject, ChinaumsGuaranteePayConfirmsVO.class); subaccountStatus = chinaumsGuaranteePayConfirmsVO.getStatus(); finishedAt = chinaumsGuaranteePayConfirmsVO.getFinishedAt(); } catch (Exception exception) { return; } } else { JSONObject params = new JSONObject(); params.put("settOrderNo", subaccount.getExternalId()); JSONObject result = byxChinaumsUtil.execute(ByxRouteUtil.ROUTE_WALLET_COMBINED_GUARANTEE_PAYMENTS_CONFIRMS_QUERY, params, JSONObject.class); if (result == null || result.get("settStatus") == null || result.get("settDate") == null) { return; } subaccountStatus = result.get("settStatus").toString(); finishedAt = result.get("settDate").toString(); // subaccountStatus: //00:未处理 //01:处理中 //02:结算成功 //03:部分结算成功 //04:结算失败 switch (subaccountStatus) { case "02": subaccountStatus = "succeeded";break; case "04": subaccountStatus = "failed";break; } } handleSubaccountStatus(subaccount, subaccountStatus, finishedAt); } private void handleSubaccountStatus(Subaccount subaccount, String subaccountStatus, String finishedAt) { if (subaccountStatus.equals("succeeded")) { handleSubaccountStatusSuccess(subaccount, finishedAt); } else if (subaccountStatus.equals("failed")) { subaccount.setSubaccountState(SubaccountState.SEPARATE_FAIL); } subaccountRepository.saveAndFlush(subaccount); } private void handleSubaccountStatusSuccess(Subaccount subaccount, String finishedAt) { // 服务费 if (subaccount.getSubaccountType().equals(SubaccountType.SERVICE_FEE)) { handleSubaccountTypeServiceFee(subaccount); } // 品牌授权费 else if (subaccount.getSubaccountType().equals(SubaccountType.BRAND_AUTH_FEE)) { handleSubaccountTypeBrandAuthFee(subaccount); } // 货款、品牌费、策划费 else { handleSubaccountTypeOtherFee(subaccount, finishedAt); } subaccount.setSubaccountState(SubaccountState.SEPARATE_SUCC); subaccount.setSeparateTime(DateTimeUtils.getLocalDateTimeByRFC3339(finishedAt)); subaccount.setExternalTime(DateTimeUtils.getLocalDateTimeByRFC3339(finishedAt)); // 查找对应的银联支付单 ChinaumsPayment chinaumsPayment = chinaumsPaymentRepository.findFirstByOrdersIdAndSubaccountType(subaccount.getOrders().getId(), subaccount.getSubaccountType()); if (chinaumsPayment != null) { // 处理已确认金额 chinaumsPayment.setConfirmedAmount(chinaumsPayment.getConfirmedAmount().add(subaccount.getSubaccountAmount())); chinaumsPaymentRepository.saveAndFlush(chinaumsPayment); } } private void handleSubaccountTypeOtherFee(Subaccount subaccount, String finishedAt) { List<Statement> statementList; if (subaccount.getShipping() != null) { statementList = statementRepository.findAllByShippingIdAndSubaccountType(subaccount.getShipping().getId(), subaccount.getSubaccountType()); } else { statementList = statementRepository.findAllByOrdersIdAndSubaccountType(subaccount.getOrders().getId(), subaccount.getSubaccountType()); } // 处理预存款账户 AccountChangeCreateDTO accountChangeCreateDTO = AccountChangeCreateDTO .builder() .company(statementList.get(0).getCompany()) .direction(ChangeDirection.ADD) .type(AccountChangeType.valueOf(statementList.get(0).getSubaccountType().getValue())) .amount(subaccount.getSubaccountAmount()) .sourceNo(subaccount.getSubaccountNo()) .sourceCompanyId(subaccount.getSourceCompany().getId()) .build(); accountService.intoAccount(accountChangeCreateDTO); for (Statement statement : statementList) { // 处理对应结算单 statement.setStatementState(StatementState.RECORDED); statement.setSubaccountTime(DateTimeUtils.getLocalDateTimeByRFC3339(finishedAt)); statementRepository.saveAndFlush(statement); } } private void handleSubaccountTypeBrandAuthFee(Subaccount subaccount) { // 处理预存款账户 AccountChangeCreateDTO accountChangeCreateDTO = AccountChangeCreateDTO .builder() .company(subaccount.getCompany()) .direction(ChangeDirection.ADD) .type(AccountChangeType.valueOf(SubaccountType.BRAND_AUTH_FEE.getValue())) .amount(subaccount.getSubaccountAmount()) .sourceNo(subaccount.getSubaccountNo()) .sourceCompanyId(subaccount.getSourceCompany().getId()) .build(); accountService.intoAccount(accountChangeCreateDTO); } private void handleSubaccountTypeServiceFee(Subaccount subaccount) { // 通过平台的电子账簿获取企业 Company company = companyRepository.findByWalletId(chinaumsUtil.getFeeBalanceAcctId()); if (company != null) { AccountChangeCreateDTO accountChangeCreateDTO = AccountChangeCreateDTO .builder() .company(company) .direction(ChangeDirection.ADD) .type(AccountChangeType.valueOf(SubaccountType.SERVICE_FEE.getValue())) .amount(subaccount.getSubaccountAmount()) .sourceNo(subaccount.getSubaccountNo()) .sourceCompanyId(subaccount.getSourceCompany().getId()) .build(); accountService.intoAccount(accountChangeCreateDTO); } } /** * 计算平台分账记录 * * @param statement 结算单 * @param orderFeeRatio 订单费用比例 * @param refundAmount 退款金额 * @return 平台分账记录 * @author huabiao * @create 2022/12/21 15:53 */ private Subaccount calculationPlatformServiceFee(Statement statement, OrderFeeRatio orderFeeRatio, BigDecimal refundAmount) { // 计算平台服务费 BigDecimal platformServiceFee; // 根据分账类型从订单费用比例中获取 BigDecimal platformServiceFeeRatio = BigDecimal.ZERO; if (statement.getSubaccountType().equals(SubaccountType.GOODS_COST)) { platformServiceFeeRatio = orderFeeRatio.getSellerServiceCostRatio(); } else if (statement.getSubaccountType().equals(SubaccountType.BRAND_FEE)) { platformServiceFeeRatio = orderFeeRatio.getBrandServiceCostRatio(); } else if (statement.getSubaccountType().equals(SubaccountType.DEVISE_FEE)) { platformServiceFeeRatio = orderFeeRatio.getDeviseServiceCostRatio(); } if (platformServiceFeeRatio.compareTo(BigDecimal.ZERO) == 1) { // statementamount platformServiceFee = statement.getStatementAmount().add(refundAmount).multiply(platformServiceFeeRatio).setScale(2, BigDecimal.ROUND_UP); if (platformServiceFee.compareTo(BigDecimal.ZERO) == 1) { // 生成平台服务费分账单 return generatePlatformSubaccount(platformServiceFeeRatio, platformServiceFee, statement.getOrders(), statement.getShipping(), statement.getCompany()); } } return null; } private BigDecimal getCostRatio(Statement statement, OrderFeeRatio orderFeeRatio) { BigDecimal costRatio = BigDecimal.ZERO; if (statement.getSubaccountType().equals(SubaccountType.GOODS_COST)) { costRatio = BigDecimal.ONE.subtract(orderFeeRatio.getBrandCostRatio()).subtract(orderFeeRatio.getDeviseCostRatio()); } else if (statement.getSubaccountType().equals(SubaccountType.BRAND_FEE)) { costRatio = orderFeeRatio.getBrandCostRatio(); } else if (statement.getSubaccountType().equals(SubaccountType.DEVISE_FEE)) { costRatio = orderFeeRatio.getDeviseCostRatio(); } return costRatio; } /** * 是否最后分账 * * @param shipping 发货单 * @return TRUE:是;FALSE:否 * @author huabiao * @create 2023/1/5 10:55 */ private Boolean isFinallySubaccount(Shipping shipping) { Boolean isFinallySubaccount = true; Order orders = shipping.getOrders(); for (Shipping ordersShipping : orders.getShippings()) { if (ordersShipping != shipping && BooleanUtils.isFalse(ordersShipping.getIsSeparateAccounts())) { isFinallySubaccount = false; } } return isFinallySubaccount; } /** * 根据发货单更新分账状态 * * @param shipping 发货单 * @description * @author huabiao * @create 2023/1/5 15:31 */ private void updateIsSeparateAccountsByShipping(Shipping shipping) { Order order = shipping.getOrders(); // 更新发货单已分账 shippingRepository.updateIsSeparateAccountsById(shipping.getId()); // 判断该订单是否已分账结束 long unSubaccountShipping = order.getShippings().stream().filter(filterShipping -> !filterShipping.getId().equals(shipping.getId()) && BooleanUtils.isFalse(filterShipping.getIsSeparateAccounts())).count(); if ((!order.getShippingStatus().equals(ShippingStatus.UN_SHIPPED) || !order.getShippingStatus().equals(ShippingStatus.PARTIAL_SHIPPED)) && unSubaccountShipping == 0) { orderRepository.updateIsSeparateAccountsById(order.getId()); } } /** * 创建分账 * * @param order 订单 * @param paymentMethod 支付方式 * @description 调用银联创建分账接口分账 * @author huabiao * @create 2023/2/6 17:16 */ @Transactional(rollbackFor = YnceErrorException.class) public void createSubaccountByOrder(Order order, PaymentMethod paymentMethod) { // 获取分账记录 List<Subaccount> subaccountList = subaccountRepository.findAllByOrdersId(order.getId()); if (CollectionUtils.isNotEmpty(subaccountList)) { // 清除失败的分账记录 subaccountList.removeIf(subaccount -> subaccount.getSubaccountState().equals(SubaccountState.SEPARATE_FAIL)); } // 判断是否已分账 if (checkIsSubaccountOrder(subaccountList)) { // 更新订单已分账 finishOrderSubaccount(order); writeSeparateLog(String.format("[分账][生成][普通订单][%s],分账单已存在,更新订单为已分账", order.getSn())); return; } OrderFeeRatio orderFeeRatio = orderFeeRatioRepository.findByOrdersId(order.getId()); // 获取所有结算单(包含正常订单和退货退款) List<Statement> allStatementList = getStatementList(order); if (allStatementList == null) return; List<ChinaumsTransferParamsDTO> chinaumsTransferParamsDTOList = new ArrayList<>(); // 正常订单结算单 List<Statement> statementList = allStatementList.stream().filter(statement -> statement.getStatementType().equals(StatementType.NORMALORDER)).collect(Collectors.toList()); // 退货退款结算单 List<Statement> allAfterSaleStatementList = allStatementList.stream().filter(statement -> statement.getStatementType().equals(StatementType.AFTERSALES)).collect(Collectors.toList()); // 平台服务费分账记录 List<Subaccount> platformSubaccountList = new ArrayList<>(); // 品牌授权费记录 List<BrandAuthFeeDTO> brandAuthFeeDTOList = new ArrayList<>(); // 新创建分账记录 List<Subaccount> newSubaccountList = new ArrayList<>(); for (Statement statement : statementList) { // 退款金额 BigDecimal refundAmount = BigDecimal.ZERO; // 退款品牌授权费 BigDecimal refundBrandAuthFee = BigDecimal.ZERO; // 该结算单对应的退款结算单 List<Statement> afterSaleStatementList = allAfterSaleStatementList.stream().filter(filterStatement -> filterStatement.getSubaccountType().equals(statement.getSubaccountType())).collect(Collectors.toList()); // 查询所有已完成售后单 List<AfterSale> afterSaleList = afterSaleRepository.findAllByOrdersIdAndAfterSaleStatus(order.getId(), AfterSaleStatus.COMPLETED); if (CollectionUtils.isNotEmpty(afterSaleList)) { if (CollectionUtils.isNotEmpty(afterSaleStatementList)) { // 若存在退款结算单,需判断单据数量是否一致(注意:可能存在非售后途径退款) if (afterSaleList.size() != afterSaleStatementList.stream().filter(filterStatement -> filterStatement.getAfterSale() != null).count()) { writeSeparateLog(String.format("[分账][生成][普通订单][%s][结算单][%s],该分账单存在退款结算单未生成", order.getSn(), statement.getStatementNo())); return; } for (Statement afterSaleStatement : afterSaleStatementList) { refundAmount = refundAmount.add(afterSaleStatement.getStatementAmount()); refundBrandAuthFee = refundBrandAuthFee.add(afterSaleStatement.getStatementLine().stream().map(StatementLine::getBrandAuthFee).reduce(BigDecimal.ZERO, BigDecimal::add)); } } else { writeSeparateLog(String.format("[分账][生成][普通订单][%s][结算单][%s],该分账单存在退款结算单未生成", order.getSn(), statement.getStatementNo())); return; } } else { refundAmount = afterSaleStatementList.stream().map(Statement::getStatementAmount).reduce(BigDecimal.ZERO, BigDecimal::add); } // 平台服务费 BigDecimal platformServiceFee = BigDecimal.ZERO; // 拼接平台服务费分账 Subaccount platformSubaccount = calculationPlatformServiceFee(statement, orderFeeRatio, refundAmount.add(refundBrandAuthFee)); if (platformSubaccount != null) { platformSubaccountList.add(platformSubaccount); platformServiceFee = platformSubaccount.getSubaccountAmount(); } // 判断是否存在分账记录(根据分账企业和分账类型) Subaccount subaccount = subaccountList.stream().filter(filterSubaccount -> filterSubaccount.getSubaccountType().equals(statement.getSubaccountType()) && filterSubaccount.getCompany() != null && filterSubaccount.getCompany().equals(statement.getCompany())).findFirst().orElse(null); if (subaccount != null) { // 若是未分账则调用银联接口 if (subaccount.getSubaccountState().equals(SubaccountState.SEPARATE_NOT)) { handleSubaccountStatus(subaccount, true); } continue; } // 拼接分账记录数据 subaccount = new Subaccount(); subaccount.setSubaccountNo(sequenceUtil.getNextSequenceNumber("FZ")); subaccount.setCompany(companyRepository.findById(statement.getCompany().getId()).orElse(null)); // 货款分账金额 = 结算金额 + 退款金额 - 平台服务费 - 品牌授权费 + 退款品牌授权费 if (statement.getSubaccountType().equals(SubaccountType.GOODS_COST)) { // 品牌授权费 BigDecimal brandAuthFee = statement.getStatementLine().stream().map(statementLine -> statementLine.getBrandAuthFee()).reduce(BigDecimal.ZERO, BigDecimal::add); subaccount.setSubaccountAmount(statement.getStatementAmount().add(refundAmount).subtract(platformServiceFee).subtract(brandAuthFee).add(refundBrandAuthFee)); if (CollectionUtils.isNotEmpty(orderFeeRatio.getOrderItemFeeRatio())) { subaccount.setBrandAuthCostRatio(orderFeeRatio.getOrderItemFeeRatio().get(0).getBrandAuthCostRatio()); } subaccount.setBrandAuthFee(brandAuthFee.add(refundBrandAuthFee)); // 拼接品牌授权费 for (StatementLine statementLine : statement.getStatementLine()) { BigDecimal lineBrandAuthFee = statementLine.getBrandAuthFee(); // 获取对应的退款结算单项 for (Statement typeAfterSaleStatement : afterSaleStatementList) { StatementLine typeAfterSaleStatementLine = typeAfterSaleStatement.getStatementLine().stream().filter(filterStatementLine -> filterStatementLine.getOrderItem().getId().equals(statementLine.getOrderItem().getId())).findFirst().orElse(null); if (typeAfterSaleStatementLine != null) { lineBrandAuthFee = lineBrandAuthFee.add(typeAfterSaleStatementLine.getBrandAuthFee()); } } BrandAuthFeeDTO brandAuthFeeDTO = brandAuthFeeDTOList.stream().filter(filterBrandAuthFeeDTO -> filterBrandAuthFeeDTO.getBrandId().equals(statementLine.getOrderItem().getBrandId())).findFirst().orElse(null); if (brandAuthFeeDTO != null) { brandAuthFeeDTO.setAmount(brandAuthFeeDTO.getAmount().add(lineBrandAuthFee)); } else { brandAuthFeeDTO = new BrandAuthFeeDTO(); brandAuthFeeDTO.setBrandId(statementLine.getOrderItem().getBrandId()); brandAuthFeeDTO.setAmount(lineBrandAuthFee); brandAuthFeeDTOList.add(brandAuthFeeDTO); } } } // 其他分账金额 = 结算金额 - 退款金额 - 平台服务费 else { subaccount.setSubaccountAmount(statement.getStatementAmount().add(refundAmount).subtract(platformServiceFee)); } // 当分账金额小于等于0时跳过 if (subaccount.getSubaccountAmount().compareTo(BigDecimal.ZERO) != 1) { continue; } subaccount.setSubaccountCostRatio(getCostRatio(statement, orderFeeRatio)); subaccount.setSubaccountType(statement.getSubaccountType()); subaccount.setOrders(statement.getOrders()); subaccount.setSubaccountState(SubaccountState.SEPARATE_NOT); subaccount.setSourceCompany(order.getBuyerCompany()); subaccount.setSubaccountTotalAmount(statement.getStatementAmount().add(refundAmount)); if (platformSubaccount != null) { subaccount.setPlatformServiceCostRatio(platformSubaccount.getSubaccountCostRatio()); subaccount.setPlatformServiceFee(platformSubaccount.getSubaccountAmount()); } newSubaccountList.add(subaccount); } // 品牌授权费 if (CollectionUtils.isNotEmpty(orderFeeRatio.getOrderItemFeeRatio())) { for (BrandAuthFeeDTO brandAuthFeeDTO : brandAuthFeeDTOList) { // 判断该品牌授权费是否存在分账记录(根据品牌ID+分账类型) Subaccount subaccount = subaccountList.stream().filter(filterSubaccount -> filterSubaccount.getBrandId() != null && filterSubaccount.getBrandId().equals(brandAuthFeeDTO.getBrandId()) && filterSubaccount.getSubaccountType().equals(SubaccountType.BRAND_AUTH_FEE)).findFirst().orElse(null); if (subaccount != null) { // 若是未分账则调用银联接口 if (subaccount.getSubaccountState().equals(SubaccountState.SEPARATE_NOT)) { handleSubaccountStatus(subaccount, true); } continue; } // 获取品牌 Brand brand = brandRepository.findById(brandAuthFeeDTO.getBrandId()).orElse(null); // 平台服务费 BigDecimal platformServiceFee = BigDecimal.ZERO; // 品牌授权费的平台服务费分账记录 Subaccount platformSubaccount = null; // 获取订单项费用比例 OrderItemFeeRatio orderItemFeeRatio = orderFeeRatio.getOrderItemFeeRatio().stream().filter(filterOrderItemFeeRatio -> filterOrderItemFeeRatio.getOrderItem().getBrandId().equals(brandAuthFeeDTO.getBrandId())).findFirst().orElse(null); if (orderItemFeeRatio != null && orderItemFeeRatio.getBrandAuthCostServiceCostRatio().compareTo(BigDecimal.ZERO) == 1) { // 计算平台服务费 platformServiceFee = brandAuthFeeDTO.getAmount().multiply(orderItemFeeRatio.getBrandAuthCostServiceCostRatio()).setScale(2, BigDecimal.ROUND_UP); // 拼接平台服务费分账 if (platformServiceFee.compareTo(BigDecimal.ZERO) == 1) { platformSubaccount = generatePlatformSubaccount(orderItemFeeRatio.getBrandAuthCostServiceCostRatio(), platformServiceFee, order, null, brand.getCompany()); if (platformSubaccount != null) { platformSubaccountList.add(platformSubaccount); platformServiceFee = platformSubaccount.getSubaccountAmount(); } } } BigDecimal subaccountAmount = brandAuthFeeDTO.getAmount().subtract(platformServiceFee); if (subaccountAmount.compareTo(BigDecimal.ZERO) == 1) { // 拼接分账记录 subaccount = new Subaccount(); subaccount.setSubaccountNo(sequenceUtil.getNextSequenceNumber("FZ")); subaccount.setCompany(brand.getCompany()); subaccount.setSubaccountAmount(subaccountAmount); subaccount.setSubaccountTotalAmount(brandAuthFeeDTO.getAmount()); subaccount.setSubaccountType(SubaccountType.BRAND_AUTH_FEE); subaccount.setOrders(order); subaccount.setSubaccountState(SubaccountState.SEPARATE_NOT); subaccount.setSourceCompany(order.getBuyerCompany()); subaccount.setBrandId(brandAuthFeeDTO.getBrandId()); if (platformSubaccount != null) { subaccount.setPlatformServiceCostRatio(platformSubaccount.getSubaccountCostRatio()); subaccount.setPlatformServiceFee(platformSubaccount.getSubaccountAmount()); } newSubaccountList.add(subaccount); } } } // 获取已生成的平台服务费分账记录 List<Subaccount> platformSubaccounts = subaccountList.stream().filter(subaccount -> subaccount.getCompany() == null).collect(Collectors.toList()); if (CollectionUtils.isNotEmpty(platformSubaccounts)) { for (Subaccount platformSubaccount : platformSubaccounts) { handleSubaccountStatus(platformSubaccount, true); } } else if (CollectionUtils.isNotEmpty(platformSubaccountList)) { newSubaccountList.addAll(platformSubaccountList); } // 对所有的分账单进行统计处理,同一企业的合并进行分账创建 if (CollectionUtils.isNotEmpty(newSubaccountList)) { // 获取平台分账记录 List<Subaccount> noCompanySubaccountList = newSubaccountList.stream().filter(subaccount -> subaccount.getCompany() == null).collect(Collectors.toList()); if (CollectionUtils.isNotEmpty(noCompanySubaccountList)) { BigDecimal noCompanySubaccountAmount = noCompanySubaccountList.stream().map(Subaccount::getSubaccountAmount).reduce(BigDecimal.ZERO, BigDecimal::add); // 商品扩展字段 ChinaumsGuaranteePayExtraDTO chinaumsGuaranteePayExtraDTO = new ChinaumsGuaranteePayExtraDTO(); chinaumsGuaranteePayExtraDTO.setProductInfos(this.handleProductInfoByOrder(order.getOrderItems(), order.getSn(), order.getAmount(), noCompanySubaccountAmount)); // 自定义参数 JSONObject metadata = new JSONObject(); metadata.put("companyId", null); metadata.put("subaccountNo", StringUtils.join(noCompanySubaccountList.stream().map(Subaccount::getSubaccountNo).collect(Collectors.toList()), ",")); // 拼接分账参数 ChinaumsTransferParamsDTO chinaumsTransferParamsDTO = ChinaumsTransferParamsDTO .builder() .recvBalanceAcctId(chinaumsUtil.getFeeBalanceAcctId()) .amount(noCompanySubaccountAmount.multiply(new BigDecimal(100)).intValue()) .remark(null) .extra(chinaumsGuaranteePayExtraDTO) .metadata(metadata) .build(); chinaumsTransferParamsDTOList.add(chinaumsTransferParamsDTO); } // 获取非平台分账记录 List<Subaccount> allCompanySubaccountList = newSubaccountList.stream().filter(subaccount -> subaccount.getCompany() != null).collect(Collectors.toList()); Map<Company, List<Subaccount>> companySubaccountListMap = allCompanySubaccountList.stream().collect(Collectors.groupingBy(Subaccount::getCompany)); for (Map.Entry<Company, List<Subaccount>> companyListEntry : companySubaccountListMap.entrySet()) { Company company = companyListEntry.getKey(); List<Subaccount> companySubaccountList = companyListEntry.getValue(); // 计算该企业总分账金额 BigDecimal companySubaccountAmount = companySubaccountList.stream().map(Subaccount::getSubaccountAmount).reduce(BigDecimal.ZERO, BigDecimal::add); // 商品扩展字段 ChinaumsGuaranteePayExtraDTO chinaumsGuaranteePayExtraDTO = new ChinaumsGuaranteePayExtraDTO(); chinaumsGuaranteePayExtraDTO.setProductInfos(this.handleProductInfoByOrder(order.getOrderItems(), order.getSn(), order.getAmount(), companySubaccountAmount)); // 自定义参数 JSONObject metadata = new JSONObject(); metadata.put("companyId", company.getId()); metadata.put("subaccountNo", StringUtils.join(companySubaccountList.stream().map(Subaccount::getSubaccountNo).collect(Collectors.toList()), ",")); // 判断该企业是否已认证 if (StringUtils.isBlank(company.getWalletId())) { writeSeparateLog(String.format("[分账][生成][普通订单][%s],[%s]暂未认证银联", order.getSn(), company.getName())); return; } // 拼接分账参数 ChinaumsTransferParamsDTO chinaumsTransferParamsDTO = ChinaumsTransferParamsDTO .builder() .recvBalanceAcctId(company.getWalletId()) .amount(companySubaccountAmount.multiply(new BigDecimal(100)).intValue()) .remark(null) .extra(chinaumsGuaranteePayExtraDTO) .metadata(metadata) .build(); chinaumsTransferParamsDTOList.add(chinaumsTransferParamsDTO); } } if (CollectionUtils.isNotEmpty(chinaumsTransferParamsDTOList)) { // 已分账金额 BigDecimal allocatedAmount = subaccountList.stream().map(Subaccount::getSubaccountAmount).reduce(BigDecimal.ZERO, BigDecimal::add); // 待分账金额 BigDecimal totalSubaccountAmount = newSubaccountList.stream().map(Subaccount::getSubaccountAmount).reduce(BigDecimal.ZERO, BigDecimal::add); // 获取所有的退款金额 List<Refund> refundList = refundRepository.findAllByOrdersId(order.getId()); BigDecimal refundAmount = CollectionUtils.isNotEmpty(refundList) ? refundList.stream().map(Refund::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add) : BigDecimal.ZERO; // 判断分账总金额是否正确 if ((allocatedAmount.add(totalSubaccountAmount)).compareTo((order.getPayAmount().subtract(refundAmount))) != 0) { writeSeparateLog(String.format("[分账][生成][普通订单][%s],分账总金额与订单支付金额不一致", order.getSn())); return; } // 银联所属企业 Company chinaumsCompany = order.getConsignmentCompany() != null ? companyRepository.getOne(order.getConsignmentCompany().getId()) : companyRepository.getOne(order.getSellerCompany().getId()); // 根据支付方式获取对应分账电子账簿ID String chinaumsBalanceAcctId; if (paymentMethod.equals(PaymentMethod.CREDIT_PAY)) { chinaumsBalanceAcctId = chinaumsUtil.getChinaumsCreditBalanceAcctId(chinaumsCompany.getId()); } else { chinaumsBalanceAcctId = chinaumsUtil.getBalanceAcctId(chinaumsCompany.getId()); } if (StringUtils.isBlank(chinaumsBalanceAcctId)) { writeSeparateLog(String.format("[分账][生成][普通订单][%s],[%s]分账电子账簿ID为空", order.getSn(), chinaumsCompany.getName())); return; } // 查询平台分账银联电子账簿是否金额充足 BigDecimal balance; try { BalanceAcctsVO balanceAcctsVO = walletService.balanceAcctsQryByAcctId(chinaumsBalanceAcctId); balance = new BigDecimal(balanceAcctsVO.getSettledAmount()).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP); } catch (Exception exception) { writeSeparateLog(String.format("[分账][生成][普通订单][%s],[%s]分账电子账簿金额查询报错", order.getSn(), chinaumsCompany.getName())); return; } // 判断余额是否充足 if (balance.compareTo(BigDecimal.ZERO) < 1 || balance.compareTo(totalSubaccountAmount) == -1) { writeSeparateLog(String.format("[分账][生成][普通订单][%s],[%s]分账电子账簿金额不足", order.getSn(), chinaumsCompany.getName())); return; } // 分账创建 ChinaumsAllocationsDTO chinaumsAllocationsDTO = ChinaumsAllocationsDTO .builder() .outOrderNo(sequenceUtil.getNextSequenceNumber("FZ")) .sentAt(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX").format(new Date())) .payBalanceAcctId(chinaumsBalanceAcctId) .transferParams(chinaumsTransferParamsDTOList) .remark(null) .build(); ChinaumsAllocationsVO chinaumsAllocationsVO; try { chinaumsAllocationsVO = walletService.createSubaccount(chinaumsAllocationsDTO); } catch (Exception exception) { // TODO 这里需要调用平台订单号查询是否调用成功 log.error("订单创建分账异常,订单号" + order.getSn() + ",分账单号" + chinaumsAllocationsDTO.getOutOrderNo()); return; } // 循环查询子订单分账是否成功 for (ChinaumsTransferResultsVO chinaumsTransferResultsVO : chinaumsAllocationsVO.getTransferResults()) { // 先判断是否为平台电子账簿 if (chinaumsTransferResultsVO.getRecvBalanceAcctId().equals(chinaumsUtil.getFeeBalanceAcctId())) { // 企业为空时获取平台分账记录 List<Subaccount> platformFeeSubaccountList = newSubaccountList.stream().filter(filterSubaccount -> filterSubaccount.getCompany() == null).collect(Collectors.toList()); for (Subaccount subaccount : platformFeeSubaccountList) { subaccount.setExternalId(chinaumsTransferResultsVO.getTransferId()); subaccountRepository.saveAndFlush(subaccount); handleSubaccountStatus(subaccount, true); } } else { // 根据收款电子账簿ID查询 Company company = companyRepository.findByWalletId(chinaumsTransferResultsVO.getRecvBalanceAcctId()); if (company == null) { continue; } // 获取对应的企业分账记录 List<Subaccount> companySubaccountList = newSubaccountList.stream().filter(filterSubaccount -> filterSubaccount.getCompany() != null && filterSubaccount.getCompany().equals(company)).collect(Collectors.toList()); for (Subaccount subaccount : companySubaccountList) { subaccount.setExternalId(chinaumsTransferResultsVO.getTransferId()); subaccountRepository.saveAndFlush(subaccount); handleSubaccountStatus(subaccount, true); } } writeSeparateLog(String.format("[分账][生成][普通订单][%s],生成分账单成功,银联结算单号[%s]。", order.getSn(), chinaumsTransferResultsVO.getTransferId())); } subaccountList.addAll(newSubaccountList); } // 判断是否已分账 if (checkIsSubaccountOrder(subaccountList)) { // 更新订单已分账 finishOrderSubaccount(order); writeSeparateLog(String.format("[分账][生成][普通订单][%s],分账单已存在,更新订单为已分账", order.getSn())); return; } } /** * 创建分账 * * @return * @description 相同收款方必须合并处理 * @author huabiao * @create 2023/2/6 17:16 */ public void createSubaccountByShipping(Shipping shipping, PaymentMethod paymentMethod) { // 自定义参数 JSONObject metadata = new JSONObject(); metadata.put("shippingSn", shipping.getShippingSn()); Order order = shipping.getOrders(); // 获取订单费用比例 OrderFeeRatio orderFeeRatio = orderFeeRatioRepository.findByOrdersId(order.getId()); // 获取分账记录 List<Subaccount> subaccountList = subaccountRepository.findAllByShippingId(shipping.getId()); if (CollectionUtils.isNotEmpty(subaccountList)) { // 清除失败的分账记录 subaccountList.removeIf(subaccount -> subaccount.getSubaccountState().equals(SubaccountState.SEPARATE_FAIL)); } // 判断发货单是否已分账 if (checkIsSubaccountByShipping(subaccountList)) { // 更新发货单已分账 updateIsSeparateAccountsByShipping(shipping); writeSeparateLog(String.format("[分账][生成][普通订单][%s][发货单][%s],分账单已存在,更新发货单为已分账", order.getSn(), shipping.getShippingSn())); // 判断订单是否已分账 if (checkIsSubaccountOrder(subaccountRepository.findAllByOrdersId(order.getId()))) { orderRepository.updateIsSeparateAccountsById(order.getId()); } return; } List<ChinaumsTransferParamsDTO> chinaumsTransferParamsDTOList = new ArrayList<>(); // 获取结算单 List<Statement> statementList = statementRepository.findAllByShippingIdAndStatementType(shipping.getId(), StatementType.NORMALORDER); // 获取退款结算单 List<Statement> allAfterSaleStatementList = statementRepository.findAllByShippingIdAndStatementType(shipping.getId(), StatementType.AFTERSALES); // 平台服务费分账记录 List<Subaccount> platformSubaccountList = new ArrayList<>(); // 品牌授权费记录 List<BrandAuthFeeDTO> brandAuthFeeDTOList = new ArrayList<>(); // 新创建分账记录 List<Subaccount> newSubaccountList = new ArrayList<>(); for (Statement statement : statementList) { // 获取结算单对应的退款结算单 List<Statement> afterSaleStatementList = allAfterSaleStatementList.stream().filter(filterStatement -> filterStatement.getSubaccountType().equals(statement.getSubaccountType())).collect(Collectors.toList()); // 退款金额 BigDecimal refundAmount = BigDecimal.ZERO; // 退款品牌授权费 BigDecimal refundBrandAuthFee = BigDecimal.ZERO; // 获取售后单 List<AfterSale> afterSaleList = afterSaleRepository.findAllByShippingIdAndAfterSaleStatus(shipping.getId(), AfterSaleStatus.COMPLETED); if (CollectionUtils.isNotEmpty(afterSaleStatementList)) { if (afterSaleList.size() != afterSaleStatementList.size()) { writeSeparateLog(String.format("[分账][生成][普通订单][%s][发货单][%s][结算单][%s],该分账单存在退款结算单未生成", order.getSn(), shipping.getShippingSn(), statement.getStatementNo())); return; } for (Statement afterSaleStatement : afterSaleStatementList) { refundAmount = refundAmount.add(afterSaleStatement.getStatementAmount()); refundBrandAuthFee = refundBrandAuthFee.add(afterSaleStatement.getStatementLine().stream().map(StatementLine::getBrandAuthFee).reduce(BigDecimal.ZERO, BigDecimal::add)); } } else { // 当不存在退款结算单时,需判断是否还未生成 if (CollectionUtils.isNotEmpty(afterSaleList)) { writeSeparateLog(String.format("[分账][生成][普通订单][%s][发货单][%s][结算单][%s],该分账单存在退款结算单未生成", order.getSn(), shipping.getShippingSn(), statement.getStatementNo())); return; } } // 平台服务费 BigDecimal platformServiceFee = BigDecimal.ZERO; // 拼接平台服务费分账 Subaccount platformSubaccount = calculationPlatformServiceFee(statement, orderFeeRatio, refundAmount.add(refundBrandAuthFee)); if (platformSubaccount != null) { platformSubaccountList.add(platformSubaccount); platformServiceFee = platformSubaccount.getSubaccountAmount(); } // 判断是否存在分账记录(根据分账企业和分账类型) Subaccount subaccount = subaccountList.stream().filter(filterSubaccount -> filterSubaccount.getSubaccountType().equals(statement.getSubaccountType()) && filterSubaccount.getCompany() != null && filterSubaccount.getCompany().equals(statement.getCompany())).findFirst().orElse(null); if (subaccount != null) { // 若是未分账则调用银联接口 if (subaccount.getSubaccountState().equals(SubaccountState.SEPARATE_NOT)) { handleSubaccountStatus(subaccount, false); } continue; } subaccount = new Subaccount(); subaccount.setSubaccountNo(sequenceUtil.getNextSequenceNumber("FZ")); subaccount.setCompany(statement.getCompany()); subaccount.setSubaccountCostRatio(getCostRatio(statement, orderFeeRatio)); // 保存品牌授权费 BigDecimal brandAuthFee = BigDecimal.ZERO; if (statement.getSubaccountType().equals(SubaccountType.GOODS_COST) && CollectionUtils.isNotEmpty(orderFeeRatio.getOrderItemFeeRatio())) { brandAuthFee = statement.getStatementLine().stream().map(StatementLine::getBrandAuthFee).reduce(BigDecimal.ZERO, BigDecimal::add); subaccount.setBrandAuthCostRatio(orderFeeRatio.getOrderItemFeeRatio().get(0).getBrandAuthCostRatio()); subaccount.setBrandAuthFee(brandAuthFee.add(refundBrandAuthFee)); } if (statement.getSubaccountType().equals(SubaccountType.GOODS_COST)) { // 货款分账金额 = 结算金额 + 退款金额 - 平台服务费 - 品牌授权费 + 退款品牌授权费 subaccount.setSubaccountAmount(statement.getStatementAmount().add(refundAmount).subtract(platformServiceFee).subtract(brandAuthFee).add(refundBrandAuthFee)); // 拼接品牌授权费 for (StatementLine statementLine : statement.getStatementLine()) { BigDecimal lineBrandAuthFee = statementLine.getBrandAuthFee(); // 获取对应的退款结算单项 for (Statement typeAfterSaleStatement : afterSaleStatementList) { StatementLine typeAfterSaleStatementLine = typeAfterSaleStatement.getStatementLine().stream().filter(filterStatementLine -> filterStatementLine.getOrderItem().getId().equals(statementLine.getOrderItem().getId())).findFirst().orElse(null); if (typeAfterSaleStatementLine != null) { lineBrandAuthFee = lineBrandAuthFee.add(typeAfterSaleStatementLine.getBrandAuthFee()); } } BrandAuthFeeDTO brandAuthFeeDTO = brandAuthFeeDTOList.stream().filter(filterBrandAuthFeeDTO -> filterBrandAuthFeeDTO.getBrandId().equals(statementLine.getOrderItem().getBrandId())).findFirst().orElse(null); if (brandAuthFeeDTO != null) { brandAuthFeeDTO.setAmount(brandAuthFeeDTO.getAmount().add(lineBrandAuthFee)); } else { brandAuthFeeDTO = new BrandAuthFeeDTO(); brandAuthFeeDTO.setBrandId(statementLine.getOrderItem().getBrandId()); brandAuthFeeDTO.setAmount(lineBrandAuthFee); brandAuthFeeDTOList.add(brandAuthFeeDTO); } } } else { // 其他分账金额 = 结算金额 - 退款金额 - 平台服务费 subaccount.setSubaccountAmount(statement.getStatementAmount().add(refundAmount).subtract(platformServiceFee)); } // 当分账金额小于等于0时跳过 if (subaccount.getSubaccountAmount().compareTo(BigDecimal.ZERO) != 1) { continue; } subaccount.setSubaccountTotalAmount(statement.getStatementAmount().add(refundAmount)); if (platformSubaccount != null) { subaccount.setPlatformServiceCostRatio(platformSubaccount.getSubaccountCostRatio()); subaccount.setPlatformServiceFee(platformSubaccount.getSubaccountAmount()); } subaccount.setSubaccountType(statement.getSubaccountType()); subaccount.setOrders(statement.getOrders()); subaccount.setShipping(statement.getShipping()); subaccount.setSubaccountState(SubaccountState.SEPARATE_NOT); subaccount.setSourceCompany(order.getBuyerCompany()); newSubaccountList.add(subaccount); } // 品牌授权费 if (CollectionUtils.isNotEmpty(orderFeeRatio.getOrderItemFeeRatio())) { for (BrandAuthFeeDTO brandAuthFeeDTO : brandAuthFeeDTOList) { // 判断该品牌授权费是否存在分账记录(根据品牌ID和分账类型) Subaccount subaccount = subaccountList.stream().filter(filterSubaccount -> filterSubaccount.getBrandId() != null && filterSubaccount.getBrandId().equals(brandAuthFeeDTO.getBrandId()) && filterSubaccount.getSubaccountType().equals(SubaccountType.BRAND_AUTH_FEE)).findFirst().orElse(null); if (subaccount != null) { // 若是未分账则调用银联接口 if (subaccount.getSubaccountState().equals(SubaccountState.SEPARATE_NOT)) { handleSubaccountStatus(subaccount, true); } continue; } // 获取品牌 Brand brand = brandRepository.findById(brandAuthFeeDTO.getBrandId()).orElse(null); // 平台服务费 BigDecimal platformServiceFee = BigDecimal.ZERO; // 平台服务费比例 BigDecimal platformServiceCostRatio = BigDecimal.ZERO; // 获取订单项费用比例 OrderItemFeeRatio orderItemFeeRatio = orderFeeRatio.getOrderItemFeeRatio().stream().filter(filterOrderItemFeeRatio -> filterOrderItemFeeRatio.getOrderItem().getBrandId().equals(brandAuthFeeDTO.getBrandId())).findFirst().orElse(null); if (orderItemFeeRatio != null && orderItemFeeRatio.getBrandAuthCostServiceCostRatio().compareTo(BigDecimal.ZERO) == 1) { // 计算平台服务费 platformServiceFee = brandAuthFeeDTO.getAmount().multiply(orderItemFeeRatio.getBrandAuthCostServiceCostRatio()).setScale(2, BigDecimal.ROUND_UP); platformServiceCostRatio = orderItemFeeRatio.getBrandAuthCostServiceCostRatio(); // 拼接平台服务费分账 if (platformServiceFee.compareTo(BigDecimal.ZERO) == 1) { Subaccount platformSubaccount = generatePlatformSubaccount(orderItemFeeRatio.getBrandAuthCostServiceCostRatio(), platformServiceFee, order, shipping, brand.getCompany()); if (platformSubaccount != null) { platformSubaccountList.add(platformSubaccount); } } } BigDecimal subaccountAmount = brandAuthFeeDTO.getAmount().subtract(platformServiceFee); if (subaccountAmount.compareTo(BigDecimal.ZERO) == 1) { // 拼接分账记录 subaccount = new Subaccount(); subaccount.setSubaccountNo(sequenceUtil.getNextSequenceNumber("FZ")); subaccount.setCompany(brand.getCompany()); subaccount.setSubaccountAmount(subaccountAmount); subaccount.setSubaccountTotalAmount(brandAuthFeeDTO.getAmount()); subaccount.setSubaccountType(SubaccountType.BRAND_AUTH_FEE); subaccount.setOrders(order); subaccount.setShipping(shipping); subaccount.setSubaccountState(SubaccountState.SEPARATE_NOT); subaccount.setSourceCompany(order.getBuyerCompany()); subaccount.setBrandId(brandAuthFeeDTO.getBrandId()); if (platformServiceFee.compareTo(BigDecimal.ZERO) == 1) { subaccount.setPlatformServiceCostRatio(platformServiceCostRatio); subaccount.setPlatformServiceFee(platformServiceFee); } newSubaccountList.add(subaccount); } } } // 获取已生成的平台服务费分账记录 List<Subaccount> platformSubaccounts = subaccountList.stream().filter(subaccount -> subaccount.getCompany() == null).collect(Collectors.toList()); if (CollectionUtils.isNotEmpty(platformSubaccounts)) { for (Subaccount platformSubaccount : platformSubaccounts) { handleSubaccountStatus(platformSubaccount, true); } } else if (CollectionUtils.isNotEmpty(platformSubaccountList)) { newSubaccountList.addAll(platformSubaccountList); } // 对所有的分账单进行统计处理,同一企业的合并进行分账创建 if (CollectionUtils.isNotEmpty(newSubaccountList)) { // 获取平台分账记录 List<Subaccount> noCompanySubaccountList = newSubaccountList.stream().filter(subaccount -> subaccount.getCompany() == null).collect(Collectors.toList()); if (CollectionUtils.isNotEmpty(noCompanySubaccountList)) { BigDecimal noCompanySubaccountAmount = noCompanySubaccountList.stream().map(Subaccount::getSubaccountAmount).reduce(BigDecimal.ZERO, BigDecimal::add); // 商品扩展字段 ChinaumsGuaranteePayExtraDTO chinaumsGuaranteePayExtraDTO = new ChinaumsGuaranteePayExtraDTO(); chinaumsGuaranteePayExtraDTO.setProductInfos(this.handleProductInfoByShipping(shipping.getShippingItem(), order.getSn(), shipping.getAmount(), noCompanySubaccountAmount)); // 自定义参数 metadata.put("companyId", null); metadata.put("subaccountNo", StringUtils.join(noCompanySubaccountList.stream().map(Subaccount::getSubaccountNo).collect(Collectors.toList()), ",")); // 拼接分账参数 ChinaumsTransferParamsDTO chinaumsTransferParamsDTO = ChinaumsTransferParamsDTO .builder() .recvBalanceAcctId(chinaumsUtil.getFeeBalanceAcctId()) .amount(noCompanySubaccountAmount.multiply(new BigDecimal(100)).intValue()) .remark(null) .extra(chinaumsGuaranteePayExtraDTO) .metadata(metadata) .build(); chinaumsTransferParamsDTOList.add(chinaumsTransferParamsDTO); } // 获取非平台分账记录 List<Subaccount> allCompanySubaccountList = newSubaccountList.stream().filter(subaccount -> subaccount.getCompany() != null).collect(Collectors.toList()); Map<Company, List<Subaccount>> companySubaccountListMap = allCompanySubaccountList.stream().collect(Collectors.groupingBy(Subaccount::getCompany)); for (Map.Entry<Company, List<Subaccount>> companyListEntry : companySubaccountListMap.entrySet()) { Company company = companyListEntry.getKey(); List<Subaccount> companySubaccountList = companyListEntry.getValue(); // 计算该企业总分账金额 BigDecimal companySubaccountAmount = companySubaccountList.stream().map(Subaccount::getSubaccountAmount).reduce(BigDecimal.ZERO, BigDecimal::add); // 商品扩展字段 ChinaumsGuaranteePayExtraDTO chinaumsGuaranteePayExtraDTO = new ChinaumsGuaranteePayExtraDTO(); chinaumsGuaranteePayExtraDTO.setProductInfos(this.handleProductInfoByShipping(shipping.getShippingItem(), order.getSn(), shipping.getAmount(), companySubaccountAmount)); // 自定义参数 metadata.put("companyId", company.getId()); metadata.put("subaccountNo", StringUtils.join(companySubaccountList.stream().map(Subaccount::getSubaccountNo).collect(Collectors.toList()), ",")); // 判断该企业是否已认证 if (StringUtils.isBlank(company.getWalletId())) { writeSeparateLog(String.format("[分账][生成][普通订单][%s][发货单][%s],[%s]暂未认证银联", order.getSn(), shipping.getShippingSn(), company.getName())); return; } // 拼接分账参数 ChinaumsTransferParamsDTO chinaumsTransferParamsDTO = ChinaumsTransferParamsDTO .builder() .recvBalanceAcctId(company.getWalletId()) .amount(companySubaccountAmount.multiply(new BigDecimal(100)).intValue()) .remark(null) .extra(chinaumsGuaranteePayExtraDTO) .metadata(metadata) .build(); chinaumsTransferParamsDTOList.add(chinaumsTransferParamsDTO); } } if (CollectionUtils.isNotEmpty(chinaumsTransferParamsDTOList)) { // 已分账金额 BigDecimal allocatedAmount = subaccountList.stream().map(Subaccount::getSubaccountAmount).reduce(BigDecimal.ZERO, BigDecimal::add); // 待分账金额 BigDecimal totalSubaccountAmount = newSubaccountList.stream().map(Subaccount::getSubaccountAmount).reduce(BigDecimal.ZERO, BigDecimal::add); // 判断(已分账金额+待分账金额)和发货单金额是否一致 if ((allocatedAmount.add(totalSubaccountAmount)).compareTo(shipping.getPayAmount()) != 0) { writeSeparateLog(String.format("[分账][生成][普通订单][%s][发货单][%s],分账总金额与发货单支付金额不一致", order.getSn(), shipping.getShippingSn())); return; } // 银联所属企业 Company chinaumsCompany = order.getConsignmentCompany() != null ? companyRepository.getOne(shipping.getOrders().getConsignmentCompany().getId()) : companyRepository.getOne(shipping.getOrders().getSellerCompany().getId()); // 根据支付方式获取对应分账电子账簿ID String chinaumsBalanceAcctId; if (paymentMethod.equals(PaymentMethod.CREDIT_PAY)) { chinaumsBalanceAcctId = chinaumsUtil.getChinaumsCreditBalanceAcctId(chinaumsCompany.getId()); } else { chinaumsBalanceAcctId = chinaumsUtil.getBalanceAcctId(chinaumsCompany.getId()); } if (StringUtils.isBlank(chinaumsBalanceAcctId)) { writeSeparateLog(String.format("[分账][生成][普通订单][%s][发货单][%s],[%s]分账电子账簿ID为空", order.getSn(), shipping.getShippingSn(), chinaumsCompany.getName())); return; } // 查询平台分账银联电子账簿是否金额充足 BigDecimal balance; try { BalanceAcctsVO balanceAcctsVO = walletService.balanceAcctsQryByAcctId(chinaumsBalanceAcctId); balance = new BigDecimal(balanceAcctsVO.getSettledAmount()).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP); } catch (Exception exception) { writeSeparateLog(String.format("[分账][生成][普通订单][%s][发货单][%s],[%s]分账电子账簿金额查询报错", order.getSn(), shipping.getShippingSn(), chinaumsCompany.getName())); return; } // 判断余额是否充足 if (balance.compareTo(BigDecimal.ZERO) < 1 || balance.compareTo(totalSubaccountAmount) == -1) { writeSeparateLog(String.format("[分账][生成][普通订单][%s][发货单][%s],[%s]分账电子账簿金额不足", order.getSn(), shipping.getShippingSn(), chinaumsCompany.getName())); return; } // 分账创建 ChinaumsAllocationsDTO chinaumsAllocationsDTO = ChinaumsAllocationsDTO .builder() .outOrderNo(sequenceUtil.getNextSequenceNumber("FZ")) .sentAt(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX").format(new Date())) .payBalanceAcctId(chinaumsBalanceAcctId) .transferParams(chinaumsTransferParamsDTOList) .remark(null) .build(); ChinaumsAllocationsVO chinaumsAllocationsVO; try { chinaumsAllocationsVO = walletService.createSubaccount(chinaumsAllocationsDTO); } catch (Exception exception) { // 当请求返回异常时,直接跳过 return; } // 循环查询子订单分账是否成功 for (ChinaumsTransferResultsVO chinaumsTransferResultsVO : chinaumsAllocationsVO.getTransferResults()) { // 先判断是否为平台电子账簿 if (chinaumsTransferResultsVO.getRecvBalanceAcctId().equals(chinaumsUtil.getFeeBalanceAcctId())) { // 企业为空时获取平台分账记录 List<Subaccount> platformFeeSubaccountList = newSubaccountList.stream().filter(filterSubaccount -> filterSubaccount.getCompany() == null).collect(Collectors.toList()); for (Subaccount subaccount : platformFeeSubaccountList) { subaccount.setExternalId(chinaumsTransferResultsVO.getTransferId()); subaccountRepository.saveAndFlush(subaccount); handleSubaccountStatus(subaccount, true); } } else { // 根据收款电子账簿ID查询 Company company = companyRepository.findByWalletId(chinaumsTransferResultsVO.getRecvBalanceAcctId()); if (company == null) { continue; } // 获取对应的企业分账记录 List<Subaccount> companySubaccountList = newSubaccountList.stream().filter(filterSubaccount -> filterSubaccount.getCompany() != null && filterSubaccount.getCompany().equals(company)).collect(Collectors.toList()); for (Subaccount subaccount : companySubaccountList) { subaccount.setExternalId(chinaumsTransferResultsVO.getTransferId()); subaccountRepository.saveAndFlush(subaccount); handleSubaccountStatus(subaccount, true); } } writeSeparateLog(String.format("[分账][生成][普通订单][%s][发货单][%s],生成分账单成功,银联结算单号[%s]。", order.getSn(), shipping.getShippingSn(), chinaumsTransferResultsVO.getTransferId())); } } // 判断是否分账结束 if (checkIsSubaccountByShipping(subaccountList)) { updateIsSeparateAccountsByShipping(shipping); // 判断订单是否已分账 if (checkIsSubaccountOrder(subaccountRepository.findAllByOrdersId(order.getId()))) { orderRepository.updateIsSeparateAccountsById(order.getId()); } } } /** * 合并消费担保确认 * * @return * @description * @author huabiao * @create 2023/2/6 17:17 */ @Transactional(rollbackFor = YnceErrorException.class) public void confirmsCombinedGuaranteeByOrder(Order order) { // 获取银联支付单 List<ChinaumsPayment> chinaumsPaymentList = getChinaumsPaymentList(order); // 获取分账记录 List<Subaccount> subaccountList = getSubaccountListAndCheck(order); if (subaccountList == null) { return; } // 获取订单费用比例 OrderFeeRatio orderFeeRatio = orderFeeRatioRepository.findByOrdersId(order.getId()); // 获取所有结算单(包含正常订单和退货退款) List<Statement> allStatementList = getStatementList(order); if (allStatementList == null) { return; } // 正常订单结算单 List<Statement> statementList = allStatementList.stream().filter(statement -> statement.getStatementType().equals(StatementType.NORMALORDER)).collect(Collectors.toList()); // 退货退款结算单 List<Statement> allAfterSaleStatementList = allStatementList.stream().filter(statement -> statement.getStatementType().equals(StatementType.AFTERSALES)).collect(Collectors.toList()); // 平台服务费分账记录 List<Subaccount> platformSubaccountList = getSubaccountListAndCheck(order, chinaumsPaymentList, subaccountList, orderFeeRatio, statementList, allAfterSaleStatementList); if (platformSubaccountList == null) { return; } // 品牌授权费 setBrandInfoToSubAccountList(order, chinaumsPaymentList, subaccountList, orderFeeRatio, statementList, allAfterSaleStatementList, platformSubaccountList); // 获取已生成的平台服务费分账记录 List<Subaccount> platformSubaccounts = subaccountList.stream().filter(subaccount -> subaccount.getCompany() == null).collect(Collectors.toList()); if (CollectionUtils.isNotEmpty(platformSubaccounts)) { for (Subaccount platformSubaccount : platformSubaccounts) { handleSubaccountStatus(platformSubaccount, false); } } else if (CollectionUtils.isNotEmpty(platformSubaccountList)) { // 获取平台电子账簿ID String balanceAcctId = chinaumsUtil.getFeeBalanceAcctId(); // 获取平台服务费对应的银联支付单 ChinaumsPayment chinaumsPayment = chinaumsPaymentRepository.findFirstByOrdersIdAndRecvBalanceAcctId(order.getId(), balanceAcctId); if (chinaumsPayment != null) { // 平台服务费退款金额 BigDecimal platformServiceFeeRefundAmount = BigDecimal.ZERO; // 获取银联退款单 List<ChinaumsRefund> chinaumsRefundList = chinaumsRefundRepository.findAllByOrigTradeId(chinaumsPayment.getGuaranteePaymentId()); if (CollectionUtils.isNotEmpty(chinaumsRefundList)) { platformServiceFeeRefundAmount = chinaumsRefundList.stream().map(ChinaumsRefund::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add); } // 分账记录总平台服务费 BigDecimal totalPlatformServiceFee = platformSubaccountList.stream().map(subaccount -> subaccount.getSubaccountAmount()).reduce(BigDecimal.ZERO, BigDecimal::add); // 银联单据计算平台服务费 BigDecimal platformServiceFee = chinaumsPayment.getAmount().subtract(platformServiceFeeRefundAmount); // 只有当分账记录的金额和银联支付单金额一致才进行分账 if (totalPlatformServiceFee.compareTo(platformServiceFee) == 0) { Company platformCompany = companyRepository.findByWalletId(balanceAcctId); BusinessRelations businessRelations = businessRelationsRepository.findFirstBySourceCompany(platformCompany); List<ByxChinaumsGuaranteePayConfirmsDetailDTO> confirmsDetailDTOList = new ArrayList<>(); ByxChinaumsGuaranteePayConfirmsDetailDTO confirmsDetailDTO = ByxChinaumsGuaranteePayConfirmsDetailDTO .builder() .profitSharingWalletId(balanceAcctId) .profitSharingAmt(platformServiceFee.multiply(new BigDecimal(100)).longValue()) .build(); confirmsDetailDTOList.add(confirmsDetailDTO); ByxChinaumsGuaranteePayConfirmsDTO byxChinaumsGuaranteePayConfirmsDTO = ByxChinaumsGuaranteePayConfirmsDTO .builder() .mctOrderNo(platformSubaccountList.get(0).getSubaccountNo()) .oriTransOrderNo(chinaumsPayment.getGuaranteePaymentId()) .platformWalletId(balanceAcctId) .settAmt(platformServiceFee.multiply(new BigDecimal(100)).longValue()) .isFinished("Y") .bizType("030001") //担保支付 030001 .profitSharingRuleId(businessRelations.getChinaumsRuleId()) .profitSharingList(confirmsDetailDTOList) .build(); try { String externalId = walletService.paySettlementConfirms(byxChinaumsGuaranteePayConfirmsDTO); writeSeparateLog(String.format("[分账][生成][普通订单][%s],生成分账单成功,银联结算单号[%s]。", order.getSn(), externalId)); for (Subaccount subaccount : platformSubaccountList) { subaccount.setExternalId(externalId); subaccountRepository.saveAndFlush(subaccount); handleSubaccountStatus(subaccount, false); } subaccountList.addAll(platformSubaccountList); } catch (Exception e) { // TODO 当请求返回异常时,直接跳过 log.error(e.getMessage()); } } else { writeSeparateLog(String.format("[分账][生成][普通订单][%s],生成分账单失败,分账金额与银联支付单剩余金额不一致。", order.getSn())); } } } // 判断是否分账结束 if (checkIsSubaccountOrder(subaccountList)) { // 更新订单已分账 finishOrderSubaccount(order); } } private void setBrandInfoToSubAccountList(Order order, List<ChinaumsPayment> chinaumsPaymentList, List<Subaccount> subaccountList, OrderFeeRatio orderFeeRatio, List<Statement> statementList, List<Statement> allAfterSaleStatementList, List<Subaccount> platformSubaccountList) { if (CollectionUtils.isNotEmpty(orderFeeRatio.getOrderItemFeeRatio())) { // 获取品牌授权费银联支付单 List<ChinaumsPayment> brandAuthFeeChinaumsPaymentList = chinaumsPaymentList.stream().filter(filterChinaumsPayment -> filterChinaumsPayment.getSubaccountType().equals(SubaccountType.BRAND_AUTH_FEE)).collect(Collectors.toList()); // 获取品牌授权费的分账记录 List<Subaccount> brandAuthFeeSubaccountList = subaccountList.stream().filter(subaccount -> subaccount.getSubaccountType().equals(SubaccountType.BRAND_AUTH_FEE)).collect(Collectors.toList()); for (ChinaumsPayment chinaumsPayment : brandAuthFeeChinaumsPaymentList) { // 获取货款结算单,并根据品牌ID获取对应的品牌授权费 Statement statement = statementList.stream().filter(filterStatement -> filterStatement.getSubaccountType().equals(SubaccountType.GOODS_COST)).findFirst().orElse(null); // 品牌授权费 BigDecimal brandAuthFee = statement.getStatementLine().stream().map(StatementLine::getBrandAuthFee).reduce(BigDecimal.ZERO, BigDecimal::add); // 品牌授权费退款金额 BigDecimal brandAuthFeeRefundAmount = BigDecimal.ZERO; // 获取退款货款结算单,并根据品牌ID获取对应的退款品牌授权费 List<Statement> afterSaleStatementList = allAfterSaleStatementList.stream().filter(filterStatement -> filterStatement.getSubaccountType().equals(SubaccountType.GOODS_COST)).collect(Collectors.toList()); if (CollectionUtils.isNotEmpty(afterSaleStatementList)) { for (Statement afterSaleStatement : afterSaleStatementList) { brandAuthFeeRefundAmount = brandAuthFeeRefundAmount.add(afterSaleStatement.getStatementLine().stream().map(StatementLine::getBrandAuthFee).reduce(BigDecimal.ZERO, BigDecimal::add)); } } // 获取分账企业 Company company = companyRepository.findByWalletId(chinaumsPayment.getRecvBalanceAcctId()); // 平台服务费 BigDecimal platformServiceFee; // 平台服务费分账记录 Subaccount platformSubaccount = null; // 获取订单项费用比例 OrderItemFeeRatio orderItemFeeRatio = orderFeeRatio.getOrderItemFeeRatio().stream().filter(filterOrderItemFeeRatio -> filterOrderItemFeeRatio.getOrderItem().getBrandId().equals(chinaumsPayment.getBrandId())).findFirst().orElse(null); if (orderItemFeeRatio != null && orderItemFeeRatio.getBrandAuthCostServiceCostRatio().compareTo(BigDecimal.ZERO) == 1) { // 计算平台服务费 platformServiceFee = brandAuthFee.subtract(brandAuthFeeRefundAmount).multiply(orderItemFeeRatio.getBrandAuthCostServiceCostRatio()).setScale(2, BigDecimal.ROUND_UP); // 拼接平台服务费分账 if (platformServiceFee.compareTo(BigDecimal.ZERO) == 1) { platformSubaccount = generatePlatformSubaccount(orderItemFeeRatio.getBrandAuthCostServiceCostRatio(), platformServiceFee, order, null, company); if (platformSubaccount != null) { platformSubaccountList.add(platformSubaccount); } } } // 判断该品牌授权费是否存在分账记录(根据品牌ID) Subaccount subaccount = brandAuthFeeSubaccountList.stream().filter(filterSubaccount -> filterSubaccount.getBrandId().equals(chinaumsPayment.getBrandId())).findFirst().orElse(null); if (subaccount != null) { // 若是未分账则调用银联接口 if (subaccount.getSubaccountState().equals(SubaccountState.SEPARATE_NOT)) { handleSubaccountStatus(subaccount, false); } continue; } // 分账金额 = 银联支付单金额 - 银联退款单金额 BigDecimal subaccountAmount = chinaumsPayment.getAmount(); // 获取银联退款单 List<ChinaumsRefund> chinaumsRefundList = chinaumsRefundRepository.findAllByOrigTradeId(chinaumsPayment.getGuaranteePaymentId()); if (CollectionUtils.isNotEmpty(chinaumsRefundList)) { for (ChinaumsRefund chinaumsRefund : chinaumsRefundList) { subaccountAmount = subaccountAmount.subtract(chinaumsRefund.getAmount()); } } if (subaccountAmount.compareTo(BigDecimal.ZERO) == 1) { // 拼接分账记录 subaccount = new Subaccount(); subaccount.setSubaccountNo(sequenceUtil.getNextSequenceNumber("FZ")); subaccount.setCompany(company); subaccount.setSubaccountAmount(subaccountAmount); subaccount.setSubaccountTotalAmount(subaccount.getSubaccountAmount()); subaccount.setSubaccountType(SubaccountType.BRAND_AUTH_FEE); subaccount.setOrders(order); subaccount.setSubaccountState(SubaccountState.SEPARATE_NOT); subaccount.setSourceCompany(order.getBuyerCompany()); subaccount.setBrandId(chinaumsPayment.getBrandId()); if (platformSubaccount != null) { subaccount.setPlatformServiceCostRatio(platformSubaccount.getSubaccountCostRatio()); subaccount.setPlatformServiceFee(platformSubaccount.getSubaccountAmount()); } // 获取平台电子账簿ID String balanceAcctId = chinaumsUtil.getFeeBalanceAcctId(); Company platformCompany = companyRepository.findByWalletId(balanceAcctId); BusinessRelations businessRelations = businessRelationsRepository.findFirstBySourceCompany(platformCompany); List<ByxChinaumsGuaranteePayConfirmsDetailDTO> confirmsDetailDTOList = new ArrayList<>(); ByxChinaumsGuaranteePayConfirmsDetailDTO confirmsDetailDTO = ByxChinaumsGuaranteePayConfirmsDetailDTO .builder() .profitSharingWalletId(subaccount.getCompany().getWalletId()) .profitSharingAmt(subaccount.getSubaccountAmount().multiply(new BigDecimal(100)).longValue()) .build(); confirmsDetailDTOList.add(confirmsDetailDTO); ByxChinaumsGuaranteePayConfirmsDTO byxChinaumsGuaranteePayConfirmsDTO = ByxChinaumsGuaranteePayConfirmsDTO .builder() .mctOrderNo(subaccount.getSubaccountNo()) .oriTransOrderNo(chinaumsPayment.getGuaranteePaymentId()) .platformWalletId(balanceAcctId) .settAmt(subaccount.getSubaccountAmount().multiply(new BigDecimal(100)).longValue()) .isFinished("N") .bizType("030001") //担保支付 030001 .profitSharingRuleId(businessRelations.getChinaumsRuleId()) .profitSharingList(confirmsDetailDTOList) .build(); String settOrderNo; try { settOrderNo = walletService.paySettlementConfirms(byxChinaumsGuaranteePayConfirmsDTO); } catch (Exception exception) { // 当请求返回异常时,直接跳过 continue; } subaccount.setExternalId(settOrderNo); subaccountRepository.saveAndFlush(subaccount); writeSeparateLog(String.format("[分账][生成][普通订单][%s],生成分账单成功,银联结算单号[%s]。", order.getSn(), settOrderNo)); handleSubaccountStatus(subaccount, false); brandAuthFeeSubaccountList.add(subaccount); } } subaccountList.addAll(brandAuthFeeSubaccountList); } } private Map<String, BigDecimal> calRefundFee(Order order, List<Statement> allAfterSaleStatementList, Statement statement) { Map<String, BigDecimal> refundFeeMap = new HashMap<>(); // 退款金额 BigDecimal refundAmount = BigDecimal.ZERO; // 退款品牌授权费 BigDecimal refundBrandAuthFee = BigDecimal.ZERO; // 该结算单对应的退款结算单 List<Statement> afterSaleStatementList = allAfterSaleStatementList.stream().filter(filterStatement -> filterStatement.getSubaccountType().equals(statement.getSubaccountType())).collect(Collectors.toList()); // 查询所有已完成售后单 List<AfterSale> afterSaleList = afterSaleRepository.findAllByOrdersIdAndAfterSaleStatus(order.getId(), AfterSaleStatus.COMPLETED); if (CollectionUtils.isNotEmpty(afterSaleList)) { if (CollectionUtils.isEmpty(afterSaleStatementList)) { writeSeparateLog(String.format("[分账][生成][普通订单][%s][结算单][%s],该分账单存在退款结算单未生成", order.getSn(), statement.getStatementNo())); return null; } // 若存在退款结算单,需判断单据数量是否一致(注意,可能存在非售后途径退款) if (afterSaleList.size() != afterSaleStatementList.stream().filter(filterStatement -> filterStatement.getAfterSale() != null).count()) { writeSeparateLog(String.format("[分账][生成][普通订单][%s][结算单][%s],该分账单存在退款结算单未生成", order.getSn(), statement.getStatementNo())); return null; } for (Statement afterSaleStatement : afterSaleStatementList) { refundAmount = refundAmount.add(afterSaleStatement.getStatementAmount()); refundBrandAuthFee = refundBrandAuthFee.add(afterSaleStatement.getStatementLine().stream().map(StatementLine::getBrandAuthFee).reduce(BigDecimal.ZERO, BigDecimal::add)); } } else { refundAmount = afterSaleStatementList.stream().map(Statement::getStatementAmount).reduce(BigDecimal.ZERO, BigDecimal::add); } refundFeeMap.put("refundAmount", refundAmount); refundFeeMap.put("refundBrandAuthFee", refundBrandAuthFee); return refundFeeMap; } private List<Subaccount> getSubaccountListAndCheck(Order order, List<ChinaumsPayment> chinaumsPaymentList, List<Subaccount> subaccountList, OrderFeeRatio orderFeeRatio, List<Statement> statementList, List<Statement> allAfterSaleStatementList) { List<Subaccount> platformSubaccountList = new ArrayList<>(); for (Statement statement : statementList) { // 计算 退款金额 和 退款品牌授权费 Map<String, BigDecimal> refundFeeMap = this.calRefundFee(order, allAfterSaleStatementList, statement); if (refundFeeMap == null) { return null; } // 退款金额 BigDecimal refundAmount = refundFeeMap.get("refundAmount"); // 退款品牌授权费 BigDecimal refundBrandAuthFee = refundFeeMap.get("refundBrandAuthFee"); // 平台服务费 BigDecimal platformServiceFee = BigDecimal.ZERO; // 拼接平台服务费分账 Subaccount platformSubaccount = calculationPlatformServiceFee(statement, orderFeeRatio, refundAmount.add(refundBrandAuthFee)); if (platformSubaccount != null) { platformSubaccountList.add(platformSubaccount); platformServiceFee = platformSubaccount.getSubaccountAmount(); } // 判断是否存在分账记录(根据分账企业和分账类型) Subaccount subaccount = subaccountList.stream().filter(filterSubaccount -> filterSubaccount.getSubaccountType().equals(statement.getSubaccountType()) && filterSubaccount.getCompany() != null && filterSubaccount.getCompany().equals(statement.getCompany())).findFirst().orElse(null); if (subaccount != null) { // 若是未分账则调用银联接口 if (subaccount.getSubaccountState().equals(SubaccountState.SEPARATE_NOT)) { handleSubaccountStatus(subaccount, false); } if (platformSubaccount != null && platformSubaccount.getSubaccountAmount().compareTo(subaccount.getPlatformServiceFee()) != 0) { platformSubaccount.setSubaccountAmount(subaccount.getPlatformServiceFee()); platformSubaccount.setSubaccountTotalAmount(subaccount.getPlatformServiceFee()); } continue; } // 获取银联支付单 ChinaumsPayment chinaumsPayment = chinaumsPaymentList.stream().filter(filterChinaumsPayment -> filterChinaumsPayment.getRecvBalanceAcctId().equals(statement.getCompany().getWalletId()) && filterChinaumsPayment.getSubaccountType().equals(statement.getSubaccountType())).findFirst().orElse(null); if (chinaumsPayment == null) { continue; } subaccount = new Subaccount(); subaccount.setSubaccountNo(sequenceUtil.getNextSequenceNumber("FZ")); subaccount.setCompany(companyRepository.findById(statement.getCompany().getId()).orElse(null)); // 以订单进行分账,则分账金额 = 银联支付单金额 if (statement.getSubaccountType().equals(SubaccountType.GOODS_COST)) { // 货款分账金额 = 结算金额 + 退款金额 - 平台服务费 - 品牌授权费 + 退款品牌授权费 BigDecimal brandAuthFee = statement.getStatementLine().stream().map(statementLine -> statementLine.getBrandAuthFee()).reduce(BigDecimal.ZERO, BigDecimal::add); subaccount.setSubaccountAmount(statement.getStatementAmount().add(refundAmount).subtract(platformServiceFee).subtract(brandAuthFee).add(refundBrandAuthFee)); if (CollectionUtils.isNotEmpty(orderFeeRatio.getOrderItemFeeRatio())) { subaccount.setBrandAuthCostRatio(orderFeeRatio.getOrderItemFeeRatio().get(0).getBrandAuthCostRatio()); } subaccount.setBrandAuthFee(brandAuthFee.add(refundBrandAuthFee)); } else { // 其他分账金额 = 结算金额 - 退款金额 - 平台服务费 subaccount.setSubaccountAmount(statement.getStatementAmount().add(refundAmount).subtract(platformServiceFee)); } // 根据银联支付单和银联退款单计算最终分账金额 List<ChinaumsRefund> chinaumsRefundList = chinaumsRefundRepository.findAllByOrigTradeId(chinaumsPayment.getGuaranteePaymentId()); BigDecimal chinaumsRefundAmount = chinaumsRefundList.stream().map(ChinaumsRefund::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add); BigDecimal finallySubaccountAmount = chinaumsPayment.getAmount().subtract(chinaumsRefundAmount); if (finallySubaccountAmount.compareTo(subaccount.getSubaccountAmount()) != 0) { BigDecimal balance = subaccount.getSubaccountAmount().subtract(finallySubaccountAmount); subaccount.setSubaccountAmount(finallySubaccountAmount); // 计算实际服务费 BigDecimal finallyPlatformSubaccountAmount = BigDecimal.ZERO; if (platformSubaccount == null) { finallyPlatformSubaccountAmount.add(balance); } else { finallyPlatformSubaccountAmount = platformSubaccount.getSubaccountAmount().add(balance); platformSubaccount.setSubaccountAmount(finallyPlatformSubaccountAmount); platformSubaccount.setSubaccountTotalAmount(finallyPlatformSubaccountAmount); } } subaccount.getSubaccountAmount(); subaccount.setSubaccountCostRatio(getCostRatio(statement, orderFeeRatio)); subaccount.setSubaccountType(statement.getSubaccountType()); subaccount.setOrders(statement.getOrders()); subaccount.setSubaccountState(SubaccountState.SEPARATE_NOT); subaccount.setSourceCompany(order.getBuyerCompany()); subaccount.setSubaccountTotalAmount(statement.getStatementAmount().add(refundAmount)); if (platformSubaccount != null) { subaccount.setPlatformServiceCostRatio(platformSubaccount.getSubaccountCostRatio()); subaccount.setPlatformServiceFee(platformSubaccount.getSubaccountAmount()); } // 获取平台电子账簿ID String balanceAcctId = chinaumsUtil.getFeeBalanceAcctId(); Company platformCompany = companyRepository.findByWalletId(balanceAcctId); BusinessRelations businessRelations = businessRelationsRepository.findFirstBySourceCompany(platformCompany); List<ByxChinaumsGuaranteePayConfirmsDetailDTO> confirmsDetailDTOList = new ArrayList<>(); ByxChinaumsGuaranteePayConfirmsDetailDTO confirmsDetailDTO = ByxChinaumsGuaranteePayConfirmsDetailDTO .builder() .profitSharingWalletId(subaccount.getCompany().getWalletId()) .profitSharingAmt(subaccount.getSubaccountAmount().multiply(new BigDecimal(100)).longValue()) .build(); confirmsDetailDTOList.add(confirmsDetailDTO); ByxChinaumsGuaranteePayConfirmsDTO byxChinaumsGuaranteePayConfirmsDTO = ByxChinaumsGuaranteePayConfirmsDTO .builder() .mctOrderNo(subaccount.getSubaccountNo()) .oriTransOrderNo(chinaumsPayment.getGuaranteePaymentId()) .platformWalletId(balanceAcctId) .settAmt(subaccount.getSubaccountAmount().multiply(new BigDecimal(100)).longValue()) .isFinished("N") .bizType("030001") //担保支付 030001 .profitSharingRuleId(businessRelations.getChinaumsRuleId()) .profitSharingList(confirmsDetailDTOList) .build(); String settOrderNo; try { settOrderNo = walletService.paySettlementConfirms(byxChinaumsGuaranteePayConfirmsDTO); } catch (Exception exception) { // 当请求返回异常时,直接跳过 platformSubaccountList.remove(platformSubaccount); continue; } subaccount.setExternalId(settOrderNo); subaccountRepository.saveAndFlush(subaccount); writeSeparateLog(String.format("[分账][生成][普通订单][%s],生成分账单成功,银联结算单号[%s]。", order.getSn(), settOrderNo)); handleSubaccountStatus(subaccount, false); subaccountList.add(subaccount); } return platformSubaccountList; } private List<Statement> getStatementList(Order order) { List<Statement> allStatementList = statementRepository.findAllByOrdersId(order.getId()); if (CollectionUtils.isEmpty(allStatementList)) { writeSeparateLog(String.format("[分账][生成][普通订单][%s],未存在结算单。", order.getSn())); return null; } return allStatementList; } private List<ChinaumsPayment> getChinaumsPaymentList(Order order) { List<ChinaumsPayment> chinaumsPaymentList = chinaumsPaymentRepository.findAllByOrdersId(order.getId()); if (CollectionUtils.isEmpty(chinaumsPaymentList)) { chinaumsPaymentList = walletService.handleChinaumsPayment(order); } return chinaumsPaymentList; } private List<Subaccount> getSubaccountListAndCheck(Order order) { List<Subaccount> subaccountList = subaccountRepository.findAllByOrdersId(order.getId()); if (subaccountList == null) { return new ArrayList<>(); } if (checkIsSubaccountOrder(subaccountList)) { // 更新订单已分账 finishOrderSubaccount(order); writeSeparateLog(String.format("[分账][生成][普通订单][%s],分账单已存在,更新订单为已分账", order.getSn())); return null; } return subaccountList; } /** * 合并消费担保确认 * * @return * @description * @author huabiao * @create 2023/2/6 17:17 */ public void confirmsCombinedGuaranteeByShipping(Shipping shipping) { // 自定义参数 JSONObject metadata = new JSONObject(); metadata.put("shippingSn", shipping.getShippingSn()); Order order = shipping.getOrders(); // 获取订单费用比例 OrderFeeRatio orderFeeRatio = orderFeeRatioRepository.findByOrdersId(order.getId()); // 获取银联支付单 List<ChinaumsPayment> chinaumsPaymentList = getChinaumsPaymentList(order); // 待确认平台服务费金额 BigDecimal toBeConfirmedServiceFeeAmount = BigDecimal.ZERO; // 查询平台服务费对应银联支付单 ChinaumsPayment serviceFeeChinaumsPayment = chinaumsPaymentList.stream().filter(filterChinaumsPayment -> filterChinaumsPayment.getSubaccountType().equals(SubaccountType.SERVICE_FEE)).findFirst().orElse(null); if (serviceFeeChinaumsPayment != null) { toBeConfirmedServiceFeeAmount = serviceFeeChinaumsPayment.getAmount().subtract(serviceFeeChinaumsPayment.getConfirmedAmount()); // 获取平台服务费银联退款单 List<ChinaumsRefund> serviceFeeChinaumsRefundList = chinaumsRefundRepository.findAllByOrigTradeId(serviceFeeChinaumsPayment.getGuaranteePaymentId()); if (CollectionUtils.isNotEmpty(serviceFeeChinaumsRefundList)) { toBeConfirmedServiceFeeAmount = toBeConfirmedServiceFeeAmount.subtract(serviceFeeChinaumsRefundList.stream().map(ChinaumsRefund::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add)); } } // 获取分账记录 List<Subaccount> subaccountList = subaccountRepository.findAllByShippingId(shipping.getId()); if (checkIsSubaccount(subaccountList, chinaumsPaymentList, toBeConfirmedServiceFeeAmount.compareTo(BigDecimal.ZERO) == 0)) { // 更新发货单已分账 updateIsSeparateAccountsByShipping(shipping); writeSeparateLog(String.format("[分账][生成][普通订单][%s][发货单][%s],分账单已存在,更新发货单为已分账", order.getSn(), shipping.getShippingSn())); return; } // 判断是否最后分账 Boolean isFinallySubaccount = isFinallySubaccount(shipping); // 获取结算单 List<Statement> statementList = statementRepository.findAllByShippingIdAndStatementType(shipping.getId(), StatementType.NORMALORDER); // 获取退款结算单 List<Statement> allAfterSaleStatementList = statementRepository.findAllByShippingIdAndStatementType(shipping.getId(), StatementType.AFTERSALES); // 平台服务费分账记录 List<Subaccount> platformSubaccountList = new ArrayList<>(); for (Statement statement : statementList) { // 获取对应分账类型的退款结算单 List<Statement> afterSaleStatementList = allAfterSaleStatementList.stream().filter(filterStatement -> filterStatement.getSubaccountType().equals(statement.getSubaccountType())).collect(Collectors.toList()); // 退款金额 BigDecimal refundAmount = BigDecimal.ZERO; // 退款品牌授权费 BigDecimal refundBrandAuthFee = BigDecimal.ZERO; // 获取售后单 List<AfterSale> afterSaleList = afterSaleRepository.findAllByShippingIdAndAfterSaleStatus(shipping.getId(), AfterSaleStatus.COMPLETED); if (CollectionUtils.isNotEmpty(afterSaleStatementList)) { if (afterSaleList.size() != afterSaleStatementList.size()) { writeSeparateLog(String.format("[分账][生成][普通订单][%s][发货单][%s][结算单][%s],该分账单存在退款结算单未生成", order.getSn(), shipping.getShippingSn(), statement.getStatementNo())); return; } for (Statement afterSaleStatement : afterSaleStatementList) { refundAmount = refundAmount.add(afterSaleStatement.getStatementAmount()); refundBrandAuthFee = refundBrandAuthFee.add(afterSaleStatement.getStatementLine().stream().map(StatementLine::getBrandAuthFee).reduce(BigDecimal.ZERO, BigDecimal::add)); } } else { // 当不存在退款结算单时,需判断是否还未生成 if (CollectionUtils.isNotEmpty(afterSaleList)) { writeSeparateLog(String.format("[分账][生成][普通订单][%s][发货单][%s][结算单][%s],该分账单存在退款结算单未生成", order.getSn(), shipping.getShippingSn(), statement.getStatementNo())); return; } } // 平台服务费 BigDecimal platformServiceFee = BigDecimal.ZERO; // 拼接平台服务费分账 Subaccount platformSubaccount = calculationPlatformServiceFee(statement, orderFeeRatio, refundAmount); if (platformSubaccount != null) { // 当待确认平台服务费大于平台服务费分账金额时 if (toBeConfirmedServiceFeeAmount.compareTo(platformSubaccount.getSubaccountAmount()) != -1) { platformSubaccountList.add(platformSubaccount); platformServiceFee = platformSubaccount.getSubaccountAmount(); } else { platformSubaccount = null; } } // 判断是否存在分账记录(根据分账企业和分账类型) Subaccount subaccount = subaccountList.stream().filter(filterSubaccount -> filterSubaccount.getSubaccountType().equals(statement.getSubaccountType()) && filterSubaccount.getCompany() != null && filterSubaccount.getCompany().equals(statement.getCompany())).findFirst().orElse(null); if (subaccount != null) { // 若是未分账则调用银联接口 if (subaccount.getSubaccountState().equals(SubaccountState.SEPARATE_NOT)) { handleSubaccountStatus(subaccount, false); } continue; } subaccount = new Subaccount(); subaccount.setSubaccountNo(sequenceUtil.getNextSequenceNumber("FZ")); subaccount.setCompany(statement.getCompany()); subaccount.setSubaccountCostRatio(getCostRatio(statement, orderFeeRatio)); if (platformSubaccount != null) { subaccount.setPlatformServiceCostRatio(platformSubaccount.getSubaccountCostRatio()); subaccount.setPlatformServiceFee(platformSubaccount.getSubaccountAmount()); } subaccount.setSubaccountTotalAmount(statement.getStatementAmount().add(refundAmount)); // 保存品牌授权费 BigDecimal brandAuthFee = BigDecimal.ZERO; if (statement.getSubaccountType().equals(SubaccountType.GOODS_COST) && CollectionUtils.isNotEmpty(orderFeeRatio.getOrderItemFeeRatio())) { brandAuthFee = statement.getStatementLine().stream().map(StatementLine::getBrandAuthFee).reduce(BigDecimal.ZERO, BigDecimal::add); subaccount.setBrandAuthCostRatio(orderFeeRatio.getOrderItemFeeRatio().get(0).getBrandAuthCostRatio()); subaccount.setBrandAuthFee(brandAuthFee.add(refundBrandAuthFee)); } if (isFinallySubaccount) { // 获取银联支付单 ChinaumsPayment chinaumsPayment = chinaumsPaymentList.stream().filter(filterChinaumsPayment -> filterChinaumsPayment.getSubaccountType().equals(statement.getSubaccountType()) && filterChinaumsPayment.getOrders().equals(order)).findFirst().orElse(null); // 获取银联退款单 List<ChinaumsRefund> chinaumsRefundList = chinaumsRefundRepository.findAllByOrigTradeId(chinaumsPayment.getGuaranteePaymentId()); BigDecimal chinaumsRefundAmount = BigDecimal.ZERO; if (CollectionUtils.isNotEmpty(chinaumsRefundList)) { chinaumsRefundAmount = chinaumsRefundList.stream().map(ChinaumsRefund::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add); } // 分账金额 = 银联支付金额 - 银联确认金额 - 银联退款金额 subaccount.setSubaccountAmount(chinaumsPayment.getAmount().subtract(chinaumsPayment.getConfirmedAmount()).subtract(chinaumsRefundAmount)); } else { if (statement.getSubaccountType().equals(SubaccountType.GOODS_COST)) { // 货款分账金额 = 结算金额 + 退款金额 - 平台服务费 - 品牌授权费 + 退款品牌授权费 subaccount.setSubaccountAmount(statement.getStatementAmount().add(refundAmount).subtract(platformServiceFee).subtract(brandAuthFee).add(refundBrandAuthFee)); } else { // 其他分账金额 = 结算金额 - 退款金额 - 平台服务费 subaccount.setSubaccountAmount(statement.getStatementAmount().add(refundAmount).subtract(platformServiceFee)); } } // 当分账金额小于等于0时跳过 if (subaccount.getSubaccountAmount().compareTo(BigDecimal.ZERO) != 1) { continue; } subaccount.setSubaccountType(statement.getSubaccountType()); subaccount.setOrders(statement.getOrders()); subaccount.setShipping(statement.getShipping()); subaccount.setSubaccountState(SubaccountState.SEPARATE_NOT); subaccount.setSourceCompany(order.getBuyerCompany()); // 获取银联支付单 ChinaumsPayment chinaumsPayment = chinaumsPaymentList.stream().filter(filterChinaumsPayment -> filterChinaumsPayment.getRecvBalanceAcctId().equals(statement.getCompany().getWalletId()) && filterChinaumsPayment.getSubaccountType().equals(statement.getSubaccountType())).findFirst().orElse(null); // 拼接扩展字段:商品信息 ChinaumsGuaranteePayExtraDTO chinaumsGuaranteePayExtraDTO = new ChinaumsGuaranteePayExtraDTO(); chinaumsGuaranteePayExtraDTO.setProductInfos(this.handleProductInfoByShipping(shipping.getShippingItem(), order.getSn(), shipping.getAmount(), subaccount.getSubaccountAmount())); // 拼接分账确认请求参数 ChinaumsGuaranteePayConfirmsDTO chinaumsGuaranteePayConfirmsDTO = ChinaumsGuaranteePayConfirmsDTO .builder() .outOrderNo(subaccount.getSubaccountNo()) .guaranteePaymentId(chinaumsPayment.getGuaranteePaymentId()) .sentAt(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX").format(new Date())) .amount(subaccount.getSubaccountAmount().multiply(new BigDecimal(100)).intValue()) .extra(chinaumsGuaranteePayExtraDTO) .metadata(metadata) .build(); ChinaumsGuaranteePayConfirmsVO chinaumsGuaranteePayConfirmsVO; try { chinaumsGuaranteePayConfirmsVO = walletService.paySettlement(chinaumsGuaranteePayConfirmsDTO); } catch (Exception exception) { // 当请求返回异常时,直接跳过 continue; } subaccount.setExternalId(chinaumsGuaranteePayConfirmsVO.getCombinedGuaranteeConfirmId()); subaccountRepository.saveAndFlush(subaccount); writeSeparateLog(String.format("[分账][生成][普通订单][%s],生成分账单成功,银联结算单号[%s]。", order.getSn(), chinaumsGuaranteePayConfirmsVO.getCombinedGuaranteeConfirmId())); handleSubaccountStatus(subaccount, false); subaccountList.add(subaccount); // 存在平台服务费时,需要在待确认金额中减去 if (platformSubaccount != null) { toBeConfirmedServiceFeeAmount = toBeConfirmedServiceFeeAmount.subtract(platformServiceFee); } } // 品牌授权费 if (CollectionUtils.isNotEmpty(orderFeeRatio.getOrderItemFeeRatio())) { // 找出品牌授权费的发货项 Map<Long, List<ShippingItem>> brandIdShippingItemListMap = new HashMap<>(); for (OrderItemFeeRatio orderItemFeeRatio : orderFeeRatio.getOrderItemFeeRatio()) { ShippingItem shippingItem = shipping.getShippingItem().stream().filter(filterShippingItem -> filterShippingItem.getOrderItemId().equals(orderItemFeeRatio.getOrderItem().getId().toString())).findFirst().orElse(null); if (shippingItem != null) { Long brandId = orderItemFeeRatio.getOrderItem().getBrandId(); if (brandIdShippingItemListMap.containsKey(brandId)) { List<ShippingItem> shippingItemList = new ArrayList<>(brandIdShippingItemListMap.get(brandId)); shippingItemList.add(shippingItem); brandIdShippingItemListMap.put(brandId, shippingItemList); } else { brandIdShippingItemListMap.put(orderItemFeeRatio.getOrderItem().getBrandId(), Arrays.asList(shippingItem)); } } } if (!brandIdShippingItemListMap.isEmpty()) { // 获取品牌授权费的分账记录 List<Subaccount> brandAuthFeeSubaccountList = subaccountList.stream().filter(subaccount -> subaccount.getSubaccountType().equals(SubaccountType.BRAND_AUTH_FEE)).collect(Collectors.toList()); // 平台服务费分账记录 Subaccount platformSubaccount = new Subaccount(); for (Map.Entry<Long, List<ShippingItem>> brandIdShippingItemListEntry : brandIdShippingItemListMap.entrySet()) { Long brandId = brandIdShippingItemListEntry.getKey(); List<ShippingItem> shippingItemList = brandIdShippingItemListEntry.getValue(); // 通过品牌ID获取银联支付单号 ChinaumsPayment chinaumsPayment = chinaumsPaymentList.stream().filter(filterChinaumsPayment -> filterChinaumsPayment.getSubaccountType().equals(SubaccountType.BRAND_AUTH_FEE) && filterChinaumsPayment.getBrandId() != null && filterChinaumsPayment.getBrandId().equals(brandId)).findFirst().orElse(null); // 判断该银联支付单是否已分账 if (chinaumsPayment != null) { // 判断该品牌授权费是否存在分账记录(根据品牌ID) Subaccount subaccount = brandAuthFeeSubaccountList.stream().filter(filterSubaccount -> filterSubaccount.getBrandId().equals(chinaumsPayment.getBrandId())).findFirst().orElse(null); if (subaccount != null) { // 若是未分账则调用银联接口 if (subaccount.getSubaccountState().equals(SubaccountState.SEPARATE_NOT)) { handleSubaccountStatus(subaccount, false); } continue; } // 获取货款结算单 Statement goodsCostStatement = statementList.stream().filter(statement -> statement.getSubaccountType().equals(SubaccountType.GOODS_COST)).findFirst().orElse(null); // 获取货款退款结算单 List<Statement> afterSaleStatementList = allAfterSaleStatementList.stream().filter(filterStatement -> filterStatement.getSubaccountType().equals(SubaccountType.GOODS_COST)).collect(Collectors.toList()); // 计算发货总金额 BigDecimal shippingAmount = BigDecimal.ZERO; // 计算品牌授权费 BigDecimal brandAuthFee = BigDecimal.ZERO; for (ShippingItem shippingItem : shippingItemList) { shippingAmount = shippingAmount.add(shippingItem.getAmount()); // 找到符合条件的对应结算单项 StatementLine statementLine = goodsCostStatement.getStatementLine().stream().filter(filterStatementLine -> filterStatementLine.getShippingItem().equals(shippingItem)).findFirst().orElse(null); if (statementLine != null) { brandAuthFee = brandAuthFee.add(statementLine.getBrandAuthFee()); } // 找到符合条件的货款退款结算单 if (CollectionUtils.isNotEmpty(afterSaleStatementList)) { for (Statement statement : afterSaleStatementList) { StatementLine afterSaleStatementLine = statement.getStatementLine().stream().filter(filterStatementLine -> filterStatementLine.getShippingItem().equals(shippingItem)).findFirst().orElse(null); if (afterSaleStatementLine != null) { brandAuthFee = brandAuthFee.subtract(afterSaleStatementLine.getBrandAuthFee()); } } } } Company company = companyRepository.findByWalletId(chinaumsPayment.getRecvBalanceAcctId()); // 计算平台服务费 BigDecimal platformServiceFee = BigDecimal.ZERO; // 获取订单项费用比例 OrderItemFeeRatio orderItemFeeRatio = orderFeeRatio.getOrderItemFeeRatio().stream().filter(filterOrderItemFeeRatio -> filterOrderItemFeeRatio.getOrderItem().getBrandId().equals(chinaumsPayment.getBrandId())).findFirst().orElse(null); if (orderItemFeeRatio != null && orderItemFeeRatio.getBrandAuthCostServiceCostRatio().compareTo(BigDecimal.ZERO) == 1) { // 计算平台服务费 platformServiceFee = brandAuthFee.multiply(orderItemFeeRatio.getBrandAuthCostServiceCostRatio()).setScale(2, BigDecimal.ROUND_UP); // 拼接平台服务费分账 if (platformServiceFee.compareTo(BigDecimal.ZERO) == 1 && toBeConfirmedServiceFeeAmount.compareTo(platformServiceFee) != -1) { platformSubaccount = generatePlatformSubaccount(orderItemFeeRatio.getBrandAuthCostServiceCostRatio(), platformServiceFee, order, shipping, company); if (platformSubaccount != null) { platformSubaccountList.add(platformSubaccount); brandAuthFee = brandAuthFee.subtract(platformServiceFee); } } else { platformServiceFee = BigDecimal.ZERO; } } // 分账总金额 BigDecimal subaccountTotalAmount = brandAuthFee.add(platformServiceFee); // 最后一笔 if (isFinallySubaccount && brandIdShippingItemListMap.size() == (brandAuthFeeSubaccountList.size() + 1)) { // 获取银联退款单 List<ChinaumsRefund> chinaumsRefundList = chinaumsRefundRepository.findAllByOrigTradeId(chinaumsPayment.getGuaranteePaymentId()); BigDecimal chinaumsRefundAmount = BigDecimal.ZERO; if (CollectionUtils.isNotEmpty(chinaumsRefundList)) { chinaumsRefundAmount = chinaumsRefundList.stream().map(ChinaumsRefund::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add); } // 分账金额 = 银联支付金额 - 银联确认金额 - 银联退款金额 brandAuthFee = chinaumsPayment.getAmount().subtract(chinaumsPayment.getConfirmedAmount()).subtract(chinaumsRefundAmount); } // 判断品牌授权费金额是否大于0 if (brandAuthFee.compareTo(BigDecimal.ZERO) != 1) { continue; } // 拼接分账记录 subaccount = new Subaccount(); subaccount.setSubaccountNo(sequenceUtil.getNextSequenceNumber("FZ")); subaccount.setCompany(company); subaccount.setSubaccountTotalAmount(subaccountTotalAmount); subaccount.setSubaccountAmount(brandAuthFee); subaccount.setSubaccountType(SubaccountType.BRAND_AUTH_FEE); subaccount.setOrders(order); subaccount.setShipping(shipping); subaccount.setSubaccountState(SubaccountState.SEPARATE_NOT); subaccount.setSourceCompany(order.getSellerCompany()); subaccount.setBrandId(brandId); if (platformSubaccount != null) { subaccount.setPlatformServiceCostRatio(platformSubaccount.getSubaccountCostRatio()); subaccount.setPlatformServiceFee(platformSubaccount.getSubaccountAmount()); } // 拼接扩展字段:商品信息 ChinaumsGuaranteePayExtraDTO chinaumsGuaranteePayExtraDTO = new ChinaumsGuaranteePayExtraDTO(); chinaumsGuaranteePayExtraDTO.setProductInfos(this.handleProductInfoByShipping(shippingItemList, order.getSn(), shippingAmount, subaccount.getSubaccountAmount())); // 拼接分账确认请求参数 ChinaumsGuaranteePayConfirmsDTO chinaumsGuaranteePayConfirmsDTO = ChinaumsGuaranteePayConfirmsDTO .builder() .outOrderNo(subaccount.getSubaccountNo()) .guaranteePaymentId(chinaumsPayment.getGuaranteePaymentId()) .sentAt(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX").format(new Date())) .amount(subaccount.getSubaccountAmount().multiply(new BigDecimal(100)).intValue()) .extra(chinaumsGuaranteePayExtraDTO) .metadata(metadata) .build(); ChinaumsGuaranteePayConfirmsVO chinaumsGuaranteePayConfirmsVO; try { chinaumsGuaranteePayConfirmsVO = walletService.paySettlement(chinaumsGuaranteePayConfirmsDTO); } catch (Exception exception) { // TODO 当请求返回异常时,直接跳过 continue; } subaccount.setExternalId(chinaumsGuaranteePayConfirmsVO.getCombinedGuaranteeConfirmId()); subaccountRepository.saveAndFlush(subaccount); writeSeparateLog(String.format("[分账][生成][普通订单][%s],生成分账单成功,银联结算单号[%s]。", order.getSn(), chinaumsGuaranteePayConfirmsVO.getCombinedGuaranteeConfirmId())); handleSubaccountStatus(subaccount, false); brandAuthFeeSubaccountList.add(subaccount); } subaccountList.addAll(brandAuthFeeSubaccountList); } } } // 获取已生成的平台服务费分账记录 List<Subaccount> platformSubaccounts = subaccountList.stream().filter(subaccount -> subaccount.getCompany() == null).collect(Collectors.toList()); if (CollectionUtils.isNotEmpty(platformSubaccounts)) { for (Subaccount platformSubaccount : platformSubaccounts) { handleSubaccountStatus(platformSubaccount, false); } } else if (CollectionUtils.isNotEmpty(platformSubaccountList)) { // 获取平台电子账簿ID String balanceAcctId = chinaumsUtil.getFeeBalanceAcctId(); // 获取平台服务费对应的银联支付单 ChinaumsPayment chinaumsPayment = chinaumsPaymentList.stream().filter(filterChinaumsPayment -> filterChinaumsPayment.getRecvBalanceAcctId().equals(balanceAcctId)).findFirst().orElse(null); if (chinaumsPayment != null) { // 获取银联退款单 List<ChinaumsRefund> chinaumsRefundList = chinaumsRefundRepository.findAllByOrigTradeId(chinaumsPayment.getGuaranteePaymentId()); BigDecimal chinaumsRefundAmount = BigDecimal.ZERO; if (CollectionUtils.isNotEmpty(chinaumsRefundList)) { chinaumsRefundAmount = chinaumsRefundList.stream().map(ChinaumsRefund::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add); } // 待确认金额 = 银联支付金额 - 确认金额 - 银联退款金额 BigDecimal toBeConfirmedAmount = chinaumsPayment.getAmount().subtract(chinaumsPayment.getConfirmedAmount()).subtract(chinaumsRefundAmount); BigDecimal platformServiceFee = platformSubaccountList.stream().map(Subaccount::getSubaccountAmount).reduce(BigDecimal.ZERO, BigDecimal::add); // 当待确认金额小于平台服务费时,以待确认金额为主 if (toBeConfirmedAmount.compareTo(platformServiceFee) == -1) { platformServiceFee = toBeConfirmedAmount; } // 拼接扩展字段:商品信息 ChinaumsGuaranteePayExtraDTO chinaumsGuaranteePayExtraDTO = new ChinaumsGuaranteePayExtraDTO(); chinaumsGuaranteePayExtraDTO.setProductInfos(this.handleProductInfoByShipping(shipping.getShippingItem(), order.getSn(), shipping.getAmount(), platformServiceFee)); // 拼接分账确认请求参数 ChinaumsGuaranteePayConfirmsDTO chinaumsGuaranteePayConfirmsDTO = ChinaumsGuaranteePayConfirmsDTO .builder() .outOrderNo(platformSubaccountList.get(0).getSubaccountNo()) .guaranteePaymentId(chinaumsPayment.getGuaranteePaymentId()) .sentAt(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX").format(new Date())) .amount(platformServiceFee.multiply(new BigDecimal(100)).intValue()) .extra(chinaumsGuaranteePayExtraDTO) .metadata(metadata) .build(); try { ChinaumsGuaranteePayConfirmsVO chinaumsGuaranteePayConfirmsVO = walletService.paySettlement(chinaumsGuaranteePayConfirmsDTO); // 已分配金额 BigDecimal allocatedAmount = BigDecimal.ZERO; for (Subaccount subaccount : platformSubaccountList) { // 待分配金额 BigDecimal toBeAllocatedAmount = platformServiceFee.subtract(allocatedAmount); // 当待分配金额大于分账金额时 if (toBeAllocatedAmount.compareTo(subaccount.getSubaccountAmount()) == 1) { subaccount.setExternalId(chinaumsGuaranteePayConfirmsVO.getCombinedGuaranteeConfirmId()); subaccountRepository.saveAndFlush(subaccount); handleSubaccountStatus(subaccount, false); } else if (toBeAllocatedAmount.compareTo(subaccount.getSubaccountAmount()) == 0) { // 当待分配金额等于分账金额,跳出循环 subaccount.setExternalId(chinaumsGuaranteePayConfirmsVO.getCombinedGuaranteeConfirmId()); subaccountRepository.saveAndFlush(subaccount); handleSubaccountStatus(subaccount, false); break; } else { // 当待分配金额小于分账金额,修改分账金额 subaccount.setSubaccountAmount(toBeAllocatedAmount); subaccount.setExternalId(chinaumsGuaranteePayConfirmsVO.getCombinedGuaranteeConfirmId()); subaccountRepository.saveAndFlush(subaccount); handleSubaccountStatus(subaccount, false); } allocatedAmount = allocatedAmount.add(subaccount.getSubaccountAmount()); } writeSeparateLog(String.format("[分账][生成][普通订单][%s],生成分账单成功,银联结算单号[%s]。", order.getSn(), chinaumsGuaranteePayConfirmsVO.getCombinedGuaranteeConfirmId())); subaccountList.addAll(platformSubaccountList); } catch (Exception exception) { // TODO 当请求返回异常时,直接跳过 } } } // 判断是否分账结束 if (checkIsSubaccount(subaccountList, chinaumsPaymentList, toBeConfirmedServiceFeeAmount.compareTo(BigDecimal.ZERO) == 0)) { updateIsSeparateAccountsByShipping(shipping); } } /** * 退款结算单-生成 * * @param subaccountType 分账类型 * @param order 订单 * @param orderRefundItemDTOList 订单关闭项数组 * @param company 分账企业 * @return 退款结算单 * @author huabiao * @create 2023/1/4 11:04 */ private Statement createRefundStatement(SubaccountType subaccountType, Order order, List<OrderRefundItemDTO> orderRefundItemDTOList, Company company) { // 获取订单费用比例 OrderFeeRatio orderFeeRatio = orderFeeRatioRepository.findByOrdersId(order.getId()); // 拼接退款结算单 Statement refundStatement = new Statement(); refundStatement.setOrders(order); refundStatement.setStatementNo(sequenceUtil.getNextSequenceNumber("FEE")); refundStatement.setStatementType(StatementType.AFTERSALES); refundStatement.setSubaccountType(subaccountType); refundStatement.setStatementState(StatementState.NOTRECORDED); // 退款总金额 BigDecimal subaccountAmount = BigDecimal.ZERO; // 拼接退款结算单行 List<StatementLine> refundStatementLineList = new ArrayList<>(); for (OrderRefundItemDTO orderRefundItemDTO : orderRefundItemDTOList) { StatementLine refundStatementLine = new StatementLine(); refundStatementLine.setStatement(refundStatement); refundStatementLine.setCompany(company); refundStatementLine.setOrderItem(orderRefundItemDTO.getOrderItem()); // 计算每个订单项的退款金额 BigDecimal subaccountLineAmount = BigDecimal.ZERO; switch (subaccountType) { case GOODS_COST: refundStatementLine.setSubaccountRatio(BigDecimal.ONE.subtract(orderFeeRatio.getBrandCostRatio()).subtract(orderFeeRatio.getDeviseCostRatio())); subaccountLineAmount = orderRefundItemDTO.getRefundAmount().subtract(orderRefundItemDTO.getHandleRefundAmount()); break; case BRAND_FEE: refundStatementLine.setSubaccountRatio(orderFeeRatio.getBrandCostRatio()); subaccountLineAmount = orderRefundItemDTO.getRefundAmount().multiply(orderFeeRatio.getBrandCostRatio()).setScale(2, BigDecimal.ROUND_HALF_UP); orderRefundItemDTO.setHandleRefundAmount(orderRefundItemDTO.getHandleRefundAmount().add(subaccountLineAmount)); break; case DEVISE_FEE: refundStatementLine.setSubaccountRatio(orderFeeRatio.getDeviseCostRatio()); subaccountLineAmount = orderRefundItemDTO.getRefundAmount().multiply(orderFeeRatio.getDeviseCostRatio()).setScale(2, BigDecimal.ROUND_HALF_UP); orderRefundItemDTO.setHandleRefundAmount(orderRefundItemDTO.getHandleRefundAmount().add(subaccountLineAmount)); break; } subaccountAmount = subaccountAmount.add(subaccountLineAmount); refundStatementLine.setSubaccountAmount(subaccountLineAmount.negate()); // 计算品牌授权费 if (subaccountType.equals(SubaccountType.GOODS_COST) && CollectionUtils.isNotEmpty(orderFeeRatio.getOrderItemFeeRatio())) { OrderItemFeeRatio orderItemFeeRatio = orderFeeRatio.getOrderItemFeeRatio().stream().filter(filterOrderItemFeeRatio -> filterOrderItemFeeRatio.getOrderItem().getId().equals(orderRefundItemDTO.getOrderItem().getId())).findFirst().orElse(null); if (orderItemFeeRatio != null) { refundStatementLine.setBrandAuthFee(subaccountLineAmount.multiply(orderItemFeeRatio.getBrandAuthCostRatio()).setScale(2, BigDecimal.ROUND_HALF_UP)); } } refundStatementLine.setQuantity(orderRefundItemDTO.getRefundQuantity()); refundStatementLineList.add(refundStatementLine); } refundStatement.setStatementLine(refundStatementLineList); refundStatement.setCompany(company); refundStatement.setStatementAmount(subaccountAmount.negate()); return refundStatement; } @Transactional(rollbackFor = Exception.class) public void finishOrderSubaccount(Order order) { order.setSubaccountTime(LocalDateTime.now()); order.setIsSeparateAccounts(true); orderRepository.save(order); } /** * 停止订单分账 * * @param orderId 订单ID * @author huabiao * @create 2023/8/24 9:49 */ private void stopOrderSubaccount(Long orderId){ // 获取该订单所有的结算单 List<Statement> statementList = statementRepository.findAllByOrdersId(orderId); // 将结算单改为已退回 statementList.stream().forEach(statement -> statement.setStatementState(StatementState.RETURNED)); statementRepository.saveAll(statementList); } }
package com.yn.bftl.thirdparty.modules.business.service.impl; import cn.hutool.core.util.ObjectUtil; import com.alibaba.fastjson.JSONObject; import com.yn.bftl.common.common.exception.YnceError; import com.yn.bftl.common.common.util.ByxRouteUtil; import com.yn.bftl.common.common.util.RouteUtil; import com.yn.bftl.common.modules.account.entity.Payment; import com.yn.bftl.common.modules.account.enums.AccountChangeType; import com.yn.bftl.common.modules.account.enums.ChangeDirection; import com.yn.bftl.common.modules.account.enums.PaymentType; import com.yn.bftl.common.modules.account.vo.BalanceAcctsVO; import com.yn.bftl.common.modules.company.entity.Brand; import com.yn.bftl.common.modules.company.entity.Company; import com.yn.bftl.common.modules.order.entity.*; import com.yn.bftl.common.modules.order.enums.*; import com.yn.bftl.common.modules.relation.entity.BusinessRelations; import com.yn.bftl.common.modules.subaccount.entity.*; import com.yn.bftl.common.modules.subaccount.enums.StatementState; import com.yn.bftl.common.modules.subaccount.enums.StatementType; import com.yn.bftl.common.modules.subaccount.enums.SubaccountState; import com.yn.bftl.common.modules.subaccount.enums.SubaccountType; import com.yn.bftl.thirdparty.common.exception.YnceErrorException; import com.yn.bftl.thirdparty.common.repository.*; import com.yn.bftl.thirdparty.common.service.ByxTradeWayService; import com.yn.bftl.thirdparty.common.util.DateTimeUtils; import com.yn.bftl.thirdparty.common.util.SequenceUtil; import com.yn.bftl.thirdparty.modules.business.abstracts.AbstractBusinessService; import com.yn.bftl.thirdparty.modules.business.dto.AccountChangeCreateDTO; import com.yn.bftl.thirdparty.modules.business.dto.CreatePaymentDTO; import com.yn.bftl.thirdparty.modules.business.dto.OrderRefundItemDTO; import com.yn.bftl.thirdparty.modules.business.repository.ChinaumsPaymentRepository; import com.yn.bftl.thirdparty.modules.business.repository.ChinaumsRefundRepository; import com.yn.bftl.thirdparty.modules.business.service.AccountService; import com.yn.bftl.thirdparty.modules.business.service.PaymentService; import com.yn.bftl.thirdparty.modules.business.service.SubaccountService; import com.yn.bftl.thirdparty.modules.chinaums.dto.BrandAuthFeeDTO; import com.yn.bftl.thirdparty.modules.chinaums.dto.byx.ByxChinaumsGuaranteePayConfirmsDTO; import com.yn.bftl.thirdparty.modules.chinaums.dto.byx.ByxChinaumsGuaranteePayConfirmsDetailDTO; import com.yn.bftl.thirdparty.modules.chinaums.dto.chinaums.ChinaumsAllocationsDTO; import com.yn.bftl.thirdparty.modules.chinaums.dto.chinaums.ChinaumsGuaranteePayConfirmsDTO; import com.yn.bftl.thirdparty.modules.chinaums.dto.chinaums.ChinaumsGuaranteePayExtraDTO; import com.yn.bftl.thirdparty.modules.chinaums.dto.chinaums.ChinaumsTransferParamsDTO; import com.yn.bftl.thirdparty.modules.chinaums.repository.ChinaumsAuthInfoRepository; import com.yn.bftl.thirdparty.modules.chinaums.service.WalletService; import com.yn.bftl.thirdparty.modules.chinaums.util.ByxChinaumsUtil; import com.yn.bftl.thirdparty.modules.chinaums.util.ChinaumsUtil; import com.yn.bftl.thirdparty.modules.chinaums.vo.chinaums.ChinaumsAllocationsVO; import com.yn.bftl.thirdparty.modules.chinaums.vo.chinaums.ChinaumsGuaranteePayConfirmsVO; import com.yn.bftl.thirdparty.modules.chinaums.vo.chinaums.ChinaumsTransferResultsVO; import com.yn.bftl.thirdparty.modules.unionpay.enums.UnionpayAppOrderType; import com.yn.bftl.thirdparty.modules.unionpay.repository.OrderFeeRatioRepository; import com.yn.bftl.thirdparty.modules.unionpay.vo.callback.ProfitSharingCallbackVO; import com.yn.bftl.thirdparty.modules.unionpay.vo.callback.SettlementCallbackVO; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; import java.math.BigDecimal; import java.math.RoundingMode; import java.text.SimpleDateFormat; import java.time.LocalDateTime; import java.util.*; import java.util.stream.Collectors; /** * 分账服务实现 * * @author huabiao * @create 2022/9/14 17:25 **/ @Service public class SubaccountServiceImpl extends AbstractBusinessService implements SubaccountService { private static final Log log = LogFactory.getLog(SubaccountServiceImpl.class); @Resource private AfterSaleRepository afterSaleRepository; @Resource private OrderRepository orderRepository; @Resource private SubaccountRepository subaccountRepository; @Resource private StatementRepository statementRepository; @Resource private SequenceUtil sequenceUtil; @Resource private PaymentRepository paymentRepository; @Resource private ShippingRepository shippingRepository; @Resource private TemporaryStatementRepository temporaryStatementRepository; @Resource private OrderFeeRatioRepository orderFeeRatioRepository; @Resource private StatementLineRepository statementLineRepository; @Resource private WalletService walletService; @Resource private ChinaumsUtil chinaumsUtil; @Resource private OrderItemRepository orderItemRepository; @Resource private ChinaumsPaymentRepository chinaumsPaymentRepository; @Resource private CompanyRepository companyRepository; @Resource private AccountService accountService; @Resource private ChinaumsRefundRepository chinaumsRefundRepository; @Resource private BrandRepository brandRepository; @Resource private RefundRepository refundRepository; @Resource private PaymentService paymentService; @Resource private ChinaumsAuthInfoRepository chinaumsAuthInfoRepository; @Resource private ByxTradeWayService byxTradeWayService; @Resource private ByxChinaumsUtil byxChinaumsUtil; @Resource private BusinessRelationsRepository businessRelationsRepository; @Override public void generateTemporaryStatement(Long orderId) { // 查询订单 Order order = orderRepository.findById(orderId).orElse(null); if (order == null) { writeCommissionLog("[临时服务费][普通订单]订单ID:" + orderId + ",未查到"); return; } if (CollectionUtils.isEmpty(order.getReceipt())) { writeCommissionLog(String.format("[临时服务费][普通订单][%s],收款单不存在", order.getSn())); return; } // 授信支付 if (PaymentMethod.CREDIT_PAY.equals(order.getReceipt().get(0).getPaymentMethod())) { // 判断是否已支付 if (PaymentStatus.UN_PAID.equals(order.getPaymentStatus())) { writeCommissionLog(String.format("[临时服务费][普通订单][%s],订单未付款", order.getSn())); } } // 其他支付方式 else { // 查看付款单是否支付 Payment payment = paymentRepository.findFirstByOrderIdAndPayStatusOrderByIdDesc(orderId.toString(), PayStatus.SUCC); if (payment == null) { writeCommissionLog(String.format("[临时服务费][普通订单][%s],支付单未付款", order.getSn())); return; } } // 判断订单是否已创建服务单据 TemporaryStatement temporaryStatement = temporaryStatementRepository.findFirstByOrdersId(orderId); if (temporaryStatement != null) { writeCommissionLog(String.format("[临时服务费][普通订单][%s],订单已创建过临时服务费单据", order.getSn())); return; } List<TemporaryStatement> temporaryStatementList = new ArrayList<>(); // 总临时结算单数量 Integer totalNumber = 0; // 生成货款临时结算单 if (order.getGoodsPayment().compareTo(BigDecimal.ZERO) == 1) { temporaryStatementList.add(generateTemporaryStatementByType(SubaccountType.GOODS_COST, order, order.getSellerCompany())); totalNumber++; } // 生成品牌临时结算单 if (order.getBrandCost().compareTo(BigDecimal.ZERO) == 1) { temporaryStatementList.add(generateTemporaryStatementByType(SubaccountType.BRAND_FEE, order, order.getBrandCompany())); totalNumber++; } // 生成策划临时结算单 if (order.getDeviseCost().compareTo(BigDecimal.ZERO) == 1) { temporaryStatementList.add(generateTemporaryStatementByType(SubaccountType.DEVISE_FEE, order, order.getDeviseCompany())); totalNumber++; } if (totalNumber != temporaryStatementList.size()) { return; } temporaryStatementRepository.saveAll(temporaryStatementList); writeCommissionLog(String.format("[临时服务费][普通订单][%s],订单临时服务费单据已创建完成", order.getSn())); } /** * 临时结算单-根据分账类型生成 * * @param order:订单 * @param subaccountType:分账类型 * @param company:分账企业 * @return 临时结算单 * @author huabiao * @create 2022/9/19 11:24 */ private TemporaryStatement generateTemporaryStatementByType(SubaccountType subaccountType, Order order, Company company) { TemporaryStatement temporaryStatement = new TemporaryStatement(); temporaryStatement.setOrderNo(sequenceUtil.getNextSequenceNumber("TFEE")); temporaryStatement.setOrders(order); temporaryStatement.setCompany(order.getSellerCompany()); temporaryStatement.setSubaccountType(subaccountType); // 通过商品明细计算对应单据 List<TemporaryStatementLine> temporaryStatementLineList = new ArrayList<>(); // 获取订单费用比例 OrderFeeRatio orderFeeRatio = orderFeeRatioRepository.findByOrdersId(order.getId()); // 计算总结算金额 BigDecimal statementAmount = BigDecimal.ZERO; for (OrderItem orderItem : order.getOrderItems()) { TemporaryStatementLine temporaryStatementLine = new TemporaryStatementLine(); if (subaccountType.equals(SubaccountType.GOODS_COST)) { temporaryStatementLine.setStatementAmount(orderItem.getGoodsPayment()); temporaryStatementLine.setSubaccountRatio(BigDecimal.ONE.subtract(orderFeeRatio.getBrandCostRatio()).subtract(orderFeeRatio.getDeviseCostRatio())); temporaryStatementLine.setCompany(order.getSellerCompany()); } else if (subaccountType.equals(SubaccountType.BRAND_FEE)) { temporaryStatementLine.setStatementAmount(orderItem.getBrandCost()); temporaryStatementLine.setCompany(order.getBrandCompany()); temporaryStatementLine.setSubaccountRatio(orderFeeRatio != null ? orderFeeRatio.getBrandCostRatio() : null); } else if (subaccountType.equals(SubaccountType.DEVISE_FEE)) { temporaryStatementLine.setStatementAmount(orderItem.getDeviseCost()); temporaryStatementLine.setCompany(order.getDeviseCompany()); temporaryStatementLine.setSubaccountRatio(orderFeeRatio != null ? orderFeeRatio.getDeviseCostRatio() : null); } temporaryStatementLine.setTemporaryStatement(temporaryStatement); temporaryStatementLine.setOrderItem(orderItem); temporaryStatementLineList.add(temporaryStatementLine); statementAmount = statementAmount.add(temporaryStatementLine.getStatementAmount()); } temporaryStatement.setTemporaryStatementLines(temporaryStatementLineList); temporaryStatement.setStatementAmount(statementAmount); temporaryStatement.setCompany(company); // 判断订单项结算金额和订单结算金额是否一致 if (subaccountType.equals(SubaccountType.GOODS_COST) && order.getGoodsPayment().compareTo(statementAmount) != 0) { writeCommissionLog(String.format("[临时服务费][普通订单][%s],订单的货款与订单行不一致", order.getSn())); return null; } else if (subaccountType.equals(SubaccountType.BRAND_FEE) && order.getBrandCost().compareTo(statementAmount) != 0) { writeCommissionLog(String.format("[临时服务费][普通订单][%s],订单的品牌费与订单行不一致", order.getSn())); return null; } else if (subaccountType.equals(SubaccountType.DEVISE_FEE) && order.getDeviseCost().compareTo(statementAmount) != 0) { writeCommissionLog(String.format("[临时服务费][普通订单][%s],订单的策划费与订单行不一致", order.getSn())); return null; } return temporaryStatement; } @Override public void generateStatementByOrder(Long orderId) { Order order = orderRepository.findById(orderId).orElse(null); if (order == null) { writeCommissionLog("[服务费][普通订单]订单ID:" + orderId + ",订单不存在"); } // 判断是否已存在对应的结算单 if (statementRepository.existsByOrdersIdAndStatementType(orderId, StatementType.NORMALORDER)) { writeCommissionLog(String.format("[服务费][普通订单][%s],订单已创建过服务费单据", order.getSn())); } // 临时结算单 List<TemporaryStatement> temporaryStatementList = new ArrayList<>(); // 结算单 List<Statement> statementList = new ArrayList<>(); // 生成货款结算单 if (order.getGoodsPayment().compareTo(BigDecimal.ZERO) == 1) { // 获取货款临时结算单 TemporaryStatement temporaryStatement = temporaryStatementRepository.findFirstByOrdersIdAndSubaccountType(orderId, SubaccountType.GOODS_COST); if (temporaryStatement == null) { writeCommissionLog(String.format("[服务费][普通订单][%s],订单的货款临时服务费单据不存在", order.getSn())); return; } statementList.add(createStatementByTemporaryStatement(temporaryStatement, null, order, true)); temporaryStatement.setIsStatement(true); temporaryStatementList.add(temporaryStatement); } // 生成品牌结算单 if (order.getBrandCost().compareTo(BigDecimal.ZERO) == 1) { // 获取品牌临时结算单 TemporaryStatement temporaryStatement = temporaryStatementRepository.findFirstByOrdersIdAndSubaccountType(orderId, SubaccountType.BRAND_FEE); if (temporaryStatement == null) { writeCommissionLog(String.format("[服务费][普通订单][%s],订单的品牌临时服务费单据不存在", order.getSn())); return; } statementList.add(createStatementByTemporaryStatement(temporaryStatement, null, order, true)); temporaryStatement.setIsStatement(true); temporaryStatementList.add(temporaryStatement); } // 生成策划结算单 if (order.getDeviseCost().compareTo(BigDecimal.ZERO) == 1) { // 获取品牌临时结算单 TemporaryStatement temporaryStatement = temporaryStatementRepository.findFirstByOrdersIdAndSubaccountType(orderId, SubaccountType.DEVISE_FEE); if (temporaryStatement == null) { writeCommissionLog(String.format("[服务费][普通订单][%s],订单的策划临时服务费单据不存在", order.getSn())); return; } statementList.add(createStatementByTemporaryStatement(temporaryStatement, null, order, true)); temporaryStatement.setIsStatement(true); temporaryStatementList.add(temporaryStatement); } if (temporaryStatementList.size() != statementList.size()) { return; } statementRepository.saveAll(statementList); // 修改临时结算单状态 temporaryStatementRepository.saveAll(temporaryStatementList); writeCommissionLog(String.format("[服务费][普通订单][%s],订单服务费单据已创建完成", order.getSn())); } @Override public void generateStatementByShipping(Long shippingId) { // 获取发货单 Shipping shipping = shippingRepository.findById(shippingId).orElse(null); if (shipping == null) { writeCommissionLog("[服务费][普通订单]发货单ID:" + shippingId + ",发货单的不存在"); return; } // 判断发货单是否已创建结算单 Statement statementRow = statementRepository.findFirstByShippingId(shippingId); if (statementRow != null) { writeCommissionLog(String.format("[服务费][普通订单][%s][发货单][%s],发货单已创建过服务费单据", shipping.getOrders().getSn(), shipping.getShippingSn())); return; } // 获取订单数据 Order order = shipping.getOrders(); Long orderId = shipping.getOrders().getId(); // 临时结算单 List<TemporaryStatement> temporaryStatementList = new ArrayList<>(); // 结算单 List<Statement> statementList = new ArrayList<>(); // 生成货款结算单 if (order.getGoodsPayment().compareTo(BigDecimal.ZERO) == 1) { // 获取货款临时结算单 TemporaryStatement temporaryStatement = temporaryStatementRepository.findFirstByOrdersIdAndSubaccountType(orderId, SubaccountType.GOODS_COST); if (temporaryStatement == null) { writeCommissionLog(String.format("[服务费][普通订单][%s][发货单][%s],订单的货款临时服务费单据不存在", shipping.getOrders().getSn(), shipping.getShippingSn())); return; } statementList.add(createStatementByTemporaryStatement(temporaryStatement, shipping, order, false)); temporaryStatementList.add(temporaryStatement); } // 生成品牌结算单 if (order.getBrandCost().compareTo(BigDecimal.ZERO) == 1) { // 获取品牌临时结算单 TemporaryStatement temporaryStatement = temporaryStatementRepository.findFirstByOrdersIdAndSubaccountType(orderId, SubaccountType.BRAND_FEE); if (temporaryStatement == null) { writeCommissionLog(String.format("[服务费][普通订单][%s][发货单][%s],订单的品牌临时服务费单据不存在", shipping.getOrders().getSn(), shipping.getShippingSn())); return; } statementList.add(createStatementByTemporaryStatement(temporaryStatement, shipping, order, false)); temporaryStatementList.add(temporaryStatement); } // 生成策划结算单 if (order.getDeviseCost().compareTo(BigDecimal.ZERO) == 1) { // 获取品牌临时结算单 TemporaryStatement temporaryStatement = temporaryStatementRepository.findFirstByOrdersIdAndSubaccountType(orderId, SubaccountType.DEVISE_FEE); if (temporaryStatement == null) { writeCommissionLog(String.format("[服务费][普通订单][%s][发货单][%s],订单的策划临时服务费单据不存在", shipping.getOrders().getSn(), shipping.getShippingSn())); return; } statementList.add(createStatementByTemporaryStatement(temporaryStatement, shipping, order, false)); temporaryStatementList.add(temporaryStatement); } if (temporaryStatementList.size() != statementList.size()) { return; } statementRepository.saveAll(statementList); // 获取已结算单据 List<Statement> allStatementList = statementRepository.findAllByOrdersId(orderId); // 计算总结算金额 BigDecimal totalStatementAmount = allStatementList.stream().map(Statement::getStatementAmount).reduce(BigDecimal.ZERO, BigDecimal::add); // 判断该临时结算是否结算完毕 if (totalStatementAmount.compareTo(order.getPayAmount()) == 0) { for (TemporaryStatement temporaryStatement : temporaryStatementList) { temporaryStatement.setIsStatement(true); } temporaryStatementRepository.saveAll(temporaryStatementList); } writeCommissionLog(String.format("[服务费][普通订单][%s][发货单][%s],发货单服务费单据已创建完成", shipping.getOrders().getSn(), shipping.getShippingSn())); } /** * 结算单-根据临时结算单生成 * <p>若是直接结算则不需要传发货单</p> * * @param temporaryStatement 临时结算单 * @param shipping 发货单 * @param order 订单 * @param isDirectSettlement 是否直接结算 * @return 结算单 * @description * @author huabiao * @create 2022/9/2 16:15 */ private Statement createStatementByTemporaryStatement(TemporaryStatement temporaryStatement, Shipping shipping, Order order, Boolean isDirectSettlement) { // 获取订单相关数据 Long orderId = order.getId(); // 获取订单费用比例 OrderFeeRatio orderFeeRatio = orderFeeRatioRepository.findByOrdersId(orderId); // 结算单构建 Statement statement = new Statement(); statement.setOrders(order); statement.setStatementNo(sequenceUtil.getNextSequenceNumber("FEE")); statement.setStatementType(StatementType.NORMALORDER); statement.setSubaccountType(temporaryStatement.getSubaccountType()); statement.setStatementState(StatementState.NOTRECORDED); statement.setShipping(shipping); statement.setCompany(temporaryStatement.getCompany()); // 结算单项 List<StatementLine> statementLineList = new ArrayList<>(); // 结算金额 BigDecimal subaccountAmount = BigDecimal.ZERO; if (isDirectSettlement) { for (OrderItem orderItem : order.getOrderItems()) { StatementLine statementLine = new StatementLine(); statementLine.setStatement(statement); if (statement.getSubaccountType().equals(SubaccountType.GOODS_COST)) { statementLine.setSubaccountAmount(orderItem.getGoodsPayment()); statementLine.setSubaccountRatio(BigDecimal.ONE.subtract(orderFeeRatio.getBrandCostRatio()).subtract(orderFeeRatio.getDeviseCostRatio())); statementLine.setCompany(temporaryStatement.getCompany()); // 计算品牌授权费 if (CollectionUtils.isNotEmpty(orderFeeRatio.getOrderItemFeeRatio())) { OrderItemFeeRatio orderItemFeeRatio = orderFeeRatio.getOrderItemFeeRatio().stream().filter(filterOrderItemFeeRatio -> filterOrderItemFeeRatio.getOrderItem().getId().equals(orderItem.getId())).findFirst().orElse(null); if (orderItemFeeRatio != null) { statementLine.setBrandAuthFee(orderItem.getGoodsPayment().multiply(orderItemFeeRatio.getBrandAuthCostRatio()).setScale(2, BigDecimal.ROUND_HALF_UP)); } } } else if (statement.getSubaccountType().equals(SubaccountType.BRAND_FEE)) { statementLine.setSubaccountAmount(orderItem.getBrandCost()); statementLine.setCompany(temporaryStatement.getCompany()); statementLine.setSubaccountRatio(orderFeeRatio != null ? orderFeeRatio.getBrandCostRatio() : null); } else if (statement.getSubaccountType().equals(SubaccountType.DEVISE_FEE)) { statementLine.setSubaccountAmount(orderItem.getDeviseCost()); statementLine.setCompany(temporaryStatement.getCompany()); statementLine.setSubaccountRatio(orderFeeRatio != null ? orderFeeRatio.getDeviseCostRatio() : null); } statementLine.setOrderItem(orderItem); statementLine.setQuantity(orderItem.getQuantity()); subaccountAmount = subaccountAmount.add(statementLine.getSubaccountAmount()); statementLineList.add(statementLine); } // 判断订单项分账金额和订单分账金额是否一致 if (temporaryStatement.getSubaccountType().equals(SubaccountType.GOODS_COST) && order.getGoodsPayment().compareTo(subaccountAmount) != 0) { writeCommissionLog(String.format("[服务费][普通订单][%s],订单的货款与订单行不一致", order.getSn())); return null; } else if (temporaryStatement.getSubaccountType().equals(SubaccountType.BRAND_FEE) && order.getBrandCost().compareTo(subaccountAmount) != 0) { writeCommissionLog(String.format("[服务费][普通订单][%s],订单的品牌费与订单行不一致", order.getSn())); return null; } else if (temporaryStatement.getSubaccountType().equals(SubaccountType.DEVISE_FEE) && order.getDeviseCost().compareTo(subaccountAmount) != 0) { writeCommissionLog(String.format("[服务费][普通订单][%s],订单的策划费与订单行不一致", order.getSn())); return null; } } else { for (ShippingItem shippingItem : shipping.getShippingItem()) { StatementLine statementLine = new StatementLine(); List<OrderItem> orderItemList = order.getOrderItems().stream().filter(filterOrderItem -> filterOrderItem.getId().equals(Long.valueOf(shippingItem.getOrderItemId()))).collect(Collectors.toList()); if (CollectionUtils.isEmpty(orderItemList)) { writeCommissionLog(String.format("[服务费][普通订单][%s][发货单][%s],发货单的订单明细[SKU_ID:%s]不存在", shipping.getOrders().getSn(), shipping.getShippingSn(), shippingItem.getSkuId())); return null; } if (orderItemList.size() > 1) { writeCommissionLog(String.format("[服务费][普通订单][%s][发货单][%s],发货单的订单明细[SKU_ID:%s]存在多条", shipping.getOrders().getSn(), shipping.getShippingSn(), shippingItem.getSkuId())); return null; } OrderItem orderItem = orderItemList.get(0); // 获取临时结算单项 TemporaryStatementLine temporaryStatementLine = temporaryStatement.getTemporaryStatementLines().stream().filter(filterTemporaryStatementLine -> filterTemporaryStatementLine.getOrderItem().equals(orderItem)).findFirst().orElse(null); if (temporaryStatementLine == null) { writeCommissionLog(String.format("[服务费][普通订单][%s][发货单][%s],发货单的临时结算明细[SKU_ID:%s]不存在", shipping.getOrders().getSn(), shipping.getShippingSn(), shippingItem.getSkuId())); return null; } BigDecimal subaccountLineAmount; // 判断是否部分发货 if (shippingItem.getShippingQuantity().equals(orderItem.getQuantity())) { // 一次性全部发完 subaccountLineAmount = temporaryStatementLine.getStatementAmount(); } else { // 获取已结算数量 BigDecimal statementQuantity = statementLineRepository.calculateSubaccountQuantity(orderItem.getId()); // 判断是否最后一次结算 if (orderItem.getQuantity().equals(shippingItem.getShippingQuantity() + statementQuantity.intValue())) { // 最后一次发货 总的减去之前计算的 BigDecimal subaccountAmountSum = statementLineRepository.calculateSubaccountAmount(orderItem.getId()); subaccountLineAmount = temporaryStatementLine.getStatementAmount().subtract(subaccountAmountSum); } else { // 部分发货 // 计算比例 总分账*(当前发货数量/总购买数量) subaccountLineAmount = temporaryStatementLine.getStatementAmount() .multiply(new BigDecimal(shippingItem.getShippingQuantity())) .divide(new BigDecimal(orderItem.getQuantity()), 2, BigDecimal.ROUND_HALF_UP); } } statementLine.setCompany(temporaryStatementLine.getCompany()); statementLine.setSubaccountAmount(subaccountLineAmount); statementLine.setOrderItem(orderItem); statementLine.setShippingItem(shippingItem); statementLine.setSubaccountRatio(temporaryStatementLine.getSubaccountRatio()); statementLine.setStatement(statement); // 计算品牌授权费 if (statement.getSubaccountType().equals(SubaccountType.GOODS_COST) && CollectionUtils.isNotEmpty(orderFeeRatio.getOrderItemFeeRatio())) { OrderItemFeeRatio orderItemFeeRatio = orderFeeRatio.getOrderItemFeeRatio().stream().filter(filterOrderItemFeeRatio -> filterOrderItemFeeRatio.getOrderItem().getId().equals(Long.valueOf(shippingItem.getOrderItemId()))).findFirst().orElse(null); if (orderItemFeeRatio != null) { statementLine.setBrandAuthFee(subaccountLineAmount.multiply(orderItemFeeRatio.getBrandAuthCostRatio()).setScale(2, BigDecimal.ROUND_HALF_UP)); } } statementLine.setQuantity(shippingItem.getShippingQuantity()); subaccountAmount = subaccountAmount.add(subaccountLineAmount); statementLineList.add(statementLine); } } statement.setStatementLine(statementLineList); statement.setStatementAmount(subaccountAmount); return statement; } @Override public void generateStatementByAfterSale(Long afterSaleId) { AfterSale afterSale = afterSaleRepository.findById(afterSaleId).orElse(null); if (afterSale == null) { writeCommissionLog("[服务费][普通订单]售后单ID:" + afterSaleId + ",售后单不存在"); return; } // 判断是否已存在对应的结算单 if (statementRepository.existsByAfterSaleId(afterSaleId)) { writeCommissionLog(String.format("[服务费][普通订单][%s][售后单][%s],售后单已创建过服务费单据", afterSale.getOrders().getSn(), afterSale.getAfterSaleSn())); return; } List<Statement> refundStatementList = new ArrayList<>(); /** * 先算品牌和策划的退款金额,而剩下的则是货款的金额 */ // 生成品牌结算单 Order order = afterSale.getOrders(); List<Statement> statementList = statementRepository.findAllByOrdersIdAndStatementType(order.getId(), StatementType.NORMALORDER); if (CollectionUtils.isEmpty(statementList)) { writeCommissionLog(String.format("[服务费][普通订单][%s][售后单][%s],结算单不存在", afterSale.getOrders().getSn(), afterSale.getAfterSaleSn())); return; } if (order.getBrandCost().compareTo(BigDecimal.ZERO) == 1) { // 获取对应订单结算单 Statement statement = statementList.stream().filter(filterStatement -> filterStatement.getSubaccountType().equals(SubaccountType.BRAND_FEE)).findFirst().orElse(null); if (statement == null) { writeCommissionLog(String.format("[服务费][普通订单][%s][售后单][%s],对应的品牌费结算单不存在", afterSale.getOrders().getSn(), afterSale.getAfterSaleSn())); return; } Statement refundStatement = createRefundStatement(statement, afterSale); refundStatementList.add(refundStatement); } // 生成策划结算单 if (order.getDeviseCost().compareTo(BigDecimal.ZERO) == 1) { Statement statement = statementList.stream().filter(filterStatement -> filterStatement.getSubaccountType().equals(SubaccountType.DEVISE_FEE)).findFirst().orElse(null); if (statement == null) { writeCommissionLog(String.format("[服务费][普通订单][%s][售后单][%s],对应的策划费结算单不存在", afterSale.getOrders().getSn(), afterSale.getAfterSaleSn())); return; } refundStatementList.add(createRefundStatement(statement, afterSale)); } // 生成货款结算单 if (order.getGoodsPayment().compareTo(BigDecimal.ZERO) == 1) { Statement statement = statementList.stream().filter(filterStatement -> filterStatement.getSubaccountType().equals(SubaccountType.GOODS_COST)).findFirst().orElse(null); if (statement == null) { writeCommissionLog(String.format("[服务费][普通订单][%s][售后单][%s],对应的货款结算单不存在", afterSale.getOrders().getSn(), afterSale.getAfterSaleSn())); return; } // 货款退款金额 = 退款金额 - 品牌费退款金额 - 策划费退款金额 refundStatementList.add(createRefundStatement(statement, afterSale)); } // 判断退款结算单和售后单的退款金额是否一致 BigDecimal totalRefundAmount = refundStatementList.stream().map(statement -> statement.getStatementAmount()).reduce(BigDecimal.ZERO, BigDecimal::add); if (totalRefundAmount.add(afterSale.getAmount()).compareTo(BigDecimal.ZERO) != 0) { writeCommissionLog(String.format("[服务费][普通订单][%s][售后单][%s],订单对冲服务费单据金额不一致", afterSale.getOrders().getSn(), afterSale.getAfterSaleSn())); return; } statementRepository.saveAll(refundStatementList); writeCommissionLog(String.format("[服务费][普通订单][%s][售后单][%s],订单对冲服务费单据已创建完成", afterSale.getOrders().getSn(), afterSale.getAfterSaleSn())); } /** * 退款结算单-生成 * * @param statement:结算单 * @param afterSale:售后单 * @return 结算单 * @description * @author huabiao * @create 2022/9/2 16:15 */ private Statement createRefundStatement(Statement statement, AfterSale afterSale) { Long afterSaleId = afterSale.getId(); Long orderId = afterSale.getOrders().getId(); // 拼接退款结算单 Statement refundStatement = new Statement(); refundStatement.setOrders(afterSale.getOrders()); refundStatement.setStatementNo(sequenceUtil.getNextSequenceNumber("FEE")); refundStatement.setStatementType(StatementType.AFTERSALES); refundStatement.setSubaccountType(statement.getSubaccountType()); refundStatement.setStatementState(StatementState.NOTRECORDED); // 拼接退款结算单行 List<StatementLine> refundStatementLineList = new ArrayList<>(); // 退款金额 BigDecimal subaccountAmount = BigDecimal.ZERO; for (AfterSaleItem afterSaleItem : afterSale.getAfterSaleItems()) { StatementLine refundStatementLine = new StatementLine(); refundStatementLine.setStatement(refundStatement); // 退款时不会有发货单 if (afterSale.getAfterSaleType().equals(AfterSaleType.RETURN_REFUND)) { // 查找对应发货单项 List<ShippingItem> shippingItemList = afterSale.getShipping().getShippingItem().stream().filter(filterShippingItem -> filterShippingItem.getSkuId().equals(afterSaleItem.getSkuId())).collect(Collectors.toList()); if (CollectionUtils.isEmpty(shippingItemList)) { writeCommissionLog(String.format("[服务费][普通订单][%s][售后单][%s],发货单项明细[SKU_ID:[%s]不存在", afterSale.getOrders().getSn(), afterSale.getAfterSaleSn(), afterSaleItem.getSkuId())); return null; } if (shippingItemList.size() > 1) { writeCommissionLog(String.format("[服务费][普通订单][%s][售后单][%s],发货单项明细[SKU_ID:[%s]存在多条", afterSale.getOrders().getSn(), afterSale.getAfterSaleSn(), afterSaleItem.getSkuId())); return null; } ShippingItem shippingItem = shippingItemList.get(0); refundStatementLine.setShippingItem(shippingItem); } // 获取订单结算单的结算单行 List<StatementLine> statementLineList = statement.getStatementLine().stream().filter(filterStatementLine -> filterStatementLine.getOrderItem().getSkuId().equals(afterSaleItem.getSkuId())).collect(Collectors.toList()); if (CollectionUtils.isEmpty(statementLineList)) { writeCommissionLog(String.format("[服务费][普通订单][%s][售后单][%s],售后单的订单明细[SKU_ID:[%s]不存在", afterSale.getOrders().getSn(), afterSale.getAfterSaleSn(), afterSaleItem.getSkuId())); return null; } if (statementLineList.size() > 1) { writeCommissionLog(String.format("[服务费][普通订单][%s][售后单][%s],售后单的订单明细[SKU_ID:[%s]存在多条", afterSale.getOrders().getSn(), afterSale.getAfterSaleSn(), afterSaleItem.getSkuId())); return null; } StatementLine statementLine = statementLineList.get(0); // 获取订单费用比例 OrderFeeRatio orderFeeRatio = orderFeeRatioRepository.findByOrdersId(orderId); refundStatementLine.setCompany(statementLine.getCompany()); refundStatementLine.setOrderItem(statementLine.getOrderItem()); // 计算每个售后项的退款金额 BigDecimal subaccountLineAmount = BigDecimal.ZERO; switch (statement.getSubaccountType()) { case GOODS_COST: subaccountLineAmount = afterSaleItem.getAmount().multiply(BigDecimal.ONE.subtract(orderFeeRatio.getBrandCostRatio()).subtract(orderFeeRatio.getDeviseCostRatio())).setScale(2, BigDecimal.ROUND_HALF_UP); break; case BRAND_FEE: refundStatementLine.setSubaccountRatio(orderFeeRatio.getBrandCostRatio()); subaccountLineAmount = afterSaleItem.getAmount().multiply(orderFeeRatio.getBrandCostRatio()).setScale(2, BigDecimal.ROUND_HALF_UP); break; case DEVISE_FEE: refundStatementLine.setSubaccountRatio(orderFeeRatio.getDeviseCostRatio()); subaccountLineAmount = afterSaleItem.getAmount().multiply(orderFeeRatio.getDeviseCostRatio()).setScale(2, BigDecimal.ROUND_HALF_UP); break; } subaccountAmount = subaccountAmount.add(subaccountLineAmount); refundStatementLine.setSubaccountAmount(subaccountLineAmount.negate()); // 计算品牌授权费 if (statement.getSubaccountType().equals(SubaccountType.GOODS_COST) && CollectionUtils.isNotEmpty(orderFeeRatio.getOrderItemFeeRatio())) { OrderItemFeeRatio orderItemFeeRatio = orderFeeRatio.getOrderItemFeeRatio().stream().filter(filterOrderItemFeeRatio -> filterOrderItemFeeRatio.getOrderItem().getId().equals(afterSaleItem.getOrderItem().getId())).findFirst().orElse(null); if (orderItemFeeRatio != null) { refundStatementLine.setBrandAuthFee(subaccountLineAmount.multiply(orderItemFeeRatio.getBrandAuthCostRatio()).setScale(2, BigDecimal.ROUND_HALF_UP)); } } refundStatementLine.setQuantity(afterSaleItem.getQuantity()); refundStatementLineList.add(refundStatementLine); } refundStatement.setStatementLine(refundStatementLineList); refundStatement.setShipping(afterSale.getShipping()); refundStatement.setAfterSale(afterSale); refundStatement.setCompany(statement.getCompany()); refundStatement.setStatementAmount(subaccountAmount.negate()); return refundStatement; } @Override public void generateSubaccountByOrder(Long orderId) { Order order = getOrderAndCheck(orderId); if (order == null) { return; } // 获取所有的退款单并判断退款结算单是否都生成 if (checkRefundList(orderId, order)) { return; } // 根据支付方式进行分账 Receipt receipt = order.getReceipt().get(0); // 电子账簿支付 if (receipt.getPaymentMethod().equals(PaymentMethod.DEPOSIT)) { confirmsCombinedGuaranteeByOrder(order); } // POS、微信、支付宝、云闪付支付 if (receipt.getPaymentMethod().equals(PaymentMethod.WECHAT) || receipt.getPaymentMethod().equals(PaymentMethod.ALIPAY) || receipt.getPaymentMethod().equals(PaymentMethod.CHINA_UNIONPAY_QUICK_PASS) || receipt.getPaymentMethod().equals(PaymentMethod.POS) || receipt.getPaymentMethod().equals(PaymentMethod.CREDIT_PAY)) { createSubaccountByOrder(order, receipt.getPaymentMethod()); } } private boolean checkRefundList(Long orderId, Order order) { List<Refund> refundList = refundRepository.findAllByOrdersId(orderId); if (CollectionUtils.isNotEmpty(refundList)) { BigDecimal refundAmount = refundList.stream().map(Refund::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add); // 获取退款结算单 List<Statement> statementList = statementRepository.findAllByOrdersIdAndStatementType(orderId, StatementType.AFTERSALES); BigDecimal refundStatementAmount = statementList.stream().map(Statement::getStatementAmount).reduce(BigDecimal.ZERO, BigDecimal::add); if (refundAmount.add(refundStatementAmount).compareTo(BigDecimal.ZERO) != 0) { writeSeparateLog(String.format("[分账][生成][普通订单][%s],退款单金额与退款结算单金额不一致,分账失败。", order.getSn())); return true; } // 判断所有退款单状态是否都为已退款 if(refundList.stream().filter(refund -> !RefundStatus.REFUNDED.equals(refund.getRefundStatus())).findAny().isPresent()){ writeSeparateLog(String.format("[分账][生成][普通订单][%s],存在未完成退款的退款单,分账失败。", order.getSn())); return true; } } return false; } private Order getOrderAndCheck(Long orderId) { Order order = orderRepository.findById(orderId).orElse(null); if (order == null) { throw new YnceErrorException(YnceError.YNCE_204003); } // 判断订单是否在申请售后中 if (order.getIsReturnRefund() || order.getIsRefund()) { writeSeparateLog(String.format("[分账][生成][普通订单][%s],订单在售后中。", order.getSn())); return null; } // 判断是否当前订单所有的商品是否全部退货 Optional<OrderItem> orderItemOptional = order.getOrderItems().stream().filter(orderItem -> orderItem.getQuantity() > (orderItem.getReturnCount() + orderItem.getCloseCount())).findAny(); if (BooleanUtils.isFalse(orderItemOptional.isPresent())) { // 此订单下面的所有商品已全部退退货,不执行分账 stopOrderSubaccount(order.getId()); writeSeparateLog(String.format("[分账][生成][普通订单][%s],订单已退货,不执行分账。", order.getSn())); return null; } // 判断当前订单是否已经退款 if (order.getPaymentStatus().equals(PaymentStatus.REFUNDED)) { stopOrderSubaccount(order.getId()); writeSeparateLog(String.format("[分账][生成][普通订单][%s],订单已退款,不执行分账。", order.getSn())); return null; } return order; } @Override public void handleSubaccount(SettlementCallbackVO settlementCallbackVO) { // 获取分账单 List<Subaccount> subaccountList = subaccountRepository.findAllByExternalId(settlementCallbackVO.getSettOrderNo()); Boolean isSeparate = false; // 存在订单结算和发货单结算 Long orderId = null; Long shippingId = null; for (Subaccount subaccount : subaccountList) { orderId = subaccount.getOrders().getId(); if (subaccount.getShipping() != null) { shippingId = subaccount.getShipping().getId(); } ProfitSharingCallbackVO profitSharingCallbackVO = settlementCallbackVO.getProfitSharingList().stream().filter(filterProfitSharingCallbackVO -> filterProfitSharingCallbackVO.getProfitSharingWalletId().equals(subaccount.getCompany().getWalletId())).findFirst().orElse(null); if (profitSharingCallbackVO != null) { // 分账成功 if (profitSharingCallbackVO.getProfitSharingStatus().equals("02")) { subaccount.setSeparateTime(LocalDateTime.now()); subaccount.setSubaccountState(SubaccountState.SEPARATE_SUCC); subaccountRepository.save(subaccount); } // 分账失败 else if (profitSharingCallbackVO.getProfitSharingStatus().equals("03")) { subaccount.setSubaccountState(SubaccountState.SEPARATE_FAIL); subaccountRepository.save(subaccount); } } } if (isSeparate) { if (shippingId != null) { // 更新发货单已分账 shippingRepository.updateIsSeparateAccountsById(orderId); } else if (orderId != null) { // 更新订单已分账 orderRepository.updateIsSeparateAccountsById(orderId); } } } @Override public void handleBrandAuthFee(String subaccountNo) { // 获取所有品牌授权费 Subaccount subaccount = subaccountRepository.findBySubaccountNo(subaccountNo); if (ObjectUtil.isNull(subaccount)) { throw new YnceErrorException("分帐单不存在"); } if (!subaccount.getSubaccountType().equals(SubaccountType.BRAND_AUTH_FEE)) { throw new YnceErrorException("分帐单类型不是品牌授权费"); } if (subaccount.getOrders().getIsSeparateAccounts()) { throw new YnceErrorException("对应订单已分账"); } // 查询订单 Order order = orderRepository.findById(subaccount.getOrders().getId()).orElse(null); if (ObjectUtil.isNull(order)) { throw new YnceErrorException(YnceError.YNCE_211004); } // 区分预存款和其他支付方式 Receipt receipt = order.getReceipt().get(0); // 获取货款数据,可获得品牌授权费 Subaccount goodsCostSubaccount = subaccountRepository.findByOrdersIdAndSubaccountType(order.getId(), SubaccountType.GOODS_COST); // 预存款支付 if (receipt.getPaymentMethod().equals(PaymentMethod.DEPOSIT)) { // 品牌授权费差额 = 银联支付单金额-已分账金额 ChinaumsPayment chinaumsPayment = chinaumsPaymentRepository.findFirstByOrdersIdAndSubaccountType(order.getId(), SubaccountType.BRAND_AUTH_FEE); BigDecimal balance = chinaumsPayment.getAmount().subtract(subaccount.getSubaccountAmount()); // 调用分账确认接口 // 拼接扩展字段:商品信息 ChinaumsGuaranteePayExtraDTO chinaumsGuaranteePayExtraDTO = new ChinaumsGuaranteePayExtraDTO(); chinaumsGuaranteePayExtraDTO.setProductInfos(this.handleProductInfoByOrder(order.getOrderItems(), order.getSn(), order.getAmount(), balance)); // 拼接分账确认请求参数 ChinaumsGuaranteePayConfirmsDTO chinaumsGuaranteePayConfirmsDTO = ChinaumsGuaranteePayConfirmsDTO .builder() .outOrderNo(subaccount.getSubaccountNo() + "-BALANCE") .guaranteePaymentId(chinaumsPayment.getGuaranteePaymentId()) .sentAt(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX").format(new Date())) .amount(balance.multiply(new BigDecimal(100)).intValue()) .extra(chinaumsGuaranteePayExtraDTO) .build(); ChinaumsGuaranteePayConfirmsVO chinaumsGuaranteePayConfirmsVO; try { chinaumsGuaranteePayConfirmsVO = walletService.paySettlement(chinaumsGuaranteePayConfirmsDTO); } catch (Exception exception) { throw new YnceErrorException("分账确认失败"); } // 当为处理中时需要调用接口查询 if (chinaumsGuaranteePayConfirmsVO.getStatus().equals("processing")) { try { long currentTimeMillis = System.currentTimeMillis(); while (true) { JSONObject jsonObject = new JSONObject(); jsonObject.put("combinedGuaranteeConfirmId", chinaumsGuaranteePayConfirmsVO.getCombinedGuaranteeConfirmId()); chinaumsGuaranteePayConfirmsVO = chinaumsUtil.execute(RouteUtil.ROUTE_WALLET_COMBINED_GUARANTEE_PAYMENTS_CONFIRMS_BY_SYS_NO, jsonObject, ChinaumsGuaranteePayConfirmsVO.class); // 当请求成功或者时间超时时,结束循环 if (!chinaumsGuaranteePayConfirmsVO.getStatus().equals("processing") || System.currentTimeMillis() - currentTimeMillis > 5000) { break; } } } catch (Exception exception) { log.error(exception.getMessage()); throw new YnceErrorException("循环查询合并消费担保确认失败"); } } subaccount.setExternalId(subaccount.getExternalId() + "," + chinaumsGuaranteePayConfirmsVO.getCombinedGuaranteeConfirmId()); writeSeparateLog(String.format("[分账][生成][普通订单][%s],生成差额分账单成功,银联结算单号[%s]。", order.getSn(), chinaumsGuaranteePayConfirmsVO.getCombinedGuaranteeConfirmId())); // 修改分账总金额 subaccount.setSubaccountTotalAmount(goodsCostSubaccount.getBrandAuthFee()); // 修改分账净额 subaccount.setSubaccountAmount(chinaumsPayment.getAmount()); // 修改服务费比例 OrderFeeRatio orderFeeRatio = orderFeeRatioRepository.findByOrdersId(order.getId()); if (CollectionUtils.isNotEmpty(orderFeeRatio.getOrderItemFeeRatio())) { subaccount.setPlatformServiceCostRatio(orderFeeRatio.getOrderItemFeeRatio().get(0).getBrandAuthCostServiceCostRatio()); } // 修改平台服务费:平台服务费 = 分账总额 - 分账净额 subaccount.setPlatformServiceFee(subaccount.getSubaccountTotalAmount().subtract(subaccount.getSubaccountAmount())); subaccountRepository.save(subaccount); // 处理预存款账户 AccountChangeCreateDTO accountChangeCreateDTO = AccountChangeCreateDTO .builder() .company(subaccount.getCompany()) .direction(ChangeDirection.ADD) .type(AccountChangeType.valueOf(SubaccountType.BRAND_AUTH_FEE.getValue())) .amount(balance) .sourceNo(chinaumsGuaranteePayConfirmsDTO.getOutOrderNo()) .sourceCompanyId(subaccount.getSourceCompany().getId()) .build(); accountService.intoAccount(accountChangeCreateDTO); // 修改已确认金额 chinaumsPayment.setConfirmedAmount(chinaumsPayment.getConfirmedAmount().add(balance)); chinaumsPaymentRepository.saveAndFlush(chinaumsPayment); } else { // 其他支付方式所生成的分帐单金额是正确的,但是分帐单有问题 // 修改分账总金额 subaccount.setSubaccountTotalAmount(goodsCostSubaccount.getBrandAuthFee()); // 修改服务费比例 OrderFeeRatio orderFeeRatio = orderFeeRatioRepository.findByOrdersId(order.getId()); if (CollectionUtils.isNotEmpty(orderFeeRatio.getOrderItemFeeRatio())) { subaccount.setPlatformServiceCostRatio(orderFeeRatio.getOrderItemFeeRatio().get(0).getBrandAuthCostServiceCostRatio()); } // 修改平台服务费:平台服务费 = 分账总额 - 分账净额 subaccount.setPlatformServiceFee(subaccount.getSubaccountTotalAmount().subtract(subaccount.getSubaccountAmount())); subaccountRepository.save(subaccount); } } @Override @Transactional(rollbackFor = Exception.class) public void generateStatementByOrderRefund(Long orderId) { Order order = orderRepository.findById(orderId).orElse(null); if (order == null) { throw new YnceErrorException(YnceError.YNCE_204003); } // 获取所有退款单 List<Refund> refundList = refundRepository.findAllByOrdersId(orderId); if (CollectionUtils.isNotEmpty(refundList)) { List<OrderRefundItemDTO> orderRefundItemDTOList = new ArrayList<>(); // 拼接订单退款项DTO for (OrderItem orderItem : order.getOrderItems()) { if (orderItem.getCloseCount() > 0) { OrderRefundItemDTO orderRefundItemDTO = new OrderRefundItemDTO(); orderRefundItemDTO.setOrderItem(orderItem); orderRefundItemDTO.setRefundAmount(orderItem.getRefundAmount()); orderRefundItemDTO.setRefundQuantity(orderItem.getCloseCount()); orderRefundItemDTOList.add(orderRefundItemDTO); } } if (CollectionUtils.isEmpty(orderRefundItemDTOList)) { return; } // 总退款金额 BigDecimal totalCloseAmount = refundList.stream().map(Refund::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add); List<Statement> refundStatementList = new ArrayList<>(); // 生成品牌结算单 if (order.getBrandCost().compareTo(BigDecimal.ZERO) == 1) { refundStatementList.add(createRefundStatement(SubaccountType.BRAND_FEE, order, orderRefundItemDTOList, order.getBrandCompany())); } // 生成策划结算单 if (order.getDeviseCost().compareTo(BigDecimal.ZERO) == 1) { refundStatementList.add(createRefundStatement(SubaccountType.DEVISE_FEE, order, orderRefundItemDTOList, order.getDeviseCompany())); } // 生成货款结算单 if (order.getGoodsPayment().compareTo(BigDecimal.ZERO) == 1) { // 货款退款金额 = 退款金额 - 品牌费退款金额 - 策划费退款金额 refundStatementList.add(createRefundStatement(SubaccountType.GOODS_COST, order, orderRefundItemDTOList, order.getSellerCompany())); } // 判断金额是否一致 BigDecimal totalRefundAmount = refundStatementList.stream().map(Statement::getStatementAmount).reduce(BigDecimal.ZERO, BigDecimal::add); if (totalRefundAmount.add(totalCloseAmount).compareTo(BigDecimal.ZERO) != 0) { log.error("订单关闭生成退款结算单失败:退款金额不一致"); return; } statementRepository.saveAll(refundStatementList); } } @Override public void handleGoodsCost(String subaccountNo, List<Long> orderItemIdList) { // 获取货款分帐单 Subaccount subaccount = subaccountRepository.findBySubaccountNo(subaccountNo); if (subaccount == null) { throw new YnceErrorException("分帐单不存在"); } if (!subaccount.getSubaccountType().equals(SubaccountType.GOODS_COST)) { throw new YnceErrorException("分帐单类型不是货款"); } if (subaccount.getOrders().getIsSeparateAccounts()) { throw new YnceErrorException("对应订单已分账"); } // 查询订单 Order order = orderRepository.findById(subaccount.getOrders().getId()).orElse(null); if (order == null) { throw new YnceErrorException(YnceError.YNCE_211004); } // 区分预存款和其他支付方式 Receipt receipt = order.getReceipt().get(0); // 预存款支付 if (receipt.getPaymentMethod().equals(PaymentMethod.DEPOSIT)) { // 货款差额 = 银联支付单金额-银联退款单金额-已分账金额 // 获取银联支付单 ChinaumsPayment chinaumsPayment = chinaumsPaymentRepository.findFirstByOrdersIdAndSubaccountType(order.getId(), SubaccountType.GOODS_COST); // 获取银联退款单 List<ChinaumsRefund> chinaumsRefundList = chinaumsRefundRepository.findAllByOrigTradeId(chinaumsPayment.getGuaranteePaymentId()); BigDecimal chinaumsRefundAmount = CollectionUtils.isNotEmpty(chinaumsRefundList) ? chinaumsRefundList.stream().map(ChinaumsRefund::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add) : BigDecimal.ZERO; BigDecimal balance = chinaumsPayment.getAmount().subtract(chinaumsRefundAmount).subtract(subaccount.getSubaccountAmount()); if (balance.compareTo(BigDecimal.ZERO) == 0) { throw new YnceErrorException("货款差额为0,无需补充"); } // 拼接扩展字段:商品信息 ChinaumsGuaranteePayExtraDTO chinaumsGuaranteePayExtraDTO = new ChinaumsGuaranteePayExtraDTO(); List<OrderItem> orderItemList = new ArrayList<>(); BigDecimal orderAmount = BigDecimal.ZERO; if (CollectionUtils.isNotEmpty(orderItemIdList)) { for (OrderItem orderItem : order.getOrderItems()) { if (orderItemIdList.contains(orderItem.getId())) { orderItemList.add(orderItem); orderAmount = orderAmount.add(orderItem.getAmount()); } } } else { orderItemList = order.getOrderItems(); orderAmount = order.getAmount(); } chinaumsGuaranteePayExtraDTO.setProductInfos(this.handleProductInfoByOrder(orderItemList, order.getSn(), orderAmount, balance)); // 拼接分账确认请求参数 ChinaumsGuaranteePayConfirmsDTO chinaumsGuaranteePayConfirmsDTO = ChinaumsGuaranteePayConfirmsDTO .builder() .outOrderNo(subaccount.getSubaccountNo() + "-BALANCE") .guaranteePaymentId(chinaumsPayment.getGuaranteePaymentId()) .sentAt(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX").format(new Date())) .amount(balance.multiply(new BigDecimal(100)).intValue()) .extra(chinaumsGuaranteePayExtraDTO) .build(); ChinaumsGuaranteePayConfirmsVO chinaumsGuaranteePayConfirmsVO; try { chinaumsGuaranteePayConfirmsVO = walletService.paySettlement(chinaumsGuaranteePayConfirmsDTO); } catch (Exception exception) { throw new YnceErrorException("分账确认失败"); } // 当为处理中时需要调用接口查询 if (chinaumsGuaranteePayConfirmsVO.getStatus().equals("processing")) { try { long currentTimeMillis = System.currentTimeMillis(); while (true) { JSONObject jsonObject = new JSONObject(); jsonObject.put("combinedGuaranteeConfirmId", chinaumsGuaranteePayConfirmsVO.getCombinedGuaranteeConfirmId()); chinaumsGuaranteePayConfirmsVO = chinaumsUtil.execute(RouteUtil.ROUTE_WALLET_COMBINED_GUARANTEE_PAYMENTS_CONFIRMS_BY_SYS_NO, jsonObject, ChinaumsGuaranteePayConfirmsVO.class); // 当请求成功或者时间超时时,结束循环 if (!chinaumsGuaranteePayConfirmsVO.getStatus().equals("processing") || System.currentTimeMillis() - currentTimeMillis > 5000) { break; } } } catch (Exception exception) { log.error(exception.getMessage()); throw new YnceErrorException("循环查询合并消费担保确认失败"); } } subaccount.setExternalId(subaccount.getExternalId() + "," + chinaumsGuaranteePayConfirmsVO.getCombinedGuaranteeConfirmId()); writeSeparateLog(String.format("[分账][生成][普通订单][%s],生成差额分账单成功,银联结算单号[%s]。", order.getSn(), chinaumsGuaranteePayConfirmsVO.getCombinedGuaranteeConfirmId())); // 修改分账净额 subaccount.setSubaccountAmount(subaccount.getSubaccountAmount().add(balance)); subaccountRepository.save(subaccount); // 处理预存款账户 AccountChangeCreateDTO accountChangeCreateDTO = AccountChangeCreateDTO .builder() .company(subaccount.getCompany()) .direction(ChangeDirection.ADD) .type(AccountChangeType.valueOf(SubaccountType.BRAND_AUTH_FEE.getValue())) .amount(balance) .sourceNo(chinaumsGuaranteePayConfirmsDTO.getOutOrderNo()) .sourceCompanyId(subaccount.getSourceCompany().getId()) .build(); accountService.intoAccount(accountChangeCreateDTO); // 修改已确认金额 chinaumsPayment.setConfirmedAmount(chinaumsPayment.getConfirmedAmount().add(balance)); chinaumsPaymentRepository.saveAndFlush(chinaumsPayment); } } @Override @Transactional(rollbackFor = Exception.class) public void generateRefundSubaccount(SubaccountRefund subaccountRefund) { Subaccount subaccount = new Subaccount(); subaccount.setSubaccountNo(sequenceUtil.getNextSequenceNumber("FZ")); subaccount.setCompany(subaccountRefund.getRefundCompany()); subaccount.setSubaccountCostRatio(subaccountRefund.getSubaccountCostRatio()); subaccount.setSubaccountAmount(subaccountRefund.getAmount().negate()); subaccount.setSubaccountTotalAmount(subaccountRefund.getAmount().negate()); subaccount.setSubaccountType(subaccountRefund.getSubaccountType()); subaccount.setOrders(subaccountRefund.getOrders()); subaccount.setSubaccountState(SubaccountState.SEPARATE_SUCC); subaccount.setSeparateTime(subaccountRefund.getRefundTime()); subaccount.setExternalId(subaccountRefund.getExternalId()); subaccount.setExternalTime(subaccountRefund.getRefundTime()); subaccount.setSourceCompany(subaccountRefund.getRefundCompany()); subaccount.setExternalTime(subaccountRefund.getRefundTime()); subaccountRepository.saveAndFlush(subaccount); // 对供应商流水进行处理 AccountChangeCreateDTO supplierAccountChangeCreateDTO = AccountChangeCreateDTO .builder() .company(subaccount.getCompany()) .direction(ChangeDirection.REDUCE) .type(AccountChangeType.REFUND) .amount(subaccountRefund.getAmount()) .sourceCompanyId(subaccountRefund.getReceiptCompany().getId()) .sourceNo(subaccountRefund.getRefundSn()) .build(); accountService.intoAccount(supplierAccountChangeCreateDTO); // 对经销商流水进行处理 AccountChangeCreateDTO dealerAccountChangeCreateDTO = AccountChangeCreateDTO .builder() .company(subaccountRefund.getReceiptCompany()) .direction(ChangeDirection.ADD) .type(AccountChangeType.REFUND) .amount(subaccountRefund.getAmount()) .sourceCompanyId(subaccountRefund.getRefundCompany().getId()) .sourceNo(subaccountRefund.getRefundSn()) .build(); accountService.intoAccount(dealerAccountChangeCreateDTO); } @Override public void generateSubaccountByShipping(Long shippingId) { Shipping shipping = shippingRepository.findById(shippingId).orElse(null); if (shipping == null) { throw new YnceErrorException(YnceError.YNCE_204010); } // 判断发货单是否售后中 AfterSale afterSale = afterSaleRepository.findFirstByShippingIdAndAfterSaleStatus(shipping.getId(), AfterSaleStatus.CREATED); if (afterSale != null) { writeSeparateLog(String.format("[分账][生成][普通订单][%s][发货单][%s],发货单在售后中。", shipping.getOrders().getSn(), shipping.getShippingSn())); return; } // 判断当前发货单是否已全部退货,若是则不参与分账 Optional<ShippingItem> shippingItemOptional = shipping.getShippingItem().stream().filter(shippingItem -> !shippingItem.getReturnQuantity().equals(shippingItem.getShippingQuantity())).findAny(); if (BooleanUtils.isFalse(shippingItemOptional.isPresent())) { // 此发货单下面的所有商品已全部退退货,不执行分账 updateIsSeparateAccountsByShipping(shipping); writeSeparateLog(String.format("[分账][生成][普通订单][%s][发货单][%s],不执行分账。", shipping.getOrders().getSn(), shipping.getShippingSn())); return; } // 根据支付方式进行分账 Receipt receipt = shipping.getOrders().getReceipt().get(0); // 电子账簿支付 if (receipt.getPaymentMethod().equals(PaymentMethod.DEPOSIT)) { confirmsCombinedGuaranteeByShipping(shipping); } // POS、微信、支付宝、云闪付支付 if (receipt.getPaymentMethod().equals(PaymentMethod.WECHAT) || receipt.getPaymentMethod().equals(PaymentMethod.ALIPAY) || receipt.getPaymentMethod().equals(PaymentMethod.CHINA_UNIONPAY_QUICK_PASS) || receipt.getPaymentMethod().equals(PaymentMethod.POS) || receipt.getPaymentMethod().equals(PaymentMethod.CREDIT_PAY)) { // 判断支付时间是否超过T+1 createSubaccountByShipping(shipping, receipt.getPaymentMethod()); } } /** * 生成平台服务费分账单 * * @param subaccountCostRatio :分账比例 * @param subaccountAmount :分账金额 * @param order :订单 * @param shipping :发货单 * @param sourceCompany :来源企业 * @return 分账单 * @author huabiao * @create 2022/9/17 16:51 */ private Subaccount generatePlatformSubaccount(BigDecimal subaccountCostRatio, BigDecimal subaccountAmount, Order order, Shipping shipping, Company sourceCompany) { Subaccount subaccount = new Subaccount(); subaccount.setSubaccountNo(sequenceUtil.getNextSequenceNumber("FZ")); subaccount.setSubaccountCostRatio(subaccountCostRatio); subaccount.setSubaccountAmount(subaccountAmount); subaccount.setSubaccountTotalAmount(subaccountAmount); subaccount.setSubaccountType(SubaccountType.SERVICE_FEE); subaccount.setOrders(order); subaccount.setShipping(shipping); subaccount.setSubaccountState(SubaccountState.SEPARATE_NOT); subaccount.setSourceCompany(sourceCompany); return subaccount; } @Override public String createPayment(Order order, PaymentType paymentType, UnionpayAppOrderType unionpayAppOrderType, String unionpaySn, PosPaymentType posType, String hardwareSn) { if (!PaymentStatus.UN_PAID.equals(order.getPaymentStatus())) { throw new YnceErrorException(YnceError.YNCE_204004); } if (paymentType == null) { paymentType = PaymentType.ORDER; } // 校验订单支付单状态 if (!PaymentType.RECHARGE.equals(paymentType)) { paymentService.checkPaymentStatus(order); } // 拼接支付单参数 CreatePaymentDTO createPaymentDTO = new CreatePaymentDTO(); createPaymentDTO.setPaymentMethod(PaymentMethod.valueOf(unionpayAppOrderType.getValue())); createPaymentDTO.setPayerId(order.getBuyerCompany().getId().toString()); createPaymentDTO.setPayerName(order.getBuyerCompany().getName()); createPaymentDTO.setPayeeId(order.getSellerCompany().getId().toString()); createPaymentDTO.setPayeeName(order.getSellerCompany().getName()); createPaymentDTO.setAmount(order.getAmount().subtract(order.getPayAmount())); createPaymentDTO.setPaymentType(paymentType); if (paymentType.equals(PaymentType.RECHARGE)) { createPaymentDTO.setTopUpOrderId(order.getId()); } else { createPaymentDTO.setOrderId(order.getId().toString()); } createPaymentDTO.setErpAccountSet(order.getErpAccountSet()); if (UnionpayAppOrderType.POS.equals(unionpayAppOrderType)) { createPaymentDTO.setPosPaymentType(posType); } createPaymentDTO.setExternalId(unionpaySn); createPaymentDTO.setUnionpaySn(unionpaySn); createPaymentDTO.setHardwareSn(hardwareSn); return createPayment(createPaymentDTO); } /*** * 支付单-创建 * * @param createPaymentDTO:创建支付单DTO * @return 银联订单号/支付单号 * @description * @author huabiao * @create 2022/9/1 16:46 */ @Transactional(rollbackFor = Exception.class) public String createPayment(CreatePaymentDTO createPaymentDTO) { Payment payment = new Payment(); payment.setSn(sequenceUtil.getNextSequenceNumber("ZF")); payment.setPayStatus(PayStatus.READY); BeanUtils.copyProperties(createPaymentDTO, payment); paymentRepository.saveAndFlush(payment); return payment.getSn(); } /** * 处理商品数据 * * @param orderItemList:订单项 * @param sn:订单号 * @param orderAmount:订单金额 * @param amount:分摊金额 * @return 处理完的银联JSON数据 * @author huabiao * @create 2022/12/15 14:08 */ private List<JSONObject> handleProductInfoByOrder(List<OrderItem> orderItemList, String sn, BigDecimal orderAmount, BigDecimal amount) { // 循环订单项 List<JSONObject> productInfos = new ArrayList<>(); BigDecimal allocatedAmount = BigDecimal.ZERO; for (int i = 0; i < orderItemList.size(); i++) { OrderItem orderItem = orderItemList.get(i); JSONObject jsonObject = new JSONObject(); jsonObject.put("orderNo", sn + "-" + orderItem.getId()); // 按比例计算,最后一项直接减完 if (i == (orderItemList.size() - 1)) { jsonObject.put("orderAmount", amount.subtract(allocatedAmount).multiply(new BigDecimal(100)).intValue()); } else { BigDecimal orderItemPlatformServiceFee = amount.multiply(orderItem.getAmount()).divide(orderAmount, 2, BigDecimal.ROUND_DOWN); // 当计算结果不大于0时,赋值0.01 if (orderItemPlatformServiceFee.compareTo(BigDecimal.ZERO) != 1) { orderItemPlatformServiceFee = new BigDecimal("0.01"); } jsonObject.put("orderAmount", orderItemPlatformServiceFee.multiply(new BigDecimal(100)).intValue()); allocatedAmount = allocatedAmount.add(orderItemPlatformServiceFee); } jsonObject.put("productName", orderItem.getGoodsName() + orderItem.getSkuName()); jsonObject.put("productCount", orderItem.getQuantity()); productInfos.add(jsonObject); } return productInfos; } /** * 处理商品数据 * * @param shippingItems:订单项 * @param sn:订单号 * @param shippingAmount:发货金额 * @param amount:分摊金额 * @return 处理完的银联JSON数据 * @author huabiao * @create 2022/12/15 14:08 */ private List<JSONObject> handleProductInfoByShipping(List<ShippingItem> shippingItems, String sn, BigDecimal shippingAmount, BigDecimal amount) { // 循环订单项 List<JSONObject> productInfos = new ArrayList<>(); BigDecimal allocatedAmount = BigDecimal.ZERO; for (int i = 0; i < shippingItems.size(); i++) { ShippingItem shippingItem = shippingItems.get(i); JSONObject jsonObject = new JSONObject(); // 找到对应的订单项 OrderItem orderItem = orderItemRepository.findById(Long.valueOf(shippingItem.getOrderItemId())).orElse(null); jsonObject.put("orderNo", sn + "-" + orderItem.getId()); // 按比例计算,最后一项直接减完 if (i == (shippingItems.size() - 1)) { jsonObject.put("orderAmount", amount.subtract(allocatedAmount).multiply(new BigDecimal(100)).intValue()); } else { BigDecimal orderItemPlatformServiceFee = amount.multiply(shippingItem.getAmount()).divide(shippingAmount, 2, BigDecimal.ROUND_DOWN); jsonObject.put("orderAmount", orderItemPlatformServiceFee.multiply(new BigDecimal(100)).intValue()); allocatedAmount = allocatedAmount.add(orderItemPlatformServiceFee); } jsonObject.put("productName", shippingItem.getGoodsName() + shippingItem.getSkuName()); jsonObject.put("productCount", shippingItem.getShippingQuantity()); productInfos.add(jsonObject); } return productInfos; } /** * 判断是否分账 * * @param subaccountList:分账记录数组 * @param chinaumsPaymentList:银联支付单数组 * @param isNoPlatformSubaccount:是否无平台分账 * @return true:已分账;false:未分账; * @description * @author huabiao * @create 2022/12/16 17:55 */ private Boolean checkIsSubaccount(List<Subaccount> subaccountList, List<ChinaumsPayment> chinaumsPaymentList, Boolean isNoPlatformSubaccount) { // 判断分帐单是否已经生成: // 1.判断是否存在分账记录; // 2.判断分账记录跟银联支付单数量是否一致 // 3.分账记录必须为成功 if (subaccountList.stream().filter(subaccount -> !subaccount.getSubaccountState().equals(SubaccountState.SEPARATE_SUCC)).count() > 0) { return false; } if (CollectionUtils.isNotEmpty(subaccountList) && CollectionUtils.isNotEmpty(chinaumsPaymentList)) { // 非平台分账记录数量 Integer noPlatformSubaccountSize = Math.toIntExact(subaccountList.stream().filter(subaccount -> subaccount.getCompany() != null).count()); // 平台分账记录数量:由于是一张银联支付单分成多张分账记录,所以这里只需要判断是否存在即可 Integer platformSubaccountSize = subaccountList.stream().filter(subaccount -> subaccount.getCompany() == null).findFirst().isPresent() ? 1 : (isNoPlatformSubaccount ? 1 : 0); if ((noPlatformSubaccountSize + platformSubaccountSize) == chinaumsPaymentList.size()) { return true; } } return false; } /** * 校验是否分账 * * @param subaccountList 分账记录 * @return true:已分账;false:未分账; * @description 只需判断已分账的金额之和是否和订单金额是否一致 * @author huabiao * @create 2023/2/11 14:49 */ private Boolean checkIsSubaccountOrder(List<Subaccount> subaccountList) { if (CollectionUtils.isEmpty(subaccountList)) { return false; } Order order = subaccountList.get(0).getOrders(); BigDecimal totalSubaccountAmount = subaccountList.stream().filter(subaccount -> subaccount.getSubaccountState().equals(SubaccountState.SEPARATE_SUCC)) .collect(Collectors.toList()).stream().map(Subaccount::getSubaccountAmount) .reduce(BigDecimal.ZERO, BigDecimal::add); if (totalSubaccountAmount.compareTo(order.getPayAmount().subtract(order.getRefundAmount())) == 0) { return true; } else { return false; } } /** * 校验是否分账 * * @param subaccountList 分账记录 * @return true:已分账;false:未分账; * @description 只需判断已分账的金额之和是否和发货单金额是否一致 * @author huabiao * @create 2023/2/11 14:49 */ private Boolean checkIsSubaccountByShipping(List<Subaccount> subaccountList) { if (CollectionUtils.isEmpty(subaccountList)) { return false; } Shipping shipping = subaccountList.get(0).getShipping(); BigDecimal totalSubaccountAmount = subaccountList.stream().filter(subaccount -> subaccount.getSubaccountState().equals(SubaccountState.SEPARATE_SUCC)) .collect(Collectors.toList()).stream().map(Subaccount::getSubaccountAmount) .reduce(BigDecimal.ZERO, BigDecimal::add); if (totalSubaccountAmount.compareTo(shipping.getPayAmount()) == 0) { return true; } else { return false; } } /** * 处理分账状态 * * @param subaccount 分账记录 * @param isOnlinePayment 是否线上支付(区分不同分账形式) * @author huabiao * @description 线上支付为POS支付和B2C支付,非线上支付为电子账簿支付 * @create 2022/12/21 14:46 */ @Transactional(rollbackFor = Exception.class) public void handleSubaccountStatus(Subaccount subaccount, Boolean isOnlinePayment) { // 分账状态 String subaccountStatus; // 分账时间 String finishedAt; // 当分账成功则返回 if (subaccount.getSubaccountState().equals(SubaccountState.SEPARATE_SUCC)) { return; } if (isOnlinePayment) { try { JSONObject jsonObject = new JSONObject(); jsonObject.put("transferId", subaccount.getExternalId()); ChinaumsGuaranteePayConfirmsVO chinaumsGuaranteePayConfirmsVO = chinaumsUtil.execute(RouteUtil.ROUTE_WALLET_UPAPI_ALLOCATIONS_TRANSFERS_BY_SYS_NO, jsonObject, ChinaumsGuaranteePayConfirmsVO.class); subaccountStatus = chinaumsGuaranteePayConfirmsVO.getStatus(); finishedAt = chinaumsGuaranteePayConfirmsVO.getFinishedAt(); } catch (Exception exception) { return; } } else { JSONObject params = new JSONObject(); params.put("settOrderNo", subaccount.getExternalId()); JSONObject result = byxChinaumsUtil.execute(ByxRouteUtil.ROUTE_WALLET_COMBINED_GUARANTEE_PAYMENTS_CONFIRMS_QUERY, params, JSONObject.class); if (result == null || result.get("settStatus") == null || result.get("settDate") == null) { return; } subaccountStatus = result.get("settStatus").toString(); finishedAt = result.get("settDate").toString(); // subaccountStatus: //00:未处理 //01:处理中 //02:结算成功 //03:部分结算成功 //04:结算失败 switch (subaccountStatus) { case "02": subaccountStatus = "succeeded";break; case "04": subaccountStatus = "failed";break; } } handleSubaccountStatus(subaccount, subaccountStatus, finishedAt); } private void handleSubaccountStatus(Subaccount subaccount, String subaccountStatus, String finishedAt) { if (subaccountStatus.equals("succeeded")) { handleSubaccountStatusSuccess(subaccount, finishedAt); } else if (subaccountStatus.equals("failed")) { subaccount.setSubaccountState(SubaccountState.SEPARATE_FAIL); } subaccountRepository.saveAndFlush(subaccount); } private void handleSubaccountStatusSuccess(Subaccount subaccount, String finishedAt) { // 服务费 if (subaccount.getSubaccountType().equals(SubaccountType.SERVICE_FEE)) { handleSubaccountTypeServiceFee(subaccount); } // 品牌授权费 else if (subaccount.getSubaccountType().equals(SubaccountType.BRAND_AUTH_FEE)) { handleSubaccountTypeBrandAuthFee(subaccount); } // 货款、品牌费、策划费 else { handleSubaccountTypeOtherFee(subaccount, finishedAt); } subaccount.setSubaccountState(SubaccountState.SEPARATE_SUCC); subaccount.setSeparateTime(DateTimeUtils.getLocalDateTimeByRFC3339(finishedAt)); subaccount.setExternalTime(DateTimeUtils.getLocalDateTimeByRFC3339(finishedAt)); // 查找对应的银联支付单 ChinaumsPayment chinaumsPayment = chinaumsPaymentRepository.findFirstByOrdersIdAndSubaccountType(subaccount.getOrders().getId(), subaccount.getSubaccountType()); if (chinaumsPayment != null) { // 处理已确认金额 chinaumsPayment.setConfirmedAmount(chinaumsPayment.getConfirmedAmount().add(subaccount.getSubaccountAmount())); chinaumsPaymentRepository.saveAndFlush(chinaumsPayment); } } private void handleSubaccountTypeOtherFee(Subaccount subaccount, String finishedAt) { List<Statement> statementList; if (subaccount.getShipping() != null) { statementList = statementRepository.findAllByShippingIdAndSubaccountType(subaccount.getShipping().getId(), subaccount.getSubaccountType()); } else { statementList = statementRepository.findAllByOrdersIdAndSubaccountType(subaccount.getOrders().getId(), subaccount.getSubaccountType()); } // 处理预存款账户 AccountChangeCreateDTO accountChangeCreateDTO = AccountChangeCreateDTO .builder() .company(statementList.get(0).getCompany()) .direction(ChangeDirection.ADD) .type(AccountChangeType.valueOf(statementList.get(0).getSubaccountType().getValue())) .amount(subaccount.getSubaccountAmount()) .sourceNo(subaccount.getSubaccountNo()) .sourceCompanyId(subaccount.getSourceCompany().getId()) .build(); accountService.intoAccount(accountChangeCreateDTO); for (Statement statement : statementList) { // 处理对应结算单 statement.setStatementState(StatementState.RECORDED); statement.setSubaccountTime(DateTimeUtils.getLocalDateTimeByRFC3339(finishedAt)); statementRepository.saveAndFlush(statement); } } private void handleSubaccountTypeBrandAuthFee(Subaccount subaccount) { // 处理预存款账户 AccountChangeCreateDTO accountChangeCreateDTO = AccountChangeCreateDTO .builder() .company(subaccount.getCompany()) .direction(ChangeDirection.ADD) .type(AccountChangeType.valueOf(SubaccountType.BRAND_AUTH_FEE.getValue())) .amount(subaccount.getSubaccountAmount()) .sourceNo(subaccount.getSubaccountNo()) .sourceCompanyId(subaccount.getSourceCompany().getId()) .build(); accountService.intoAccount(accountChangeCreateDTO); } private void handleSubaccountTypeServiceFee(Subaccount subaccount) { // 通过平台的电子账簿获取企业 Company company = companyRepository.findByWalletId(chinaumsUtil.getFeeBalanceAcctId()); if (company != null) { AccountChangeCreateDTO accountChangeCreateDTO = AccountChangeCreateDTO .builder() .company(company) .direction(ChangeDirection.ADD) .type(AccountChangeType.valueOf(SubaccountType.SERVICE_FEE.getValue())) .amount(subaccount.getSubaccountAmount()) .sourceNo(subaccount.getSubaccountNo()) .sourceCompanyId(subaccount.getSourceCompany().getId()) .build(); accountService.intoAccount(accountChangeCreateDTO); } } /** * 计算平台分账记录 * * @param statement 结算单 * @param orderFeeRatio 订单费用比例 * @param refundAmount 退款金额 * @return 平台分账记录 * @author huabiao * @create 2022/12/21 15:53 */ private Subaccount calculationPlatformServiceFee(Statement statement, OrderFeeRatio orderFeeRatio, BigDecimal refundAmount) { // 计算平台服务费 BigDecimal platformServiceFee; // 根据分账类型从订单费用比例中获取 BigDecimal platformServiceFeeRatio = BigDecimal.ZERO; if (statement.getSubaccountType().equals(SubaccountType.GOODS_COST)) { platformServiceFeeRatio = orderFeeRatio.getSellerServiceCostRatio(); } else if (statement.getSubaccountType().equals(SubaccountType.BRAND_FEE)) { platformServiceFeeRatio = orderFeeRatio.getBrandServiceCostRatio(); } else if (statement.getSubaccountType().equals(SubaccountType.DEVISE_FEE)) { platformServiceFeeRatio = orderFeeRatio.getDeviseServiceCostRatio(); } if (platformServiceFeeRatio.compareTo(BigDecimal.ZERO) == 1) { // statementamount platformServiceFee = statement.getStatementAmount().add(refundAmount).multiply(platformServiceFeeRatio).setScale(2, BigDecimal.ROUND_UP); if (platformServiceFee.compareTo(BigDecimal.ZERO) == 1) { // 生成平台服务费分账单 return generatePlatformSubaccount(platformServiceFeeRatio, platformServiceFee, statement.getOrders(), statement.getShipping(), statement.getCompany()); } } return null; } private BigDecimal getCostRatio(Statement statement, OrderFeeRatio orderFeeRatio) { BigDecimal costRatio = BigDecimal.ZERO; if (statement.getSubaccountType().equals(SubaccountType.GOODS_COST)) { costRatio = BigDecimal.ONE.subtract(orderFeeRatio.getBrandCostRatio()).subtract(orderFeeRatio.getDeviseCostRatio()); } else if (statement.getSubaccountType().equals(SubaccountType.BRAND_FEE)) { costRatio = orderFeeRatio.getBrandCostRatio(); } else if (statement.getSubaccountType().equals(SubaccountType.DEVISE_FEE)) { costRatio = orderFeeRatio.getDeviseCostRatio(); } return costRatio; } /** * 是否最后分账 * * @param shipping 发货单 * @return TRUE:是;FALSE:否 * @author huabiao * @create 2023/1/5 10:55 */ private Boolean isFinallySubaccount(Shipping shipping) { Boolean isFinallySubaccount = true; Order orders = shipping.getOrders(); for (Shipping ordersShipping : orders.getShippings()) { if (ordersShipping != shipping && BooleanUtils.isFalse(ordersShipping.getIsSeparateAccounts())) { isFinallySubaccount = false; } } return isFinallySubaccount; } /** * 根据发货单更新分账状态 * * @param shipping 发货单 * @description * @author huabiao * @create 2023/1/5 15:31 */ private void updateIsSeparateAccountsByShipping(Shipping shipping) { Order order = shipping.getOrders(); // 更新发货单已分账 shippingRepository.updateIsSeparateAccountsById(shipping.getId()); // 判断该订单是否已分账结束 long unSubaccountShipping = order.getShippings().stream().filter(filterShipping -> !filterShipping.getId().equals(shipping.getId()) && BooleanUtils.isFalse(filterShipping.getIsSeparateAccounts())).count(); if ((!order.getShippingStatus().equals(ShippingStatus.UN_SHIPPED) || !order.getShippingStatus().equals(ShippingStatus.PARTIAL_SHIPPED)) && unSubaccountShipping == 0) { orderRepository.updateIsSeparateAccountsById(order.getId()); } } /** * 创建分账 * * @param order 订单 * @param paymentMethod 支付方式 * @description 调用银联创建分账接口分账 * @author huabiao * @create 2023/2/6 17:16 */ @Transactional(rollbackFor = YnceErrorException.class) public void createSubaccountByOrder(Order order, PaymentMethod paymentMethod) { // 获取分账记录 List<Subaccount> subaccountList = subaccountRepository.findAllByOrdersId(order.getId()); if (CollectionUtils.isNotEmpty(subaccountList)) { // 清除失败的分账记录 subaccountList.removeIf(subaccount -> subaccount.getSubaccountState().equals(SubaccountState.SEPARATE_FAIL)); } // 判断是否已分账 if (checkIsSubaccountOrder(subaccountList)) { // 更新订单已分账 finishOrderSubaccount(order); writeSeparateLog(String.format("[分账][生成][普通订单][%s],分账单已存在,更新订单为已分账", order.getSn())); return; } OrderFeeRatio orderFeeRatio = orderFeeRatioRepository.findByOrdersId(order.getId()); // 获取所有结算单(包含正常订单和退货退款) List<Statement> allStatementList = getStatementList(order); if (allStatementList == null) return; List<ChinaumsTransferParamsDTO> chinaumsTransferParamsDTOList = new ArrayList<>(); // 正常订单结算单 List<Statement> statementList = allStatementList.stream().filter(statement -> statement.getStatementType().equals(StatementType.NORMALORDER)).collect(Collectors.toList()); // 退货退款结算单 List<Statement> allAfterSaleStatementList = allStatementList.stream().filter(statement -> statement.getStatementType().equals(StatementType.AFTERSALES)).collect(Collectors.toList()); // 平台服务费分账记录 List<Subaccount> platformSubaccountList = new ArrayList<>(); // 品牌授权费记录 List<BrandAuthFeeDTO> brandAuthFeeDTOList = new ArrayList<>(); // 新创建分账记录 List<Subaccount> newSubaccountList = new ArrayList<>(); for (Statement statement : statementList) { // 退款金额 BigDecimal refundAmount = BigDecimal.ZERO; // 退款品牌授权费 BigDecimal refundBrandAuthFee = BigDecimal.ZERO; // 该结算单对应的退款结算单 List<Statement> afterSaleStatementList = allAfterSaleStatementList.stream().filter(filterStatement -> filterStatement.getSubaccountType().equals(statement.getSubaccountType())).collect(Collectors.toList()); // 查询所有已完成售后单 List<AfterSale> afterSaleList = afterSaleRepository.findAllByOrdersIdAndAfterSaleStatus(order.getId(), AfterSaleStatus.COMPLETED); if (CollectionUtils.isNotEmpty(afterSaleList)) { if (CollectionUtils.isNotEmpty(afterSaleStatementList)) { // 若存在退款结算单,需判断单据数量是否一致(注意:可能存在非售后途径退款) if (afterSaleList.size() != afterSaleStatementList.stream().filter(filterStatement -> filterStatement.getAfterSale() != null).count()) { writeSeparateLog(String.format("[分账][生成][普通订单][%s][结算单][%s],该分账单存在退款结算单未生成", order.getSn(), statement.getStatementNo())); return; } for (Statement afterSaleStatement : afterSaleStatementList) { refundAmount = refundAmount.add(afterSaleStatement.getStatementAmount()); refundBrandAuthFee = refundBrandAuthFee.add(afterSaleStatement.getStatementLine().stream().map(StatementLine::getBrandAuthFee).reduce(BigDecimal.ZERO, BigDecimal::add)); } } else { writeSeparateLog(String.format("[分账][生成][普通订单][%s][结算单][%s],该分账单存在退款结算单未生成", order.getSn(), statement.getStatementNo())); return; } } else { refundAmount = afterSaleStatementList.stream().map(Statement::getStatementAmount).reduce(BigDecimal.ZERO, BigDecimal::add); } // 平台服务费 BigDecimal platformServiceFee = BigDecimal.ZERO; // 拼接平台服务费分账 Subaccount platformSubaccount = calculationPlatformServiceFee(statement, orderFeeRatio, refundAmount.add(refundBrandAuthFee)); if (platformSubaccount != null) { platformSubaccountList.add(platformSubaccount); platformServiceFee = platformSubaccount.getSubaccountAmount(); } // 判断是否存在分账记录(根据分账企业和分账类型) Subaccount subaccount = subaccountList.stream().filter(filterSubaccount -> filterSubaccount.getSubaccountType().equals(statement.getSubaccountType()) && filterSubaccount.getCompany() != null && filterSubaccount.getCompany().equals(statement.getCompany())).findFirst().orElse(null); if (subaccount != null) { // 若是未分账则调用银联接口 if (subaccount.getSubaccountState().equals(SubaccountState.SEPARATE_NOT)) { handleSubaccountStatus(subaccount, true); } continue; } // 拼接分账记录数据 subaccount = new Subaccount(); subaccount.setSubaccountNo(sequenceUtil.getNextSequenceNumber("FZ")); subaccount.setCompany(companyRepository.findById(statement.getCompany().getId()).orElse(null)); // 货款分账金额 = 结算金额 + 退款金额 - 平台服务费 - 品牌授权费 + 退款品牌授权费 if (statement.getSubaccountType().equals(SubaccountType.GOODS_COST)) { // 品牌授权费 BigDecimal brandAuthFee = statement.getStatementLine().stream().map(statementLine -> statementLine.getBrandAuthFee()).reduce(BigDecimal.ZERO, BigDecimal::add); subaccount.setSubaccountAmount(statement.getStatementAmount().add(refundAmount).subtract(platformServiceFee).subtract(brandAuthFee).add(refundBrandAuthFee)); if (CollectionUtils.isNotEmpty(orderFeeRatio.getOrderItemFeeRatio())) { subaccount.setBrandAuthCostRatio(orderFeeRatio.getOrderItemFeeRatio().get(0).getBrandAuthCostRatio()); } subaccount.setBrandAuthFee(brandAuthFee.add(refundBrandAuthFee)); // 拼接品牌授权费 for (StatementLine statementLine : statement.getStatementLine()) { BigDecimal lineBrandAuthFee = statementLine.getBrandAuthFee(); // 获取对应的退款结算单项 for (Statement typeAfterSaleStatement : afterSaleStatementList) { StatementLine typeAfterSaleStatementLine = typeAfterSaleStatement.getStatementLine().stream().filter(filterStatementLine -> filterStatementLine.getOrderItem().getId().equals(statementLine.getOrderItem().getId())).findFirst().orElse(null); if (typeAfterSaleStatementLine != null) { lineBrandAuthFee = lineBrandAuthFee.add(typeAfterSaleStatementLine.getBrandAuthFee()); } } BrandAuthFeeDTO brandAuthFeeDTO = brandAuthFeeDTOList.stream().filter(filterBrandAuthFeeDTO -> filterBrandAuthFeeDTO.getBrandId().equals(statementLine.getOrderItem().getBrandId())).findFirst().orElse(null); if (brandAuthFeeDTO != null) { brandAuthFeeDTO.setAmount(brandAuthFeeDTO.getAmount().add(lineBrandAuthFee)); } else { brandAuthFeeDTO = new BrandAuthFeeDTO(); brandAuthFeeDTO.setBrandId(statementLine.getOrderItem().getBrandId()); brandAuthFeeDTO.setAmount(lineBrandAuthFee); brandAuthFeeDTOList.add(brandAuthFeeDTO); } } } // 其他分账金额 = 结算金额 - 退款金额 - 平台服务费 else { subaccount.setSubaccountAmount(statement.getStatementAmount().add(refundAmount).subtract(platformServiceFee)); } // 当分账金额小于等于0时跳过 if (subaccount.getSubaccountAmount().compareTo(BigDecimal.ZERO) != 1) { continue; } subaccount.setSubaccountCostRatio(getCostRatio(statement, orderFeeRatio)); subaccount.setSubaccountType(statement.getSubaccountType()); subaccount.setOrders(statement.getOrders()); subaccount.setSubaccountState(SubaccountState.SEPARATE_NOT); subaccount.setSourceCompany(order.getBuyerCompany()); subaccount.setSubaccountTotalAmount(statement.getStatementAmount().add(refundAmount)); if (platformSubaccount != null) { subaccount.setPlatformServiceCostRatio(platformSubaccount.getSubaccountCostRatio()); subaccount.setPlatformServiceFee(platformSubaccount.getSubaccountAmount()); } newSubaccountList.add(subaccount); } // 品牌授权费 if (CollectionUtils.isNotEmpty(orderFeeRatio.getOrderItemFeeRatio())) { for (BrandAuthFeeDTO brandAuthFeeDTO : brandAuthFeeDTOList) { // 判断该品牌授权费是否存在分账记录(根据品牌ID+分账类型) Subaccount subaccount = subaccountList.stream().filter(filterSubaccount -> filterSubaccount.getBrandId() != null && filterSubaccount.getBrandId().equals(brandAuthFeeDTO.getBrandId()) && filterSubaccount.getSubaccountType().equals(SubaccountType.BRAND_AUTH_FEE)).findFirst().orElse(null); if (subaccount != null) { // 若是未分账则调用银联接口 if (subaccount.getSubaccountState().equals(SubaccountState.SEPARATE_NOT)) { handleSubaccountStatus(subaccount, true); } continue; } // 获取品牌 Brand brand = brandRepository.findById(brandAuthFeeDTO.getBrandId()).orElse(null); // 平台服务费 BigDecimal platformServiceFee = BigDecimal.ZERO; // 品牌授权费的平台服务费分账记录 Subaccount platformSubaccount = null; // 获取订单项费用比例 OrderItemFeeRatio orderItemFeeRatio = orderFeeRatio.getOrderItemFeeRatio().stream().filter(filterOrderItemFeeRatio -> filterOrderItemFeeRatio.getOrderItem().getBrandId().equals(brandAuthFeeDTO.getBrandId())).findFirst().orElse(null); if (orderItemFeeRatio != null && orderItemFeeRatio.getBrandAuthCostServiceCostRatio().compareTo(BigDecimal.ZERO) == 1) { // 计算平台服务费 platformServiceFee = brandAuthFeeDTO.getAmount().multiply(orderItemFeeRatio.getBrandAuthCostServiceCostRatio()).setScale(2, BigDecimal.ROUND_UP); // 拼接平台服务费分账 if (platformServiceFee.compareTo(BigDecimal.ZERO) == 1) { platformSubaccount = generatePlatformSubaccount(orderItemFeeRatio.getBrandAuthCostServiceCostRatio(), platformServiceFee, order, null, brand.getCompany()); if (platformSubaccount != null) { platformSubaccountList.add(platformSubaccount); platformServiceFee = platformSubaccount.getSubaccountAmount(); } } } BigDecimal subaccountAmount = brandAuthFeeDTO.getAmount().subtract(platformServiceFee); if (subaccountAmount.compareTo(BigDecimal.ZERO) == 1) { // 拼接分账记录 subaccount = new Subaccount(); subaccount.setSubaccountNo(sequenceUtil.getNextSequenceNumber("FZ")); subaccount.setCompany(brand.getCompany()); subaccount.setSubaccountAmount(subaccountAmount); subaccount.setSubaccountTotalAmount(brandAuthFeeDTO.getAmount()); subaccount.setSubaccountType(SubaccountType.BRAND_AUTH_FEE); subaccount.setOrders(order); subaccount.setSubaccountState(SubaccountState.SEPARATE_NOT); subaccount.setSourceCompany(order.getBuyerCompany()); subaccount.setBrandId(brandAuthFeeDTO.getBrandId()); if (platformSubaccount != null) { subaccount.setPlatformServiceCostRatio(platformSubaccount.getSubaccountCostRatio()); subaccount.setPlatformServiceFee(platformSubaccount.getSubaccountAmount()); } newSubaccountList.add(subaccount); } } } // 获取已生成的平台服务费分账记录 List<Subaccount> platformSubaccounts = subaccountList.stream().filter(subaccount -> subaccount.getCompany() == null).collect(Collectors.toList()); if (CollectionUtils.isNotEmpty(platformSubaccounts)) { for (Subaccount platformSubaccount : platformSubaccounts) { handleSubaccountStatus(platformSubaccount, true); } } else if (CollectionUtils.isNotEmpty(platformSubaccountList)) { newSubaccountList.addAll(platformSubaccountList); } // 对所有的分账单进行统计处理,同一企业的合并进行分账创建 if (CollectionUtils.isNotEmpty(newSubaccountList)) { // 获取平台分账记录 List<Subaccount> noCompanySubaccountList = newSubaccountList.stream().filter(subaccount -> subaccount.getCompany() == null).collect(Collectors.toList()); if (CollectionUtils.isNotEmpty(noCompanySubaccountList)) { BigDecimal noCompanySubaccountAmount = noCompanySubaccountList.stream().map(Subaccount::getSubaccountAmount).reduce(BigDecimal.ZERO, BigDecimal::add); // 商品扩展字段 ChinaumsGuaranteePayExtraDTO chinaumsGuaranteePayExtraDTO = new ChinaumsGuaranteePayExtraDTO(); chinaumsGuaranteePayExtraDTO.setProductInfos(this.handleProductInfoByOrder(order.getOrderItems(), order.getSn(), order.getAmount(), noCompanySubaccountAmount)); // 自定义参数 JSONObject metadata = new JSONObject(); metadata.put("companyId", null); metadata.put("subaccountNo", StringUtils.join(noCompanySubaccountList.stream().map(Subaccount::getSubaccountNo).collect(Collectors.toList()), ",")); // 拼接分账参数 ChinaumsTransferParamsDTO chinaumsTransferParamsDTO = ChinaumsTransferParamsDTO .builder() .recvBalanceAcctId(chinaumsUtil.getFeeBalanceAcctId()) .amount(noCompanySubaccountAmount.multiply(new BigDecimal(100)).intValue()) .remark(null) .extra(chinaumsGuaranteePayExtraDTO) .metadata(metadata) .build(); chinaumsTransferParamsDTOList.add(chinaumsTransferParamsDTO); } // 获取非平台分账记录 List<Subaccount> allCompanySubaccountList = newSubaccountList.stream().filter(subaccount -> subaccount.getCompany() != null).collect(Collectors.toList()); Map<Company, List<Subaccount>> companySubaccountListMap = allCompanySubaccountList.stream().collect(Collectors.groupingBy(Subaccount::getCompany)); for (Map.Entry<Company, List<Subaccount>> companyListEntry : companySubaccountListMap.entrySet()) { Company company = companyListEntry.getKey(); List<Subaccount> companySubaccountList = companyListEntry.getValue(); // 计算该企业总分账金额 BigDecimal companySubaccountAmount = companySubaccountList.stream().map(Subaccount::getSubaccountAmount).reduce(BigDecimal.ZERO, BigDecimal::add); // 商品扩展字段 ChinaumsGuaranteePayExtraDTO chinaumsGuaranteePayExtraDTO = new ChinaumsGuaranteePayExtraDTO(); chinaumsGuaranteePayExtraDTO.setProductInfos(this.handleProductInfoByOrder(order.getOrderItems(), order.getSn(), order.getAmount(), companySubaccountAmount)); // 自定义参数 JSONObject metadata = new JSONObject(); metadata.put("companyId", company.getId()); metadata.put("subaccountNo", StringUtils.join(companySubaccountList.stream().map(Subaccount::getSubaccountNo).collect(Collectors.toList()), ",")); // 判断该企业是否已认证 if (StringUtils.isBlank(company.getWalletId())) { writeSeparateLog(String.format("[分账][生成][普通订单][%s],[%s]暂未认证银联", order.getSn(), company.getName())); return; } // 拼接分账参数 ChinaumsTransferParamsDTO chinaumsTransferParamsDTO = ChinaumsTransferParamsDTO .builder() .recvBalanceAcctId(company.getWalletId()) .amount(companySubaccountAmount.multiply(new BigDecimal(100)).intValue()) .remark(null) .extra(chinaumsGuaranteePayExtraDTO) .metadata(metadata) .build(); chinaumsTransferParamsDTOList.add(chinaumsTransferParamsDTO); } } if (CollectionUtils.isNotEmpty(chinaumsTransferParamsDTOList)) { // 已分账金额 BigDecimal allocatedAmount = subaccountList.stream().map(Subaccount::getSubaccountAmount).reduce(BigDecimal.ZERO, BigDecimal::add); // 待分账金额 BigDecimal totalSubaccountAmount = newSubaccountList.stream().map(Subaccount::getSubaccountAmount).reduce(BigDecimal.ZERO, BigDecimal::add); // 获取所有的退款金额 List<Refund> refundList = refundRepository.findAllByOrdersId(order.getId()); BigDecimal refundAmount = CollectionUtils.isNotEmpty(refundList) ? refundList.stream().map(Refund::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add) : BigDecimal.ZERO; // 判断分账总金额是否正确 if ((allocatedAmount.add(totalSubaccountAmount)).compareTo((order.getPayAmount().subtract(refundAmount))) != 0) { writeSeparateLog(String.format("[分账][生成][普通订单][%s],分账总金额与订单支付金额不一致", order.getSn())); return; } // 银联所属企业 Company chinaumsCompany = order.getConsignmentCompany() != null ? companyRepository.getOne(order.getConsignmentCompany().getId()) : companyRepository.getOne(order.getSellerCompany().getId()); // 根据支付方式获取对应分账电子账簿ID String chinaumsBalanceAcctId; if (paymentMethod.equals(PaymentMethod.CREDIT_PAY)) { chinaumsBalanceAcctId = chinaumsUtil.getChinaumsCreditBalanceAcctId(chinaumsCompany.getId()); } else { chinaumsBalanceAcctId = chinaumsUtil.getBalanceAcctId(chinaumsCompany.getId()); } if (StringUtils.isBlank(chinaumsBalanceAcctId)) { writeSeparateLog(String.format("[分账][生成][普通订单][%s],[%s]分账电子账簿ID为空", order.getSn(), chinaumsCompany.getName())); return; } // 查询平台分账银联电子账簿是否金额充足 BigDecimal balance; try { BalanceAcctsVO balanceAcctsVO = walletService.balanceAcctsQryByAcctId(chinaumsBalanceAcctId); balance = new BigDecimal(balanceAcctsVO.getSettledAmount()).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP); } catch (Exception exception) { writeSeparateLog(String.format("[分账][生成][普通订单][%s],[%s]分账电子账簿金额查询报错", order.getSn(), chinaumsCompany.getName())); return; } // 判断余额是否充足 if (balance.compareTo(BigDecimal.ZERO) < 1 || balance.compareTo(totalSubaccountAmount) == -1) { writeSeparateLog(String.format("[分账][生成][普通订单][%s],[%s]分账电子账簿金额不足", order.getSn(), chinaumsCompany.getName())); return; } // 分账创建 ChinaumsAllocationsDTO chinaumsAllocationsDTO = ChinaumsAllocationsDTO .builder() .outOrderNo(sequenceUtil.getNextSequenceNumber("FZ")) .sentAt(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX").format(new Date())) .payBalanceAcctId(chinaumsBalanceAcctId) .transferParams(chinaumsTransferParamsDTOList) .remark(null) .build(); ChinaumsAllocationsVO chinaumsAllocationsVO; try { chinaumsAllocationsVO = walletService.createSubaccount(chinaumsAllocationsDTO); } catch (Exception exception) { // TODO 这里需要调用平台订单号查询是否调用成功 log.error("订单创建分账异常,订单号" + order.getSn() + ",分账单号" + chinaumsAllocationsDTO.getOutOrderNo()); return; } // 循环查询子订单分账是否成功 for (ChinaumsTransferResultsVO chinaumsTransferResultsVO : chinaumsAllocationsVO.getTransferResults()) { // 先判断是否为平台电子账簿 if (chinaumsTransferResultsVO.getRecvBalanceAcctId().equals(chinaumsUtil.getFeeBalanceAcctId())) { // 企业为空时获取平台分账记录 List<Subaccount> platformFeeSubaccountList = newSubaccountList.stream().filter(filterSubaccount -> filterSubaccount.getCompany() == null).collect(Collectors.toList()); for (Subaccount subaccount : platformFeeSubaccountList) { subaccount.setExternalId(chinaumsTransferResultsVO.getTransferId()); subaccountRepository.saveAndFlush(subaccount); handleSubaccountStatus(subaccount, true); } } else { // 根据收款电子账簿ID查询 Company company = companyRepository.findByWalletId(chinaumsTransferResultsVO.getRecvBalanceAcctId()); if (company == null) { continue; } // 获取对应的企业分账记录 List<Subaccount> companySubaccountList = newSubaccountList.stream().filter(filterSubaccount -> filterSubaccount.getCompany() != null && filterSubaccount.getCompany().equals(company)).collect(Collectors.toList()); for (Subaccount subaccount : companySubaccountList) { subaccount.setExternalId(chinaumsTransferResultsVO.getTransferId()); subaccountRepository.saveAndFlush(subaccount); handleSubaccountStatus(subaccount, true); } } writeSeparateLog(String.format("[分账][生成][普通订单][%s],生成分账单成功,银联结算单号[%s]。", order.getSn(), chinaumsTransferResultsVO.getTransferId())); } subaccountList.addAll(newSubaccountList); } // 判断是否已分账 if (checkIsSubaccountOrder(subaccountList)) { // 更新订单已分账 finishOrderSubaccount(order); writeSeparateLog(String.format("[分账][生成][普通订单][%s],分账单已存在,更新订单为已分账", order.getSn())); return; } } /** * 创建分账 * * @return * @description 相同收款方必须合并处理 * @author huabiao * @create 2023/2/6 17:16 */ public void createSubaccountByShipping(Shipping shipping, PaymentMethod paymentMethod) { // 自定义参数 JSONObject metadata = new JSONObject(); metadata.put("shippingSn", shipping.getShippingSn()); Order order = shipping.getOrders(); // 获取订单费用比例 OrderFeeRatio orderFeeRatio = orderFeeRatioRepository.findByOrdersId(order.getId()); // 获取分账记录 List<Subaccount> subaccountList = subaccountRepository.findAllByShippingId(shipping.getId()); if (CollectionUtils.isNotEmpty(subaccountList)) { // 清除失败的分账记录 subaccountList.removeIf(subaccount -> subaccount.getSubaccountState().equals(SubaccountState.SEPARATE_FAIL)); } // 判断发货单是否已分账 if (checkIsSubaccountByShipping(subaccountList)) { // 更新发货单已分账 updateIsSeparateAccountsByShipping(shipping); writeSeparateLog(String.format("[分账][生成][普通订单][%s][发货单][%s],分账单已存在,更新发货单为已分账", order.getSn(), shipping.getShippingSn())); // 判断订单是否已分账 if (checkIsSubaccountOrder(subaccountRepository.findAllByOrdersId(order.getId()))) { orderRepository.updateIsSeparateAccountsById(order.getId()); } return; } List<ChinaumsTransferParamsDTO> chinaumsTransferParamsDTOList = new ArrayList<>(); // 获取结算单 List<Statement> statementList = statementRepository.findAllByShippingIdAndStatementType(shipping.getId(), StatementType.NORMALORDER); // 获取退款结算单 List<Statement> allAfterSaleStatementList = statementRepository.findAllByShippingIdAndStatementType(shipping.getId(), StatementType.AFTERSALES); // 平台服务费分账记录 List<Subaccount> platformSubaccountList = new ArrayList<>(); // 品牌授权费记录 List<BrandAuthFeeDTO> brandAuthFeeDTOList = new ArrayList<>(); // 新创建分账记录 List<Subaccount> newSubaccountList = new ArrayList<>(); for (Statement statement : statementList) { // 获取结算单对应的退款结算单 List<Statement> afterSaleStatementList = allAfterSaleStatementList.stream().filter(filterStatement -> filterStatement.getSubaccountType().equals(statement.getSubaccountType())).collect(Collectors.toList()); // 退款金额 BigDecimal refundAmount = BigDecimal.ZERO; // 退款品牌授权费 BigDecimal refundBrandAuthFee = BigDecimal.ZERO; // 获取售后单 List<AfterSale> afterSaleList = afterSaleRepository.findAllByShippingIdAndAfterSaleStatus(shipping.getId(), AfterSaleStatus.COMPLETED); if (CollectionUtils.isNotEmpty(afterSaleStatementList)) { if (afterSaleList.size() != afterSaleStatementList.size()) { writeSeparateLog(String.format("[分账][生成][普通订单][%s][发货单][%s][结算单][%s],该分账单存在退款结算单未生成", order.getSn(), shipping.getShippingSn(), statement.getStatementNo())); return; } for (Statement afterSaleStatement : afterSaleStatementList) { refundAmount = refundAmount.add(afterSaleStatement.getStatementAmount()); refundBrandAuthFee = refundBrandAuthFee.add(afterSaleStatement.getStatementLine().stream().map(StatementLine::getBrandAuthFee).reduce(BigDecimal.ZERO, BigDecimal::add)); } } else { // 当不存在退款结算单时,需判断是否还未生成 if (CollectionUtils.isNotEmpty(afterSaleList)) { writeSeparateLog(String.format("[分账][生成][普通订单][%s][发货单][%s][结算单][%s],该分账单存在退款结算单未生成", order.getSn(), shipping.getShippingSn(), statement.getStatementNo())); return; } } // 平台服务费 BigDecimal platformServiceFee = BigDecimal.ZERO; // 拼接平台服务费分账 Subaccount platformSubaccount = calculationPlatformServiceFee(statement, orderFeeRatio, refundAmount.add(refundBrandAuthFee)); if (platformSubaccount != null) { platformSubaccountList.add(platformSubaccount); platformServiceFee = platformSubaccount.getSubaccountAmount(); } // 判断是否存在分账记录(根据分账企业和分账类型) Subaccount subaccount = subaccountList.stream().filter(filterSubaccount -> filterSubaccount.getSubaccountType().equals(statement.getSubaccountType()) && filterSubaccount.getCompany() != null && filterSubaccount.getCompany().equals(statement.getCompany())).findFirst().orElse(null); if (subaccount != null) { // 若是未分账则调用银联接口 if (subaccount.getSubaccountState().equals(SubaccountState.SEPARATE_NOT)) { handleSubaccountStatus(subaccount, false); } continue; } subaccount = new Subaccount(); subaccount.setSubaccountNo(sequenceUtil.getNextSequenceNumber("FZ")); subaccount.setCompany(statement.getCompany()); subaccount.setSubaccountCostRatio(getCostRatio(statement, orderFeeRatio)); // 保存品牌授权费 BigDecimal brandAuthFee = BigDecimal.ZERO; if (statement.getSubaccountType().equals(SubaccountType.GOODS_COST) && CollectionUtils.isNotEmpty(orderFeeRatio.getOrderItemFeeRatio())) { brandAuthFee = statement.getStatementLine().stream().map(StatementLine::getBrandAuthFee).reduce(BigDecimal.ZERO, BigDecimal::add); subaccount.setBrandAuthCostRatio(orderFeeRatio.getOrderItemFeeRatio().get(0).getBrandAuthCostRatio()); subaccount.setBrandAuthFee(brandAuthFee.add(refundBrandAuthFee)); } if (statement.getSubaccountType().equals(SubaccountType.GOODS_COST)) { // 货款分账金额 = 结算金额 + 退款金额 - 平台服务费 - 品牌授权费 + 退款品牌授权费 subaccount.setSubaccountAmount(statement.getStatementAmount().add(refundAmount).subtract(platformServiceFee).subtract(brandAuthFee).add(refundBrandAuthFee)); // 拼接品牌授权费 for (StatementLine statementLine : statement.getStatementLine()) { BigDecimal lineBrandAuthFee = statementLine.getBrandAuthFee(); // 获取对应的退款结算单项 for (Statement typeAfterSaleStatement : afterSaleStatementList) { StatementLine typeAfterSaleStatementLine = typeAfterSaleStatement.getStatementLine().stream().filter(filterStatementLine -> filterStatementLine.getOrderItem().getId().equals(statementLine.getOrderItem().getId())).findFirst().orElse(null); if (typeAfterSaleStatementLine != null) { lineBrandAuthFee = lineBrandAuthFee.add(typeAfterSaleStatementLine.getBrandAuthFee()); } } BrandAuthFeeDTO brandAuthFeeDTO = brandAuthFeeDTOList.stream().filter(filterBrandAuthFeeDTO -> filterBrandAuthFeeDTO.getBrandId().equals(statementLine.getOrderItem().getBrandId())).findFirst().orElse(null); if (brandAuthFeeDTO != null) { brandAuthFeeDTO.setAmount(brandAuthFeeDTO.getAmount().add(lineBrandAuthFee)); } else { brandAuthFeeDTO = new BrandAuthFeeDTO(); brandAuthFeeDTO.setBrandId(statementLine.getOrderItem().getBrandId()); brandAuthFeeDTO.setAmount(lineBrandAuthFee); brandAuthFeeDTOList.add(brandAuthFeeDTO); } } } else { // 其他分账金额 = 结算金额 - 退款金额 - 平台服务费 subaccount.setSubaccountAmount(statement.getStatementAmount().add(refundAmount).subtract(platformServiceFee)); } // 当分账金额小于等于0时跳过 if (subaccount.getSubaccountAmount().compareTo(BigDecimal.ZERO) != 1) { continue; } subaccount.setSubaccountTotalAmount(statement.getStatementAmount().add(refundAmount)); if (platformSubaccount != null) { subaccount.setPlatformServiceCostRatio(platformSubaccount.getSubaccountCostRatio()); subaccount.setPlatformServiceFee(platformSubaccount.getSubaccountAmount()); } subaccount.setSubaccountType(statement.getSubaccountType()); subaccount.setOrders(statement.getOrders()); subaccount.setShipping(statement.getShipping()); subaccount.setSubaccountState(SubaccountState.SEPARATE_NOT); subaccount.setSourceCompany(order.getBuyerCompany()); newSubaccountList.add(subaccount); } // 品牌授权费 if (CollectionUtils.isNotEmpty(orderFeeRatio.getOrderItemFeeRatio())) { for (BrandAuthFeeDTO brandAuthFeeDTO : brandAuthFeeDTOList) { // 判断该品牌授权费是否存在分账记录(根据品牌ID和分账类型) Subaccount subaccount = subaccountList.stream().filter(filterSubaccount -> filterSubaccount.getBrandId() != null && filterSubaccount.getBrandId().equals(brandAuthFeeDTO.getBrandId()) && filterSubaccount.getSubaccountType().equals(SubaccountType.BRAND_AUTH_FEE)).findFirst().orElse(null); if (subaccount != null) { // 若是未分账则调用银联接口 if (subaccount.getSubaccountState().equals(SubaccountState.SEPARATE_NOT)) { handleSubaccountStatus(subaccount, true); } continue; } // 获取品牌 Brand brand = brandRepository.findById(brandAuthFeeDTO.getBrandId()).orElse(null); // 平台服务费 BigDecimal platformServiceFee = BigDecimal.ZERO; // 平台服务费比例 BigDecimal platformServiceCostRatio = BigDecimal.ZERO; // 获取订单项费用比例 OrderItemFeeRatio orderItemFeeRatio = orderFeeRatio.getOrderItemFeeRatio().stream().filter(filterOrderItemFeeRatio -> filterOrderItemFeeRatio.getOrderItem().getBrandId().equals(brandAuthFeeDTO.getBrandId())).findFirst().orElse(null); if (orderItemFeeRatio != null && orderItemFeeRatio.getBrandAuthCostServiceCostRatio().compareTo(BigDecimal.ZERO) == 1) { // 计算平台服务费 platformServiceFee = brandAuthFeeDTO.getAmount().multiply(orderItemFeeRatio.getBrandAuthCostServiceCostRatio()).setScale(2, BigDecimal.ROUND_UP); platformServiceCostRatio = orderItemFeeRatio.getBrandAuthCostServiceCostRatio(); // 拼接平台服务费分账 if (platformServiceFee.compareTo(BigDecimal.ZERO) == 1) { Subaccount platformSubaccount = generatePlatformSubaccount(orderItemFeeRatio.getBrandAuthCostServiceCostRatio(), platformServiceFee, order, shipping, brand.getCompany()); if (platformSubaccount != null) { platformSubaccountList.add(platformSubaccount); } } } BigDecimal subaccountAmount = brandAuthFeeDTO.getAmount().subtract(platformServiceFee); if (subaccountAmount.compareTo(BigDecimal.ZERO) == 1) { // 拼接分账记录 subaccount = new Subaccount(); subaccount.setSubaccountNo(sequenceUtil.getNextSequenceNumber("FZ")); subaccount.setCompany(brand.getCompany()); subaccount.setSubaccountAmount(subaccountAmount); subaccount.setSubaccountTotalAmount(brandAuthFeeDTO.getAmount()); subaccount.setSubaccountType(SubaccountType.BRAND_AUTH_FEE); subaccount.setOrders(order); subaccount.setShipping(shipping); subaccount.setSubaccountState(SubaccountState.SEPARATE_NOT); subaccount.setSourceCompany(order.getBuyerCompany()); subaccount.setBrandId(brandAuthFeeDTO.getBrandId()); if (platformServiceFee.compareTo(BigDecimal.ZERO) == 1) { subaccount.setPlatformServiceCostRatio(platformServiceCostRatio); subaccount.setPlatformServiceFee(platformServiceFee); } newSubaccountList.add(subaccount); } } } // 获取已生成的平台服务费分账记录 List<Subaccount> platformSubaccounts = subaccountList.stream().filter(subaccount -> subaccount.getCompany() == null).collect(Collectors.toList()); if (CollectionUtils.isNotEmpty(platformSubaccounts)) { for (Subaccount platformSubaccount : platformSubaccounts) { handleSubaccountStatus(platformSubaccount, true); } } else if (CollectionUtils.isNotEmpty(platformSubaccountList)) { newSubaccountList.addAll(platformSubaccountList); } // 对所有的分账单进行统计处理,同一企业的合并进行分账创建 if (CollectionUtils.isNotEmpty(newSubaccountList)) { // 获取平台分账记录 List<Subaccount> noCompanySubaccountList = newSubaccountList.stream().filter(subaccount -> subaccount.getCompany() == null).collect(Collectors.toList()); if (CollectionUtils.isNotEmpty(noCompanySubaccountList)) { BigDecimal noCompanySubaccountAmount = noCompanySubaccountList.stream().map(Subaccount::getSubaccountAmount).reduce(BigDecimal.ZERO, BigDecimal::add); // 商品扩展字段 ChinaumsGuaranteePayExtraDTO chinaumsGuaranteePayExtraDTO = new ChinaumsGuaranteePayExtraDTO(); chinaumsGuaranteePayExtraDTO.setProductInfos(this.handleProductInfoByShipping(shipping.getShippingItem(), order.getSn(), shipping.getAmount(), noCompanySubaccountAmount)); // 自定义参数 metadata.put("companyId", null); metadata.put("subaccountNo", StringUtils.join(noCompanySubaccountList.stream().map(Subaccount::getSubaccountNo).collect(Collectors.toList()), ",")); // 拼接分账参数 ChinaumsTransferParamsDTO chinaumsTransferParamsDTO = ChinaumsTransferParamsDTO .builder() .recvBalanceAcctId(chinaumsUtil.getFeeBalanceAcctId()) .amount(noCompanySubaccountAmount.multiply(new BigDecimal(100)).intValue()) .remark(null) .extra(chinaumsGuaranteePayExtraDTO) .metadata(metadata) .build(); chinaumsTransferParamsDTOList.add(chinaumsTransferParamsDTO); } // 获取非平台分账记录 List<Subaccount> allCompanySubaccountList = newSubaccountList.stream().filter(subaccount -> subaccount.getCompany() != null).collect(Collectors.toList()); Map<Company, List<Subaccount>> companySubaccountListMap = allCompanySubaccountList.stream().collect(Collectors.groupingBy(Subaccount::getCompany)); for (Map.Entry<Company, List<Subaccount>> companyListEntry : companySubaccountListMap.entrySet()) { Company company = companyListEntry.getKey(); List<Subaccount> companySubaccountList = companyListEntry.getValue(); // 计算该企业总分账金额 BigDecimal companySubaccountAmount = companySubaccountList.stream().map(Subaccount::getSubaccountAmount).reduce(BigDecimal.ZERO, BigDecimal::add); // 商品扩展字段 ChinaumsGuaranteePayExtraDTO chinaumsGuaranteePayExtraDTO = new ChinaumsGuaranteePayExtraDTO(); chinaumsGuaranteePayExtraDTO.setProductInfos(this.handleProductInfoByShipping(shipping.getShippingItem(), order.getSn(), shipping.getAmount(), companySubaccountAmount)); // 自定义参数 metadata.put("companyId", company.getId()); metadata.put("subaccountNo", StringUtils.join(companySubaccountList.stream().map(Subaccount::getSubaccountNo).collect(Collectors.toList()), ",")); // 判断该企业是否已认证 if (StringUtils.isBlank(company.getWalletId())) { writeSeparateLog(String.format("[分账][生成][普通订单][%s][发货单][%s],[%s]暂未认证银联", order.getSn(), shipping.getShippingSn(), company.getName())); return; } // 拼接分账参数 ChinaumsTransferParamsDTO chinaumsTransferParamsDTO = ChinaumsTransferParamsDTO .builder() .recvBalanceAcctId(company.getWalletId()) .amount(companySubaccountAmount.multiply(new BigDecimal(100)).intValue()) .remark(null) .extra(chinaumsGuaranteePayExtraDTO) .metadata(metadata) .build(); chinaumsTransferParamsDTOList.add(chinaumsTransferParamsDTO); } } if (CollectionUtils.isNotEmpty(chinaumsTransferParamsDTOList)) { // 已分账金额 BigDecimal allocatedAmount = subaccountList.stream().map(Subaccount::getSubaccountAmount).reduce(BigDecimal.ZERO, BigDecimal::add); // 待分账金额 BigDecimal totalSubaccountAmount = newSubaccountList.stream().map(Subaccount::getSubaccountAmount).reduce(BigDecimal.ZERO, BigDecimal::add); // 判断(已分账金额+待分账金额)和发货单金额是否一致 if ((allocatedAmount.add(totalSubaccountAmount)).compareTo(shipping.getPayAmount()) != 0) { writeSeparateLog(String.format("[分账][生成][普通订单][%s][发货单][%s],分账总金额与发货单支付金额不一致", order.getSn(), shipping.getShippingSn())); return; } // 银联所属企业 Company chinaumsCompany = order.getConsignmentCompany() != null ? companyRepository.getOne(shipping.getOrders().getConsignmentCompany().getId()) : companyRepository.getOne(shipping.getOrders().getSellerCompany().getId()); // 根据支付方式获取对应分账电子账簿ID String chinaumsBalanceAcctId; if (paymentMethod.equals(PaymentMethod.CREDIT_PAY)) { chinaumsBalanceAcctId = chinaumsUtil.getChinaumsCreditBalanceAcctId(chinaumsCompany.getId()); } else { chinaumsBalanceAcctId = chinaumsUtil.getBalanceAcctId(chinaumsCompany.getId()); } if (StringUtils.isBlank(chinaumsBalanceAcctId)) { writeSeparateLog(String.format("[分账][生成][普通订单][%s][发货单][%s],[%s]分账电子账簿ID为空", order.getSn(), shipping.getShippingSn(), chinaumsCompany.getName())); return; } // 查询平台分账银联电子账簿是否金额充足 BigDecimal balance; try { BalanceAcctsVO balanceAcctsVO = walletService.balanceAcctsQryByAcctId(chinaumsBalanceAcctId); balance = new BigDecimal(balanceAcctsVO.getSettledAmount()).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP); } catch (Exception exception) { writeSeparateLog(String.format("[分账][生成][普通订单][%s][发货单][%s],[%s]分账电子账簿金额查询报错", order.getSn(), shipping.getShippingSn(), chinaumsCompany.getName())); return; } // 判断余额是否充足 if (balance.compareTo(BigDecimal.ZERO) < 1 || balance.compareTo(totalSubaccountAmount) == -1) { writeSeparateLog(String.format("[分账][生成][普通订单][%s][发货单][%s],[%s]分账电子账簿金额不足", order.getSn(), shipping.getShippingSn(), chinaumsCompany.getName())); return; } // 分账创建 ChinaumsAllocationsDTO chinaumsAllocationsDTO = ChinaumsAllocationsDTO .builder() .outOrderNo(sequenceUtil.getNextSequenceNumber("FZ")) .sentAt(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX").format(new Date())) .payBalanceAcctId(chinaumsBalanceAcctId) .transferParams(chinaumsTransferParamsDTOList) .remark(null) .build(); ChinaumsAllocationsVO chinaumsAllocationsVO; try { chinaumsAllocationsVO = walletService.createSubaccount(chinaumsAllocationsDTO); } catch (Exception exception) { // 当请求返回异常时,直接跳过 return; } // 循环查询子订单分账是否成功 for (ChinaumsTransferResultsVO chinaumsTransferResultsVO : chinaumsAllocationsVO.getTransferResults()) { // 先判断是否为平台电子账簿 if (chinaumsTransferResultsVO.getRecvBalanceAcctId().equals(chinaumsUtil.getFeeBalanceAcctId())) { // 企业为空时获取平台分账记录 List<Subaccount> platformFeeSubaccountList = newSubaccountList.stream().filter(filterSubaccount -> filterSubaccount.getCompany() == null).collect(Collectors.toList()); for (Subaccount subaccount : platformFeeSubaccountList) { subaccount.setExternalId(chinaumsTransferResultsVO.getTransferId()); subaccountRepository.saveAndFlush(subaccount); handleSubaccountStatus(subaccount, true); } } else { // 根据收款电子账簿ID查询 Company company = companyRepository.findByWalletId(chinaumsTransferResultsVO.getRecvBalanceAcctId()); if (company == null) { continue; } // 获取对应的企业分账记录 List<Subaccount> companySubaccountList = newSubaccountList.stream().filter(filterSubaccount -> filterSubaccount.getCompany() != null && filterSubaccount.getCompany().equals(company)).collect(Collectors.toList()); for (Subaccount subaccount : companySubaccountList) { subaccount.setExternalId(chinaumsTransferResultsVO.getTransferId()); subaccountRepository.saveAndFlush(subaccount); handleSubaccountStatus(subaccount, true); } } writeSeparateLog(String.format("[分账][生成][普通订单][%s][发货单][%s],生成分账单成功,银联结算单号[%s]。", order.getSn(), shipping.getShippingSn(), chinaumsTransferResultsVO.getTransferId())); } } // 判断是否分账结束 if (checkIsSubaccountByShipping(subaccountList)) { updateIsSeparateAccountsByShipping(shipping); // 判断订单是否已分账 if (checkIsSubaccountOrder(subaccountRepository.findAllByOrdersId(order.getId()))) { orderRepository.updateIsSeparateAccountsById(order.getId()); } } } /** * 合并消费担保确认 * * @return * @description * @author huabiao * @create 2023/2/6 17:17 */ @Transactional(rollbackFor = YnceErrorException.class) public void confirmsCombinedGuaranteeByOrder(Order order) { // 获取银联支付单 List<ChinaumsPayment> chinaumsPaymentList = getChinaumsPaymentList(order); // 获取分账记录 List<Subaccount> subaccountList = getSubaccountListAndCheck(order); if (subaccountList == null) { return; } // 获取订单费用比例 OrderFeeRatio orderFeeRatio = orderFeeRatioRepository.findByOrdersId(order.getId()); // 获取所有结算单(包含正常订单和退货退款) List<Statement> allStatementList = getStatementList(order); if (allStatementList == null) { return; } // 正常订单结算单 List<Statement> statementList = allStatementList.stream().filter(statement -> statement.getStatementType().equals(StatementType.NORMALORDER)).collect(Collectors.toList()); // 退货退款结算单 List<Statement> allAfterSaleStatementList = allStatementList.stream().filter(statement -> statement.getStatementType().equals(StatementType.AFTERSALES)).collect(Collectors.toList()); // 平台服务费分账记录 List<Subaccount> platformSubaccountList = getSubaccountListAndCheck(order, chinaumsPaymentList, subaccountList, orderFeeRatio, statementList, allAfterSaleStatementList); if (platformSubaccountList == null) { return; } // 品牌授权费 setBrandInfoToSubAccountList(order, chinaumsPaymentList, subaccountList, orderFeeRatio, statementList, allAfterSaleStatementList, platformSubaccountList); // 获取已生成的平台服务费分账记录 List<Subaccount> platformSubaccounts = subaccountList.stream().filter(subaccount -> subaccount.getCompany() == null).collect(Collectors.toList()); if (CollectionUtils.isNotEmpty(platformSubaccounts)) { for (Subaccount platformSubaccount : platformSubaccounts) { handleSubaccountStatus(platformSubaccount, false); } } else if (CollectionUtils.isNotEmpty(platformSubaccountList)) { // 获取平台电子账簿ID String balanceAcctId = chinaumsUtil.getFeeBalanceAcctId(); // 获取平台服务费对应的银联支付单 ChinaumsPayment chinaumsPayment = chinaumsPaymentRepository.findFirstByOrdersIdAndRecvBalanceAcctId(order.getId(), balanceAcctId); if (chinaumsPayment != null) { // 平台服务费退款金额 BigDecimal platformServiceFeeRefundAmount = BigDecimal.ZERO; // 获取银联退款单 List<ChinaumsRefund> chinaumsRefundList = chinaumsRefundRepository.findAllByOrigTradeId(chinaumsPayment.getGuaranteePaymentId()); if (CollectionUtils.isNotEmpty(chinaumsRefundList)) { platformServiceFeeRefundAmount = chinaumsRefundList.stream().map(ChinaumsRefund::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add); } // 分账记录总平台服务费 BigDecimal totalPlatformServiceFee = platformSubaccountList.stream().map(subaccount -> subaccount.getSubaccountAmount()).reduce(BigDecimal.ZERO, BigDecimal::add); // 银联单据计算平台服务费 BigDecimal platformServiceFee = chinaumsPayment.getAmount().subtract(platformServiceFeeRefundAmount); // 只有当分账记录的金额和银联支付单金额一致才进行分账 if (totalPlatformServiceFee.compareTo(platformServiceFee) == 0) { Company platformCompany = companyRepository.findByWalletId(balanceAcctId); BusinessRelations businessRelations = businessRelationsRepository.findFirstBySourceCompany(platformCompany); List<ByxChinaumsGuaranteePayConfirmsDetailDTO> confirmsDetailDTOList = new ArrayList<>(); ByxChinaumsGuaranteePayConfirmsDetailDTO confirmsDetailDTO = ByxChinaumsGuaranteePayConfirmsDetailDTO .builder() .profitSharingWalletId(balanceAcctId) .profitSharingAmt(platformServiceFee.multiply(new BigDecimal(100)).longValue()) .build(); confirmsDetailDTOList.add(confirmsDetailDTO); ByxChinaumsGuaranteePayConfirmsDTO byxChinaumsGuaranteePayConfirmsDTO = ByxChinaumsGuaranteePayConfirmsDTO .builder() .mctOrderNo(platformSubaccountList.get(0).getSubaccountNo()) .oriTransOrderNo(chinaumsPayment.getGuaranteePaymentId()) .platformWalletId(balanceAcctId) .settAmt(platformServiceFee.multiply(new BigDecimal(100)).longValue()) .isFinished("Y") .bizType("030001") //担保支付 030001 .profitSharingRuleId(businessRelations.getChinaumsRuleId()) .profitSharingList(confirmsDetailDTOList) .build(); try { String externalId = walletService.paySettlementConfirms(byxChinaumsGuaranteePayConfirmsDTO); writeSeparateLog(String.format("[分账][生成][普通订单][%s],生成分账单成功,银联结算单号[%s]。", order.getSn(), externalId)); for (Subaccount subaccount : platformSubaccountList) { subaccount.setExternalId(externalId); subaccountRepository.saveAndFlush(subaccount); handleSubaccountStatus(subaccount, false); } subaccountList.addAll(platformSubaccountList); } catch (Exception e) { // TODO 当请求返回异常时,直接跳过 log.error(e.getMessage()); } } else { writeSeparateLog(String.format("[分账][生成][普通订单][%s],生成分账单失败,分账金额与银联支付单剩余金额不一致。", order.getSn())); } } } // 判断是否分账结束 if (checkIsSubaccountOrder(subaccountList)) { // 更新订单已分账 finishOrderSubaccount(order); } } private void setBrandInfoToSubAccountList(Order order, List<ChinaumsPayment> chinaumsPaymentList, List<Subaccount> subaccountList, OrderFeeRatio orderFeeRatio, List<Statement> statementList, List<Statement> allAfterSaleStatementList, List<Subaccount> platformSubaccountList) { if (CollectionUtils.isNotEmpty(orderFeeRatio.getOrderItemFeeRatio())) { // 获取品牌授权费银联支付单 List<ChinaumsPayment> brandAuthFeeChinaumsPaymentList = chinaumsPaymentList.stream().filter(filterChinaumsPayment -> filterChinaumsPayment.getSubaccountType().equals(SubaccountType.BRAND_AUTH_FEE)).collect(Collectors.toList()); // 获取品牌授权费的分账记录 List<Subaccount> brandAuthFeeSubaccountList = subaccountList.stream().filter(subaccount -> subaccount.getSubaccountType().equals(SubaccountType.BRAND_AUTH_FEE)).collect(Collectors.toList()); for (ChinaumsPayment chinaumsPayment : brandAuthFeeChinaumsPaymentList) { // 获取货款结算单,并根据品牌ID获取对应的品牌授权费 Statement statement = statementList.stream().filter(filterStatement -> filterStatement.getSubaccountType().equals(SubaccountType.GOODS_COST)).findFirst().orElse(null); // 品牌授权费 BigDecimal brandAuthFee = statement.getStatementLine().stream().map(StatementLine::getBrandAuthFee).reduce(BigDecimal.ZERO, BigDecimal::add); // 品牌授权费退款金额 BigDecimal brandAuthFeeRefundAmount = BigDecimal.ZERO; // 获取退款货款结算单,并根据品牌ID获取对应的退款品牌授权费 List<Statement> afterSaleStatementList = allAfterSaleStatementList.stream().filter(filterStatement -> filterStatement.getSubaccountType().equals(SubaccountType.GOODS_COST)).collect(Collectors.toList()); if (CollectionUtils.isNotEmpty(afterSaleStatementList)) { for (Statement afterSaleStatement : afterSaleStatementList) { brandAuthFeeRefundAmount = brandAuthFeeRefundAmount.add(afterSaleStatement.getStatementLine().stream().map(StatementLine::getBrandAuthFee).reduce(BigDecimal.ZERO, BigDecimal::add)); } } // 获取分账企业 Company company = companyRepository.findByWalletId(chinaumsPayment.getRecvBalanceAcctId()); // 平台服务费 BigDecimal platformServiceFee; // 平台服务费分账记录 Subaccount platformSubaccount = null; // 获取订单项费用比例 OrderItemFeeRatio orderItemFeeRatio = orderFeeRatio.getOrderItemFeeRatio().stream().filter(filterOrderItemFeeRatio -> filterOrderItemFeeRatio.getOrderItem().getBrandId().equals(chinaumsPayment.getBrandId())).findFirst().orElse(null); if (orderItemFeeRatio != null && orderItemFeeRatio.getBrandAuthCostServiceCostRatio().compareTo(BigDecimal.ZERO) == 1) { // 计算平台服务费 platformServiceFee = brandAuthFee.subtract(brandAuthFeeRefundAmount).multiply(orderItemFeeRatio.getBrandAuthCostServiceCostRatio()).setScale(2, BigDecimal.ROUND_UP); // 拼接平台服务费分账 if (platformServiceFee.compareTo(BigDecimal.ZERO) == 1) { platformSubaccount = generatePlatformSubaccount(orderItemFeeRatio.getBrandAuthCostServiceCostRatio(), platformServiceFee, order, null, company); if (platformSubaccount != null) { platformSubaccountList.add(platformSubaccount); } } } // 判断该品牌授权费是否存在分账记录(根据品牌ID) Subaccount subaccount = brandAuthFeeSubaccountList.stream().filter(filterSubaccount -> filterSubaccount.getBrandId().equals(chinaumsPayment.getBrandId())).findFirst().orElse(null); if (subaccount != null) { // 若是未分账则调用银联接口 if (subaccount.getSubaccountState().equals(SubaccountState.SEPARATE_NOT)) { handleSubaccountStatus(subaccount, false); } continue; } // 分账金额 = 银联支付单金额 - 银联退款单金额 BigDecimal subaccountAmount = chinaumsPayment.getAmount(); // 获取银联退款单 List<ChinaumsRefund> chinaumsRefundList = chinaumsRefundRepository.findAllByOrigTradeId(chinaumsPayment.getGuaranteePaymentId()); if (CollectionUtils.isNotEmpty(chinaumsRefundList)) { for (ChinaumsRefund chinaumsRefund : chinaumsRefundList) { subaccountAmount = subaccountAmount.subtract(chinaumsRefund.getAmount()); } } if (subaccountAmount.compareTo(BigDecimal.ZERO) == 1) { // 拼接分账记录 subaccount = new Subaccount(); subaccount.setSubaccountNo(sequenceUtil.getNextSequenceNumber("FZ")); subaccount.setCompany(company); subaccount.setSubaccountAmount(subaccountAmount); subaccount.setSubaccountTotalAmount(subaccount.getSubaccountAmount()); subaccount.setSubaccountType(SubaccountType.BRAND_AUTH_FEE); subaccount.setOrders(order); subaccount.setSubaccountState(SubaccountState.SEPARATE_NOT); subaccount.setSourceCompany(order.getBuyerCompany()); subaccount.setBrandId(chinaumsPayment.getBrandId()); if (platformSubaccount != null) { subaccount.setPlatformServiceCostRatio(platformSubaccount.getSubaccountCostRatio()); subaccount.setPlatformServiceFee(platformSubaccount.getSubaccountAmount()); } // 获取平台电子账簿ID String balanceAcctId = chinaumsUtil.getFeeBalanceAcctId(); Company platformCompany = companyRepository.findByWalletId(balanceAcctId); BusinessRelations businessRelations = businessRelationsRepository.findFirstBySourceCompany(platformCompany); List<ByxChinaumsGuaranteePayConfirmsDetailDTO> confirmsDetailDTOList = new ArrayList<>(); ByxChinaumsGuaranteePayConfirmsDetailDTO confirmsDetailDTO = ByxChinaumsGuaranteePayConfirmsDetailDTO .builder() .profitSharingWalletId(subaccount.getCompany().getWalletId()) .profitSharingAmt(subaccount.getSubaccountAmount().multiply(new BigDecimal(100)).longValue()) .build(); confirmsDetailDTOList.add(confirmsDetailDTO); ByxChinaumsGuaranteePayConfirmsDTO byxChinaumsGuaranteePayConfirmsDTO = ByxChinaumsGuaranteePayConfirmsDTO .builder() .mctOrderNo(subaccount.getSubaccountNo()) .oriTransOrderNo(chinaumsPayment.getGuaranteePaymentId()) .platformWalletId(balanceAcctId) .settAmt(subaccount.getSubaccountAmount().multiply(new BigDecimal(100)).longValue()) .isFinished("N") .bizType("030001") //担保支付 030001 .profitSharingRuleId(businessRelations.getChinaumsRuleId()) .profitSharingList(confirmsDetailDTOList) .build(); String settOrderNo; try { settOrderNo = walletService.paySettlementConfirms(byxChinaumsGuaranteePayConfirmsDTO); } catch (Exception exception) { // 当请求返回异常时,直接跳过 continue; } subaccount.setExternalId(settOrderNo); subaccountRepository.saveAndFlush(subaccount); writeSeparateLog(String.format("[分账][生成][普通订单][%s],生成分账单成功,银联结算单号[%s]。", order.getSn(), settOrderNo)); handleSubaccountStatus(subaccount, false); brandAuthFeeSubaccountList.add(subaccount); } } subaccountList.addAll(brandAuthFeeSubaccountList); } } private Map<String, BigDecimal> calRefundFee(Order order, List<Statement> allAfterSaleStatementList, Statement statement) { Map<String, BigDecimal> refundFeeMap = new HashMap<>(); // 退款金额 BigDecimal refundAmount = BigDecimal.ZERO; // 退款品牌授权费 BigDecimal refundBrandAuthFee = BigDecimal.ZERO; // 该结算单对应的退款结算单 List<Statement> afterSaleStatementList = allAfterSaleStatementList.stream().filter(filterStatement -> filterStatement.getSubaccountType().equals(statement.getSubaccountType())).collect(Collectors.toList()); // 查询所有已完成售后单 List<AfterSale> afterSaleList = afterSaleRepository.findAllByOrdersIdAndAfterSaleStatus(order.getId(), AfterSaleStatus.COMPLETED); if (CollectionUtils.isNotEmpty(afterSaleList)) { if (CollectionUtils.isEmpty(afterSaleStatementList)) { writeSeparateLog(String.format("[分账][生成][普通订单][%s][结算单][%s],该分账单存在退款结算单未生成", order.getSn(), statement.getStatementNo())); return null; } // 若存在退款结算单,需判断单据数量是否一致(注意,可能存在非售后途径退款) if (afterSaleList.size() != afterSaleStatementList.stream().filter(filterStatement -> filterStatement.getAfterSale() != null).count()) { writeSeparateLog(String.format("[分账][生成][普通订单][%s][结算单][%s],该分账单存在退款结算单未生成", order.getSn(), statement.getStatementNo())); return null; } for (Statement afterSaleStatement : afterSaleStatementList) { refundAmount = refundAmount.add(afterSaleStatement.getStatementAmount()); refundBrandAuthFee = refundBrandAuthFee.add(afterSaleStatement.getStatementLine().stream().map(StatementLine::getBrandAuthFee).reduce(BigDecimal.ZERO, BigDecimal::add)); } } else { refundAmount = afterSaleStatementList.stream().map(Statement::getStatementAmount).reduce(BigDecimal.ZERO, BigDecimal::add); } refundFeeMap.put("refundAmount", refundAmount); refundFeeMap.put("refundBrandAuthFee", refundBrandAuthFee); return refundFeeMap; } private List<Subaccount> getSubaccountListAndCheck(Order order, List<ChinaumsPayment> chinaumsPaymentList, List<Subaccount> subaccountList, OrderFeeRatio orderFeeRatio, List<Statement> statementList, List<Statement> allAfterSaleStatementList) { List<Subaccount> platformSubaccountList = new ArrayList<>(); for (Statement statement : statementList) { // 计算 退款金额 和 退款品牌授权费 Map<String, BigDecimal> refundFeeMap = this.calRefundFee(order, allAfterSaleStatementList, statement); if (refundFeeMap == null) { return null; } // 退款金额 BigDecimal refundAmount = refundFeeMap.get("refundAmount"); // 退款品牌授权费 BigDecimal refundBrandAuthFee = refundFeeMap.get("refundBrandAuthFee"); // 平台服务费 BigDecimal platformServiceFee = BigDecimal.ZERO; // 拼接平台服务费分账 Subaccount platformSubaccount = calculationPlatformServiceFee(statement, orderFeeRatio, refundAmount.add(refundBrandAuthFee)); if (platformSubaccount != null) { platformSubaccountList.add(platformSubaccount); platformServiceFee = platformSubaccount.getSubaccountAmount(); } // 判断是否存在分账记录(根据分账企业和分账类型) Subaccount subaccount = subaccountList.stream().filter(filterSubaccount -> filterSubaccount.getSubaccountType().equals(statement.getSubaccountType()) && filterSubaccount.getCompany() != null && filterSubaccount.getCompany().equals(statement.getCompany())).findFirst().orElse(null); if (subaccount != null) { // 若是未分账则调用银联接口 if (subaccount.getSubaccountState().equals(SubaccountState.SEPARATE_NOT)) { handleSubaccountStatus(subaccount, false); } if (platformSubaccount != null && platformSubaccount.getSubaccountAmount().compareTo(subaccount.getPlatformServiceFee()) != 0) { platformSubaccount.setSubaccountAmount(subaccount.getPlatformServiceFee()); platformSubaccount.setSubaccountTotalAmount(subaccount.getPlatformServiceFee()); } continue; } // 获取银联支付单 ChinaumsPayment chinaumsPayment = chinaumsPaymentList.stream().filter(filterChinaumsPayment -> filterChinaumsPayment.getRecvBalanceAcctId().equals(statement.getCompany().getWalletId()) && filterChinaumsPayment.getSubaccountType().equals(statement.getSubaccountType())).findFirst().orElse(null); if (chinaumsPayment == null) { continue; } subaccount = new Subaccount(); subaccount.setSubaccountNo(sequenceUtil.getNextSequenceNumber("FZ")); subaccount.setCompany(companyRepository.findById(statement.getCompany().getId()).orElse(null)); // 以订单进行分账,则分账金额 = 银联支付单金额 if (statement.getSubaccountType().equals(SubaccountType.GOODS_COST)) { // 货款分账金额 = 结算金额 + 退款金额 - 平台服务费 - 品牌授权费 + 退款品牌授权费 BigDecimal brandAuthFee = statement.getStatementLine().stream().map(statementLine -> statementLine.getBrandAuthFee()).reduce(BigDecimal.ZERO, BigDecimal::add); subaccount.setSubaccountAmount(statement.getStatementAmount().add(refundAmount).subtract(platformServiceFee).subtract(brandAuthFee).add(refundBrandAuthFee)); if (CollectionUtils.isNotEmpty(orderFeeRatio.getOrderItemFeeRatio())) { subaccount.setBrandAuthCostRatio(orderFeeRatio.getOrderItemFeeRatio().get(0).getBrandAuthCostRatio()); } subaccount.setBrandAuthFee(brandAuthFee.add(refundBrandAuthFee)); } else { // 其他分账金额 = 结算金额 - 退款金额 - 平台服务费 subaccount.setSubaccountAmount(statement.getStatementAmount().add(refundAmount).subtract(platformServiceFee)); } // 根据银联支付单和银联退款单计算最终分账金额 List<ChinaumsRefund> chinaumsRefundList = chinaumsRefundRepository.findAllByOrigTradeId(chinaumsPayment.getGuaranteePaymentId()); BigDecimal chinaumsRefundAmount = chinaumsRefundList.stream().map(ChinaumsRefund::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add); BigDecimal finallySubaccountAmount = chinaumsPayment.getAmount().subtract(chinaumsRefundAmount); if (finallySubaccountAmount.compareTo(subaccount.getSubaccountAmount()) != 0) { BigDecimal balance = subaccount.getSubaccountAmount().subtract(finallySubaccountAmount); subaccount.setSubaccountAmount(finallySubaccountAmount); // 计算实际服务费 BigDecimal finallyPlatformSubaccountAmount = platformSubaccount.getSubaccountAmount().add(balance); platformSubaccount.setSubaccountAmount(finallyPlatformSubaccountAmount); platformSubaccount.setSubaccountTotalAmount(finallyPlatformSubaccountAmount); } subaccount.getSubaccountAmount(); subaccount.setSubaccountCostRatio(getCostRatio(statement, orderFeeRatio)); subaccount.setSubaccountType(statement.getSubaccountType()); subaccount.setOrders(statement.getOrders()); subaccount.setSubaccountState(SubaccountState.SEPARATE_NOT); subaccount.setSourceCompany(order.getBuyerCompany()); subaccount.setSubaccountTotalAmount(statement.getStatementAmount().add(refundAmount)); if (platformSubaccount != null) { subaccount.setPlatformServiceCostRatio(platformSubaccount.getSubaccountCostRatio()); subaccount.setPlatformServiceFee(platformSubaccount.getSubaccountAmount()); } // 获取平台电子账簿ID String balanceAcctId = chinaumsUtil.getFeeBalanceAcctId(); Company platformCompany = companyRepository.findByWalletId(balanceAcctId); BusinessRelations businessRelations = businessRelationsRepository.findFirstBySourceCompany(platformCompany); List<ByxChinaumsGuaranteePayConfirmsDetailDTO> confirmsDetailDTOList = new ArrayList<>(); ByxChinaumsGuaranteePayConfirmsDetailDTO confirmsDetailDTO = ByxChinaumsGuaranteePayConfirmsDetailDTO .builder() .profitSharingWalletId(subaccount.getCompany().getWalletId()) .profitSharingAmt(subaccount.getSubaccountAmount().multiply(new BigDecimal(100)).longValue()) .build(); confirmsDetailDTOList.add(confirmsDetailDTO); ByxChinaumsGuaranteePayConfirmsDTO byxChinaumsGuaranteePayConfirmsDTO = ByxChinaumsGuaranteePayConfirmsDTO .builder() .mctOrderNo(subaccount.getSubaccountNo()) .oriTransOrderNo(chinaumsPayment.getGuaranteePaymentId()) .platformWalletId(balanceAcctId) .settAmt(subaccount.getSubaccountAmount().multiply(new BigDecimal(100)).longValue()) .isFinished("N") .bizType("030001") //担保支付 030001 .profitSharingRuleId(businessRelations.getChinaumsRuleId()) .profitSharingList(confirmsDetailDTOList) .build(); String settOrderNo; try { settOrderNo = walletService.paySettlementConfirms(byxChinaumsGuaranteePayConfirmsDTO); } catch (Exception exception) { // 当请求返回异常时,直接跳过 platformSubaccountList.remove(platformSubaccount); continue; } subaccount.setExternalId(settOrderNo); subaccountRepository.saveAndFlush(subaccount); writeSeparateLog(String.format("[分账][生成][普通订单][%s],生成分账单成功,银联结算单号[%s]。", order.getSn(), settOrderNo)); handleSubaccountStatus(subaccount, false); subaccountList.add(subaccount); } return platformSubaccountList; } private List<Statement> getStatementList(Order order) { List<Statement> allStatementList = statementRepository.findAllByOrdersId(order.getId()); if (CollectionUtils.isEmpty(allStatementList)) { writeSeparateLog(String.format("[分账][生成][普通订单][%s],未存在结算单。", order.getSn())); return null; } return allStatementList; } private List<ChinaumsPayment> getChinaumsPaymentList(Order order) { List<ChinaumsPayment> chinaumsPaymentList = chinaumsPaymentRepository.findAllByOrdersId(order.getId()); if (CollectionUtils.isEmpty(chinaumsPaymentList)) { chinaumsPaymentList = walletService.handleChinaumsPayment(order); } return chinaumsPaymentList; } private List<Subaccount> getSubaccountListAndCheck(Order order) { List<Subaccount> subaccountList = subaccountRepository.findAllByOrdersId(order.getId()); if (subaccountList == null) { return new ArrayList<>(); } if (checkIsSubaccountOrder(subaccountList)) { // 更新订单已分账 finishOrderSubaccount(order); writeSeparateLog(String.format("[分账][生成][普通订单][%s],分账单已存在,更新订单为已分账", order.getSn())); return null; } return subaccountList; } /** * 合并消费担保确认 * * @return * @description * @author huabiao * @create 2023/2/6 17:17 */ public void confirmsCombinedGuaranteeByShipping(Shipping shipping) { // 自定义参数 JSONObject metadata = new JSONObject(); metadata.put("shippingSn", shipping.getShippingSn()); Order order = shipping.getOrders(); // 获取订单费用比例 OrderFeeRatio orderFeeRatio = orderFeeRatioRepository.findByOrdersId(order.getId()); // 获取银联支付单 List<ChinaumsPayment> chinaumsPaymentList = getChinaumsPaymentList(order); // 待确认平台服务费金额 BigDecimal toBeConfirmedServiceFeeAmount = BigDecimal.ZERO; // 查询平台服务费对应银联支付单 ChinaumsPayment serviceFeeChinaumsPayment = chinaumsPaymentList.stream().filter(filterChinaumsPayment -> filterChinaumsPayment.getSubaccountType().equals(SubaccountType.SERVICE_FEE)).findFirst().orElse(null); if (serviceFeeChinaumsPayment != null) { toBeConfirmedServiceFeeAmount = serviceFeeChinaumsPayment.getAmount().subtract(serviceFeeChinaumsPayment.getConfirmedAmount()); // 获取平台服务费银联退款单 List<ChinaumsRefund> serviceFeeChinaumsRefundList = chinaumsRefundRepository.findAllByOrigTradeId(serviceFeeChinaumsPayment.getGuaranteePaymentId()); if (CollectionUtils.isNotEmpty(serviceFeeChinaumsRefundList)) { toBeConfirmedServiceFeeAmount = toBeConfirmedServiceFeeAmount.subtract(serviceFeeChinaumsRefundList.stream().map(ChinaumsRefund::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add)); } } // 获取分账记录 List<Subaccount> subaccountList = subaccountRepository.findAllByShippingId(shipping.getId()); if (checkIsSubaccount(subaccountList, chinaumsPaymentList, toBeConfirmedServiceFeeAmount.compareTo(BigDecimal.ZERO) == 0)) { // 更新发货单已分账 updateIsSeparateAccountsByShipping(shipping); writeSeparateLog(String.format("[分账][生成][普通订单][%s][发货单][%s],分账单已存在,更新发货单为已分账", order.getSn(), shipping.getShippingSn())); return; } // 判断是否最后分账 Boolean isFinallySubaccount = isFinallySubaccount(shipping); // 获取结算单 List<Statement> statementList = statementRepository.findAllByShippingIdAndStatementType(shipping.getId(), StatementType.NORMALORDER); // 获取退款结算单 List<Statement> allAfterSaleStatementList = statementRepository.findAllByShippingIdAndStatementType(shipping.getId(), StatementType.AFTERSALES); // 平台服务费分账记录 List<Subaccount> platformSubaccountList = new ArrayList<>(); for (Statement statement : statementList) { // 获取对应分账类型的退款结算单 List<Statement> afterSaleStatementList = allAfterSaleStatementList.stream().filter(filterStatement -> filterStatement.getSubaccountType().equals(statement.getSubaccountType())).collect(Collectors.toList()); // 退款金额 BigDecimal refundAmount = BigDecimal.ZERO; // 退款品牌授权费 BigDecimal refundBrandAuthFee = BigDecimal.ZERO; // 获取售后单 List<AfterSale> afterSaleList = afterSaleRepository.findAllByShippingIdAndAfterSaleStatus(shipping.getId(), AfterSaleStatus.COMPLETED); if (CollectionUtils.isNotEmpty(afterSaleStatementList)) { if (afterSaleList.size() != afterSaleStatementList.size()) { writeSeparateLog(String.format("[分账][生成][普通订单][%s][发货单][%s][结算单][%s],该分账单存在退款结算单未生成", order.getSn(), shipping.getShippingSn(), statement.getStatementNo())); return; } for (Statement afterSaleStatement : afterSaleStatementList) { refundAmount = refundAmount.add(afterSaleStatement.getStatementAmount()); refundBrandAuthFee = refundBrandAuthFee.add(afterSaleStatement.getStatementLine().stream().map(StatementLine::getBrandAuthFee).reduce(BigDecimal.ZERO, BigDecimal::add)); } } else { // 当不存在退款结算单时,需判断是否还未生成 if (CollectionUtils.isNotEmpty(afterSaleList)) { writeSeparateLog(String.format("[分账][生成][普通订单][%s][发货单][%s][结算单][%s],该分账单存在退款结算单未生成", order.getSn(), shipping.getShippingSn(), statement.getStatementNo())); return; } } // 平台服务费 BigDecimal platformServiceFee = BigDecimal.ZERO; // 拼接平台服务费分账 Subaccount platformSubaccount = calculationPlatformServiceFee(statement, orderFeeRatio, refundAmount); if (platformSubaccount != null) { // 当待确认平台服务费大于平台服务费分账金额时 if (toBeConfirmedServiceFeeAmount.compareTo(platformSubaccount.getSubaccountAmount()) != -1) { platformSubaccountList.add(platformSubaccount); platformServiceFee = platformSubaccount.getSubaccountAmount(); } else { platformSubaccount = null; } } // 判断是否存在分账记录(根据分账企业和分账类型) Subaccount subaccount = subaccountList.stream().filter(filterSubaccount -> filterSubaccount.getSubaccountType().equals(statement.getSubaccountType()) && filterSubaccount.getCompany() != null && filterSubaccount.getCompany().equals(statement.getCompany())).findFirst().orElse(null); if (subaccount != null) { // 若是未分账则调用银联接口 if (subaccount.getSubaccountState().equals(SubaccountState.SEPARATE_NOT)) { handleSubaccountStatus(subaccount, false); } continue; } subaccount = new Subaccount(); subaccount.setSubaccountNo(sequenceUtil.getNextSequenceNumber("FZ")); subaccount.setCompany(statement.getCompany()); subaccount.setSubaccountCostRatio(getCostRatio(statement, orderFeeRatio)); if (platformSubaccount != null) { subaccount.setPlatformServiceCostRatio(platformSubaccount.getSubaccountCostRatio()); subaccount.setPlatformServiceFee(platformSubaccount.getSubaccountAmount()); } subaccount.setSubaccountTotalAmount(statement.getStatementAmount().add(refundAmount)); // 保存品牌授权费 BigDecimal brandAuthFee = BigDecimal.ZERO; if (statement.getSubaccountType().equals(SubaccountType.GOODS_COST) && CollectionUtils.isNotEmpty(orderFeeRatio.getOrderItemFeeRatio())) { brandAuthFee = statement.getStatementLine().stream().map(StatementLine::getBrandAuthFee).reduce(BigDecimal.ZERO, BigDecimal::add); subaccount.setBrandAuthCostRatio(orderFeeRatio.getOrderItemFeeRatio().get(0).getBrandAuthCostRatio()); subaccount.setBrandAuthFee(brandAuthFee.add(refundBrandAuthFee)); } if (isFinallySubaccount) { // 获取银联支付单 ChinaumsPayment chinaumsPayment = chinaumsPaymentList.stream().filter(filterChinaumsPayment -> filterChinaumsPayment.getSubaccountType().equals(statement.getSubaccountType()) && filterChinaumsPayment.getOrders().equals(order)).findFirst().orElse(null); // 获取银联退款单 List<ChinaumsRefund> chinaumsRefundList = chinaumsRefundRepository.findAllByOrigTradeId(chinaumsPayment.getGuaranteePaymentId()); BigDecimal chinaumsRefundAmount = BigDecimal.ZERO; if (CollectionUtils.isNotEmpty(chinaumsRefundList)) { chinaumsRefundAmount = chinaumsRefundList.stream().map(ChinaumsRefund::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add); } // 分账金额 = 银联支付金额 - 银联确认金额 - 银联退款金额 subaccount.setSubaccountAmount(chinaumsPayment.getAmount().subtract(chinaumsPayment.getConfirmedAmount()).subtract(chinaumsRefundAmount)); } else { if (statement.getSubaccountType().equals(SubaccountType.GOODS_COST)) { // 货款分账金额 = 结算金额 + 退款金额 - 平台服务费 - 品牌授权费 + 退款品牌授权费 subaccount.setSubaccountAmount(statement.getStatementAmount().add(refundAmount).subtract(platformServiceFee).subtract(brandAuthFee).add(refundBrandAuthFee)); } else { // 其他分账金额 = 结算金额 - 退款金额 - 平台服务费 subaccount.setSubaccountAmount(statement.getStatementAmount().add(refundAmount).subtract(platformServiceFee)); } } // 当分账金额小于等于0时跳过 if (subaccount.getSubaccountAmount().compareTo(BigDecimal.ZERO) != 1) { continue; } subaccount.setSubaccountType(statement.getSubaccountType()); subaccount.setOrders(statement.getOrders()); subaccount.setShipping(statement.getShipping()); subaccount.setSubaccountState(SubaccountState.SEPARATE_NOT); subaccount.setSourceCompany(order.getBuyerCompany()); // 获取银联支付单 ChinaumsPayment chinaumsPayment = chinaumsPaymentList.stream().filter(filterChinaumsPayment -> filterChinaumsPayment.getRecvBalanceAcctId().equals(statement.getCompany().getWalletId()) && filterChinaumsPayment.getSubaccountType().equals(statement.getSubaccountType())).findFirst().orElse(null); // 拼接扩展字段:商品信息 ChinaumsGuaranteePayExtraDTO chinaumsGuaranteePayExtraDTO = new ChinaumsGuaranteePayExtraDTO(); chinaumsGuaranteePayExtraDTO.setProductInfos(this.handleProductInfoByShipping(shipping.getShippingItem(), order.getSn(), shipping.getAmount(), subaccount.getSubaccountAmount())); // 拼接分账确认请求参数 ChinaumsGuaranteePayConfirmsDTO chinaumsGuaranteePayConfirmsDTO = ChinaumsGuaranteePayConfirmsDTO .builder() .outOrderNo(subaccount.getSubaccountNo()) .guaranteePaymentId(chinaumsPayment.getGuaranteePaymentId()) .sentAt(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX").format(new Date())) .amount(subaccount.getSubaccountAmount().multiply(new BigDecimal(100)).intValue()) .extra(chinaumsGuaranteePayExtraDTO) .metadata(metadata) .build(); ChinaumsGuaranteePayConfirmsVO chinaumsGuaranteePayConfirmsVO; try { chinaumsGuaranteePayConfirmsVO = walletService.paySettlement(chinaumsGuaranteePayConfirmsDTO); } catch (Exception exception) { // 当请求返回异常时,直接跳过 continue; } subaccount.setExternalId(chinaumsGuaranteePayConfirmsVO.getCombinedGuaranteeConfirmId()); subaccountRepository.saveAndFlush(subaccount); writeSeparateLog(String.format("[分账][生成][普通订单][%s],生成分账单成功,银联结算单号[%s]。", order.getSn(), chinaumsGuaranteePayConfirmsVO.getCombinedGuaranteeConfirmId())); handleSubaccountStatus(subaccount, false); subaccountList.add(subaccount); // 存在平台服务费时,需要在待确认金额中减去 if (platformSubaccount != null) { toBeConfirmedServiceFeeAmount = toBeConfirmedServiceFeeAmount.subtract(platformServiceFee); } } // 品牌授权费 if (CollectionUtils.isNotEmpty(orderFeeRatio.getOrderItemFeeRatio())) { // 找出品牌授权费的发货项 Map<Long, List<ShippingItem>> brandIdShippingItemListMap = new HashMap<>(); for (OrderItemFeeRatio orderItemFeeRatio : orderFeeRatio.getOrderItemFeeRatio()) { ShippingItem shippingItem = shipping.getShippingItem().stream().filter(filterShippingItem -> filterShippingItem.getOrderItemId().equals(orderItemFeeRatio.getOrderItem().getId().toString())).findFirst().orElse(null); if (shippingItem != null) { Long brandId = orderItemFeeRatio.getOrderItem().getBrandId(); if (brandIdShippingItemListMap.containsKey(brandId)) { List<ShippingItem> shippingItemList = new ArrayList<>(brandIdShippingItemListMap.get(brandId)); shippingItemList.add(shippingItem); brandIdShippingItemListMap.put(brandId, shippingItemList); } else { brandIdShippingItemListMap.put(orderItemFeeRatio.getOrderItem().getBrandId(), Arrays.asList(shippingItem)); } } } if (!brandIdShippingItemListMap.isEmpty()) { // 获取品牌授权费的分账记录 List<Subaccount> brandAuthFeeSubaccountList = subaccountList.stream().filter(subaccount -> subaccount.getSubaccountType().equals(SubaccountType.BRAND_AUTH_FEE)).collect(Collectors.toList()); // 平台服务费分账记录 Subaccount platformSubaccount = new Subaccount(); for (Map.Entry<Long, List<ShippingItem>> brandIdShippingItemListEntry : brandIdShippingItemListMap.entrySet()) { Long brandId = brandIdShippingItemListEntry.getKey(); List<ShippingItem> shippingItemList = brandIdShippingItemListEntry.getValue(); // 通过品牌ID获取银联支付单号 ChinaumsPayment chinaumsPayment = chinaumsPaymentList.stream().filter(filterChinaumsPayment -> filterChinaumsPayment.getSubaccountType().equals(SubaccountType.BRAND_AUTH_FEE) && filterChinaumsPayment.getBrandId() != null && filterChinaumsPayment.getBrandId().equals(brandId)).findFirst().orElse(null); // 判断该银联支付单是否已分账 if (chinaumsPayment != null) { // 判断该品牌授权费是否存在分账记录(根据品牌ID) Subaccount subaccount = brandAuthFeeSubaccountList.stream().filter(filterSubaccount -> filterSubaccount.getBrandId().equals(chinaumsPayment.getBrandId())).findFirst().orElse(null); if (subaccount != null) { // 若是未分账则调用银联接口 if (subaccount.getSubaccountState().equals(SubaccountState.SEPARATE_NOT)) { handleSubaccountStatus(subaccount, false); } continue; } // 获取货款结算单 Statement goodsCostStatement = statementList.stream().filter(statement -> statement.getSubaccountType().equals(SubaccountType.GOODS_COST)).findFirst().orElse(null); // 获取货款退款结算单 List<Statement> afterSaleStatementList = allAfterSaleStatementList.stream().filter(filterStatement -> filterStatement.getSubaccountType().equals(SubaccountType.GOODS_COST)).collect(Collectors.toList()); // 计算发货总金额 BigDecimal shippingAmount = BigDecimal.ZERO; // 计算品牌授权费 BigDecimal brandAuthFee = BigDecimal.ZERO; for (ShippingItem shippingItem : shippingItemList) { shippingAmount = shippingAmount.add(shippingItem.getAmount()); // 找到符合条件的对应结算单项 StatementLine statementLine = goodsCostStatement.getStatementLine().stream().filter(filterStatementLine -> filterStatementLine.getShippingItem().equals(shippingItem)).findFirst().orElse(null); if (statementLine != null) { brandAuthFee = brandAuthFee.add(statementLine.getBrandAuthFee()); } // 找到符合条件的货款退款结算单 if (CollectionUtils.isNotEmpty(afterSaleStatementList)) { for (Statement statement : afterSaleStatementList) { StatementLine afterSaleStatementLine = statement.getStatementLine().stream().filter(filterStatementLine -> filterStatementLine.getShippingItem().equals(shippingItem)).findFirst().orElse(null); if (afterSaleStatementLine != null) { brandAuthFee = brandAuthFee.subtract(afterSaleStatementLine.getBrandAuthFee()); } } } } Company company = companyRepository.findByWalletId(chinaumsPayment.getRecvBalanceAcctId()); // 计算平台服务费 BigDecimal platformServiceFee = BigDecimal.ZERO; // 获取订单项费用比例 OrderItemFeeRatio orderItemFeeRatio = orderFeeRatio.getOrderItemFeeRatio().stream().filter(filterOrderItemFeeRatio -> filterOrderItemFeeRatio.getOrderItem().getBrandId().equals(chinaumsPayment.getBrandId())).findFirst().orElse(null); if (orderItemFeeRatio != null && orderItemFeeRatio.getBrandAuthCostServiceCostRatio().compareTo(BigDecimal.ZERO) == 1) { // 计算平台服务费 platformServiceFee = brandAuthFee.multiply(orderItemFeeRatio.getBrandAuthCostServiceCostRatio()).setScale(2, BigDecimal.ROUND_UP); // 拼接平台服务费分账 if (platformServiceFee.compareTo(BigDecimal.ZERO) == 1 && toBeConfirmedServiceFeeAmount.compareTo(platformServiceFee) != -1) { platformSubaccount = generatePlatformSubaccount(orderItemFeeRatio.getBrandAuthCostServiceCostRatio(), platformServiceFee, order, shipping, company); if (platformSubaccount != null) { platformSubaccountList.add(platformSubaccount); brandAuthFee = brandAuthFee.subtract(platformServiceFee); } } else { platformServiceFee = BigDecimal.ZERO; } } // 分账总金额 BigDecimal subaccountTotalAmount = brandAuthFee.add(platformServiceFee); // 最后一笔 if (isFinallySubaccount && brandIdShippingItemListMap.size() == (brandAuthFeeSubaccountList.size() + 1)) { // 获取银联退款单 List<ChinaumsRefund> chinaumsRefundList = chinaumsRefundRepository.findAllByOrigTradeId(chinaumsPayment.getGuaranteePaymentId()); BigDecimal chinaumsRefundAmount = BigDecimal.ZERO; if (CollectionUtils.isNotEmpty(chinaumsRefundList)) { chinaumsRefundAmount = chinaumsRefundList.stream().map(ChinaumsRefund::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add); } // 分账金额 = 银联支付金额 - 银联确认金额 - 银联退款金额 brandAuthFee = chinaumsPayment.getAmount().subtract(chinaumsPayment.getConfirmedAmount()).subtract(chinaumsRefundAmount); } // 判断品牌授权费金额是否大于0 if (brandAuthFee.compareTo(BigDecimal.ZERO) != 1) { continue; } // 拼接分账记录 subaccount = new Subaccount(); subaccount.setSubaccountNo(sequenceUtil.getNextSequenceNumber("FZ")); subaccount.setCompany(company); subaccount.setSubaccountTotalAmount(subaccountTotalAmount); subaccount.setSubaccountAmount(brandAuthFee); subaccount.setSubaccountType(SubaccountType.BRAND_AUTH_FEE); subaccount.setOrders(order); subaccount.setShipping(shipping); subaccount.setSubaccountState(SubaccountState.SEPARATE_NOT); subaccount.setSourceCompany(order.getSellerCompany()); subaccount.setBrandId(brandId); if (platformSubaccount != null) { subaccount.setPlatformServiceCostRatio(platformSubaccount.getSubaccountCostRatio()); subaccount.setPlatformServiceFee(platformSubaccount.getSubaccountAmount()); } // 拼接扩展字段:商品信息 ChinaumsGuaranteePayExtraDTO chinaumsGuaranteePayExtraDTO = new ChinaumsGuaranteePayExtraDTO(); chinaumsGuaranteePayExtraDTO.setProductInfos(this.handleProductInfoByShipping(shippingItemList, order.getSn(), shippingAmount, subaccount.getSubaccountAmount())); // 拼接分账确认请求参数 ChinaumsGuaranteePayConfirmsDTO chinaumsGuaranteePayConfirmsDTO = ChinaumsGuaranteePayConfirmsDTO .builder() .outOrderNo(subaccount.getSubaccountNo()) .guaranteePaymentId(chinaumsPayment.getGuaranteePaymentId()) .sentAt(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX").format(new Date())) .amount(subaccount.getSubaccountAmount().multiply(new BigDecimal(100)).intValue()) .extra(chinaumsGuaranteePayExtraDTO) .metadata(metadata) .build(); ChinaumsGuaranteePayConfirmsVO chinaumsGuaranteePayConfirmsVO; try { chinaumsGuaranteePayConfirmsVO = walletService.paySettlement(chinaumsGuaranteePayConfirmsDTO); } catch (Exception exception) { // TODO 当请求返回异常时,直接跳过 continue; } subaccount.setExternalId(chinaumsGuaranteePayConfirmsVO.getCombinedGuaranteeConfirmId()); subaccountRepository.saveAndFlush(subaccount); writeSeparateLog(String.format("[分账][生成][普通订单][%s],生成分账单成功,银联结算单号[%s]。", order.getSn(), chinaumsGuaranteePayConfirmsVO.getCombinedGuaranteeConfirmId())); handleSubaccountStatus(subaccount, false); brandAuthFeeSubaccountList.add(subaccount); } subaccountList.addAll(brandAuthFeeSubaccountList); } } } // 获取已生成的平台服务费分账记录 List<Subaccount> platformSubaccounts = subaccountList.stream().filter(subaccount -> subaccount.getCompany() == null).collect(Collectors.toList()); if (CollectionUtils.isNotEmpty(platformSubaccounts)) { for (Subaccount platformSubaccount : platformSubaccounts) { handleSubaccountStatus(platformSubaccount, false); } } else if (CollectionUtils.isNotEmpty(platformSubaccountList)) { // 获取平台电子账簿ID String balanceAcctId = chinaumsUtil.getFeeBalanceAcctId(); // 获取平台服务费对应的银联支付单 ChinaumsPayment chinaumsPayment = chinaumsPaymentList.stream().filter(filterChinaumsPayment -> filterChinaumsPayment.getRecvBalanceAcctId().equals(balanceAcctId)).findFirst().orElse(null); if (chinaumsPayment != null) { // 获取银联退款单 List<ChinaumsRefund> chinaumsRefundList = chinaumsRefundRepository.findAllByOrigTradeId(chinaumsPayment.getGuaranteePaymentId()); BigDecimal chinaumsRefundAmount = BigDecimal.ZERO; if (CollectionUtils.isNotEmpty(chinaumsRefundList)) { chinaumsRefundAmount = chinaumsRefundList.stream().map(ChinaumsRefund::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add); } // 待确认金额 = 银联支付金额 - 确认金额 - 银联退款金额 BigDecimal toBeConfirmedAmount = chinaumsPayment.getAmount().subtract(chinaumsPayment.getConfirmedAmount()).subtract(chinaumsRefundAmount); BigDecimal platformServiceFee = platformSubaccountList.stream().map(Subaccount::getSubaccountAmount).reduce(BigDecimal.ZERO, BigDecimal::add); // 当待确认金额小于平台服务费时,以待确认金额为主 if (toBeConfirmedAmount.compareTo(platformServiceFee) == -1) { platformServiceFee = toBeConfirmedAmount; } // 拼接扩展字段:商品信息 ChinaumsGuaranteePayExtraDTO chinaumsGuaranteePayExtraDTO = new ChinaumsGuaranteePayExtraDTO(); chinaumsGuaranteePayExtraDTO.setProductInfos(this.handleProductInfoByShipping(shipping.getShippingItem(), order.getSn(), shipping.getAmount(), platformServiceFee)); // 拼接分账确认请求参数 ChinaumsGuaranteePayConfirmsDTO chinaumsGuaranteePayConfirmsDTO = ChinaumsGuaranteePayConfirmsDTO .builder() .outOrderNo(platformSubaccountList.get(0).getSubaccountNo()) .guaranteePaymentId(chinaumsPayment.getGuaranteePaymentId()) .sentAt(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX").format(new Date())) .amount(platformServiceFee.multiply(new BigDecimal(100)).intValue()) .extra(chinaumsGuaranteePayExtraDTO) .metadata(metadata) .build(); try { ChinaumsGuaranteePayConfirmsVO chinaumsGuaranteePayConfirmsVO = walletService.paySettlement(chinaumsGuaranteePayConfirmsDTO); // 已分配金额 BigDecimal allocatedAmount = BigDecimal.ZERO; for (Subaccount subaccount : platformSubaccountList) { // 待分配金额 BigDecimal toBeAllocatedAmount = platformServiceFee.subtract(allocatedAmount); // 当待分配金额大于分账金额时 if (toBeAllocatedAmount.compareTo(subaccount.getSubaccountAmount()) == 1) { subaccount.setExternalId(chinaumsGuaranteePayConfirmsVO.getCombinedGuaranteeConfirmId()); subaccountRepository.saveAndFlush(subaccount); handleSubaccountStatus(subaccount, false); } else if (toBeAllocatedAmount.compareTo(subaccount.getSubaccountAmount()) == 0) { // 当待分配金额等于分账金额,跳出循环 subaccount.setExternalId(chinaumsGuaranteePayConfirmsVO.getCombinedGuaranteeConfirmId()); subaccountRepository.saveAndFlush(subaccount); handleSubaccountStatus(subaccount, false); break; } else { // 当待分配金额小于分账金额,修改分账金额 subaccount.setSubaccountAmount(toBeAllocatedAmount); subaccount.setExternalId(chinaumsGuaranteePayConfirmsVO.getCombinedGuaranteeConfirmId()); subaccountRepository.saveAndFlush(subaccount); handleSubaccountStatus(subaccount, false); } allocatedAmount = allocatedAmount.add(subaccount.getSubaccountAmount()); } writeSeparateLog(String.format("[分账][生成][普通订单][%s],生成分账单成功,银联结算单号[%s]。", order.getSn(), chinaumsGuaranteePayConfirmsVO.getCombinedGuaranteeConfirmId())); subaccountList.addAll(platformSubaccountList); } catch (Exception exception) { // TODO 当请求返回异常时,直接跳过 } } } // 判断是否分账结束 if (checkIsSubaccount(subaccountList, chinaumsPaymentList, toBeConfirmedServiceFeeAmount.compareTo(BigDecimal.ZERO) == 0)) { updateIsSeparateAccountsByShipping(shipping); } } /** * 退款结算单-生成 * * @param subaccountType 分账类型 * @param order 订单 * @param orderRefundItemDTOList 订单关闭项数组 * @param company 分账企业 * @return 退款结算单 * @author huabiao * @create 2023/1/4 11:04 */ private Statement createRefundStatement(SubaccountType subaccountType, Order order, List<OrderRefundItemDTO> orderRefundItemDTOList, Company company) { // 获取订单费用比例 OrderFeeRatio orderFeeRatio = orderFeeRatioRepository.findByOrdersId(order.getId()); // 拼接退款结算单 Statement refundStatement = new Statement(); refundStatement.setOrders(order); refundStatement.setStatementNo(sequenceUtil.getNextSequenceNumber("FEE")); refundStatement.setStatementType(StatementType.AFTERSALES); refundStatement.setSubaccountType(subaccountType); refundStatement.setStatementState(StatementState.NOTRECORDED); // 退款总金额 BigDecimal subaccountAmount = BigDecimal.ZERO; // 拼接退款结算单行 List<StatementLine> refundStatementLineList = new ArrayList<>(); for (OrderRefundItemDTO orderRefundItemDTO : orderRefundItemDTOList) { StatementLine refundStatementLine = new StatementLine(); refundStatementLine.setStatement(refundStatement); refundStatementLine.setCompany(company); refundStatementLine.setOrderItem(orderRefundItemDTO.getOrderItem()); // 计算每个订单项的退款金额 BigDecimal subaccountLineAmount = BigDecimal.ZERO; switch (subaccountType) { case GOODS_COST: refundStatementLine.setSubaccountRatio(BigDecimal.ONE.subtract(orderFeeRatio.getBrandCostRatio()).subtract(orderFeeRatio.getDeviseCostRatio())); subaccountLineAmount = orderRefundItemDTO.getRefundAmount().subtract(orderRefundItemDTO.getHandleRefundAmount()); break; case BRAND_FEE: refundStatementLine.setSubaccountRatio(orderFeeRatio.getBrandCostRatio()); subaccountLineAmount = orderRefundItemDTO.getRefundAmount().multiply(orderFeeRatio.getBrandCostRatio()).setScale(2, BigDecimal.ROUND_HALF_UP); orderRefundItemDTO.setHandleRefundAmount(orderRefundItemDTO.getHandleRefundAmount().add(subaccountLineAmount)); break; case DEVISE_FEE: refundStatementLine.setSubaccountRatio(orderFeeRatio.getDeviseCostRatio()); subaccountLineAmount = orderRefundItemDTO.getRefundAmount().multiply(orderFeeRatio.getDeviseCostRatio()).setScale(2, BigDecimal.ROUND_HALF_UP); orderRefundItemDTO.setHandleRefundAmount(orderRefundItemDTO.getHandleRefundAmount().add(subaccountLineAmount)); break; } subaccountAmount = subaccountAmount.add(subaccountLineAmount); refundStatementLine.setSubaccountAmount(subaccountLineAmount.negate()); // 计算品牌授权费 if (subaccountType.equals(SubaccountType.GOODS_COST) && CollectionUtils.isNotEmpty(orderFeeRatio.getOrderItemFeeRatio())) { OrderItemFeeRatio orderItemFeeRatio = orderFeeRatio.getOrderItemFeeRatio().stream().filter(filterOrderItemFeeRatio -> filterOrderItemFeeRatio.getOrderItem().getId().equals(orderRefundItemDTO.getOrderItem().getId())).findFirst().orElse(null); if (orderItemFeeRatio != null) { refundStatementLine.setBrandAuthFee(subaccountLineAmount.multiply(orderItemFeeRatio.getBrandAuthCostRatio()).setScale(2, BigDecimal.ROUND_HALF_UP)); } } refundStatementLine.setQuantity(orderRefundItemDTO.getRefundQuantity()); refundStatementLineList.add(refundStatementLine); } refundStatement.setStatementLine(refundStatementLineList); refundStatement.setCompany(company); refundStatement.setStatementAmount(subaccountAmount.negate()); return refundStatement; } @Transactional(rollbackFor = Exception.class) public void finishOrderSubaccount(Order order) { order.setSubaccountTime(LocalDateTime.now()); order.setIsSeparateAccounts(true); orderRepository.save(order); } /** * 停止订单分账 * * @param orderId 订单ID * @author huabiao * @create 2023/8/24 9:49 */ private void stopOrderSubaccount(Long orderId){ // 获取该订单所有的结算单 List<Statement> statementList = statementRepository.findAllByOrdersId(orderId); // 将结算单改为已退回 statementList.stream().forEach(statement -> statement.setStatementState(StatementState.RETURNED)); statementRepository.saveAll(statementList); } }
Show line notes below