Compare commits
2 Commits
41cefd5fd5
...
a58de9bb7e
| Author | SHA1 | Date | |
|---|---|---|---|
| a58de9bb7e | |||
| a211f06663 |
@@ -42,14 +42,14 @@ bms:
|
||||
order-source-sync-threads: 16
|
||||
# Order-list local rebill workers (2~24). Pair with Druid maxActive >= threads + 8.
|
||||
local-rebill-threads: 16
|
||||
# Night auto-rebill: hours 0-8, pull 500 (all statuses) -> bill -> next 500 until empty / 09:00.
|
||||
# Empty page => no billing.
|
||||
# Auto-rebill: every hour all day, pull 500 (all statuses) -> bill -> next 500 until empty.
|
||||
# Empty page => no billing. Window [start-hour, end-hour).
|
||||
night-retry:
|
||||
enabled: true
|
||||
start-hour: 0
|
||||
end-hour: 9
|
||||
end-hour: 24
|
||||
batch-size: 500
|
||||
cron: "0 0/1 0-8 * * ?"
|
||||
cron: "0 0 * * * ?"
|
||||
oracle:
|
||||
# SLAVE datasource Oracle main-order table (schema.table allowed)
|
||||
order-table: WEISHI_USER.TAB_ORDER
|
||||
|
||||
@@ -25,7 +25,7 @@ public class BillingProperties
|
||||
* Keep below Druid maxActive with headroom for other traffic.
|
||||
*/
|
||||
private int localRebillThreads = 16;
|
||||
/** Night window auto-retry of prc_billing_task (all statuses) */
|
||||
/** Hourly auto-retry of prc_billing_task (all statuses) */
|
||||
private NightRetry nightRetry = new NightRetry();
|
||||
private Oracle oracle = new Oracle();
|
||||
|
||||
@@ -120,8 +120,8 @@ public class BillingProperties
|
||||
}
|
||||
|
||||
/**
|
||||
* Overnight rebill window: pull prc_billing_task (all success_status) and retryTask.
|
||||
* Default hours [0, 9) local time; empty result skips billing.
|
||||
* Auto rebill window: pull prc_billing_task (all success_status) and retryTask.
|
||||
* Default hours [0, 24) local time (all day); empty result skips billing.
|
||||
*/
|
||||
public static class NightRetry
|
||||
{
|
||||
@@ -129,8 +129,8 @@ public class BillingProperties
|
||||
private boolean enabled = true;
|
||||
/** Inclusive start hour (0 = 00:00) */
|
||||
private int startHour = 0;
|
||||
/** Exclusive end hour (9 = stop at 09:00) */
|
||||
private int endHour = 9;
|
||||
/** Exclusive end hour (24 = all day) */
|
||||
private int endHour = 24;
|
||||
/** Page size: bill this many then pull next page (default 500) */
|
||||
private int batchSize = 500;
|
||||
|
||||
|
||||
@@ -122,7 +122,7 @@ public class PrcOrderBill extends BaseEntity
|
||||
private String creditArrearsStatus;
|
||||
/** NONE / REFUNDED */
|
||||
private String refundStatus;
|
||||
/** Billing fail: 0 ok; 1/2/3 sales miss; 23/24/25 catalog miss; soft-fail amount=0, no fee rows */
|
||||
/** Billing fail: 0 ok writes income bill+fee; non-0 amount=0, no income bill/fee */
|
||||
private Integer billingFailStatus;
|
||||
/** 失败原因 */
|
||||
private String errorMessage;
|
||||
|
||||
@@ -103,7 +103,7 @@ public class TmsPriceQuoteResult implements Serializable
|
||||
private String creditArrearsStatus;
|
||||
/** NONE / REFUNDED */
|
||||
private String refundStatus;
|
||||
/** Billing fail: 0 ok; 1/2/3 sales; 23/24/25 catalog (soft-fail on bill sync) */
|
||||
/** Billing fail: 0 ok (income bill+fee); 1/2/3 sales; 23/24/25 catalog */
|
||||
private Integer billingFailStatus;
|
||||
private Integer pieces;
|
||||
private BigDecimal actualWeight;
|
||||
|
||||
@@ -6,7 +6,8 @@ package com.bms.price.enums;
|
||||
* 1/2/3 sales-price (package) miss: product / country / weight;
|
||||
* 23/24/25 product-catalog price miss: product / country / weight;
|
||||
* 4+ map to prc_billing_task.fail_code.
|
||||
* Soft-fail income bill: 0/1/2/3/23/24/25; fee rows only for 0.
|
||||
* 26 not billed yet (order-source sync only).
|
||||
* Income bill + fee rows: only status 0.
|
||||
*/
|
||||
public enum BillBillingFailStatus
|
||||
{
|
||||
@@ -38,7 +39,9 @@ public enum BillBillingFailStatus
|
||||
/** Product catalog miss: product hit but country/zone miss. */
|
||||
CATALOG_COUNTRY(24),
|
||||
/** Product catalog miss: product+country hit but weight band miss. */
|
||||
CATALOG_WEIGHT(25);
|
||||
CATALOG_WEIGHT(25),
|
||||
/** Order landed from upstream but not billed yet. */
|
||||
NOT_BILLED(26);
|
||||
|
||||
private final int code;
|
||||
|
||||
@@ -70,16 +73,23 @@ public enum BillBillingFailStatus
|
||||
|
||||
public static boolean isFail(Integer code)
|
||||
{
|
||||
return code != null && code.intValue() > SUCCESS.code;
|
||||
if (code == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
int value = code.intValue();
|
||||
return value != SUCCESS.code && value != NOT_BILLED.code;
|
||||
}
|
||||
|
||||
/** Soft-fail sales/catalog misses also persist prc_income_bill. */
|
||||
public static boolean isNotBilled(Integer code)
|
||||
{
|
||||
return code != null && code.intValue() == NOT_BILLED.code;
|
||||
}
|
||||
|
||||
/** Only success (0) persists prc_income_bill. */
|
||||
public static boolean storesIncomeBill(Integer code)
|
||||
{
|
||||
int value = code == null ? SUCCESS.code : code.intValue();
|
||||
return value == SUCCESS.code
|
||||
|| value == PRODUCT.code || value == COUNTRY.code || value == WEIGHT.code
|
||||
|| value == CATALOG_PRODUCT.code || value == CATALOG_COUNTRY.code || value == CATALOG_WEIGHT.code;
|
||||
return code == null || code.intValue() == SUCCESS.code;
|
||||
}
|
||||
|
||||
/** 仅 0 落 prc_income_bill_fee。 */
|
||||
@@ -96,7 +106,7 @@ public enum BillBillingFailStatus
|
||||
}
|
||||
for (BillBillingFailStatus status : values())
|
||||
{
|
||||
if (status == SUCCESS)
|
||||
if (status == SUCCESS || status == NOT_BILLED)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -113,6 +123,7 @@ public enum BillBillingFailStatus
|
||||
switch (this)
|
||||
{
|
||||
case SUCCESS:
|
||||
case NOT_BILLED:
|
||||
return null;
|
||||
case PRODUCT:
|
||||
return BillTaskFailCode.PRODUCT_NOT_HIT.getCode();
|
||||
|
||||
+2
-1
@@ -3089,7 +3089,8 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService
|
||||
bill.setBillId(UUID.randomUUID().toString());
|
||||
bill.setArBillStatus(ArOrderBillStatus.UNBILLED.getCode());
|
||||
bill.setRefundStatus(BillRefundStatus.NONE.getCode());
|
||||
bill.setBillingFailStatus(Integer.valueOf(BillBillingFailStatus.SUCCESS.getCode()));
|
||||
// Order-source sync only: mark not billed until quote/bill runs.
|
||||
bill.setBillingFailStatus(Integer.valueOf(BillBillingFailStatus.NOT_BILLED.getCode()));
|
||||
bill.setFreightRate(BigDecimal.ZERO);
|
||||
bill.setBaseFreightRate(BigDecimal.ZERO);
|
||||
bill.setRegistrationFee(BigDecimal.ZERO);
|
||||
|
||||
+1
@@ -265,6 +265,7 @@ public final class OrderBillExportSupport
|
||||
case 20: return "客户已停用";
|
||||
case 21: return "运费为空";
|
||||
case 22: return "未知失败";
|
||||
case 26: return "未计费";
|
||||
default: return String.valueOf(status);
|
||||
}
|
||||
}
|
||||
|
||||
+7
-7
@@ -16,13 +16,13 @@ import com.bms.price.mapper.PrcBillingTaskMapper;
|
||||
import com.bms.price.service.IPrcBillingTaskService;
|
||||
|
||||
/**
|
||||
* 夜间窗口按 prc_billing_task 自动重计费。
|
||||
* Auto retry prc_billing_task on a schedule.
|
||||
*
|
||||
* <p>在 [startHour, endHour) 内(默认 00:00-09:00):最多拉取 {@value #DEFAULT_BATCH}
|
||||
* 条任务 id(不限 success_status)-> 全部计费 -> 立刻拉下一页。
|
||||
* 空页则跳过计费并结束本轮(下次 cron 再处理新数据)。</p>
|
||||
* <p>Within [startHour, endHour) (default all day 00:00-24:00): pull up to {@value #DEFAULT_BATCH}
|
||||
* task ids (any success_status) -> bill all -> pull next page.
|
||||
* Empty page skips billing and ends this tick (next cron handles new rows).</p>
|
||||
*
|
||||
* <p>与监控手工重试 / 条件重试同一条重计费路径(先重置为 WAITING 再处理)。</p>
|
||||
* <p>Same path as monitor manual / filter retry (reset to WAITING then process).</p>
|
||||
*/
|
||||
@Component
|
||||
public class PrcBillingTaskNightRetryTask
|
||||
@@ -52,10 +52,10 @@ public class PrcBillingTaskNightRetryTask
|
||||
private IPrcBillingTaskService billingTaskService;
|
||||
|
||||
/**
|
||||
* Fire every minute; if a previous run is still paging batches, skip.
|
||||
* Fire every hour by default; if a previous run is still paging batches, skip.
|
||||
* Hour gate uses bms.billing.night-retry start/end.
|
||||
*/
|
||||
@Scheduled(cron = "${bms.billing.night-retry.cron:0 0/1 0-8 * * ?}")
|
||||
@Scheduled(cron = "${bms.billing.night-retry.cron:0 0 * * * ?}")
|
||||
public void scheduledTick()
|
||||
{
|
||||
BillingProperties.NightRetry cfg = billingProperties == null ? null : billingProperties.getNightRetry();
|
||||
|
||||
+1
@@ -1748,6 +1748,7 @@ public class ArBillServiceImpl implements IArBillService {
|
||||
}
|
||||
return switch (status) {
|
||||
case SUCCESS -> "";
|
||||
case NOT_BILLED -> "未计费";
|
||||
case PRODUCT -> "销售价未匹配产品";
|
||||
case COUNTRY -> "销售价未匹配国家";
|
||||
case WEIGHT -> "销售价未匹配重量段";
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
-- prc_order_bill.billing_fail_status: add 26 NOT_BILLED
|
||||
ALTER TABLE prc_order_bill
|
||||
MODIFY COLUMN billing_fail_status tinyint NOT NULL DEFAULT 0 COMMENT '计费失败状态:0成功/1销售价未匹配产品/2销售价未匹配国家/3销售价未匹配重量段/23产品价未匹配产品/24产品价未匹配国家/25产品价未匹配重量段/4未绑定套餐/5无生效套餐版本/6已生成应收账单/7产品档案缺失/8未命中价格/9分区无价格/10邮编必填/11邮编未匹配分区/12上游订单不存在/13上游订单号为空/14上游客户为空/15上游产品为空/16上游重量无效/17计费时间为空/18退费订单无法解析/19客户代码为空/20客户已停用/21运费为空/22未知失败/26未计费。仅0写入应收主表,仅0写入应收费用';
|
||||
@@ -1098,6 +1098,7 @@ function billingFailLabel(status) {
|
||||
|
||||
function billingFailTagType(status) {
|
||||
const code = status == null ? 0 : Number(status)
|
||||
if (code === 26) return 'info'
|
||||
if (code > 0) return 'danger'
|
||||
return 'success'
|
||||
}
|
||||
|
||||
@@ -254,7 +254,8 @@ function billingFailStatusLabel(code) {
|
||||
3: '销售价未匹配重量段',
|
||||
23: '产品价未匹配产品',
|
||||
24: '产品价未匹配国家',
|
||||
25: '产品价未匹配重量段'
|
||||
25: '产品价未匹配重量段',
|
||||
26: '未计费'
|
||||
}
|
||||
const key = Number(code)
|
||||
return map[key] != null ? map[key] : String(code)
|
||||
|
||||
@@ -405,7 +405,8 @@ const billingFailStatusOptions = [
|
||||
{ label: '客户代码为空', value: 19 },
|
||||
{ label: '客户已停用', value: 20 },
|
||||
{ label: '运费为空', value: 21 },
|
||||
{ label: '未知失败', value: 22 }
|
||||
{ label: '未知失败', value: 22 },
|
||||
{ label: '未计费', value: 26 }
|
||||
]
|
||||
|
||||
function billingFailLabel(status) {
|
||||
@@ -416,6 +417,7 @@ function billingFailLabel(status) {
|
||||
|
||||
function billingFailTagType(status) {
|
||||
const code = status == null ? 0 : Number(status)
|
||||
if (code === 26) return 'info'
|
||||
if (code > 0) return 'danger'
|
||||
return 'success'
|
||||
}
|
||||
|
||||
@@ -494,7 +494,8 @@ const billingFailStatusOptions = [
|
||||
{ label: '客户代码为空', value: 19 },
|
||||
{ label: '客户已停用', value: 20 },
|
||||
{ label: '运费为空', value: 21 },
|
||||
{ label: '未知失败', value: 22 }
|
||||
{ label: '未知失败', value: 22 },
|
||||
{ label: '未计费', value: 26 }
|
||||
]
|
||||
|
||||
const orderStatusAllValues = computed(() => orderStatusOptions.map(o => o.value))
|
||||
@@ -1003,6 +1004,7 @@ function billingFailLabel(status) {
|
||||
|
||||
function billingFailTagType(status) {
|
||||
const code = status == null ? 0 : Number(status)
|
||||
if (code === 26) return 'info'
|
||||
return code > 0 ? 'danger' : 'success'
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user