优化销售订单优惠金额分摊逻辑

- 新增OFS销售订单优惠金额分摊到明细行的功能
- 在销售出库单生成U8C销售订单时,携带优惠金额
- 优化OFS销售订单金额分摊逻辑,支持各类优惠金额的分摊
- 新增测试用例,验证优惠金额分摊的正确性
This commit is contained in:
liuy 2024-10-09 16:13:37 +08:00
parent 467120fa5e
commit 7b154fc238
6 changed files with 248 additions and 21 deletions

View File

@ -122,12 +122,12 @@ public class ProxyPurchaseReturn extends PluginBaseEntity {
@Override
public String getPluginName() {
return "OFS退出库单生成U8C红字采购订单(代理品牌采购退货)";
return "OFS退出库单生成U8C红字采购订单(代理品牌采购退货)";
}
@Override
public String getPluginLabel() {
return "OFS退出库单生成U8C红字采购订单(代理品牌采购退货)";
return "OFS退出库单生成U8C红字采购订单(代理品牌采购退货)";
}
@Override

View File

@ -158,6 +158,9 @@ public class SoSaleOutPluginInitializerToC extends PluginBaseEntity {
@Autowired
private OfsUnifiedService ofsUnifiedService;
@Autowired
private OfsOrderSaleAmountAllocationUtil ofsOrderSaleAmountAllocationUtil;
@Autowired
private TocOrderBasicArchivesCacheUtil basicArchivesCacheUtil;
@ -834,6 +837,28 @@ public class SoSaleOutPluginInitializerToC extends PluginBaseEntity {
// saleorderRequestChildrenDto.setCrecwareid(bdStordocEntity1.getPkStordoc());//收货仓库
// saleorderRequestChildrenDto.setVdef2(bdCostsubjEntity.getCostname());//收支项目
// saleorderRequestChildrenDto.setPk_defdoc2(bdCostsubjEntity.getPkCostsubj());
//如果优惠金额为0则传0
if (sonDetailsDto != null && !"0".equals(sonDetailsDto.getVdef4().stripTrailingZeros().toPlainString())) {
saleorderRequestChildrenDto.setVdef4(sonDetailsDto.getVdef4().stripTrailingZeros().toPlainString());
} else {
saleorderRequestChildrenDto.setVdef4("0");
}
if (sonDetailsDto != null && !"0".equals(sonDetailsDto.getVdef5().stripTrailingZeros().toPlainString())) {
saleorderRequestChildrenDto.setVdef5(sonDetailsDto.getVdef5().stripTrailingZeros().toPlainString());
} else {
saleorderRequestChildrenDto.setVdef5("0");
}
if (sonDetailsDto != null && !"0".equals(sonDetailsDto.getVdef6().stripTrailingZeros().toPlainString())) {
saleorderRequestChildrenDto.setVdef6(sonDetailsDto.getVdef6().stripTrailingZeros().toPlainString());
} else {
saleorderRequestChildrenDto.setVdef6("0");
}
if (sonDetailsDto != null && !"0".equals(sonDetailsDto.getVdef7().stripTrailingZeros().toPlainString())) {
saleorderRequestChildrenDto.setVdef7(sonDetailsDto.getVdef7().stripTrailingZeros().toPlainString());
} else {
saleorderRequestChildrenDto.setVdef7("0");
}
saleorderRequestChildrenDtoList.add(saleorderRequestChildrenDto);
//销售订单单据推送到u8c
@ -954,6 +979,8 @@ public class SoSaleOutPluginInitializerToC extends PluginBaseEntity {
//查询对应的OFS销售订单
List<com.hzya.frame.ttxofs.dto.ofssalesordersearch.HeaderDetailsDto> headerDetailsDtos = queryOfsOrder(headerDetailsDtoList);
findMatchingOfsOrder(headerDetailsDtos, headerDetailsDtoList);
//计算OFS销售订单优惠金额分摊到明细行
ofsOrderSaleAmountAllocationUtil.batchTocSalesAmountAllocation(headerDetailsDtos);
for (int i = 0; i < headerDetailsDtoList.size(); i++) {
HeaderDetailsDto headerDetailsDto = headerDetailsDtoList.get(i);
@ -1355,6 +1382,7 @@ public class SoSaleOutPluginInitializerToC extends PluginBaseEntity {
* 合并明细行
* 单价计算公式sum(实付金额/实发数量) 最后除以条数
*
* @param sonDetailsDtoList 销售出库单明细行集合
* @author liuyang
*/
private SonDetailsDto groupMergeDetailedRows(List<SonDetailsDto> sonDetailsDtoList) throws Exception {
@ -1379,6 +1407,11 @@ public class SoSaleOutPluginInitializerToC extends PluginBaseEntity {
SonDetailsDto sonDetailsDto = sonDetailsDtoList.get(0);
sonDetailsDto.setGroupShipQty(groupShipQty);
sonDetailsDto.setGroupTotalPayAmount(groupTotalPayAmount);
//累加4个优惠金额放在第0号元素
accumulationDiscountAmount(sonDetailsDtoList);
//累加各类优惠
logger.info("{}个明细行发生了合并!", sonDetailsDtoList.size());
return sonDetailsDto;
} else {
@ -2328,4 +2361,70 @@ public class SoSaleOutPluginInitializerToC extends PluginBaseEntity {
}
}
}
/**
* 累加平台优惠
*
* @author liuyang
*/
private void accumulationDiscountAmount(List<SonDetailsDto> sonDetailsDtoList) throws Exception {
Assert.notNull(sonDetailsDtoList, "sonDetailsDtoList不能为空");
if (sonDetailsDtoList.size() > 0) {
BigDecimal totalShareTargetPlatformDiscounts = new BigDecimal("0");
BigDecimal totalShareTargetMerchantDiscounts = new BigDecimal("0");
BigDecimal totalShareTargetExpertDiscounts = new BigDecimal("0");
BigDecimal totalShareTargetPayDiscounts = new BigDecimal("0");
for (int i = 0; i < sonDetailsDtoList.size(); i++) {
SonDetailsDto sonDetailsDto = sonDetailsDtoList.get(i);
com.hzya.frame.ttxofs.dto.ofssalesordersearch.HeaderDetailsDto headerDetailsDto = sonDetailsDto.getHeaderDetailsDto();
Assert.notNull(headerDetailsDto, "无法关联到OFS销售订单 销售订单号:{}", sonDetailsDto.getRefOrderCode());
com.hzya.frame.ttxofs.dto.ofssalesordersearch.HeaderDto header = headerDetailsDto.getHeader();
List<com.hzya.frame.ttxofs.dto.ofssalesordersearch.DetailsDto> details = headerDetailsDto.getDetails();
com.hzya.frame.ttxofs.dto.ofssalesordersearch.DetailsDto ofsOrderDetail = findOfsOrderDetail(details, sonDetailsDto);
if (ofsOrderDetail.getShareTargetPlatformDiscounts() != null) {
totalShareTargetPlatformDiscounts = totalShareTargetPlatformDiscounts.add(ofsOrderDetail.getShareTargetPlatformDiscounts());
}
if (ofsOrderDetail.getShareTargetMerchantDiscounts() != null) {
totalShareTargetMerchantDiscounts = totalShareTargetMerchantDiscounts.add(ofsOrderDetail.getShareTargetMerchantDiscounts());
}
if (ofsOrderDetail.getShareTargetExpertDiscounts() != null) {
totalShareTargetExpertDiscounts = totalShareTargetExpertDiscounts.add(ofsOrderDetail.getShareTargetExpertDiscounts());
}
if (ofsOrderDetail.getShareTargetPayDiscounts() != null) {
totalShareTargetPayDiscounts = totalShareTargetPayDiscounts.add(ofsOrderDetail.getShareTargetPayDiscounts());
}
}
sonDetailsDtoList.get(0).setVdef4(totalShareTargetPlatformDiscounts);
sonDetailsDtoList.get(0).setVdef5(totalShareTargetMerchantDiscounts);
sonDetailsDtoList.get(0).setVdef6(totalShareTargetExpertDiscounts);
sonDetailsDtoList.get(0).setVdef7(totalShareTargetPayDiscounts);
} else {
logger.info("accumulationDiscountAmount方法对应的sonDetailsDtoList.size为零");
}
}
/**
* 根据OFS销售出库单明细行查找OFS销售订单明细行
*
* @param details OFS销售订单明细行
* @param sonDetailsDto OFS销售出库单明细行
* @author liuyang
*/
private com.hzya.frame.ttxofs.dto.ofssalesordersearch.DetailsDto findOfsOrderDetail(List<com.hzya.frame.ttxofs.dto.ofssalesordersearch.DetailsDto> details, SonDetailsDto sonDetailsDto) {
Assert.notNull(details, "details不能为空");
Assert.notNull(sonDetailsDto, "sonDetailsDto不能为空");
for (int i = 0; i < details.size(); i++) {
com.hzya.frame.ttxofs.dto.ofssalesordersearch.DetailsDto detailsDto = details.get(i);
if (detailsDto.getId().equals(sonDetailsDto.getRefOrderDetailId())) {
return detailsDto;
}
}
Assert.state(false, "根据OFS销售出库单明细行无法查找OFS销售订单明细行 来源明细行主键:{} 来源明细行编码:{}", sonDetailsDto.getRefOrderDetailId(), sonDetailsDto.getRefOrderCode());
return null;
}
}

View File

@ -79,4 +79,16 @@ public class SonDetailsDto extends DetailsDto {
//对应的OFS销售订单
private com.hzya.frame.ttxofs.dto.ofssalesordersearch.HeaderDetailsDto headerDetailsDto;
//累加平台优惠
private BigDecimal vdef4;
//累加支付优惠
private BigDecimal vdef5;
//累加达人优惠
private BigDecimal vdef6;
//累加商家优惠
private BigDecimal vdef7;
}

View File

@ -27,6 +27,23 @@ public class OfsOrderSaleAmountAllocationUtil {
Logger logger = LoggerFactory.getLogger(OfsOrderSaleAmountAllocationUtil.class);
/**
* TOC销售金额批量分摊
*
* @author liuyang
*/
public void batchTocSalesAmountAllocation(List<com.hzya.frame.ttxofs.dto.ofssalesordersearch.HeaderDetailsDto> headerDetailsDtoList) {
Assert.notNull(headerDetailsDtoList, "headerDetailsDtoList不能为空");
headerDetailsDtoList.forEach(headerDetailsDto -> {
try {
tocSalesAmountAllocation(headerDetailsDto);
} catch (Exception e) {
logger.error("batchTocSalesAmountAllocation方法抛出异常批量处理TOC销售金额分摊异常", e);
}
});
}
/**
* TOC销售金额分摊
*
@ -40,12 +57,12 @@ public class OfsOrderSaleAmountAllocationUtil {
HeaderDto header = headerDetailsDto.getHeader();
List<DetailsDto> detailsOld = headerDetailsDto.getDetails();
//拷贝一份List集合并移除没有实付金额的原始
//拷贝一份List集合并移除没有商品金额的OFS销售订单明细行
List<DetailsDto> details = copyDetailsDto(detailsOld);
details.removeIf(dto -> dto.getTotalPayAmount() == null || "0".equals(new BigDecimal(dto.getTotalPayAmount()).stripTrailingZeros().toPlainString()));
details.removeIf(dto -> dto.getItemTotalAmount() == null || "0".equals(new BigDecimal(dto.getItemTotalAmount()).stripTrailingZeros().toPlainString()));
//计算分摊百分比
calculatePercentage(headerDetailsDto);
calculatePercentage(headerDetailsDto, details, header.getCode());
String platformDiscounts = header.getPlatformDiscounts();
String merchantDiscounts = header.getMerchantDiscounts();
@ -104,21 +121,21 @@ public class OfsOrderSaleAmountAllocationUtil {
detailsDto.setOriginalTargetMerchantDiscounts(targetMerchantDiscounts);
detailsDto.setShareTargetMerchantDiscounts(shareTargetMerchantDiscounts);
totalShareTargetMerchantDiscounts = totalShareTargetPlatformDiscounts.add(shareTargetMerchantDiscounts);
totalShareTargetMerchantDiscounts = totalShareTargetMerchantDiscounts.add(shareTargetMerchantDiscounts);
}
if (sharingRatio != null && targetExpertDiscounts != null) {
shareTargetExpertDiscounts = targetExpertDiscounts.multiply(sharingRatio).setScale(8, BigDecimal.ROUND_HALF_UP);
detailsDto.setOriginalTargetExpertDiscounts(targetExpertDiscounts);
detailsDto.setShareTargetExpertDiscounts(shareTargetExpertDiscounts);
totalShareTargetExpertDiscounts = totalShareTargetPlatformDiscounts.add(shareTargetExpertDiscounts);
totalShareTargetExpertDiscounts = totalShareTargetExpertDiscounts.add(shareTargetExpertDiscounts);
}
if (sharingRatio != null && targetPayDiscounts != null) {
shareTargetPayDiscounts = targetPayDiscounts.multiply(sharingRatio).setScale(8, BigDecimal.ROUND_HALF_UP);
detailsDto.setOriginalTargetPayDiscounts(targetPayDiscounts);
detailsDto.setShareTargetPayDiscounts(shareTargetPayDiscounts);
totalShareTargetPayDiscounts = totalShareTargetPlatformDiscounts.add(shareTargetPayDiscounts);
totalShareTargetPayDiscounts = totalShareTargetPayDiscounts.add(shareTargetPayDiscounts);
}
//如果是最后一行则把尾差进行追加
@ -160,7 +177,7 @@ public class OfsOrderSaleAmountAllocationUtil {
* @param headerDetailsDto2 OFS销售订单
* @author liuyang
*/
private void calculatePercentage(com.hzya.frame.ttxofs.dto.ofssalesordersearch.HeaderDetailsDto headerDetailsDto2) throws Exception {
private void calculatePercentage(com.hzya.frame.ttxofs.dto.ofssalesordersearch.HeaderDetailsDto headerDetailsDto2, List<DetailsDto> details, String ofsCode) throws Exception {
Assert.notNull(headerDetailsDto2, "headerDetailsDto2不能为空");
HeaderDto header1 = headerDetailsDto2.getHeader();
List<DetailsDto> details1 = headerDetailsDto2.getDetails();
@ -169,13 +186,22 @@ public class OfsOrderSaleAmountAllocationUtil {
for (int i = 0; i < details1.size(); i++) {
DetailsDto detailsDto = details1.get(i);
String totalPayAmount = detailsDto.getTotalPayAmount();
BigDecimal totalPayAmountBigDecimal = new BigDecimal(totalPayAmount);
String totalPayAmount = detailsDto.getItemTotalAmount();
//如果实付金额为0则不进行分摊
if (!"0".equals(totalPayAmountBigDecimal.stripTrailingZeros().toPlainString())) {
if (totalPayAmount != null && !"0".equals(new BigDecimal(totalPayAmount).stripTrailingZeros().toPlainString())) {
BigDecimal totalPayAmountBigDecimal = new BigDecimal(totalPayAmount);
//得到分摊比例
BigDecimal percentageBigDecimal = totalPayAmountBigDecimal.divide(sumActualPaymentAmountBigDecimal, 20, BigDecimal.ROUND_HALF_UP).setScale(8, BigDecimal.ROUND_HALF_UP);
detailsDto.setSharingRatio(percentageBigDecimal);
for (int j = 0; j < details.size(); j++) {
DetailsDto detailsDto1 = details.get(j);
if (detailsDto1.getId() != null && detailsDto.getId() != null) {
if (detailsDto1.getId().equals(detailsDto.getId())) {
details.get(j).setSharingRatio(percentageBigDecimal);
}
}
}
} else {
logger.info(totalPayAmount, "totalPayAmount(商品金额)为空OFS销售订单号{} 存货编码:{}", ofsCode, detailsDto.getSkuCode());
}
}
}
@ -195,15 +221,22 @@ public class OfsOrderSaleAmountAllocationUtil {
for (int i = 0; i < details1.size(); i++) {
DetailsDto detailsDto = details1.get(i);
String totalPayAmount = detailsDto.getTotalPayAmount();
if (totalPayAmount == null || "".equals(totalPayAmount.trim())) {
Assert.state(false, "销售订单收付金额不能为空 OFS销售订单号{}", code);
String itemTotalAmount = detailsDto.getItemTotalAmount();
// if (itemTotalAmount == null || "".equals(itemTotalAmount.trim())) {
// Assert.state(false, "销售订单收付金额不能为空 OFS销售订单号{}", code);
// }
if (itemTotalAmount != null && !"0".equals(new BigDecimal(itemTotalAmount).stripTrailingZeros().toPlainString())) {
BigDecimal itemTotalAmountBigDecimal = new BigDecimal(itemTotalAmount);
actualPaymentAmountBigDecimal = actualPaymentAmountBigDecimal.add(itemTotalAmountBigDecimal);
logger.info("商品金额:{}", itemTotalAmount);
}
BigDecimal totalPayAmountBigDecimal = new BigDecimal(totalPayAmount);
actualPaymentAmountBigDecimal = actualPaymentAmountBigDecimal.add(totalPayAmountBigDecimal);
}
//如果整单所有的商品金额为0则全部都不参与分摊
// if ("0".equals(actualPaymentAmountBigDecimal.stripTrailingZeros().toPlainString())) {
// Assert.state(false, "销售订单收付金额(合并后)不能为0 OFS销售订单号{}", code);
// }
if ("0".equals(actualPaymentAmountBigDecimal.stripTrailingZeros().toPlainString())) {
Assert.state(false, "销售订单收付金额(合并后)不能为0 OFS销售订单号{}", code);
logger.info("OFS销售订单号{} 整单明细行全部的商品金额都为0都不参与分摊", code);
}
return actualPaymentAmountBigDecimal;
}

View File

@ -1,10 +1,14 @@
package com.hzya.frame.plugin.lets.util;
import com.hzya.frame.WebappApplication;
import com.hzya.frame.ttxofs.dto.ofssalesordersearch.DetailsDto;
import com.hzya.frame.ttxofs.dto.ofssalesordersearch.HeaderDetailsDto;
import com.hzya.frame.ttxofs.dto.ofssalesordersearch.HeaderDto;
import com.hzya.frame.ttxofs.dto.ofssalesordersearch.SaleOrderMessageDto;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@ -25,6 +29,8 @@ import static org.junit.Assert.*;
@SpringBootTest(classes = WebappApplication.class)
public class OfsOrderSaleAmountAllocationUtilTest {
Logger logger = LoggerFactory.getLogger(OfsOrderSaleAmountAllocationUtil.class);
@Autowired
private OfsOrderSaleAmountAllocationUtil ofsOrderSaleAmountAllocationUtil;
@ -37,10 +43,87 @@ public class OfsOrderSaleAmountAllocationUtilTest {
SaleOrderMessageDto ofsOrder = afterSalesOrderUtil.getOfsOrder("LETS-SO2024092500000020");
List<HeaderDetailsDto> data = ofsOrder.getData();
if (data.size() > 0) {
ofsOrderSaleAmountAllocationUtil.tocSalesAmountAllocation(data.get(0));
//测试一所有优惠金额都为0
//测试二所有优惠金额都有null
// data.get(0).getHeader().setPlatformDiscounts(null);
// data.get(0).getHeader().setMerchantDiscounts(null);
// data.get(0).getHeader().setExpertDiscounts(null);
// data.get(0).getHeader().setPayDiscounts(null);
//测试三全部存在优惠金额数值
// data.get(0).getHeader().setPlatformDiscounts("2.3");
// data.get(0).getHeader().setMerchantDiscounts("4.9");
// data.get(0).getHeader().setExpertDiscounts("1.2");
// data.get(0).getHeader().setPayDiscounts("6.7");
//测试四没有商品金额的行过滤
// data.get(0).getDetails().get(0).setItemTotalAmount(null);
//
// data.get(0).getHeader().setPlatformDiscounts("2.3");
// data.get(0).getHeader().setMerchantDiscounts("4.9");
// data.get(0).getHeader().setExpertDiscounts("1.2");
// data.get(0).getHeader().setPayDiscounts("6.7");
// ofsOrderSaleAmountAllocationUtil.tocSalesAmountAllocation(data.get(0));
//测试五部分金额不存在的过滤
// data.get(0).getHeader().setPlatformDiscounts("2.3");
// data.get(0).getHeader().setMerchantDiscounts("4.9");
// data.get(0).getHeader().setExpertDiscounts(null);
// data.get(0).getHeader().setPayDiscounts(null);
// ofsOrderSaleAmountAllocationUtil.tocSalesAmountAllocation(data.get(0));
//测试六优惠金额全部都为0
// ofsOrderSaleAmountAllocationUtil.tocSalesAmountAllocation(data.get(0));
printNum(data);
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void printNum(List<HeaderDetailsDto> headerDetailsDtoList) {
try {
for (int i = 0; i < headerDetailsDtoList.size(); i++) {
HeaderDetailsDto headerDetailsDto = headerDetailsDtoList.get(i);
HeaderDto header = headerDetailsDto.getHeader();
List<DetailsDto> details = headerDetailsDto.getDetails();
logger.info("OFS销售订单号{} 平台优惠:{} 商家优惠:{} 达人优惠:{} 支付优惠:{}", header.getCode(), header.getPlatformDiscounts(), header.getMerchantDiscounts(), header.getExpertDiscounts(), header.getPayDiscounts());
for (int j = 0; j < details.size(); j++) {
DetailsDto detailsDto = details.get(j);
logger.info("start================================");
if (detailsDto.getSharingRatio() != null) {
logger.info("分摊比例:{}", detailsDto.getSharingRatio().stripTrailingZeros().toPlainString());
} else {
logger.info("分摊比例:无");
}
logger.info("商品金额:{}", detailsDto.getItemTotalAmount());
if (detailsDto.getShareTargetPlatformDiscounts() != null) {
logger.info("分摊平台优惠:{}", detailsDto.getShareTargetPlatformDiscounts().stripTrailingZeros().toPlainString());
} else {
logger.info("分摊平台优惠:无");
}
if (detailsDto.getShareTargetMerchantDiscounts() != null) {
logger.info("分摊商家优惠:{}", detailsDto.getShareTargetMerchantDiscounts().stripTrailingZeros().toPlainString());
} else {
logger.info("分摊商家优惠:无");
}
if (detailsDto.getShareTargetExpertDiscounts() != null) {
logger.info("分摊达人优惠:{}", detailsDto.getShareTargetExpertDiscounts().stripTrailingZeros().toPlainString());
} else {
logger.info("分摊达人优惠:无");
}
if (detailsDto.getShareTargetPayDiscounts() != null) {
logger.info("分摊支付优惠:{}", detailsDto.getShareTargetPayDiscounts().stripTrailingZeros().toPlainString());
} else {
logger.info("分摊支付优惠:无");
}
logger.info("end================================");
}
}
} catch (Exception e) {
e.printStackTrace();
logger.error("printNum方法抛出异常", e);
}
}
}

View File

@ -77,7 +77,7 @@ public class BeanUtil {
try {
// 忽略 null
if (field.get(source) != null) {
logger.info("xxx:{}", field.getName());
// logger.info("xxx:{}", field.getName());
if ("java.lang.Long".equals(it.getType().getName())) {
it.set(target, Long.valueOf(field.get(source) + ""));
} else {