增加订单失败状态
This commit is contained in:
@@ -206,3 +206,6 @@ price.set.detail.duplicate.fixed=产品{0} 国家{1} 重量段{2} {3}(共{4}
|
|||||||
price.set.detail.duplicate.discount=产品{0}(共{1}条)
|
price.set.detail.duplicate.discount=产品{0}(共{1}条)
|
||||||
price.set.detail.duplicate.hasZone=有分区({0})
|
price.set.detail.duplicate.hasZone=有分区({0})
|
||||||
price.set.detail.duplicate.noZone=无分区
|
price.set.detail.duplicate.noZone=无分区
|
||||||
|
price.bill.billingFail.product=计费失败:未匹配产品
|
||||||
|
price.bill.billingFail.country=计费失败:未匹配国家
|
||||||
|
price.bill.billingFail.weight=计费失败:未匹配重量段
|
||||||
|
|||||||
@@ -116,6 +116,8 @@ public class PrcOrderBill extends BaseEntity
|
|||||||
private String creditArrearsStatus;
|
private String creditArrearsStatus;
|
||||||
/** NONE / REFUNDED */
|
/** NONE / REFUNDED */
|
||||||
private String refundStatus;
|
private String refundStatus;
|
||||||
|
/** 计费失败状态:0成功/1未匹配产品/2未匹配国家/3未匹配重量段;软失败时金额为0且不落费用明细 */
|
||||||
|
private Integer billingFailStatus;
|
||||||
private String roundMode;
|
private String roundMode;
|
||||||
|
|
||||||
private List<PrcIncomeBillFee> incomeFees;
|
private List<PrcIncomeBillFee> incomeFees;
|
||||||
|
|||||||
+20
-2
@@ -4,10 +4,8 @@ import java.io.Serializable;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import com.bms.price.domain.PrcOrderBill;
|
import com.bms.price.domain.PrcOrderBill;
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
/** Preview matched bills before async batch add fee. */
|
/** Preview matched bills before async batch add fee. */
|
||||||
@Data
|
|
||||||
public class BatchAddIncomeBillFeePreview implements Serializable
|
public class BatchAddIncomeBillFeePreview implements Serializable
|
||||||
{
|
{
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
@@ -15,4 +13,24 @@ public class BatchAddIncomeBillFeePreview implements Serializable
|
|||||||
private int matchCount;
|
private int matchCount;
|
||||||
/** First N rows for UI preview. */
|
/** First N rows for UI preview. */
|
||||||
private List<PrcOrderBill> samples = new ArrayList<PrcOrderBill>();
|
private List<PrcOrderBill> samples = new ArrayList<PrcOrderBill>();
|
||||||
|
|
||||||
|
public int getMatchCount()
|
||||||
|
{
|
||||||
|
return matchCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMatchCount(int matchCount)
|
||||||
|
{
|
||||||
|
this.matchCount = matchCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<PrcOrderBill> getSamples()
|
||||||
|
{
|
||||||
|
return samples;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSamples(List<PrcOrderBill> samples)
|
||||||
|
{
|
||||||
|
this.samples = samples;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -103,6 +103,8 @@ public class TmsPriceQuoteResult implements Serializable
|
|||||||
private String creditArrearsStatus;
|
private String creditArrearsStatus;
|
||||||
/** NONE / REFUNDED */
|
/** NONE / REFUNDED */
|
||||||
private String refundStatus;
|
private String refundStatus;
|
||||||
|
/** 计费失败状态:0成功/1未匹配产品/2未匹配国家/3未匹配重量段(仅上游同步计费软失败) */
|
||||||
|
private Integer billingFailStatus;
|
||||||
private Integer pieces;
|
private Integer pieces;
|
||||||
private BigDecimal actualWeight;
|
private BigDecimal actualWeight;
|
||||||
/** Receive weight from upstream TAB_ORDER.WEIGHT */
|
/** Receive weight from upstream TAB_ORDER.WEIGHT */
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package com.bms.price.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* prc_order_bill.billing_fail_status 计费失败状态。
|
||||||
|
* 0=成功;1=未匹配产品;2=未匹配国家;3=未匹配重量段。
|
||||||
|
*/
|
||||||
|
public enum BillBillingFailStatus
|
||||||
|
{
|
||||||
|
SUCCESS(0),
|
||||||
|
PRODUCT(1),
|
||||||
|
COUNTRY(2),
|
||||||
|
WEIGHT(3);
|
||||||
|
|
||||||
|
private final int code;
|
||||||
|
|
||||||
|
BillBillingFailStatus(int code)
|
||||||
|
{
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCode()
|
||||||
|
{
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BillBillingFailStatus of(Integer code)
|
||||||
|
{
|
||||||
|
if (code == null)
|
||||||
|
{
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
for (BillBillingFailStatus status : values())
|
||||||
|
{
|
||||||
|
if (status.code == code.intValue())
|
||||||
|
{
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isFail(Integer code)
|
||||||
|
{
|
||||||
|
return code != null && code.intValue() > SUCCESS.code;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -104,4 +104,20 @@ public interface BmsProductCountryMapper
|
|||||||
@Param("countryCode") String countryCode,
|
@Param("countryCode") String countryCode,
|
||||||
@Param("countryName") String countryName,
|
@Param("countryName") String countryName,
|
||||||
@Param("bizDate") Date bizDate);
|
@Param("bizDate") Date bizDate);
|
||||||
|
|
||||||
|
/** Count catalog rows by product (+ bizDate window), ignore country/zone/weight. */
|
||||||
|
public int countByProduct(
|
||||||
|
@Param("productCode") String productCode,
|
||||||
|
@Param("bizDate") Date bizDate);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Count catalog rows by product + country + zone (+ bizDate), ignore weight.
|
||||||
|
* Used to diagnose country miss vs weight miss.
|
||||||
|
*/
|
||||||
|
public int countByProductCountryZone(
|
||||||
|
@Param("productCode") String productCode,
|
||||||
|
@Param("countryCode") String countryCode,
|
||||||
|
@Param("countryName") String countryName,
|
||||||
|
@Param("zoneCode") String zoneCode,
|
||||||
|
@Param("bizDate") Date bizDate);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,6 +82,22 @@ public interface PrcPriceSetDetailMapper
|
|||||||
@Param("countryCode") String countryCode,
|
@Param("countryCode") String countryCode,
|
||||||
@Param("countryName") String countryName);
|
@Param("countryName") String countryName);
|
||||||
|
|
||||||
|
/** Count FIXED details by version + product (ignore country/zone/weight). */
|
||||||
|
public int countByPsvProduct(
|
||||||
|
@Param("psvId") Long psvId,
|
||||||
|
@Param("productCode") String productCode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Count FIXED details by version + product + country + zone (ignore weight).
|
||||||
|
* Used to diagnose country miss vs weight miss.
|
||||||
|
*/
|
||||||
|
public int countByPsvProductCountryZone(
|
||||||
|
@Param("psvId") Long psvId,
|
||||||
|
@Param("productCode") String productCode,
|
||||||
|
@Param("countryCode") String countryCode,
|
||||||
|
@Param("countryName") String countryName,
|
||||||
|
@Param("zoneCode") String zoneCode);
|
||||||
|
|
||||||
/** DISCOUNT by product; optional psvId scopes to version */
|
/** DISCOUNT by product; optional psvId scopes to version */
|
||||||
public PrcPriceSetDetail selectDiscountMatch(
|
public PrcPriceSetDetail selectDiscountMatch(
|
||||||
@Param("priceSetId") Long priceSetId,
|
@Param("priceSetId") Long priceSetId,
|
||||||
|
|||||||
+72
-21
@@ -60,6 +60,7 @@ import com.bms.price.domain.vo.TmsPriceQuoteResult;
|
|||||||
import com.bms.price.enums.BillCreditArrearsStatus;
|
import com.bms.price.enums.BillCreditArrearsStatus;
|
||||||
import com.bms.price.enums.BillCustomerActiveStatus;
|
import com.bms.price.enums.BillCustomerActiveStatus;
|
||||||
import com.bms.price.enums.BillRefundStatus;
|
import com.bms.price.enums.BillRefundStatus;
|
||||||
|
import com.bms.price.enums.BillBillingFailStatus;
|
||||||
import com.bms.price.enums.TmsOrderBillMatchType;
|
import com.bms.price.enums.TmsOrderBillMatchType;
|
||||||
import com.bms.price.mapper.PrcIncomeBillFeeMapper;
|
import com.bms.price.mapper.PrcIncomeBillFeeMapper;
|
||||||
import com.bms.price.mapper.PrcIncomeBillMapper;
|
import com.bms.price.mapper.PrcIncomeBillMapper;
|
||||||
@@ -1129,15 +1130,51 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService
|
|||||||
bill.setWeightLabel(result.getWeightLabel());
|
bill.setWeightLabel(result.getWeightLabel());
|
||||||
bill.setEffectiveDate(result.getEffectiveDate());
|
bill.setEffectiveDate(result.getEffectiveDate());
|
||||||
bill.setChargeWeight(resolvePersistChargeWeight(weight, result.getChargeWeight()));
|
bill.setChargeWeight(resolvePersistChargeWeight(weight, result.getChargeWeight()));
|
||||||
bill.setFreightRate(result.getFreightRate());
|
Integer billingFailStatus = result.getBillingFailStatus();
|
||||||
bill.setBaseFreightRate(result.getBaseFreightRate());
|
if (billingFailStatus == null)
|
||||||
bill.setDiscountPercent(result.getDiscountPercent());
|
{
|
||||||
bill.setRegistrationFee(result.getRegistrationFee());
|
billingFailStatus = Integer.valueOf(BillBillingFailStatus.SUCCESS.getCode());
|
||||||
bill.setFreightAmount(result.getFreightAmount());
|
}
|
||||||
bill.setSurchargeAmount(result.getSurchargeAmount());
|
bill.setBillingFailStatus(billingFailStatus);
|
||||||
bill.setIncomeTotal(result.getPayableTotal());
|
boolean billingFailed = BillBillingFailStatus.isFail(billingFailStatus);
|
||||||
// 应付总额与产品目录价解耦:试算未产出 pay_total 时留空,不再用 product_amount 兜底
|
if (billingFailed)
|
||||||
bill.setPayTotal(result.getPayTotal());
|
{
|
||||||
|
// Soft-fail: persist order snapshot with zero amounts; skip fee detail rows.
|
||||||
|
bill.setFreightRate(BigDecimal.ZERO);
|
||||||
|
bill.setBaseFreightRate(BigDecimal.ZERO);
|
||||||
|
bill.setDiscountPercent(null);
|
||||||
|
bill.setRegistrationFee(BigDecimal.ZERO);
|
||||||
|
bill.setFreightAmount(BigDecimal.ZERO);
|
||||||
|
bill.setSurchargeAmount(BigDecimal.ZERO);
|
||||||
|
bill.setIncomeTotal(BigDecimal.ZERO);
|
||||||
|
bill.setPayTotal(BigDecimal.ZERO);
|
||||||
|
result.setFreightRate(BigDecimal.ZERO);
|
||||||
|
result.setBaseFreightRate(BigDecimal.ZERO);
|
||||||
|
result.setDiscountPercent(null);
|
||||||
|
result.setRegistrationFee(BigDecimal.ZERO);
|
||||||
|
result.setFreightAmount(BigDecimal.ZERO);
|
||||||
|
result.setSurchargeAmount(BigDecimal.ZERO);
|
||||||
|
result.setProductAmount(BigDecimal.ZERO);
|
||||||
|
result.setRedlineAmount(BigDecimal.ZERO);
|
||||||
|
result.setCostAmount(BigDecimal.ZERO);
|
||||||
|
result.setIncomeTotal(BigDecimal.ZERO);
|
||||||
|
result.setPayTotal(BigDecimal.ZERO);
|
||||||
|
result.setPayableTotal(BigDecimal.ZERO);
|
||||||
|
result.setFeeDetails(new ArrayList<TmsPriceQuoteFeeLine>());
|
||||||
|
result.setPayFeeDetails(new ArrayList<TmsPriceQuoteFeeLine>());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bill.setFreightRate(result.getFreightRate());
|
||||||
|
bill.setBaseFreightRate(result.getBaseFreightRate());
|
||||||
|
bill.setDiscountPercent(result.getDiscountPercent());
|
||||||
|
bill.setRegistrationFee(result.getRegistrationFee());
|
||||||
|
bill.setFreightAmount(result.getFreightAmount());
|
||||||
|
bill.setSurchargeAmount(result.getSurchargeAmount());
|
||||||
|
bill.setIncomeTotal(result.getPayableTotal());
|
||||||
|
// Payable total is decoupled from product catalog; leave null when quote has no pay_total.
|
||||||
|
bill.setPayTotal(result.getPayTotal());
|
||||||
|
}
|
||||||
bill.setCurrency(result.getCurrency());
|
bill.setCurrency(result.getCurrency());
|
||||||
bill.setRoundMode(result.getRoundMode());
|
bill.setRoundMode(result.getRoundMode());
|
||||||
// Credit soft-fail before persist so insert/update stores arrears flag in one write.
|
// Credit soft-fail before persist so insert/update stores arrears flag in one write.
|
||||||
@@ -1155,6 +1192,7 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService
|
|||||||
result.setCustomerActiveStatus(customerActiveStatus);
|
result.setCustomerActiveStatus(customerActiveStatus);
|
||||||
result.setCreditArrearsStatus(creditArrearsStatus);
|
result.setCreditArrearsStatus(creditArrearsStatus);
|
||||||
result.setRefundStatus(bill.getRefundStatus());
|
result.setRefundStatus(bill.getRefundStatus());
|
||||||
|
result.setBillingFailStatus(billingFailStatus);
|
||||||
result.setIncomeTotal(bill.getIncomeTotal());
|
result.setIncomeTotal(bill.getIncomeTotal());
|
||||||
result.setPayTotal(bill.getPayTotal());
|
result.setPayTotal(bill.getPayTotal());
|
||||||
result.setPayableTotal(bill.getIncomeTotal());
|
result.setPayableTotal(bill.getIncomeTotal());
|
||||||
@@ -1169,23 +1207,34 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
orderBillMapper.updatePrcOrderBill(bill);
|
orderBillMapper.updatePrcOrderBill(bill);
|
||||||
// Keep manually added fees (manual_flag=1) across rebill
|
if (billingFailed)
|
||||||
incomeBillFeeMapper.deleteAutoFeesByBillId(bill.getBillId());
|
{
|
||||||
|
// Soft-fail rebill: clear all fee details (no fee rows for failed billing).
|
||||||
|
incomeBillFeeMapper.deleteByBillId(bill.getBillId());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Keep manually added fees (manual_flag=1) across rebill
|
||||||
|
incomeBillFeeMapper.deleteAutoFeesByBillId(bill.getBillId());
|
||||||
|
}
|
||||||
// Payable not in scope yet: skip prc_pay_bill_fee cleanup/write.
|
// Payable not in scope yet: skip prc_pay_bill_fee cleanup/write.
|
||||||
// payBillFeeMapper.deleteByBillId(bill.getBillId());
|
// payBillFeeMapper.deleteByBillId(bill.getBillId());
|
||||||
}
|
}
|
||||||
PrcIncomeBill incomeBill = persistIncomeBill(bill, result);
|
PrcIncomeBill incomeBill = persistIncomeBill(bill, result);
|
||||||
List<PrcIncomeBillFee> fees = toFeeRows(bill.getBillId(),
|
if (!billingFailed)
|
||||||
incomeBill == null ? null : incomeBill.getIncomeBillId(), result);
|
|
||||||
if (existed != null)
|
|
||||||
{
|
{
|
||||||
fees = filterAutoFeesAgainstManual(bill.getBillId(), fees);
|
List<PrcIncomeBillFee> fees = toFeeRows(bill.getBillId(),
|
||||||
|
incomeBill == null ? null : incomeBill.getIncomeBillId(), result);
|
||||||
|
if (existed != null)
|
||||||
|
{
|
||||||
|
fees = filterAutoFeesAgainstManual(bill.getBillId(), fees);
|
||||||
|
}
|
||||||
|
if (!fees.isEmpty())
|
||||||
|
{
|
||||||
|
incomeBillFeeMapper.insertBatch(fees);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!fees.isEmpty())
|
if (existed != null && !billingFailed)
|
||||||
{
|
|
||||||
incomeBillFeeMapper.insertBatch(fees);
|
|
||||||
}
|
|
||||||
if (existed != null)
|
|
||||||
{
|
{
|
||||||
// Quote totals were written above; recalc so retained manual fees join income/credit
|
// Quote totals were written above; recalc so retained manual fees join income/credit
|
||||||
TmsPriceQuoteResult refreshed = refreshBillIncomeTotals(bill);
|
TmsPriceQuoteResult refreshed = refreshBillIncomeTotals(bill);
|
||||||
@@ -1199,7 +1248,7 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService
|
|||||||
result.setFeeDetails(refreshed.getFeeDetails());
|
result.setFeeDetails(refreshed.getFeeDetails());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else if (existed == null)
|
||||||
{
|
{
|
||||||
bill.setRefundStatus(BillRefundStatus.NONE.getCode());
|
bill.setRefundStatus(BillRefundStatus.NONE.getCode());
|
||||||
result.setRefundStatus(bill.getRefundStatus());
|
result.setRefundStatus(bill.getRefundStatus());
|
||||||
@@ -1619,6 +1668,8 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService
|
|||||||
r.setCustomerActiveStatus(bill.getCustomerActiveStatus());
|
r.setCustomerActiveStatus(bill.getCustomerActiveStatus());
|
||||||
r.setCreditArrearsStatus(bill.getCreditArrearsStatus());
|
r.setCreditArrearsStatus(bill.getCreditArrearsStatus());
|
||||||
r.setRefundStatus(bill.getRefundStatus());
|
r.setRefundStatus(bill.getRefundStatus());
|
||||||
|
r.setBillingFailStatus(bill.getBillingFailStatus() == null
|
||||||
|
? Integer.valueOf(BillBillingFailStatus.SUCCESS.getCode()) : bill.getBillingFailStatus());
|
||||||
r.setFeeDetails(toIncomeFeeLines(incomeFees));
|
r.setFeeDetails(toIncomeFeeLines(incomeFees));
|
||||||
r.setPayFeeDetails(toPayFeeLines(payFees));
|
r.setPayFeeDetails(toPayFeeLines(payFees));
|
||||||
PrcIncomeBill incomeBill = incomeBillMapper.selectByBillId(bill.getBillId());
|
PrcIncomeBill incomeBill = incomeBillMapper.selectByBillId(bill.getBillId());
|
||||||
|
|||||||
+136
-2
@@ -42,6 +42,7 @@ import com.bms.price.domain.vo.TmsPriceBillRequest;
|
|||||||
import com.bms.price.domain.vo.TmsPriceQuoteFeeLine;
|
import com.bms.price.domain.vo.TmsPriceQuoteFeeLine;
|
||||||
import com.bms.price.domain.vo.TmsPriceQuoteRequest;
|
import com.bms.price.domain.vo.TmsPriceQuoteRequest;
|
||||||
import com.bms.price.domain.vo.TmsPriceQuoteResult;
|
import com.bms.price.domain.vo.TmsPriceQuoteResult;
|
||||||
|
import com.bms.price.enums.BillBillingFailStatus;
|
||||||
import com.bms.price.enums.BillCustomerActiveStatus;
|
import com.bms.price.enums.BillCustomerActiveStatus;
|
||||||
import com.bms.price.mapper.BmsProductCountryMapper;
|
import com.bms.price.mapper.BmsProductCountryMapper;
|
||||||
import com.bms.price.mapper.BmsProductMapper;
|
import com.bms.price.mapper.BmsProductMapper;
|
||||||
@@ -64,7 +65,8 @@ import com.bms.system.service.IBmsProductCodeMappingService;
|
|||||||
* Shared quote/bill calc: customer bind + package version by bizDate (version effective_time).
|
* Shared quote/bill calc: customer bind + package version by bizDate (version effective_time).
|
||||||
* Bind pr_begindate/pr_enddate is not used for billing time gate.
|
* Bind pr_begindate/pr_enddate is not used for billing time gate.
|
||||||
* Sales price comes from package snapshot only (FIXED detail / DISCOUNT on catalog base).
|
* Sales price comes from package snapshot only (FIXED detail / DISCOUNT on catalog base).
|
||||||
* No bind / no active version / package miss: quote and bill both fail hard (no PRODUCT_DEFAULT).
|
* No bind / no active version: quote and bill both fail hard (no PRODUCT_DEFAULT).
|
||||||
|
* Bill sync soft-fails for product/country/weight miss (billing_fail_status 1/2/3, zero amounts).
|
||||||
* product_country is only for product_amount/cost and DISCOUNT freight base.
|
* product_country is only for product_amount/cost and DISCOUNT freight base.
|
||||||
*
|
*
|
||||||
* @author bms
|
* @author bms
|
||||||
@@ -207,7 +209,11 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
|
|||||||
String customerActiveStatus = softResolveCustomer(request);
|
String customerActiveStatus = softResolveCustomer(request);
|
||||||
Date bizDate = resolveBizDate(request.getBizDate());
|
Date bizDate = resolveBizDate(request.getBizDate());
|
||||||
TmsPriceQuoteResult result = doQuote(request, bizDate);
|
TmsPriceQuoteResult result = doQuote(request, bizDate);
|
||||||
applySurchargesAndFees(result);
|
if (!BillBillingFailStatus.isFail(result.getBillingFailStatus()))
|
||||||
|
{
|
||||||
|
applySurchargesAndFees(result);
|
||||||
|
result.setBillingFailStatus(BillBillingFailStatus.SUCCESS.getCode());
|
||||||
|
}
|
||||||
result.setCustomerActiveStatus(customerActiveStatus);
|
result.setCustomerActiveStatus(customerActiveStatus);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -405,6 +411,8 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
|
|||||||
boolean productExcludedBySetProducts = false;
|
boolean productExcludedBySetProducts = false;
|
||||||
boolean attemptedPriceMatch = false;
|
boolean attemptedPriceMatch = false;
|
||||||
boolean anyZoneRequired = false;
|
boolean anyZoneRequired = false;
|
||||||
|
// Highest specificity among soft-failable misses: WEIGHT(3) > COUNTRY(2) > PRODUCT(1).
|
||||||
|
int missCode = 0;
|
||||||
// Match version by exact bill datetime (effective_time / expire_time), not end-of-day.
|
// Match version by exact bill datetime (effective_time / expire_time), not end-of-day.
|
||||||
Date asOf = bizDate != null ? bizDate : new Date();
|
Date asOf = bizDate != null ? bizDate : new Date();
|
||||||
for (PrcCustomerPriceSet bind : binds)
|
for (PrcCustomerPriceSet bind : binds)
|
||||||
@@ -450,6 +458,7 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
|
|||||||
if (anyProducts != null && !anyProducts.isEmpty())
|
if (anyProducts != null && !anyProducts.isEmpty())
|
||||||
{
|
{
|
||||||
productExcludedBySetProducts = true;
|
productExcludedBySetProducts = true;
|
||||||
|
missCode = Math.max(missCode, BillBillingFailStatus.PRODUCT.getCode());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -482,11 +491,13 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
|
|||||||
stampRequestMeta(request, hit);
|
stampRequestMeta(request, hit);
|
||||||
return hit;
|
return hit;
|
||||||
}
|
}
|
||||||
|
missCode = Math.max(missCode, diagnoseFixedMiss(version.getPsvId(), productCode, cc, cn, zone.zoneCode));
|
||||||
}
|
}
|
||||||
else if (TYPE_DISCOUNT.equals(setType))
|
else if (TYPE_DISCOUNT.equals(setType))
|
||||||
{
|
{
|
||||||
if (catalog == null)
|
if (catalog == null)
|
||||||
{
|
{
|
||||||
|
missCode = Math.max(missCode, diagnoseCatalogMiss(productCode, cc, cn, zone.zoneCode, bizDate));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
TmsPriceQuoteResult hit = tryDiscount(bind, set, version, catalog, productCode, productName, weight, bizDate);
|
TmsPriceQuoteResult hit = tryDiscount(bind, set, version, catalog, productCode, productName, weight, bizDate);
|
||||||
@@ -495,6 +506,8 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
|
|||||||
stampRequestMeta(request, hit);
|
stampRequestMeta(request, hit);
|
||||||
return hit;
|
return hit;
|
||||||
}
|
}
|
||||||
|
// Discount detail missing for product (or invalid discount) after catalog hit.
|
||||||
|
missCode = Math.max(missCode, BillBillingFailStatus.PRODUCT.getCode());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -506,6 +519,15 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
|
|||||||
throw new ServiceException(MessageUtils.message(msgKey));
|
throw new ServiceException(MessageUtils.message(msgKey));
|
||||||
}
|
}
|
||||||
if (!attemptedPriceMatch && productExcludedBySetProducts)
|
if (!attemptedPriceMatch && productExcludedBySetProducts)
|
||||||
|
{
|
||||||
|
missCode = Math.max(missCode, BillBillingFailStatus.PRODUCT.getCode());
|
||||||
|
}
|
||||||
|
if (request instanceof TmsPriceBillRequest && BillBillingFailStatus.isFail(Integer.valueOf(missCode)))
|
||||||
|
{
|
||||||
|
return buildBillingMissResult(request, productCode, productName, countryCode, countryName,
|
||||||
|
weight, bizDate, missCode);
|
||||||
|
}
|
||||||
|
if (!attemptedPriceMatch && productExcludedBySetProducts)
|
||||||
{
|
{
|
||||||
String msgKey = request instanceof TmsPriceBillRequest
|
String msgKey = request instanceof TmsPriceBillRequest
|
||||||
? "price.bill.productNotInPackage"
|
? "price.bill.productNotInPackage"
|
||||||
@@ -528,6 +550,118 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
|
|||||||
throw new ServiceException(MessageUtils.message(missKey));
|
throw new ServiceException(MessageUtils.message(missKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Diagnose FIXED miss: product rows absent -> 1; country/zone absent -> 2; else weight -> 3.
|
||||||
|
*/
|
||||||
|
private int diagnoseFixedMiss(Long psvId, String productCode, String countryCode,
|
||||||
|
String countryName, String zoneCode)
|
||||||
|
{
|
||||||
|
if (psvId == null || StringUtils.isEmpty(productCode))
|
||||||
|
{
|
||||||
|
return BillBillingFailStatus.PRODUCT.getCode();
|
||||||
|
}
|
||||||
|
int byProduct = detailMapper.countByPsvProduct(psvId, productCode);
|
||||||
|
if (byProduct <= 0)
|
||||||
|
{
|
||||||
|
return BillBillingFailStatus.PRODUCT.getCode();
|
||||||
|
}
|
||||||
|
int byCountry = detailMapper.countByPsvProductCountryZone(
|
||||||
|
psvId, productCode, countryCode, countryName, zoneCode);
|
||||||
|
if (byCountry <= 0)
|
||||||
|
{
|
||||||
|
return BillBillingFailStatus.COUNTRY.getCode();
|
||||||
|
}
|
||||||
|
return BillBillingFailStatus.WEIGHT.getCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Diagnose catalog miss for DISCOUNT base price.
|
||||||
|
*/
|
||||||
|
private int diagnoseCatalogMiss(String productCode, String countryCode, String countryName,
|
||||||
|
String zoneCode, Date bizDate)
|
||||||
|
{
|
||||||
|
if (StringUtils.isEmpty(productCode))
|
||||||
|
{
|
||||||
|
return BillBillingFailStatus.PRODUCT.getCode();
|
||||||
|
}
|
||||||
|
int byProduct = productCountryMapper.countByProduct(productCode, bizDate);
|
||||||
|
if (byProduct <= 0)
|
||||||
|
{
|
||||||
|
return BillBillingFailStatus.PRODUCT.getCode();
|
||||||
|
}
|
||||||
|
int byCountry = productCountryMapper.countByProductCountryZone(
|
||||||
|
productCode, countryCode, countryName, zoneCode, bizDate);
|
||||||
|
if (byCountry <= 0)
|
||||||
|
{
|
||||||
|
return BillBillingFailStatus.COUNTRY.getCode();
|
||||||
|
}
|
||||||
|
return BillBillingFailStatus.WEIGHT.getCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Soft-fail bill result: keep order snapshot fields, all amounts zero, set billingFailStatus.
|
||||||
|
*/
|
||||||
|
private TmsPriceQuoteResult buildBillingMissResult(TmsPriceQuoteRequest request, String productCode,
|
||||||
|
String productName, String countryCode, String countryName, BigDecimal weight, Date bizDate,
|
||||||
|
int missCode)
|
||||||
|
{
|
||||||
|
TmsPriceQuoteResult r = new TmsPriceQuoteResult();
|
||||||
|
r.setBillingFailStatus(Integer.valueOf(missCode));
|
||||||
|
r.setMatchSource("BILLING_FAIL");
|
||||||
|
r.setMatchMessage(billingFailMessage(missCode));
|
||||||
|
r.setProductCode(productCode);
|
||||||
|
r.setProductName(productName);
|
||||||
|
r.setCountryCode(countryCode);
|
||||||
|
r.setCountryName(countryName);
|
||||||
|
r.setWeight(weight);
|
||||||
|
r.setChargeWeight(weight);
|
||||||
|
r.setBizDate(bizDate);
|
||||||
|
r.setFreightRate(BigDecimal.ZERO);
|
||||||
|
r.setBaseFreightRate(BigDecimal.ZERO);
|
||||||
|
r.setDiscountPercent(null);
|
||||||
|
r.setRegistrationFee(BigDecimal.ZERO);
|
||||||
|
r.setFreightAmount(BigDecimal.ZERO);
|
||||||
|
r.setSurchargeAmount(BigDecimal.ZERO);
|
||||||
|
r.setProductAmount(BigDecimal.ZERO);
|
||||||
|
r.setRedlineAmount(BigDecimal.ZERO);
|
||||||
|
r.setCostAmount(BigDecimal.ZERO);
|
||||||
|
r.setIncomeTotal(BigDecimal.ZERO);
|
||||||
|
r.setPayTotal(BigDecimal.ZERO);
|
||||||
|
r.setPayableTotal(BigDecimal.ZERO);
|
||||||
|
r.setCurrency("CNY");
|
||||||
|
r.setRoundMode("HALF_UP");
|
||||||
|
r.setFromCache(Boolean.FALSE);
|
||||||
|
r.setFeeDetails(Collections.<TmsPriceQuoteFeeLine>emptyList());
|
||||||
|
r.setPayFeeDetails(Collections.<TmsPriceQuoteFeeLine>emptyList());
|
||||||
|
stampRequestMeta(request, r);
|
||||||
|
if (request instanceof TmsPriceBillRequest)
|
||||||
|
{
|
||||||
|
TmsPriceBillRequest billReq = (TmsPriceBillRequest) request;
|
||||||
|
if (StringUtils.isEmpty(r.getCustomerName()) && StringUtils.isNotEmpty(billReq.getCustomerName()))
|
||||||
|
{
|
||||||
|
r.setCustomerName(billReq.getCustomerName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String billingFailMessage(int missCode)
|
||||||
|
{
|
||||||
|
if (missCode == BillBillingFailStatus.PRODUCT.getCode())
|
||||||
|
{
|
||||||
|
return MessageUtils.message("price.bill.billingFail.product");
|
||||||
|
}
|
||||||
|
if (missCode == BillBillingFailStatus.COUNTRY.getCode())
|
||||||
|
{
|
||||||
|
return MessageUtils.message("price.bill.billingFail.country");
|
||||||
|
}
|
||||||
|
if (missCode == BillBillingFailStatus.WEIGHT.getCode())
|
||||||
|
{
|
||||||
|
return MessageUtils.message("price.bill.billingFail.weight");
|
||||||
|
}
|
||||||
|
return MessageUtils.message("price.bill.packagePriceNotHit");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Soft lookup of package product row; null when version has no such product.
|
* Soft lookup of package product row; null when version has no such product.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -317,6 +317,53 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
</if>
|
</if>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="countByProduct" resultType="int">
|
||||||
|
select count(1)
|
||||||
|
from product_country
|
||||||
|
where product_code = #{productCode}
|
||||||
|
and ifnull(is_del, '0') = '0'
|
||||||
|
<if test="bizDate != null">
|
||||||
|
and (effective_date is null or effective_date <= #{bizDate})
|
||||||
|
and (expire_date is null or expire_date > #{bizDate})
|
||||||
|
</if>
|
||||||
|
<if test="bizDate == null">
|
||||||
|
and expire_date is null
|
||||||
|
</if>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="countByProductCountryZone" resultType="int">
|
||||||
|
select count(1)
|
||||||
|
from product_country
|
||||||
|
where product_code = #{productCode}
|
||||||
|
and ifnull(is_del, '0') = '0'
|
||||||
|
<choose>
|
||||||
|
<when test="countryCode != null and countryCode != ''">
|
||||||
|
and upper(country_code) = upper(#{countryCode})
|
||||||
|
</when>
|
||||||
|
<when test="countryName != null and countryName != ''">
|
||||||
|
and country_name = #{countryName}
|
||||||
|
</when>
|
||||||
|
<otherwise>
|
||||||
|
and 1 = 0
|
||||||
|
</otherwise>
|
||||||
|
</choose>
|
||||||
|
<choose>
|
||||||
|
<when test="zoneCode != null and zoneCode != ''">
|
||||||
|
and upper(ifnull(zone_code,'')) = upper(#{zoneCode})
|
||||||
|
</when>
|
||||||
|
<otherwise>
|
||||||
|
and (zone_code is null or zone_code = '')
|
||||||
|
</otherwise>
|
||||||
|
</choose>
|
||||||
|
<if test="bizDate != null">
|
||||||
|
and (effective_date is null or effective_date <= #{bizDate})
|
||||||
|
and (expire_date is null or expire_date > #{bizDate})
|
||||||
|
</if>
|
||||||
|
<if test="bizDate == null">
|
||||||
|
and expire_date is null
|
||||||
|
</if>
|
||||||
|
</select>
|
||||||
|
|
||||||
<select id="selectOpenByProductCode" resultMap="BmsProductCountryResult">
|
<select id="selectOpenByProductCode" resultMap="BmsProductCountryResult">
|
||||||
<include refid="selectVo"/>
|
<include refid="selectVo"/>
|
||||||
where c.product_code = #{productCode}
|
where c.product_code = #{productCode}
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<result property="customerActiveStatus" column="customer_active_status" />
|
<result property="customerActiveStatus" column="customer_active_status" />
|
||||||
<result property="creditArrearsStatus" column="credit_arrears_status" />
|
<result property="creditArrearsStatus" column="credit_arrears_status" />
|
||||||
<result property="refundStatus" column="refund_status" />
|
<result property="refundStatus" column="refund_status" />
|
||||||
|
<result property="billingFailStatus" column="billing_fail_status" />
|
||||||
<result property="roundMode" column="round_mode" />
|
<result property="roundMode" column="round_mode" />
|
||||||
<result property="createBy" column="created_by" />
|
<result property="createBy" column="created_by" />
|
||||||
<result property="createTime" column="create_time" />
|
<result property="createTime" column="create_time" />
|
||||||
@@ -94,7 +95,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
weight_min, weight_max, weight_label, effective_date, charge_weight,
|
weight_min, weight_max, weight_label, effective_date, charge_weight,
|
||||||
freight_rate, base_freight_rate, discount_percent, registration_fee,
|
freight_rate, base_freight_rate, discount_percent, registration_fee,
|
||||||
freight_amount, surcharge_amount, income_total, pay_total, currency, ar_bill_status,
|
freight_amount, surcharge_amount, income_total, pay_total, currency, ar_bill_status,
|
||||||
customer_active_status, credit_arrears_status, refund_status, round_mode,
|
customer_active_status, credit_arrears_status, refund_status, billing_fail_status, round_mode,
|
||||||
created_by, create_time, updated_by, update_time
|
created_by, create_time, updated_by, update_time
|
||||||
from prc_order_bill p
|
from prc_order_bill p
|
||||||
</sql>
|
</sql>
|
||||||
@@ -530,7 +531,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
weight_min, weight_max, weight_label, effective_date, charge_weight,
|
weight_min, weight_max, weight_label, effective_date, charge_weight,
|
||||||
freight_rate, base_freight_rate, discount_percent, registration_fee,
|
freight_rate, base_freight_rate, discount_percent, registration_fee,
|
||||||
freight_amount, surcharge_amount, income_total, pay_total, currency, ar_bill_status,
|
freight_amount, surcharge_amount, income_total, pay_total, currency, ar_bill_status,
|
||||||
customer_active_status, credit_arrears_status, refund_status, round_mode,
|
customer_active_status, credit_arrears_status, refund_status, billing_fail_status, round_mode,
|
||||||
create_time
|
create_time
|
||||||
) values (
|
) values (
|
||||||
#{billId}, #{billKey}, #{orderNo}, #{trackingNo}, #{transferNo},
|
#{billId}, #{billKey}, #{orderNo}, #{trackingNo}, #{transferNo},
|
||||||
@@ -544,7 +545,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
#{weightMin}, #{weightMax}, #{weightLabel}, #{effectiveDate}, #{chargeWeight},
|
#{weightMin}, #{weightMax}, #{weightLabel}, #{effectiveDate}, #{chargeWeight},
|
||||||
#{freightRate}, #{baseFreightRate}, #{discountPercent}, #{registrationFee},
|
#{freightRate}, #{baseFreightRate}, #{discountPercent}, #{registrationFee},
|
||||||
#{freightAmount}, #{surchargeAmount}, #{incomeTotal}, #{payTotal}, #{currency}, #{arBillStatus},
|
#{freightAmount}, #{surchargeAmount}, #{incomeTotal}, #{payTotal}, #{currency}, #{arBillStatus},
|
||||||
#{customerActiveStatus}, #{creditArrearsStatus}, #{refundStatus}, #{roundMode},
|
#{customerActiveStatus}, #{creditArrearsStatus}, #{refundStatus}, #{billingFailStatus}, #{roundMode},
|
||||||
sysdate()
|
sysdate()
|
||||||
)
|
)
|
||||||
</insert>
|
</insert>
|
||||||
@@ -614,6 +615,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
customer_active_status = #{customerActiveStatus},
|
customer_active_status = #{customerActiveStatus},
|
||||||
credit_arrears_status = #{creditArrearsStatus},
|
credit_arrears_status = #{creditArrearsStatus},
|
||||||
refund_status = #{refundStatus},
|
refund_status = #{refundStatus},
|
||||||
|
billing_fail_status = #{billingFailStatus},
|
||||||
round_mode = #{roundMode},
|
round_mode = #{roundMode},
|
||||||
update_time = sysdate()
|
update_time = sysdate()
|
||||||
where bill_id = #{billId}
|
where bill_id = #{billId}
|
||||||
|
|||||||
@@ -462,6 +462,39 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
</choose>
|
</choose>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="countByPsvProduct" resultType="int">
|
||||||
|
select count(1)
|
||||||
|
from prc_price_set_detail
|
||||||
|
where psv_id = #{psvId}
|
||||||
|
and product_code = #{productCode}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="countByPsvProductCountryZone" resultType="int">
|
||||||
|
select count(1)
|
||||||
|
from prc_price_set_detail
|
||||||
|
where psv_id = #{psvId}
|
||||||
|
and product_code = #{productCode}
|
||||||
|
<choose>
|
||||||
|
<when test="countryCode != null and countryCode != ''">
|
||||||
|
and upper(ifnull(country_code,'')) = upper(#{countryCode})
|
||||||
|
</when>
|
||||||
|
<when test="countryName != null and countryName != ''">
|
||||||
|
and country_name = #{countryName}
|
||||||
|
</when>
|
||||||
|
<otherwise>
|
||||||
|
and 1 = 0
|
||||||
|
</otherwise>
|
||||||
|
</choose>
|
||||||
|
<choose>
|
||||||
|
<when test="zoneCode != null and zoneCode != ''">
|
||||||
|
and upper(ifnull(zone_code,'')) = upper(#{zoneCode})
|
||||||
|
</when>
|
||||||
|
<otherwise>
|
||||||
|
and (zone_code is null or zone_code = '')
|
||||||
|
</otherwise>
|
||||||
|
</choose>
|
||||||
|
</select>
|
||||||
|
|
||||||
<select id="selectDiscountMatch" resultMap="PrcPriceSetDetailResult">
|
<select id="selectDiscountMatch" resultMap="PrcPriceSetDetailResult">
|
||||||
<include refid="selectPrcPriceSetDetailVo"/>
|
<include refid="selectPrcPriceSetDetailVo"/>
|
||||||
where price_set_id = #{priceSetId}
|
where price_set_id = #{priceSetId}
|
||||||
|
|||||||
@@ -1052,6 +1052,7 @@ CREATE TABLE `prc_order_bill` (
|
|||||||
`customer_active_status` varchar(20) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '客户生效状态:ACTIVE正常 MISSING不存在 DISABLED停用',
|
`customer_active_status` varchar(20) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '客户生效状态:ACTIVE正常 MISSING不存在 DISABLED停用',
|
||||||
`credit_arrears_status` varchar(20) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '额度欠费状态:NORMAL正常 ARREARS欠费',
|
`credit_arrears_status` varchar(20) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '额度欠费状态:NORMAL正常 ARREARS欠费',
|
||||||
`refund_status` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'NONE' COMMENT '退费状态:NONE未退费/REFUNDED已退费',
|
`refund_status` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'NONE' COMMENT '退费状态:NONE未退费/REFUNDED已退费',
|
||||||
|
`billing_fail_status` tinyint NOT NULL DEFAULT '0' COMMENT '计费失败状态:0成功/1未匹配产品/2未匹配国家/3未匹配重量段',
|
||||||
`round_mode` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'HALF_UP' COMMENT '取值方式',
|
`round_mode` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'HALF_UP' COMMENT '取值方式',
|
||||||
`created_by` varchar(64) COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '创建人',
|
`created_by` varchar(64) COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '创建人',
|
||||||
`create_time` datetime DEFAULT NULL,
|
`create_time` datetime DEFAULT NULL,
|
||||||
@@ -1068,6 +1069,7 @@ CREATE TABLE `prc_order_bill` (
|
|||||||
KEY `idx_order_bill_customer_active` (`customer_active_status`),
|
KEY `idx_order_bill_customer_active` (`customer_active_status`),
|
||||||
KEY `idx_order_bill_credit_arrears` (`credit_arrears_status`),
|
KEY `idx_order_bill_credit_arrears` (`credit_arrears_status`),
|
||||||
KEY `idx_order_bill_refund_status` (`refund_status`),
|
KEY `idx_order_bill_refund_status` (`refund_status`),
|
||||||
|
KEY `idx_order_bill_billing_fail_status` (`billing_fail_status`),
|
||||||
KEY `idx_order_bill_psv` (`psv_id`),
|
KEY `idx_order_bill_psv` (`psv_id`),
|
||||||
KEY `idx_order_bill_psd` (`psd_id`),
|
KEY `idx_order_bill_psd` (`psd_id`),
|
||||||
KEY `idx_ar_order_bill_status_scope` (`customer_id`,`currency`,`ar_bill_status`,`biz_date`,`bill_id`)
|
KEY `idx_ar_order_bill_status_scope` (`customer_id`,`currency`,`ar_bill_status`,`biz_date`,`bill_id`)
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
-- prc_order_bill.billing_fail_status: 0 success / 1 product / 2 country / 3 weight
|
||||||
|
SET NAMES utf8mb4;
|
||||||
|
|
||||||
|
SET @col := (
|
||||||
|
SELECT COLUMN_NAME FROM information_schema.COLUMNS
|
||||||
|
WHERE TABLE_SCHEMA = DATABASE()
|
||||||
|
AND TABLE_NAME = 'prc_order_bill'
|
||||||
|
AND COLUMN_NAME = 'billing_fail_status'
|
||||||
|
LIMIT 1
|
||||||
|
);
|
||||||
|
SET @sql := IF(
|
||||||
|
@col IS NULL,
|
||||||
|
'ALTER TABLE prc_order_bill ADD COLUMN billing_fail_status tinyint NOT NULL DEFAULT 0 COMMENT ''计费失败状态:0成功/1未匹配产品/2未匹配国家/3未匹配重量段'' AFTER refund_status, ADD KEY idx_order_bill_billing_fail_status (billing_fail_status)',
|
||||||
|
'SELECT 1'
|
||||||
|
);
|
||||||
|
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||||
@@ -58,6 +58,9 @@
|
|||||||
<template #col-matchSource="{ row }">
|
<template #col-matchSource="{ row }">
|
||||||
<el-tag size="small" :type="sourceTagType(row.matchSource)">{{ sourceLabel(row.matchSource) }}</el-tag>
|
<el-tag size="small" :type="sourceTagType(row.matchSource)">{{ sourceLabel(row.matchSource) }}</el-tag>
|
||||||
</template>
|
</template>
|
||||||
|
<template #col-billingFailStatus="{ row }">
|
||||||
|
<el-tag size="small" :type="billingFailTagType(row.billingFailStatus)">{{ billingFailLabel(row.billingFailStatus) }}</el-tag>
|
||||||
|
</template>
|
||||||
<template #col-customerActiveStatus="{ row }">
|
<template #col-customerActiveStatus="{ row }">
|
||||||
<el-tag size="small" :type="customerActiveTagType(row.customerActiveStatus)">{{ customerActiveLabel(row.customerActiveStatus) }}</el-tag>
|
<el-tag size="small" :type="customerActiveTagType(row.customerActiveStatus)">{{ customerActiveLabel(row.customerActiveStatus) }}</el-tag>
|
||||||
</template>
|
</template>
|
||||||
@@ -243,6 +246,7 @@ const columns = [
|
|||||||
{ label: '应收总额', prop: 'incomeTotal', align: 'right', width: 120, slot: 'incomeTotal' },
|
{ label: '应收总额', prop: 'incomeTotal', align: 'right', width: 120, slot: 'incomeTotal' },
|
||||||
{ label: '应付总额', prop: 'payTotal', align: 'right', width: 120, slot: 'payTotal' },
|
{ label: '应付总额', prop: 'payTotal', align: 'right', width: 120, slot: 'payTotal' },
|
||||||
{ label: '计价来源', prop: 'matchSource', align: 'center', width: 130, slot: 'matchSource' },
|
{ label: '计价来源', prop: 'matchSource', align: 'center', width: 130, slot: 'matchSource' },
|
||||||
|
{ label: '计费状态', prop: 'billingFailStatus', align: 'center', width: 120, slot: 'billingFailStatus' },
|
||||||
{ label: '客户状态', prop: 'customerActiveStatus', align: 'center', width: 100, slot: 'customerActiveStatus' },
|
{ label: '客户状态', prop: 'customerActiveStatus', align: 'center', width: 100, slot: 'customerActiveStatus' },
|
||||||
{ label: '额度欠费', prop: 'creditArrearsStatus', align: 'center', width: 100, slot: 'creditArrearsStatus' },
|
{ label: '额度欠费', prop: 'creditArrearsStatus', align: 'center', width: 100, slot: 'creditArrearsStatus' },
|
||||||
// { label: '退费状态', prop: 'refundStatus', align: 'center', width: 100, slot: 'refundStatus' },
|
// { label: '退费状态', prop: 'refundStatus', align: 'center', width: 100, slot: 'refundStatus' },
|
||||||
@@ -523,11 +527,26 @@ function formatWeight(val) {
|
|||||||
return num.toFixed(3)
|
return num.toFixed(3)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function billingFailLabel(status) {
|
||||||
|
const code = status == null ? 0 : Number(status)
|
||||||
|
if (code === 1) return '未匹配产品'
|
||||||
|
if (code === 2) return '未匹配国家'
|
||||||
|
if (code === 3) return '未匹配重量段'
|
||||||
|
return '计费成功'
|
||||||
|
}
|
||||||
|
|
||||||
|
function billingFailTagType(status) {
|
||||||
|
const code = status == null ? 0 : Number(status)
|
||||||
|
if (code === 1 || code === 2 || code === 3) return 'danger'
|
||||||
|
return 'success'
|
||||||
|
}
|
||||||
|
|
||||||
function sourceLabel(source) {
|
function sourceLabel(source) {
|
||||||
const map = {
|
const map = {
|
||||||
PACKAGE_FIXED: '客户固定价套餐',
|
PACKAGE_FIXED: '客户固定价套餐',
|
||||||
PACKAGE_DISCOUNT: '客户折扣套餐',
|
PACKAGE_DISCOUNT: '客户折扣套餐',
|
||||||
PRODUCT_DEFAULT: '产品默认价',
|
PRODUCT_DEFAULT: '产品默认价',
|
||||||
|
BILLING_FAIL: '计费失败',
|
||||||
FIXED: '客户固定价套餐',
|
FIXED: '客户固定价套餐',
|
||||||
DISCOUNT: '客户折扣套餐'
|
DISCOUNT: '客户折扣套餐'
|
||||||
}
|
}
|
||||||
@@ -538,6 +557,7 @@ function sourceTagType(source) {
|
|||||||
if (source === 'PACKAGE_FIXED' || source === 'FIXED') return 'success'
|
if (source === 'PACKAGE_FIXED' || source === 'FIXED') return 'success'
|
||||||
if (source === 'PACKAGE_DISCOUNT' || source === 'DISCOUNT') return 'warning'
|
if (source === 'PACKAGE_DISCOUNT' || source === 'DISCOUNT') return 'warning'
|
||||||
if (source === 'PRODUCT_DEFAULT') return 'info'
|
if (source === 'PRODUCT_DEFAULT') return 'info'
|
||||||
|
if (source === 'BILLING_FAIL') return 'danger'
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -73,6 +73,9 @@
|
|||||||
<el-descriptions-item label="计价来源">
|
<el-descriptions-item label="计价来源">
|
||||||
<el-tag size="small" :type="sourceTagType(detail.matchSource)">{{ sourceLabel(detail.matchSource) }}</el-tag>
|
<el-tag size="small" :type="sourceTagType(detail.matchSource)">{{ sourceLabel(detail.matchSource) }}</el-tag>
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="计费状态">
|
||||||
|
<el-tag size="small" :type="billingFailTagType(detail.billingFailStatus)">{{ billingFailLabel(detail.billingFailStatus) }}</el-tag>
|
||||||
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="套餐">{{ priceSetLabel(detail) }}</el-descriptions-item>
|
<el-descriptions-item label="套餐">{{ priceSetLabel(detail) }}</el-descriptions-item>
|
||||||
<!-- <el-descriptions-item label="套餐版本">{{ detail.versionNo || (detail.psvId ? ('psv=' + detail.psvId) : '-') }}</el-descriptions-item> -->
|
<!-- <el-descriptions-item label="套餐版本">{{ detail.versionNo || (detail.psvId ? ('psv=' + detail.psvId) : '-') }}</el-descriptions-item> -->
|
||||||
<!-- <el-descriptions-item label="套餐明细ID">{{ detail.psdId != null ? detail.psdId : '-' }}</el-descriptions-item> -->
|
<!-- <el-descriptions-item label="套餐明细ID">{{ detail.psdId != null ? detail.psdId : '-' }}</el-descriptions-item> -->
|
||||||
@@ -332,11 +335,26 @@ function formatDateTime(val) {
|
|||||||
return d.getFullYear() + '-' + pad(d.getMonth() + 1) + '-' + pad(d.getDate()) + ' ' + pad(d.getHours()) + ':' + pad(d.getMinutes()) + ':' + pad(d.getSeconds())
|
return d.getFullYear() + '-' + pad(d.getMonth() + 1) + '-' + pad(d.getDate()) + ' ' + pad(d.getHours()) + ':' + pad(d.getMinutes()) + ':' + pad(d.getSeconds())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function billingFailLabel(status) {
|
||||||
|
const code = status == null ? 0 : Number(status)
|
||||||
|
if (code === 1) return '未匹配产品'
|
||||||
|
if (code === 2) return '未匹配国家'
|
||||||
|
if (code === 3) return '未匹配重量段'
|
||||||
|
return '计费成功'
|
||||||
|
}
|
||||||
|
|
||||||
|
function billingFailTagType(status) {
|
||||||
|
const code = status == null ? 0 : Number(status)
|
||||||
|
if (code === 1 || code === 2 || code === 3) return 'danger'
|
||||||
|
return 'success'
|
||||||
|
}
|
||||||
|
|
||||||
function sourceLabel(source) {
|
function sourceLabel(source) {
|
||||||
const map = {
|
const map = {
|
||||||
PACKAGE_FIXED: '客户固定价套餐',
|
PACKAGE_FIXED: '客户固定价套餐',
|
||||||
PACKAGE_DISCOUNT: '客户折扣套餐',
|
PACKAGE_DISCOUNT: '客户折扣套餐',
|
||||||
PRODUCT_DEFAULT: '产品默认价',
|
PRODUCT_DEFAULT: '产品默认价',
|
||||||
|
BILLING_FAIL: '计费失败',
|
||||||
FIXED: '客户固定价套餐',
|
FIXED: '客户固定价套餐',
|
||||||
DISCOUNT: '客户折扣套餐'
|
DISCOUNT: '客户折扣套餐'
|
||||||
}
|
}
|
||||||
@@ -379,6 +397,7 @@ function sourceTagType(source) {
|
|||||||
if (source === 'PACKAGE_FIXED' || source === 'FIXED') return 'success'
|
if (source === 'PACKAGE_FIXED' || source === 'FIXED') return 'success'
|
||||||
if (source === 'PACKAGE_DISCOUNT' || source === 'DISCOUNT') return 'warning'
|
if (source === 'PACKAGE_DISCOUNT' || source === 'DISCOUNT') return 'warning'
|
||||||
if (source === 'PRODUCT_DEFAULT') return 'info'
|
if (source === 'PRODUCT_DEFAULT') return 'info'
|
||||||
|
if (source === 'BILLING_FAIL') return 'danger'
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user