修改计费失败原因

This commit is contained in:
wuweihua
2026-11-11 11:30:17 +08:00
parent 5f679b5a6e
commit 5db27e00ba
8 changed files with 582 additions and 46 deletions
@@ -0,0 +1,61 @@
package com.bms.price.domain.vo;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
/**
* Order-list billing fail reason popup payload.
*/
@Data
public class OrderBillFailReasonVo implements Serializable
{
private static final long serialVersionUID = 1L;
private String billId;
private String orderNo;
private String transferNo;
private String trackingNo;
private String customerCode;
private String customerName;
private String productCode;
private String productName;
private String countryCode;
private String countryName;
private String zoneCode;
private String zoneName;
private String destPostcode;
private Long priceSetId;
private String priceSetCode;
private String priceSetName;
private String setType;
private Long psvId;
private String versionNo;
private Long psdId;
private BigDecimal weight;
private BigDecimal chargeWeight;
private BigDecimal weightMin;
private BigDecimal weightMax;
private String weightLabel;
private BigDecimal freightRate;
private BigDecimal freightAmount;
private BigDecimal incomeTotal;
private String currency;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date bizDate;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date pickupDate;
private Integer billingFailStatus;
private String billingFailStatusLabel;
/** Raw persisted fail text. */
private String errorMessage;
/** Templated human-readable fail reason. */
private String failReasonDetail;
}
@@ -13,6 +13,7 @@ import com.bms.price.domain.vo.BatchAddIncomeBillFeeRequest;
import com.bms.price.domain.vo.ChargeWeightImportRow;
import com.bms.price.domain.vo.ChargeWeightTemplateRequest;
import com.bms.price.domain.vo.LocalRebillRequest;
import com.bms.price.domain.vo.OrderBillFailReasonVo;
import com.bms.price.domain.vo.RecalcBillPriceRequest;
import com.bms.price.domain.vo.UpdateIncomeBillFeeRequest;
import com.bms.price.domain.vo.TmsPriceBillRequest;
@@ -60,6 +61,9 @@ public interface IPrcOrderBillService
TmsPriceQuoteResult getBill(String billId);
/** Billing fail reason for order-list popup (data-scoped). */
OrderBillFailReasonVo getBillingFailReason(String billId);
TmsPriceQuoteResult getBillByOrderNo(String orderNo);
/** Manual add income fee from surcharge config; refresh receivable totals. */
@@ -62,6 +62,7 @@ import com.bms.price.domain.vo.BatchAddIncomeBillFeeRequest;
import com.bms.price.domain.vo.ChargeWeightImportRow;
import com.bms.price.domain.vo.ChargeWeightTemplateRequest;
import com.bms.price.domain.vo.LocalRebillRequest;
import com.bms.price.domain.vo.OrderBillFailReasonVo;
import com.bms.price.domain.vo.RecalcBillPriceRequest;
import com.bms.price.domain.vo.UpdateIncomeBillFeeRequest;
import com.bms.price.task.PrcBatchAddIncomeFeeAsyncRunner;
@@ -70,6 +71,7 @@ import com.bms.price.task.PrcChargeWeightImportAsyncRunner.ChargeWeightImportWor
import com.bms.price.task.PrcOrderBillExportAsyncRunner;
import com.bms.price.task.PrcOrderBillLocalRebillAsyncRunner;
import com.bms.price.task.PrcRecalcBillPriceAsyncRunner;
import com.bms.price.service.support.BillingFailReasonSupport;
import com.bms.price.service.support.OrderBillExportSupport;
import com.bms.price.domain.vo.TmsPriceBillRequest;
import com.bms.price.domain.vo.TmsOrderBillStatusResult;
@@ -85,6 +87,10 @@ import com.bms.price.mapper.PrcIncomeBillFeeMapper;
import com.bms.price.mapper.PrcIncomeBillMapper;
import com.bms.price.mapper.PrcOrderBillExtMapper;
import com.bms.price.mapper.PrcOrderBillMapper;
import com.bms.price.mapper.PrcPriceSetDetailMapper;
import com.bms.price.mapper.PrcPriceSetVersionMapper;
import com.bms.price.domain.PrcPriceSetDetail;
import com.bms.price.domain.PrcPriceSetVersion;
import com.bms.price.mapper.PrcPayBillFeeMapper;
import com.bms.price.mapper.PrcPayBillMapper;
import com.bms.price.oracle.OracleOrderBillExtFiller;
@@ -120,6 +126,12 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService
@Autowired
private PrcOrderBillMapper orderBillMapper;
@Autowired
private PrcPriceSetVersionMapper priceSetVersionMapper;
@Autowired
private PrcPriceSetDetailMapper priceSetDetailMapper;
/** TMS 实时状态查询使用客户主档案,不读取订单上的历史状态快照。 */
@Autowired
private BmsCustomerMapper bmsCustomerMapper;
@@ -432,6 +444,86 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService
payBillFeeMapper.selectByBillId(bill.getBillId()));
}
@Override
public OrderBillFailReasonVo getBillingFailReason(String billId)
{
if (StringUtils.isEmpty(billId))
{
throw new ServiceException(MessageUtils.message("price.bill.billIdRequired"));
}
PrcOrderBill query = new PrcOrderBill();
query.setBillId(billId.trim());
List<PrcOrderBill> list = self.selectBillList(query);
if (list == null || list.isEmpty())
{
throw new ServiceException(MessageUtils.message("price.bill.notFound"));
}
PrcOrderBill bill = list.get(0);
OrderBillFailReasonVo vo = new OrderBillFailReasonVo();
vo.setBillId(bill.getBillId());
vo.setOrderNo(bill.getOrderNo());
vo.setTransferNo(bill.getTransferNo());
vo.setTrackingNo(bill.getTrackingNo());
vo.setCustomerCode(bill.getCustomerCode());
vo.setCustomerName(bill.getCustomerName());
vo.setProductCode(bill.getProductCode());
vo.setProductName(bill.getProductName());
vo.setCountryCode(bill.getCountryCode());
vo.setCountryName(bill.getCountryName());
vo.setDestPostcode(bill.getDestPostcode());
vo.setPriceSetId(bill.getPriceSetId());
vo.setPriceSetCode(bill.getPriceSetCode());
vo.setPriceSetName(bill.getPriceSetName());
vo.setSetType(bill.getSetType());
vo.setPsvId(bill.getPsvId());
vo.setPsdId(bill.getPsdId());
vo.setWeight(bill.getWeight());
vo.setChargeWeight(bill.getChargeWeight());
vo.setWeightMin(bill.getWeightMin());
vo.setWeightMax(bill.getWeightMax());
vo.setWeightLabel(bill.getWeightLabel());
vo.setFreightRate(bill.getFreightRate());
vo.setFreightAmount(bill.getFreightAmount());
vo.setIncomeTotal(bill.getIncomeTotal());
vo.setCurrency(bill.getCurrency());
vo.setBizDate(bill.getBizDate());
vo.setPickupDate(bill.getPickupDate());
Integer status = bill.getBillingFailStatus() == null
? Integer.valueOf(BillBillingFailStatus.SUCCESS.getCode()) : bill.getBillingFailStatus();
vo.setBillingFailStatus(status);
vo.setBillingFailStatusLabel(OrderBillExportSupport.billingFailStatusLabel(status));
if (bill.getPsvId() != null && priceSetVersionMapper != null)
{
PrcPriceSetVersion ver = priceSetVersionMapper.selectPrcPriceSetVersionById(bill.getPsvId());
if (ver != null)
{
vo.setVersionNo(ver.getVersionNo());
}
}
if (bill.getPsdId() != null && priceSetDetailMapper != null)
{
PrcPriceSetDetail detail = priceSetDetailMapper.selectPrcPriceSetDetailById(bill.getPsdId());
if (detail != null)
{
vo.setZoneCode(detail.getZoneCode());
vo.setZoneName(detail.getZoneName());
}
}
String reason = bill.getErrorMessage();
if (StringUtils.isEmpty(reason))
{
reason = bill.getMatchMessage();
}
if (StringUtils.isEmpty(reason))
{
reason = vo.getBillingFailStatusLabel();
}
vo.setErrorMessage(reason);
vo.setFailReasonDetail(BillingFailReasonSupport.buildDetail(vo, reason));
return vo;
}
@Override
public TmsPriceQuoteResult getBillByOrderNo(String orderNo)
{
@@ -0,0 +1,114 @@
package com.bms.price.service.support;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import com.bms.common.utils.StringUtils;
import com.bms.price.domain.vo.OrderBillFailReasonVo;
/**
* Build templated billing-fail reason text for order-list popup.
*/
public final class BillingFailReasonSupport
{
private BillingFailReasonSupport() {}
private static final Map<Integer, String> TEMPLATES = new HashMap<Integer, String>();
static
{
TEMPLATES.put(Integer.valueOf(1), "\u3010\u9500\u552e\u4ef7\u672a\u5339\u914d\u4ea7\u54c1\u3011\n\u8ba2\u5355 {orderNo}\uff08\u8f6c\u5355\u53f7 {transferNo}\uff09\uff0c\u5ba2\u6237 {customer}\uff0c\u4ea7\u54c1 {product}\uff0c\u56fd\u5bb6 {country}\uff0c\u8ba1\u8d39\u65f6\u95f4 {bizDate}\u3002\n\u5728\u5ba2\u6237\u9500\u552e\u4ef7\u5957\u9910\u300c{priceSet}\u300d\u4e2d\u672a\u627e\u5230\u8be5\u4ea7\u54c1\uff0c\u8bf7\u68c0\u67e5\u5957\u9910\u4ea7\u54c1\u8303\u56f4\u6216\u4ea7\u54c1\u4ee3\u7801\u6620\u5c04\u3002");
TEMPLATES.put(Integer.valueOf(2), "\u3010\u9500\u552e\u4ef7\u672a\u5339\u914d\u56fd\u5bb6\u3011\n\u8ba2\u5355 {orderNo}\uff08\u8f6c\u5355\u53f7 {transferNo}\uff09\uff0c\u5ba2\u6237 {customer}\uff0c\u4ea7\u54c1 {product}\uff0c\u76ee\u7684\u56fd\u5bb6 {country}\uff0c\u90ae\u7f16 {postcode}\uff0c\u8ba1\u8d39\u65f6\u95f4 {bizDate}\u3002\n\u5957\u9910\u300c{priceSet}\u300d\u7248\u672c {version}\u5df2\u547d\u4e2d\u4ea7\u54c1\uff0c\u4f46\u672a\u547d\u4e2d\u56fd\u5bb6/\u5206\u533a\uff0c\u8bf7\u8865\u9f50\u56fd\u5bb6\u4e0e\u5206\u533a\u4ef7\u683c\u3002");
TEMPLATES.put(Integer.valueOf(3), "\u3010\u9500\u552e\u4ef7\u672a\u5339\u914d\u91cd\u91cf\u6bb5\u3011\n\u8ba2\u5355 {orderNo}\uff08\u8f6c\u5355\u53f7 {transferNo}\uff09\uff0c\u5ba2\u6237 {customer}\uff0c\u4ea7\u54c1 {product}\uff0c\u56fd\u5bb6 {country}\uff0c\u5206\u533a {zone}\uff0c\u8ba1\u8d39\u91cd {chargeWeight} kg\uff0c\u8ba1\u8d39\u65f6\u95f4 {bizDate}\u3002\n\u5957\u9910\u300c{priceSet}\u300d\u7248\u672c {version}\u5df2\u547d\u4e2d\u4ea7\u54c1\u4e0e\u56fd\u5bb6\uff0c\u4f46\u8ba1\u8d39\u91cd\u672a\u843d\u5728\u4ef7\u683c\u91cd\u91cf\u6bb5\u5185\uff0c\u8bf7\u68c0\u67e5\u91cd\u91cf\u6bb5\u8bbe\u7f6e\u3002");
TEMPLATES.put(Integer.valueOf(23), "\u3010\u4ea7\u54c1\u4ef7\u672a\u5339\u914d\u4ea7\u54c1\u3011\n\u8ba2\u5355 {orderNo}\uff08\u8f6c\u5355\u53f7 {transferNo}\uff09\uff0c\u5ba2\u6237 {customer}\uff0c\u4ea7\u54c1 {product}\uff0c\u56fd\u5bb6 {country}\uff0c\u8ba1\u8d39\u65f6\u95f4 {bizDate}\u3002\n\u4ea7\u54c1\u4ef7\u76ee\u5f55\u4e2d\u672a\u627e\u5230\u8be5\u4ea7\u54c1\uff0c\u8bf7\u68c0\u67e5\u4ea7\u54c1\u4ef7\u6863\u6848\u662f\u5426\u5df2\u7ef4\u62a4\u3002");
TEMPLATES.put(Integer.valueOf(24), "\u3010\u4ea7\u54c1\u4ef7\u672a\u5339\u914d\u56fd\u5bb6\u3011\n\u8ba2\u5355 {orderNo}\uff08\u8f6c\u5355\u53f7 {transferNo}\uff09\uff0c\u4ea7\u54c1 {product}\uff0c\u76ee\u7684\u56fd\u5bb6 {country}\uff0c\u90ae\u7f16 {postcode}\uff0c\u8ba1\u8d39\u65f6\u95f4 {bizDate}\u3002\n\u4ea7\u54c1\u4ef7\u5df2\u547d\u4e2d\u4ea7\u54c1\uff0c\u4f46\u672a\u547d\u4e2d\u56fd\u5bb6/\u5206\u533a\uff0c\u8bf7\u8865\u9f50\u4ea7\u54c1\u4ef7\u56fd\u5bb6\u4ef7\u683c\u3002");
TEMPLATES.put(Integer.valueOf(25), "\u3010\u4ea7\u54c1\u4ef7\u672a\u5339\u914d\u91cd\u91cf\u6bb5\u3011\n\u8ba2\u5355 {orderNo}\uff08\u8f6c\u5355\u53f7 {transferNo}\uff09\uff0c\u4ea7\u54c1 {product}\uff0c\u56fd\u5bb6 {country}\uff0c\u5206\u533a {zone}\uff0c\u8ba1\u8d39\u91cd {chargeWeight} kg\uff0c\u8ba1\u8d39\u65f6\u95f4 {bizDate}\u3002\n\u4ea7\u54c1\u4ef7\u5df2\u547d\u4e2d\u4ea7\u54c1\u4e0e\u56fd\u5bb6\uff0c\u4f46\u8ba1\u8d39\u91cd\u672a\u843d\u5728\u91cd\u91cf\u6bb5\u5185\uff0c\u8bf7\u68c0\u67e5\u4ea7\u54c1\u4ef7\u91cd\u91cf\u6bb5\u3002");
TEMPLATES.put(Integer.valueOf(4), "\u3010\u672a\u7ed1\u5b9a\u5957\u9910\u3011\n\u8ba2\u5355 {orderNo}\uff08\u8f6c\u5355\u53f7 {transferNo}\uff09\uff0c\u5ba2\u6237 {customer}\uff0c\u8ba1\u8d39\u65f6\u95f4 {bizDate}\u3002\n\u8be5\u5ba2\u6237\u672a\u7ed1\u5b9a\u9500\u552e\u4ef7\u5957\u9910\uff0c\u65e0\u6cd5\u6309\u5957\u9910\u53d6\u4ef7\uff0c\u8bf7\u5148\u5728\u5ba2\u6237/\u5957\u9910\u7ed1\u5b9a\u540e\u518d\u8ba1\u8d39\u3002");
TEMPLATES.put(Integer.valueOf(5), "\u3010\u5957\u9910\u672a\u542f\u7528/\u65e0\u751f\u6548\u7248\u672c\u3011\n\u8ba2\u5355 {orderNo}\uff08\u8f6c\u5355\u53f7 {transferNo}\uff09\uff0c\u5ba2\u6237 {customer}\uff0c\u5957\u9910\u300c{priceSet}\u300d\uff0c\u8ba1\u8d39\u65f6\u95f4 {bizDate}\u3002\n\u8ba1\u8d39\u65e5\u6ca1\u6709\u53ef\u7528\u7684\u5957\u9910\u751f\u6548\u7248\u672c\uff0c\u8bf7\u68c0\u67e5\u5957\u9910\u542f\u7528\u72b6\u6001\u4e0e\u7248\u672c\u751f\u6548\u671f\u3002");
}
public static String buildDetail(OrderBillFailReasonVo vo, String fallback)
{
if (vo == null)
{
return fallback;
}
Integer status = vo.getBillingFailStatus();
String tpl = status == null ? null : TEMPLATES.get(status);
if (StringUtils.isEmpty(tpl))
{
StringBuilder sb = new StringBuilder();
sb.append("\u3010").append(nz(vo.getBillingFailStatusLabel(), "\u8ba1\u8d39\u5931\u8d25")).append("\u3011\n");
sb.append("\u8ba2\u5355 ").append(nz(vo.getOrderNo(), "-"));
sb.append("\uff08\u8f6c\u5355\u53f7 ").append(nz(vo.getTransferNo(), "-")).append("\uff09");
sb.append("\uff0c\u5ba2\u6237 ").append(joinCodeName(vo.getCustomerCode(), vo.getCustomerName()));
sb.append("\uff0c\u4ea7\u54c1 ").append(joinCodeName(vo.getProductCode(), vo.getProductName()));
sb.append("\uff0c\u56fd\u5bb6 ").append(joinCodeName(vo.getCountryCode(), vo.getCountryName()));
sb.append("\uff0c\u8ba1\u8d39\u65f6\u95f4 ").append(fmtDate(vo.getBizDate())).append("\u3002\n");
sb.append(nz(fallback, nz(vo.getErrorMessage(), vo.getBillingFailStatusLabel())));
return sb.toString();
}
Map<String, String> ctx = new HashMap<String, String>();
ctx.put("orderNo", nz(vo.getOrderNo(), "-"));
ctx.put("transferNo", nz(vo.getTransferNo(), "-"));
ctx.put("trackingNo", nz(vo.getTrackingNo(), "-"));
ctx.put("customer", joinCodeName(vo.getCustomerCode(), vo.getCustomerName()));
ctx.put("product", joinCodeName(vo.getProductCode(), vo.getProductName()));
ctx.put("country", joinCodeName(vo.getCountryCode(), vo.getCountryName()));
ctx.put("zone", joinCodeName(vo.getZoneCode(), vo.getZoneName()));
ctx.put("postcode", nz(vo.getDestPostcode(), "-"));
ctx.put("priceSet", joinCodeName(vo.getPriceSetCode(), vo.getPriceSetName()));
ctx.put("version", nz(vo.getVersionNo(), "-"));
ctx.put("chargeWeight", fmtNum(vo.getChargeWeight()));
ctx.put("bizDate", fmtDate(vo.getBizDate()));
ctx.put("pickupDate", fmtDate(vo.getPickupDate()));
String out = tpl;
for (Map.Entry<String, String> e : ctx.entrySet())
{
out = out.replace("{" + e.getKey() + "}", e.getValue());
}
if (StringUtils.isNotEmpty(fallback) && !fallback.equals(vo.getBillingFailStatusLabel()))
{
out = out + "\n\u8be6\u60c5\uff1a" + fallback;
}
return out;
}
private static String joinCodeName(String code, String name)
{
if (StringUtils.isEmpty(code) && StringUtils.isEmpty(name))
{
return "-";
}
if (StringUtils.isEmpty(code))
{
return name;
}
if (StringUtils.isEmpty(name) || name.equals(code))
{
return code;
}
return code + "/" + name;
}
private static String fmtDate(Date d)
{
if (d == null)
{
return "-";
}
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(d);
}
private static String fmtNum(BigDecimal n)
{
return n == null ? "-" : n.stripTrailingZeros().toPlainString();
}
private static String nz(String v, String def)
{
return StringUtils.isEmpty(v) ? def : v;
}
}