优化落库功能

This commit is contained in:
wuweihua
2026-10-26 23:23:22 +08:00
parent 8fba64e2d6
commit 2bae431e74
9 changed files with 370 additions and 204 deletions
@@ -24,6 +24,16 @@ public interface IPrcOrderBillService
{
TmsPriceQuoteResult bill(TmsPriceBillRequest request);
/**
* Order-source sync only: overwrite local {@code prc_order_bill} + {@code prc_order_bill_ext}
* from an Oracle TAB_ORDER row. No quote / credit / fee / refund / AR validation.
* Rebilling remains on the order-list local-rebill path.
*
* @param upstreamRow Oracle TAB_ORDER full row
* @return billId
*/
String syncUpstreamOverwrite(java.util.Map<String, Object> upstreamRow);
/**
* Persist prc_order_bill and ext when billing cannot produce a quote.
* Status outside 0/1/2/3 does not write prc_income_bill.
@@ -290,6 +290,19 @@ public class PrcBillingTaskServiceImpl implements IPrcBillingTaskService
task.setCustomerCode(billReq.getCustomerCode());
try
{
// No hard validate on customer/product/weight: always try bill (or soft-fail snapshot)
// so upstream fields still overwrite. Quote failures land in persistFailedSnapshot.
if (StringUtils.isEmpty(billReq.getOrderNo()))
{
if (StringUtils.isNotEmpty(billReq.getTransferNo()))
{
billReq.setOrderNo(billReq.getTransferNo().trim());
}
else if (StringUtils.isNotEmpty(billReq.getTrackingNo()))
{
billReq.setOrderNo(billReq.getTrackingNo().trim());
}
}
if (StringUtils.isEmpty(billReq.getOrderNo()) && StringUtils.isEmpty(billReq.getTransferNo()))
{
throw new ServiceException("Oracle order mapped orderNo empty");
@@ -308,18 +321,6 @@ public class PrcBillingTaskServiceImpl implements IPrcBillingTaskService
deleteTaskAfterBillSaved(task);
return;
}
if (StringUtils.isEmpty(billReq.getCustomerCode()))
{
throw new ServiceException("Oracle order mapped customerCode empty");
}
if (StringUtils.isEmpty(billReq.getProductCode()))
{
throw new ServiceException("Oracle order mapped productCode empty");
}
if (billReq.getWeight() == null || billReq.getWeight().signum() <= 0)
{
throw new ServiceException("Oracle order mapped weight invalid");
}
billWithDbRetry(taskId, billReq);
}
catch (RuntimeException e)
@@ -46,6 +46,7 @@ import com.bms.customer.customerinfo.domain.BmsCustomer;
import com.bms.customer.customerinfo.mapper.BmsCustomerMapper;
import com.bms.system.mapper.SysUserMapper;
import com.bms.system.service.IBmsBizRuleService;
import com.bms.system.service.IBmsProductCodeMappingService;
import com.bms.price.domain.PrcIncomeBill;
import com.bms.price.domain.PrcIncomeBillFee;
import com.bms.price.domain.PrcOrderBill;
@@ -88,6 +89,7 @@ import com.bms.price.mapper.PrcOrderBillMapper;
import com.bms.price.mapper.PrcPayBillFeeMapper;
import com.bms.price.mapper.PrcPayBillMapper;
import com.bms.price.oracle.OracleOrderBillExtFiller;
import com.bms.price.oracle.OracleOrderBillMapper;
import com.bms.price.search.EsBizLogSupport;
import com.bms.price.search.EsLogType;
import com.bms.price.search.IBillSearchStore;
@@ -129,6 +131,9 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService
@Autowired
private PrcOrderBillExtMapper orderBillExtMapper;
@Autowired
private OracleOrderBillMapper oracleOrderBillMapper;
@Autowired
private PrcIncomeBillFeeMapper incomeBillFeeMapper;
@@ -171,6 +176,9 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService
@Autowired
private IBmsBizRuleService bizRuleService;
@Autowired
private IBmsProductCodeMappingService productCodeMappingService;
private static final int BATCH_ADD_FEE_MAX = 5000;
private static final int BATCH_ADD_FEE_PREVIEW_LIMIT = 20;
private static final int CHARGE_WEIGHT_IMPORT_MAX = 5000;
@@ -1322,12 +1330,14 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService
bill.setSurchargeAmount(surchargeTotal);
bill.setIncomeTotal(incomeTotal);
String refundStatus = resolveRefundStatus(fees);
PrcIncomeBill incomeBill = incomeBillMapper.selectByBillId(bill.getBillId());
if (incomeBill != null)
{
incomeBill.setSalesAmount(incomeTotal);
incomeBill.setIncomeTotal(incomeTotal);
incomeBill.setCurrency(StringUtils.isEmpty(bill.getCurrency()) ? "CNY" : bill.getCurrency());
incomeBill.setRefundStatus(refundStatus);
incomeBillMapper.updatePrcIncomeBill(incomeBill);
}
@@ -1335,7 +1345,7 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService
StringUtils.isEmpty(bill.getCustomerActiveStatus())
? BillCustomerActiveStatus.ACTIVE.getCode() : bill.getCustomerActiveStatus());
bill.setCreditArrearsStatus(creditArrearsStatus);
bill.setRefundStatus(resolveRefundStatus(fees));
bill.setRefundStatus(refundStatus);
orderBillMapper.updatePrcOrderBill(bill);
orderBillMapper.refreshArBillStatusByBillIds(Arrays.asList(bill.getBillId()));
return toResult(bill, fees, payBillFeeMapper.selectByBillId(bill.getBillId()));
@@ -1660,54 +1670,49 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService
}
bill.setBillKey(billKey);
bill.setOrderNo(orderNo);
// Upstream header overwrite (no validate); charge_weight kept via resolvePersistChargeWeight below.
applyUpstreamBillHeaderFields(bill, request);
Long customerId = request.getCustomerId();
if (customerId == null && result != null)
{
customerId = result.getCustomerId();
}
bill.setCustomerId(customerId == null ? Long.valueOf(0L) : customerId);
String customerCode = request.getCustomerCode();
if (StringUtils.isEmpty(customerCode) && result != null)
if (customerId == null || customerId.longValue() <= 0L)
{
customerCode = result.getCustomerCode();
customerId = resolveCustomerIdByCode(request.getCustomerCode(), bill.getCustomerId());
}
bill.setCustomerId(customerId == null ? Long.valueOf(0L) : customerId);
if (StringUtils.isEmpty(bill.getCustomerCode()) && result != null)
{
bill.setCustomerCode(result.getCustomerCode());
}
bill.setCustomerCode(customerCode);
bill.setCustomerName(request.getCustomerName());
bill.setTrackingNo(request.getTrackingNo());
bill.setTransferNo(request.getTransferNo());
// Oracle 中文人员名 -> sys_user.nick_name,*_code 写 user_name(数据权限)
resolveOrderStaffFromSysUser(request);
bill.setBelongSaler(request.getBelongSaler());
bill.setBelongSalerCode(request.getBelongSalerCode());
bill.setSettlementMan(request.getSettlementMan());
bill.setSettlementManCode(request.getSettlementManCode());
bill.setServiceMan(request.getServiceMan());
bill.setServiceManCode(request.getServiceManCode());
String customerActiveStatus = result == null ? null : result.getCustomerActiveStatus();
if (StringUtils.isEmpty(customerActiveStatus))
{
customerActiveStatus = BillCustomerActiveStatus.ACTIVE.getCode();
}
bill.setCustomerActiveStatus(customerActiveStatus);
bill.setPieces(request.getPieces());
bill.setActualWeight(request.getActualWeight());
bill.setReceiveWeight(request.getReceiveWeight());
bill.setVolume(request.getVolume());
bill.setVolumeWeight(request.getVolumeWeight());
bill.setPkgLength(request.getPkgLength());
bill.setPkgWidth(request.getPkgWidth());
bill.setPkgHeight(request.getPkgHeight());
bill.setShipperName(request.getShipperName());
bill.setConsigneeName(request.getConsigneeName());
bill.setDestPostcode(request.getDestPostcode());
bill.setWarehouseCode(request.getWarehouseCode());
bill.setOrderTime(request.getOrderTime());
applyUpstreamOrderStatus(bill, request);
bill.setOrderRemark(request.getOrderRemark());
bill.setProductCode(result.getProductCode());
bill.setProductName(result.getProductName());
bill.setCountryCode(result.getCountryCode());
bill.setCountryName(result.getCountryName());
// Product: quote result already resolved LINE_CODE via product_code_mapping.
if (result != null && StringUtils.isNotEmpty(result.getProductCode()))
{
bill.setProductCode(result.getProductCode());
}
else
{
applyProductCodeMapping(bill, request);
}
if (result != null && StringUtils.isNotEmpty(result.getProductName()))
{
bill.setProductName(result.getProductName());
}
if (StringUtils.isEmpty(bill.getCountryCode()) && result != null)
{
bill.setCountryCode(result.getCountryCode());
}
if (StringUtils.isEmpty(bill.getCountryName()) && result != null)
{
bill.setCountryName(result.getCountryName());
}
// weight = system/original; charge_weight = effective (may be manual override)
bill.setWeight(weight);
bill.setBizDate(bizDate);
@@ -2803,6 +2808,151 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService
return parsed;
}
/**
* Order-source sync: full upstream field overwrite onto local bill + ext.
* Does not quote, occupy credit, touch fees, or validate AR / refund.
*/
@Override
@Transactional(rollbackFor = Exception.class)
public String syncUpstreamOverwrite(java.util.Map<String, Object> upstreamRow)
{
if (upstreamRow == null || upstreamRow.isEmpty())
{
throw new ServiceException("Oracle order row empty");
}
TmsPriceBillRequest request = oracleOrderBillMapper.toBillRequest(upstreamRow, null);
if (request == null)
{
throw new ServiceException("Oracle order mapped empty");
}
request.setUpstreamRow(upstreamRow);
String orderNo = StringUtils.trim(request.getOrderNo());
String transferNo = StringUtils.trim(request.getTransferNo());
String trackingNo = StringUtils.trim(request.getTrackingNo());
if (StringUtils.isEmpty(orderNo))
{
orderNo = transferNo;
}
if (StringUtils.isEmpty(orderNo))
{
orderNo = trackingNo;
}
if (StringUtils.isEmpty(orderNo))
{
throw new ServiceException("Oracle order mapped orderNo empty");
}
request.setOrderNo(orderNo);
PrcOrderBill existed = orderBillMapper.selectPrcOrderBillByOrderNo(orderNo);
if (existed == null && StringUtils.isNotEmpty(transferNo))
{
existed = orderBillMapper.selectPrcOrderBillByTransferNo(transferNo);
}
if (existed == null && StringUtils.isNotEmpty(trackingNo))
{
List<PrcOrderBill> byTrack = orderBillMapper.selectPrcOrderBillByTmsIdentifier(trackingNo);
if (byTrack != null && !byTrack.isEmpty())
{
existed = byTrack.get(0);
}
}
boolean creating = existed == null;
PrcOrderBill bill = creating ? new PrcOrderBill() : existed;
if (creating)
{
bill.setBillId(UUID.randomUUID().toString());
bill.setArBillStatus(ArOrderBillStatus.UNBILLED.getCode());
bill.setRefundStatus(BillRefundStatus.NONE.getCode());
bill.setBillingFailStatus(Integer.valueOf(BillBillingFailStatus.SUCCESS.getCode()));
bill.setFreightRate(BigDecimal.ZERO);
bill.setBaseFreightRate(BigDecimal.ZERO);
bill.setRegistrationFee(BigDecimal.ZERO);
bill.setFreightAmount(BigDecimal.ZERO);
bill.setSurchargeAmount(BigDecimal.ZERO);
bill.setIncomeTotal(BigDecimal.ZERO);
bill.setPayTotal(BigDecimal.ZERO);
bill.setCurrency("CNY");
bill.setRoundMode("HALF_UP");
bill.setCustomerActiveStatus(BillCustomerActiveStatus.ACTIVE.getCode());
bill.setCreditArrearsStatus(BillCreditArrearsStatus.NORMAL.getCode());
}
bill.setBillKey(Md5Utils.hash(orderNo));
bill.setOrderNo(orderNo);
applyUpstreamBillHeaderFields(bill, request);
applyProductCodeMapping(bill, request);
Long customerId = resolveCustomerIdByCode(request.getCustomerCode(), bill.getCustomerId());
bill.setCustomerId(customerId == null ? Long.valueOf(0L) : customerId);
// System weight overwrite; charge_weight keeps existing manual override when present.
if (request.getWeight() != null)
{
bill.setWeight(request.getWeight());
if (creating || bill.getChargeWeight() == null)
{
bill.setChargeWeight(request.getWeight());
}
}
if (creating)
{
Date bizDate = request.getPickupDate() != null ? request.getPickupDate() : new Date();
bill.setBizDate(bizDate);
}
if (creating)
{
orderBillMapper.insertPrcOrderBill(bill);
}
else
{
orderBillMapper.updatePrcOrderBill(bill);
}
persistBillExt(bill, upstreamRow);
JSONObject req = new JSONObject();
req.put("action", "UPSTREAM_SYNC");
req.put("orderNo", orderNo);
req.put("transferNo", bill.getTransferNo());
req.put("billId", bill.getBillId());
req.put("orderStatus", bill.getOrderStatus());
req.put("creating", Boolean.valueOf(creating));
billSearchStore.save(EsLogType.BILL, bill.getBillId(), req.toJSONString(),
"{\"ok\":true,\"action\":\"UPSTREAM_SYNC\"}");
return bill.getBillId();
}
/** Best-effort customer id by code; keep previous id when lookup misses. */
private Long resolveCustomerIdByCode(String customerCode, Long previousId)
{
if (StringUtils.isEmpty(customerCode))
{
return previousId;
}
try
{
BmsCustomer query = new BmsCustomer();
query.setCustomerCode(customerCode.trim());
List<BmsCustomer> list = bmsCustomerMapper.selectBmsCustomerList(query);
if (list != null)
{
for (BmsCustomer row : list)
{
if (row != null && row.getCustomerId() != null
&& customerCode.trim().equalsIgnoreCase(StringUtils.trim(row.getCustomerCode())))
{
return row.getCustomerId();
}
}
}
}
catch (RuntimeException e)
{
log.warn("resolveCustomerIdByCode skip code={} msg={}", customerCode, e.getMessage());
}
return previousId;
}
@Override
@Transactional(rollbackFor = Exception.class)
public void persistFailedSnapshot(TmsPriceBillRequest request, int billingFailStatus, String errorMessage)
@@ -2839,41 +2989,19 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService
}
bill.setBillKey(Md5Utils.hash(orderNo));
bill.setOrderNo(orderNo);
bill.setCustomerId(request.getCustomerId() == null ? Long.valueOf(0L) : request.getCustomerId());
bill.setCustomerCode(request.getCustomerCode());
bill.setCustomerName(request.getCustomerName());
bill.setTrackingNo(request.getTrackingNo());
bill.setTransferNo(request.getTransferNo());
resolveOrderStaffFromSysUser(request);
bill.setBelongSaler(request.getBelongSaler());
bill.setBelongSalerCode(request.getBelongSalerCode());
bill.setSettlementMan(request.getSettlementMan());
bill.setSettlementManCode(request.getSettlementManCode());
bill.setServiceMan(request.getServiceMan());
bill.setServiceManCode(request.getServiceManCode());
applyUpstreamBillHeaderFields(bill, request);
applyProductCodeMapping(bill, request);
Long customerId = request.getCustomerId();
if (customerId == null || customerId.longValue() <= 0L)
{
customerId = resolveCustomerIdByCode(request.getCustomerCode(), bill.getCustomerId());
}
bill.setCustomerId(customerId == null ? Long.valueOf(0L) : customerId);
if (StringUtils.isEmpty(bill.getCustomerActiveStatus()))
{
bill.setCustomerActiveStatus(BillCustomerActiveStatus.ACTIVE.getCode());
}
bill.setPieces(request.getPieces());
bill.setActualWeight(request.getActualWeight());
bill.setReceiveWeight(request.getReceiveWeight());
bill.setVolume(request.getVolume());
bill.setVolumeWeight(request.getVolumeWeight());
bill.setPkgLength(request.getPkgLength());
bill.setPkgWidth(request.getPkgWidth());
bill.setPkgHeight(request.getPkgHeight());
bill.setShipperName(request.getShipperName());
bill.setConsigneeName(request.getConsigneeName());
bill.setDestPostcode(request.getDestPostcode());
bill.setWarehouseCode(request.getWarehouseCode());
bill.setOrderTime(request.getOrderTime());
applyUpstreamOrderStatus(bill, request);
bill.setOrderRemark(request.getOrderRemark());
bill.setProductCode(request.getProductCode());
bill.setProductName(request.getProductName());
bill.setCountryCode(request.getCountryCode());
bill.setCountryName(request.getCountryName());
// Soft-fail snapshot: overwrite system weight; do not touch charge_weight (keep current logic).
bill.setWeight(request.getWeight());
Date bizDate = StringUtils.isEmpty(request.getBizDate()) ? new Date() : resolveBizDate(request.getBizDate());
bill.setBizDate(bizDate);
@@ -2920,22 +3048,18 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService
}
/**
* Locked by AR bill: write fail status + upstream ORDER_STATUS only.
* Amounts / income fees stay untouched.
* Locked by AR bill: overwrite upstream header + ext; keep amounts / fees / charge_weight.
*/
private void persistFailedSnapshotWhenLocked(PrcOrderBill bill, TmsPriceBillRequest request,
int billingFailStatus, String errorMessage)
{
applyUpstreamOrderStatus(bill, request);
if (request != null)
{
if (StringUtils.isNotEmpty(request.getTrackingNo()))
applyUpstreamBillHeaderFields(bill, request);
applyProductCodeMapping(bill, request);
if (request.getWeight() != null)
{
bill.setTrackingNo(request.getTrackingNo());
}
if (StringUtils.isNotEmpty(request.getTransferNo()))
{
bill.setTransferNo(request.getTransferNo());
bill.setWeight(request.getWeight());
}
}
applyBillingFailText(bill, billingFailStatus, errorMessage);
@@ -2946,19 +3070,92 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService
}
}
/** Prefer request status fields; never clear existing order_status with null. */
/**
* Overwrite local bill header fields from upstream request (no validation).
* Does not set weight / charge_weight / bizDate / amounts / customerId.
*/
private void applyUpstreamBillHeaderFields(PrcOrderBill bill, TmsPriceBillRequest request)
{
if (bill == null || request == null)
{
return;
}
resolveOrderStaffFromSysUser(request);
bill.setCustomerCode(request.getCustomerCode());
bill.setCustomerName(request.getCustomerName());
bill.setTrackingNo(request.getTrackingNo());
bill.setTransferNo(request.getTransferNo());
bill.setBelongSaler(request.getBelongSaler());
bill.setBelongSalerCode(request.getBelongSalerCode());
bill.setSettlementMan(request.getSettlementMan());
bill.setSettlementManCode(request.getSettlementManCode());
bill.setServiceMan(request.getServiceMan());
bill.setServiceManCode(request.getServiceManCode());
bill.setPieces(request.getPieces());
bill.setActualWeight(request.getActualWeight());
bill.setReceiveWeight(request.getReceiveWeight());
bill.setVolume(request.getVolume());
bill.setVolumeWeight(request.getVolumeWeight());
bill.setPkgLength(request.getPkgLength());
bill.setPkgWidth(request.getPkgWidth());
bill.setPkgHeight(request.getPkgHeight());
bill.setShipperName(request.getShipperName());
bill.setConsigneeName(request.getConsigneeName());
bill.setDestPostcode(request.getDestPostcode());
bill.setWarehouseCode(request.getWarehouseCode());
bill.setOrderTime(request.getOrderTime());
applyUpstreamOrderStatus(bill, request);
bill.setOrderRemark(request.getOrderRemark());
// Source = TAB_ORDER.LINE_CODE / LINE_NAME (mapping applied by caller after quote / sync).
bill.setProductCode(request.getProductCode());
bill.setProductName(request.getProductName());
bill.setCountryCode(request.getCountryCode());
bill.setCountryName(request.getCountryName());
}
/**
* LINE_CODE (on request/bill) -> BMS product via product_code_mapping when configured.
*/
private void applyProductCodeMapping(PrcOrderBill bill, TmsPriceBillRequest request)
{
if (bill == null || productCodeMappingService == null)
{
return;
}
String upstream = bill.getProductCode();
if (StringUtils.isEmpty(upstream) && request != null)
{
upstream = request.getProductCode();
}
if (StringUtils.isEmpty(upstream))
{
return;
}
String mapped = productCodeMappingService.resolveBmsProductCode(upstream.trim());
if (StringUtils.isEmpty(mapped))
{
return;
}
mapped = mapped.trim();
bill.setProductCode(mapped);
if (request != null)
{
request.setProductCode(mapped);
}
}
/**
* Prefer request status fields; never clear existing order_status with null.
* Do not pin order_status to 9/10 when refundStatus=REFUNDED — rebill / upstream
* bill must follow Oracle ORDER_STATUS. Actual fee refund still sets 9 in {@link #refund}.
*/
private static void applyUpstreamOrderStatus(PrcOrderBill bill, TmsPriceBillRequest request)
{
if (bill == null || request == null)
{
return;
}
// Fee refund marks order_status=9 (已退件); do not let Oracle sync overwrite it.
if (BillRefundStatus.REFUNDED.getCode().equalsIgnoreCase(bill.getRefundStatus()))
{
bill.setOrderStatus(BillOrderStatus.REFUNDED.getCodeBoxed());
}
else if (request.getOrderStatus() != null)
if (request.getOrderStatus() != null)
{
bill.setOrderStatus(request.getOrderStatus());
}