同步计费优化

This commit is contained in:
luojiaquan
2026-10-16 10:59:59 +08:00
parent 2689138b6a
commit 132688b9cf
10 changed files with 305 additions and 109 deletions
@@ -1,6 +1,7 @@
package com.bms.price.service;
import java.util.List;
import java.util.Map;
import com.bms.price.domain.PrcBillingTask;
import com.bms.price.domain.PrcBillingTaskRetryTask;
import com.bms.price.domain.vo.BillingTaskRetryByFilterRequest;
@@ -14,6 +15,12 @@ public interface IPrcBillingTaskService
/** Monitor sync: create task then process immediately (no extra MQ). */
PrcBillingTask submitAndProcess(BillingTaskSubmitRequest request);
/**
* Monitor sync with upstream Oracle full row already fetched by order list:
* billing maps the row directly, skipping per-order Oracle public-network queries.
*/
PrcBillingTask submitAndProcess(BillingTaskSubmitRequest request, Map<String, Object> upstreamRow);
/** MQ consumer entry: Oracle query -> bill -> writeback success status. */
void processTask(Long taskId);
@@ -115,6 +115,47 @@ public class PrcBillingTaskServiceImpl implements IPrcBillingTaskService
return billingTaskMapper.selectPrcBillingTaskById(task.getTaskId());
}
@Override
public PrcBillingTask submitAndProcess(BillingTaskSubmitRequest request, Map<String, Object> upstreamRow)
{
PrcBillingTask task = createWaitingTask(request, "monitor");
// 退款不依赖上游行;行缺失时也回退到按单号查询 Oracle 的原有路径
if (upstreamRow == null || upstreamRow.isEmpty()
|| BillTaskType.REFUND == BillTaskType.fromCode(task.getBillType()))
{
processTask(task.getTaskId());
}
else
{
processTaskWithUpstreamRow(task, upstreamRow);
}
return billingTaskMapper.selectPrcBillingTaskById(task.getTaskId());
}
/** 订单列表已拉回 Oracle 全行时直接计费,跳过 findMainOrder 的多次公网往返。 */
private void processTaskWithUpstreamRow(PrcBillingTask task, Map<String, Object> row)
{
Long taskId = task.getTaskId();
if (BillTaskSuccessStatus.SUCCESS.getCode().equals(task.getSuccessStatus()))
{
log.info("billing task already success taskId={}", taskId);
return;
}
try
{
if (task.getBillTime() == null)
{
throw new ServiceException("task billTime empty (billing time from mobile required)");
}
billFromUpstreamRow(task, row);
}
catch (RuntimeException e)
{
log.error("billing task failed taskId={}", taskId, e);
writeback(task, BillTaskSuccessStatus.FAILED, null, cut(e.getMessage(), 900), null);
}
}
private PrcBillingTask createWaitingTask(BillingTaskSubmitRequest request, String createBy)
{
if (request == null)
@@ -198,57 +239,7 @@ public class PrcBillingTaskServiceImpl implements IPrcBillingTaskService
{
throw new ServiceException("Oracle main order not found");
}
TmsPriceBillRequest billReq = oracleOrderBillMapper.toBillRequest(row,
billingProperties.getOracle().getDefaultProductCode());
if (billReq == null || StringUtils.isEmpty(billReq.getOrderNo()))
{
throw new ServiceException("Oracle order mapped orderNo empty");
}
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");
}
// Identity keys from mobile inbound are source of truth; do not replace with Oracle remap.
if (StringUtils.isNotEmpty(task.getTransferNo()))
{
billReq.setTransferNo(task.getTransferNo());
}
if (StringUtils.isNotEmpty(task.getTrackingNo()))
{
billReq.setTrackingNo(task.getTrackingNo());
}
if (StringUtils.isNotEmpty(task.getOrderNo()))
{
billReq.setOrderNo(task.getOrderNo());
}
// Billing datetime from task.bill_time (keep HH:mm:ss), not Oracle CREATE_DATE.
billReq.setBizDate(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(task.getBillTime()));
task.setCustomerCode(billReq.getCustomerCode());
TmsPriceQuoteResult result = billWithDbRetry(taskId, billReq);
// Soft-fail (product/country/weight miss): order bill already persisted with zero amounts;
// still mark task FAILED so it appears in abnormal-task list for retry/ops.
if (result != null && BillBillingFailStatus.isFail(result.getBillingFailStatus()))
{
String err = StringUtils.isNotEmpty(result.getMatchMessage())
? result.getMatchMessage()
: ("billingFailStatus=" + result.getBillingFailStatus());
writeback(task, BillTaskSuccessStatus.FAILED, result.getBillId(), cut(err, 900),
BillBillingFailStatus.toTaskFailCode(result.getBillingFailStatus()));
}
else
{
writeback(task, BillTaskSuccessStatus.SUCCESS, result == null ? null : result.getBillId(),
null, null);
}
billFromUpstreamRow(task, row);
}
catch (RuntimeException e)
{
@@ -257,6 +248,66 @@ public class PrcBillingTaskServiceImpl implements IPrcBillingTaskService
}
}
/**
* 用上游 Oracle 全行数据映射并计费(公共逻辑:MQ 处理与订单列表同步复用)。
* 订单列表同步时行数据已由分页查询拉回,避免每单再走 findMainOrder 的公网往返。
*/
private void billFromUpstreamRow(PrcBillingTask task, Map<String, Object> row)
{
Long taskId = task.getTaskId();
TmsPriceBillRequest billReq = oracleOrderBillMapper.toBillRequest(row,
billingProperties.getOracle().getDefaultProductCode());
if (billReq == null || StringUtils.isEmpty(billReq.getOrderNo()))
{
throw new ServiceException("Oracle order mapped orderNo empty");
}
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");
}
// Identity keys from mobile inbound are source of truth; do not replace with Oracle remap.
if (StringUtils.isNotEmpty(task.getTransferNo()))
{
billReq.setTransferNo(task.getTransferNo());
}
if (StringUtils.isNotEmpty(task.getTrackingNo()))
{
billReq.setTrackingNo(task.getTrackingNo());
}
if (StringUtils.isNotEmpty(task.getOrderNo()))
{
billReq.setOrderNo(task.getOrderNo());
}
// Billing datetime from task.bill_time (keep HH:mm:ss), not Oracle CREATE_DATE.
billReq.setBizDate(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(task.getBillTime()));
task.setCustomerCode(billReq.getCustomerCode());
TmsPriceQuoteResult result = billWithDbRetry(taskId, billReq);
// Soft-fail (product/country/weight miss): order bill already persisted with zero amounts;
// still mark task FAILED so it appears in abnormal-task list for retry/ops.
if (result != null && BillBillingFailStatus.isFail(result.getBillingFailStatus()))
{
String err = StringUtils.isNotEmpty(result.getMatchMessage())
? result.getMatchMessage()
: ("billingFailStatus=" + result.getBillingFailStatus());
writeback(task, BillTaskSuccessStatus.FAILED, result.getBillId(), cut(err, 900),
BillBillingFailStatus.toTaskFailCode(result.getBillingFailStatus()));
}
else
{
writeback(task, BillTaskSuccessStatus.SUCCESS, result == null ? null : result.getBillId(),
null, null);
}
}
/** Resolve orderNo for REFUND from task keys or existing bill (no Oracle quote required). */
private String resolveRefundOrderNo(PrcBillingTask task)
{