一.
public void batchAssignSettlement(BuySettleVo vo) {
//查询账单下所有一级国内运费费用明细
List<SettlementCost> settlementCostList = settlementCostModelObjectFactory.select().eq("settlement", vo.getSettlementId()).eq("settleCostItem.name", "国内运费").isNull("uc_settlement_cost").findAll();
if (ObjectUtil.isNotEmpty(settlementCostList)) {
//总含税金额
BigDecimal allTotalAmount = settlementCostList.stream().map(SettlementCost::getTotalAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
//已分配的金额
BigDecimal assignedAmount = BigDecimal.ZERO;
//输入的要分配的含税金额
BigDecimal needAssignedAmount = vo.getTotalAmount();
for (int i = 0; i < settlementCostList.size(); i++) {
SettlementCost settlementCost = settlementCostList.get(i);
if ((i == settlementCostList.size() - 1 && i != 0) || settlementCostList.size() == 1) {
//最后一条减法避免尾差,只有一条全额分摊
vo.setTotalAmount(needAssignedAmount.subtract(assignedAmount));
} else {
//按比例分摊
BigDecimal assignAmount = needAssignedAmount.multiply(settlementCost.getTotalAmount()).divide(allTotalAmount, 2, RoundingMode.HALF_UP);
vo.setTotalAmount(assignAmount);
assignedAmount = assignedAmount.add(assignAmount);
}
assignSettlement(settlementCost, vo);
}
} else {
throw bizMessage.error("该账单无结算费用:国内运费");
}
}
二.
/**
* 加权分摊算法
*
* @param needAssignedAmount 要分配的金额
* @param factor 系数
* @param factorSum 总数
* @param assignedAmount 已分配金额
* @param totalSize 总数量
* @param index 序列(第几条)
* @param scale 保留小数位
* @return 要分配的金额*系数/总含税金额
*/
public static BigDecimal getWeightingShare(BigDecimal needAssignedAmount, BigDecimal factor, BigDecimal factorSum, BigDecimal assignedAmount, int totalSize, int index, int scale) {
if ((index == totalSize - 1 && index != 0) || totalSize == 1) {
//最后一条减法避免尾差,只有一条全额分摊
return needAssignedAmount.subtract(assignedAmount);
} else {
//按比例分摊
return needAssignedAmount.multiply(factor).divide(factorSum, scale, RoundingMode.HALF_UP);
}
}
List<Map<String, Object>> maps = jdbcTemplate.getJdbcTemplate().queryForList(getSql(0, OffsetDateTimeUtil.formatDateTime(beginTime), OffsetDateTimeUtil.formatDateTime(endTime)));
for (Map<String, Object> map : maps) {
Object orderId = map.get("ORDER_ID");
Object sellerId = map.get("SELLER_ID");
Object buyerId = map.get("BUYER_ID");
BigDecimal cnySettleTotalAmount = (BigDecimal) map.get("CNY_SETTLE_TOTAL_AMOUNT");
BigDecimal usdSettleTotalAmount = (BigDecimal) map.get("USD_SETTLE_TOTAL_AMOUNT");
Party seller = partyModelObjectFactory.find(sellerId);
Party buyer = partyModelObjectFactory.find(buyerId);
InternationalOrder internationalOrder = internationalOrderModelObjectFactory.find(orderId);
BigDecimal netWeight = internationalOrder.getNetWeight();
List<OrderContainerLine> orderContainerLineList = internationalOrder.getContainers().getValue();
BigDecimal totalTeu = orderContainerLineList.stream().map(orderContainerLine -> ((BigDecimal) orderContainerLine.getGoods().getRefer().get("uc_teu")).multiply(orderContainerLine.getQty())).reduce(BigDecimal.ZERO, BigDecimal::add);
//按集装箱箱型做合并
Map<Thing, List<OrderContainerLine>> groupMap = orderContainerLineList.stream().collect(Collectors.groupingBy(orderContainerLine -> orderContainerLine.getGoods().getRefer()));
int groupMapSize = groupMap.entrySet().size();
int i = 0;
BigDecimal assignedWeight = BigDecimal.ZERO;
BigDecimal assignedAmountCny = BigDecimal.ZERO;
BigDecimal assignedAmountUsd = BigDecimal.ZERO;
for (Thing containerMode : groupMap.keySet()) {
List<OrderContainerLine> items = groupMap.get(containerMode);
BigDecimal qty = items.stream().map(OrderContainerLine::getQty).reduce(BigDecimal.ZERO, BigDecimal::add);
BigDecimal teu = items.stream().map(orderContainerLine -> ((BigDecimal) orderContainerLine.getGoods().getRefer().get("uc_teu")).multiply(orderContainerLine.getQty())).reduce(BigDecimal.ZERO, BigDecimal::add);
ExportCarrierReport exportCarrierReport = exportCarrierReportModelObjectFactory.create();
exportCarrierReport.setOrderId(internationalOrder.getId());
exportCarrierReport.setOrderNo(internationalOrder.getOrderNo());
exportCarrierReport.getSeller().setValue(seller);
exportCarrierReport.getBuyer().setValue(buyer);
exportCarrierReport.setPostDate(ObjectUtil.isNotEmpty(internationalOrder.get("uc_post_date")) ? (OffsetDateTime) internationalOrder.get("uc_post_date") : internationalOrder.getOrderDate());
exportCarrierReport.setFreightForwarder(internationalOrder.get("uc_is_freight_forwarder"));
exportCarrierReport.getContainerMode().setValue(containerMode);
exportCarrierReport.setContainerQty(qty);
exportCarrierReport.setIncoTerms(internationalOrder.getIncoTerms());
exportCarrierReport.setTeu(teu);
exportCarrierReport.getOriginalStation().setValue(internationalOrder.getOriginalStation());
exportCarrierReport.getDestinationStation().setValue(internationalOrder.getDestinationStation());
if (totalTeu.compareTo(BigDecimal.ZERO) > 0) {
//加权分摊重量/人民币金额/美元金额
BigDecimal weight = SettlementUtil.getWeightingShare(netWeight, teu, totalTeu, assignedWeight, groupMapSize, i, 0);
assignedWeight = assignedWeight.add(weight);
exportCarrierReport.setWeight(weight.divide(new BigDecimal("1000"), 3, RoundingMode.HALF_UP));
BigDecimal amountCny = SettlementUtil.getWeightingShare(cnySettleTotalAmount, teu, totalTeu, assignedAmountCny, groupMapSize, i, 2);
assignedAmountCny = assignedAmountCny.add(amountCny);
exportCarrierReport.setAmountCny(amountCny);
BigDecimal amountUsd = SettlementUtil.getWeightingShare(usdSettleTotalAmount, teu, totalTeu, assignedAmountUsd, groupMapSize, i, 2);
assignedAmountUsd = assignedAmountUsd.add(amountUsd);
exportCarrierReport.setAmountUsd(amountUsd);
} else {
//teu为0则均分
BigDecimal weight = SettlementUtil.getWeightingShare(netWeight, BigDecimal.ONE, new BigDecimal(orderContainerLineList.size()), assignedWeight, groupMapSize, i, 0);
assignedWeight = assignedWeight.add(weight);
exportCarrierReport.setWeight(weight.divide(new BigDecimal("1000"), 3, RoundingMode.HALF_UP));
BigDecimal amountCny = SettlementUtil.getWeightingShare(cnySettleTotalAmount, BigDecimal.ONE, new BigDecimal(orderContainerLineList.size()), assignedAmountCny, groupMapSize, i, 2);
assignedAmountCny = assignedAmountCny.add(amountCny);
exportCarrierReport.setAmountCny(amountCny);
BigDecimal amountUsd = SettlementUtil.getWeightingShare(usdSettleTotalAmount, BigDecimal.ONE, new BigDecimal(orderContainerLineList.size()), assignedAmountUsd, groupMapSize, i, 2);
assignedAmountUsd = assignedAmountUsd.add(amountUsd);
exportCarrierReport.setAmountUsd(amountUsd);
}
exportCarrierReport.insert();
i++;
}
}