增加规则配置

This commit is contained in:
wuweihua
2026-11-10 17:15:38 +08:00
parent f26e03efb1
commit 3c49175cea
5 changed files with 269 additions and 47 deletions
@@ -207,21 +207,7 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService
assertOrderBillEditable(request.getOrderNo());
PrcOrderBill existed = orderBillMapper.selectPrcOrderBillByOrderNo(request.getOrderNo());
BigDecimal systemWeight = request.getWeight();
// Upstream Oracle sync: always use TAB_ORDER weight (same overwrite as weight/charge_weight).
// Local rebill / manual charge_weight edit: keep resolveCalcWeight preference.
BigDecimal calcWeight = isUpstreamSyncRequest(request)
? systemWeight
: resolveCalcWeight(existed, systemWeight);
// Three-side sum rule disabled: upstream already applies it.
// Manual charge_weight wins; otherwise apply active biz rules (e.g. three-side).
// if (!isManualChargeWeight(existed))
// {
// BigDecimal ruled = bizRuleService.resolveWeightByRule(request, systemWeight);
// if (ruled != null)
// {
// calcWeight = ruled;
// }
// }
BigDecimal calcWeight = resolveBillCalcWeight(request, existed, systemWeight);
request.setWeight(calcWeight);
TmsPriceQuoteResult result = tmsPriceQuoteService.calculate(request);
persistBill(request, systemWeight, bizDate, result);
@@ -1836,8 +1822,8 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService
{
bill.setCountryName(result.getCountryName());
}
// weight = system/original; charge_weight follows weight on upstream sync,
// otherwise may keep manual override via resolvePersistChargeWeight.
// weight = system/original upstream weight; charge_weight may differ when VOL_8000
// (or manual override) raised/lowered the billed weight.
bill.setWeight(weight);
bill.setBizDate(bizDate);
bill.setTmsId(request.getTmsId() == null ? null : Long.valueOf(request.getTmsId()));
@@ -1857,7 +1843,9 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService
bill.setEffectiveDate(result.getEffectiveDate());
if (isUpstreamSyncRequest(request))
{
bill.setChargeWeight(weight);
// request.weight already carries ruled/calc weight used for quote
BigDecimal cw = request.getWeight() != null ? request.getWeight() : weight;
bill.setChargeWeight(cw);
}
else
{
@@ -2883,6 +2871,51 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService
return systemWeight;
}
/**
* Resolve weight used for quote/persist.
* Upstream: TAB_ORDER weight then biz-rule. Local: manual charge_weight wins, else biz-rule.
*/
private BigDecimal resolveBillCalcWeight(TmsPriceBillRequest request, PrcOrderBill existed,
BigDecimal systemWeight)
{
BigDecimal calcWeight = isUpstreamSyncRequest(request)
? systemWeight
: resolveCalcWeight(existed, systemWeight);
if (isUpstreamSyncRequest(request) || !isManualChargeWeight(existed))
{
calcWeight = applyBizRuleWeight(request, calcWeight);
}
return calcWeight;
}
/**
* Upstream sync / soft-fail: keep original weight, charge_weight may follow biz-rule.
*/
private void applyUpstreamWeightFields(PrcOrderBill bill, TmsPriceBillRequest request)
{
if (bill == null || request == null || request.getWeight() == null)
{
return;
}
BigDecimal systemWeight = request.getWeight();
bill.setWeight(systemWeight);
bill.setChargeWeight(applyBizRuleWeight(request, systemWeight));
}
/**
* Biz-rule charge weight (VOL_8000 etc).
* To disable: comment out the resolveWeightByRule call and always return baseWeight.
*/
private BigDecimal applyBizRuleWeight(TmsPriceBillRequest request, BigDecimal baseWeight)
{
if (request == null || baseWeight == null)
{
return baseWeight;
}
BigDecimal ruled = bizRuleService.resolveWeightByRule(request, baseWeight);
return ruled != null ? ruled : baseWeight;
}
/**
* Persist charge_weight: keep manual override when calc weight != system weight,
* or when existing bill already had a manual override.
@@ -3077,12 +3110,7 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService
applyProductCodeMapping(bill, request);
Long customerId = resolveCustomerIdByCode(request.getCustomerCode(), bill.getCustomerId());
bill.setCustomerId(customerId == null ? Long.valueOf(0L) : customerId);
// Order-source sync: overwrite weight and charge_weight the same way from upstream.
if (request.getWeight() != null)
{
bill.setWeight(request.getWeight());
bill.setChargeWeight(request.getWeight());
}
applyUpstreamWeightFields(bill, request);
if (creating)
{
Date bizDate = request.getPickupDate() != null ? request.getPickupDate() : new Date();
@@ -3194,12 +3222,7 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService
{
bill.setCustomerActiveStatus(BillCustomerActiveStatus.ACTIVE.getCode());
}
// Soft-fail snapshot: overwrite weight and charge_weight the same way from upstream.
bill.setWeight(request.getWeight());
if (request.getWeight() != null)
{
bill.setChargeWeight(request.getWeight());
}
applyUpstreamWeightFields(bill, request);
Date bizDate = StringUtils.isEmpty(request.getBizDate()) ? new Date() : resolveBizDate(request.getBizDate());
bill.setBizDate(bizDate);
if (StringUtils.isEmpty(bill.getCurrency()))
@@ -3267,11 +3290,7 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService
{
applyUpstreamBillHeaderFields(bill, request);
applyProductCodeMapping(bill, request);
if (request.getWeight() != null)
{
bill.setWeight(request.getWeight());
bill.setChargeWeight(request.getWeight());
}
applyUpstreamWeightFields(bill, request);
}
applyBillingFailText(bill, billingFailStatus, errorMessage);
orderBillMapper.updatePrcOrderBill(bill);
@@ -21,8 +21,8 @@ public interface IBmsBizRuleService
int deleteByIds(Long[] ruleIds);
/**
* Apply active weight rules to bill request.
* @return overridden weight when a rule matches; null when no rule applies
* Apply active weight rules (currently VOL_8000) to bill request.
* @return overridden charge weight when a rule matches; null when no rule applies
*/
BigDecimal resolveWeightByRule(TmsPriceBillRequest request, BigDecimal systemWeight);
}
@@ -1,6 +1,7 @@
package com.bms.system.service.impl;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashSet;
@@ -12,6 +13,8 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.bms.common.exception.ServiceException;
import com.bms.common.utils.StringUtils;
import com.bms.customer.customerinfo.domain.BmsCustomer;
import com.bms.customer.customerinfo.mapper.BmsCustomerMapper;
import com.bms.price.domain.vo.TmsPriceBillRequest;
import com.bms.system.domain.BmsBizRule;
import com.bms.system.mapper.BmsBizRuleMapper;
@@ -22,8 +25,12 @@ import com.bms.system.service.IBmsProductCodeMappingService;
public class BmsBizRuleServiceImpl implements IBmsBizRuleService
{
public static final String RULE_TYPE_THREE_SIDE = "THREE_SIDE";
/** Charge weight = max(L*W*H/8000, weightSource). */
public static final String RULE_TYPE_VOL_8000 = "VOL_8000";
public static final String WEIGHT_SOURCE_RECEIVE = "RECEIVE_WEIGHT";
public static final String WEIGHT_SOURCE_CHARGE = "CHARGE_WEIGHT";
public static final String WEIGHT_SOURCE_VOLUME = "VOLUME_WEIGHT";
private static final BigDecimal VOL_DIVISOR_8000 = new BigDecimal("8000");
@Autowired
private BmsBizRuleMapper bizRuleMapper;
@@ -31,6 +38,9 @@ public class BmsBizRuleServiceImpl implements IBmsBizRuleService
@Autowired
private IBmsProductCodeMappingService productCodeMappingService;
@Autowired
private BmsCustomerMapper bmsCustomerMapper;
@Override
public List<BmsBizRule> selectList(BmsBizRule query)
{
@@ -126,21 +136,88 @@ public class BmsBizRuleServiceImpl implements IBmsBizRuleService
{
return null;
}
List<BmsBizRule> rules = bizRuleMapper.selectActiveByType(RULE_TYPE_THREE_SIDE);
// VOL_8000 is applied on local ingest / bill. THREE_SIDE stays config-only
// (upstream already applies that product rule).
BigDecimal vol8000 = resolveVol8000(request, systemWeight);
if (vol8000 != null)
{
return vol8000;
}
return null;
}
/**
* VOL_8000: chargeWeight = max(L*W*H/8000, weightSource).
* weightSource RECEIVE_WEIGHT / CHARGE_WEIGHT / VOLUME_WEIGHT.
*/
private BigDecimal resolveVol8000(TmsPriceBillRequest request, BigDecimal systemWeight)
{
List<BmsBizRule> rules = bizRuleMapper.selectActiveByType(RULE_TYPE_VOL_8000);
if (rules == null || rules.isEmpty())
{
return null;
}
BigDecimal dimVol = calcVolumeWeight8000(request);
if (dimVol == null)
{
return null;
}
for (BmsBizRule rule : rules)
{
if (matchThreeSide(rule, request, systemWeight))
if (!matchVol8000(rule, request, systemWeight))
{
return pickWeight(rule.getWeightSource(), request, systemWeight);
continue;
}
BigDecimal other = pickWeight(rule.getWeightSource(), request, systemWeight);
if (other == null)
{
return dimVol;
}
return other.max(dimVol).setScale(3, RoundingMode.HALF_UP);
}
return null;
}
private boolean matchVol8000(BmsBizRule rule, TmsPriceBillRequest request, BigDecimal systemWeight)
{
if (rule == null)
{
return false;
}
if (!dimMatch(request.getProductCode(), rule.getProductCode(), true))
{
return false;
}
if (!dimMatch(request.getCountryCode(), rule.getCountryCode(), false))
{
return false;
}
if (!matchCustomerDim(request.getCustomerCode(), rule.getCustomerCode()))
{
return false;
}
BigDecimal checkWeight = firstPositive(request.getReceiveWeight(), request.getActualWeight(),
systemWeight, request.getWeight(), request.getVolumeWeight());
return inWeightRange(checkWeight, rule.getWeightMin(), rule.getWeightMax());
}
private static BigDecimal calcVolumeWeight8000(TmsPriceBillRequest request)
{
if (request == null)
{
return null;
}
BigDecimal l = nzDim(request.getPkgLength());
BigDecimal w = nzDim(request.getPkgWidth());
BigDecimal h = nzDim(request.getPkgHeight());
if (l == null || w == null || h == null)
{
return null;
}
return l.multiply(w).multiply(h)
.divide(VOL_DIVISOR_8000, 3, RoundingMode.HALF_UP);
}
private void assertUnique(BmsBizRule row, Long excludeId)
{
int cnt = bizRuleMapper.countByDim(row.getRuleType(), row.getProductCode(), row.getCountryCode(),
@@ -210,7 +287,7 @@ public class BmsBizRuleServiceImpl implements IBmsBizRuleService
{
return false;
}
if (!dimMatch(request.getCustomerCode(), rule.getCustomerCode(), false))
if (!matchCustomerDim(request.getCustomerCode(), rule.getCustomerCode()))
{
return false;
}
@@ -254,17 +331,109 @@ public class BmsBizRuleServiceImpl implements IBmsBizRuleService
return false;
}
/**
* Customer dim: rule may store customer_code or customer_code_dw (对外代码).
* Request may carry either form from upstream / local bill.
*/
private boolean matchCustomerDim(String requestCode, String ruleCode)
{
if (StringUtils.isEmpty(ruleCode))
{
return true;
}
if (StringUtils.isEmpty(requestCode))
{
return false;
}
String req = normalizeCode(requestCode);
String rule = normalizeCode(ruleCode);
if (req == null || rule == null)
{
return false;
}
if (req.equals(rule))
{
return true;
}
BmsCustomer byReq = findCustomerByCodeOrDw(req);
if (byReq != null && customerHasCode(byReq, rule))
{
return true;
}
BmsCustomer byRule = findCustomerByCodeOrDw(rule);
return byRule != null && customerHasCode(byRule, req);
}
private static boolean customerHasCode(BmsCustomer customer, String code)
{
if (customer == null || code == null)
{
return false;
}
String c = normalizeCode(customer.getCustomerCode());
String dw = normalizeCode(customer.getCustomerCodeDw());
return code.equals(c) || code.equals(dw);
}
private BmsCustomer findCustomerByCodeOrDw(String code)
{
if (code == null || bmsCustomerMapper == null)
{
return null;
}
try
{
BmsCustomer q = new BmsCustomer();
q.setCustomerCode(code);
List<BmsCustomer> list = bmsCustomerMapper.selectBmsCustomerList(q);
BmsCustomer hit = firstCustomerWithCode(list, code);
if (hit != null)
{
return hit;
}
q = new BmsCustomer();
q.setCustomerCodeDw(code);
list = bmsCustomerMapper.selectBmsCustomerList(q);
return firstCustomerWithCode(list, code);
}
catch (RuntimeException e)
{
return null;
}
}
private static BmsCustomer firstCustomerWithCode(List<BmsCustomer> list, String code)
{
if (list == null || list.isEmpty() || code == null)
{
return null;
}
for (BmsCustomer row : list)
{
if (customerHasCode(row, code))
{
return row;
}
}
return null;
}
private static BigDecimal pickWeight(String weightSource, TmsPriceBillRequest request, BigDecimal systemWeight)
{
if (WEIGHT_SOURCE_RECEIVE.equalsIgnoreCase(weightSource))
{
BigDecimal rw = firstPositive(request.getReceiveWeight(), request.getActualWeight());
// Prefer actual (实重), then receive weight.
BigDecimal rw = firstPositive(request.getActualWeight(), request.getReceiveWeight());
return rw != null ? rw : systemWeight;
}
if (WEIGHT_SOURCE_CHARGE.equalsIgnoreCase(weightSource))
{
return systemWeight != null ? systemWeight : request.getWeight();
}
if (WEIGHT_SOURCE_VOLUME.equalsIgnoreCase(weightSource))
{
return firstPositive(request.getVolumeWeight());
}
return null;
}
@@ -372,12 +541,12 @@ public class BmsBizRuleServiceImpl implements IBmsBizRuleService
}
if (RULE_TYPE_THREE_SIDE.equalsIgnoreCase(row.getRuleType()) && row.getSideSumMax() == null)
{
throw new ServiceException("三边规则必须填写三边和上限");
throw new ServiceException("\u4e09\u8fb9\u89c4\u5219\u5fc5\u987b\u586b\u5199\u4e09\u8fb9\u548c\u4e0a\u9650");
}
if (row.getWeightMin() != null && row.getWeightMax() != null
&& row.getWeightMin().compareTo(row.getWeightMax()) > 0)
{
throw new ServiceException("重量段最小值不能大于最大值");
throw new ServiceException("\u91cd\u91cf\u6bb5\u6700\u5c0f\u503c\u4e0d\u80fd\u5927\u4e8e\u6700\u5927\u503c");
}
}
}