diff --git a/bms-back/bms-system/src/main/java/com/bms/price/domain/vo/TabOrderMonitorQuery.java b/bms-back/bms-system/src/main/java/com/bms/price/domain/vo/TabOrderMonitorQuery.java index 69f56d68..59eb4e02 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/domain/vo/TabOrderMonitorQuery.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/domain/vo/TabOrderMonitorQuery.java @@ -38,6 +38,11 @@ public class TabOrderMonitorQuery implements Serializable private List orderIdentifiers; /** 上游产品代码 LINE_CODE(产品比对点进订单号时使用) */ private String productCode; + /** + * 订单状态 ORDER_STATUS 多选。 + * 空则服务端回落默认 3,4,5,6,7,8,11(与历史硬编码一致)。 + */ + private List orderStatuses; /** 分批同步计费每批条数 */ private Integer batchSize; } diff --git a/bms-back/bms-system/src/main/java/com/bms/price/enums/BillOrderStatus.java b/bms-back/bms-system/src/main/java/com/bms/price/enums/BillOrderStatus.java new file mode 100644 index 00000000..acd1a731 --- /dev/null +++ b/bms-back/bms-system/src/main/java/com/bms/price/enums/BillOrderStatus.java @@ -0,0 +1,49 @@ +package com.bms.price.enums; + +/** + * Snapshot of prc_order_bill.order_status (aligned with upstream TAB_ORDER). + * Fee refund sets {@link #REFUNDED} (9 / 已退件). + */ +public enum BillOrderStatus +{ + /** Upstream: returned package; also set after billing-list fee refund. */ + REFUNDED(9); + + private final int code; + + BillOrderStatus(int code) + { + this.code = code; + } + + public int getCode() + { + return code; + } + + public Integer getCodeBoxed() + { + return Integer.valueOf(code); + } + + public boolean matches(Integer status) + { + return status != null && status.intValue() == code; + } + + public static BillOrderStatus of(Integer status) + { + if (status == null) + { + return null; + } + for (BillOrderStatus value : values()) + { + if (value.code == status.intValue()) + { + return value; + } + } + return null; + } +} diff --git a/bms-back/bms-system/src/main/java/com/bms/price/oracle/TabOrderMonitorService.java b/bms-back/bms-system/src/main/java/com/bms/price/oracle/TabOrderMonitorService.java index 20d6f5cd..4b501eb4 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/oracle/TabOrderMonitorService.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/oracle/TabOrderMonitorService.java @@ -3,6 +3,7 @@ package com.bms.price.oracle; import java.math.BigDecimal; import java.sql.Timestamp; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.Date; @@ -71,6 +72,12 @@ public class TabOrderMonitorService /** 单批 Oracle 查询最长等待(从库 socketTimeout 为 120s,留同样余量)。 */ private static final long COLLECT_BATCH_TIMEOUT_SECONDS = 120L; + /** Same default as historical hardcoded ORDER_STATUS IN (...). */ + private static final List DEFAULT_ORDER_STATUSES = + Collections.unmodifiableList(Arrays.asList( + Integer.valueOf(3), Integer.valueOf(4), Integer.valueOf(5), Integer.valueOf(6), + Integer.valueOf(7), Integer.valueOf(8), Integer.valueOf(11))); + @Autowired private OracleUpstreamOrderMapper oracleUpstreamOrderMapper; @@ -994,7 +1001,8 @@ public class TabOrderMonitorService appendSorted(sb, q.getCustomerCodes()); sb.append('|').append(safe(q.getBeginTime())).append('|').append(safe(q.getEndTime())) .append('|').append(safe(q.getOrderId())).append('|').append(safe(q.getOrgOrderId())) - .append('|').append(safe(q.getTransferOrderId())); + .append('|').append(safe(q.getTransferOrderId())).append('|'); + appendSortedInts(sb, q.getOrderStatuses()); return Integer.toHexString(sb.toString().hashCode()); } @@ -1012,6 +1020,20 @@ public class TabOrderMonitorService } } + private static void appendSortedInts(StringBuilder sb, List values) + { + if (values == null || values.isEmpty()) + { + return; + } + List copy = new ArrayList(values); + Collections.sort(copy); + for (Integer v : copy) + { + sb.append(v).append(','); + } + } + private static String safe(String s) { return s == null ? "" : s; @@ -1152,6 +1174,25 @@ public class TabOrderMonitorService query.setOrderId(trimToNull(query.getOrderId())); query.setOrgOrderId(trimToNull(query.getOrgOrderId())); query.setTransferOrderId(trimToNull(query.getTransferOrderId())); + normalizeOrderStatuses(query); + } + + /** Empty/missing -> default 3,4,5,6,7,8,11 so SQL always has a status IN list. */ + private static void normalizeOrderStatuses(TabOrderMonitorQuery query) + { + List statuses = query.getOrderStatuses(); + List cleaned = new ArrayList(); + if (statuses != null) + { + for (Integer s : statuses) + { + if (s != null) + { + cleaned.add(s); + } + } + } + query.setOrderStatuses(cleaned.isEmpty() ? new ArrayList(DEFAULT_ORDER_STATUSES) : cleaned); } /** diff --git a/bms-back/bms-system/src/main/java/com/bms/price/service/impl/PrcOrderBillServiceImpl.java b/bms-back/bms-system/src/main/java/com/bms/price/service/impl/PrcOrderBillServiceImpl.java index df4def8b..335b5c79 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/service/impl/PrcOrderBillServiceImpl.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/service/impl/PrcOrderBillServiceImpl.java @@ -77,6 +77,7 @@ import com.bms.price.domain.vo.TmsPriceQuoteFeeLine; import com.bms.price.domain.vo.TmsPriceQuoteResult; import com.bms.price.enums.BillCreditArrearsStatus; import com.bms.price.enums.BillCustomerActiveStatus; +import com.bms.price.enums.BillOrderStatus; import com.bms.price.enums.BillRefundStatus; import com.bms.price.enums.BillBillingFailStatus; import com.bms.price.enums.TmsOrderBillMatchType; @@ -300,6 +301,8 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService refundFee.setManualFlag("0"); incomeBillFeeMapper.insertPrcIncomeBillFee(refundFee); bill.setRefundStatus(BillRefundStatus.REFUNDED.getCode()); + // Align with upstream 已退件 after fee refund. + bill.setOrderStatus(BillOrderStatus.REFUNDED.getCodeBoxed()); if (incomeBill != null) { incomeBill.setRefundStatus(BillRefundStatus.REFUNDED.getCode()); @@ -315,6 +318,7 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService req.put("refundAmount", feeSum.negate()); req.put("feeId", refundFee.getFeeId()); req.put("refundStatus", bill.getRefundStatus()); + req.put("orderStatus", bill.getOrderStatus()); if (billSearchStore != null) { billSearchStore.save(EsLogType.BILL, @@ -762,6 +766,7 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService { throw new ServiceException(MessageUtils.message("price.bill.bizDateRequired")); } + assertOrderBillNotRefunded(bill); TmsPriceBillRequest req = buildBillRequestFromBill(bill); return billLocalWithDbRetry(billId.trim(), req); } @@ -1631,6 +1636,7 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService String billKey = Md5Utils.hash(orderNo); PrcOrderBill existed = orderBillMapper.selectPrcOrderBillByOrderNo(orderNo); assertOrderBillEditable(existed); + assertOrderBillNotRefunded(existed); BigDecimal previousIncome = existed == null ? BigDecimal.ZERO : nz(existed.getIncomeTotal()); PrcOrderBill bill = existed == null ? new PrcOrderBill() : existed; if (existed == null) @@ -2087,6 +2093,15 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService } } + /** Block rebill when refundStatus=REFUNDED (order_status=9 alone is logistics return, not fee refund). */ + private void assertOrderBillNotRefunded(PrcOrderBill bill) + { + if (bill != null && BillRefundStatus.REFUNDED.getCode().equalsIgnoreCase(bill.getRefundStatus())) + { + throw new ServiceException("\u8ba2\u5355\u5df2\u9000\u8d39\uff0c\u4e0d\u53ef\u91cd\u65b0\u8ba1\u8d39"); + } + } + private static BigDecimal nz(BigDecimal v) { return v == null ? BigDecimal.ZERO : v; @@ -2931,7 +2946,12 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService { return; } - if (request.getOrderStatus() != null) + // 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) { bill.setOrderStatus(request.getOrderStatus()); } diff --git a/bms-back/bms-system/src/main/resources/mapper/price/OracleUpstreamOrderMapper.xml b/bms-back/bms-system/src/main/resources/mapper/price/OracleUpstreamOrderMapper.xml index c7568477..a3361914 100644 --- a/bms-back/bms-system/src/main/resources/mapper/price/OracleUpstreamOrderMapper.xml +++ b/bms-back/bms-system/src/main/resources/mapper/price/OracleUpstreamOrderMapper.xml @@ -67,7 +67,15 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" AND o.PICKUP_DATE <= TO_DATE(#{query.endTime}, 'YYYY-MM-DD HH24:MI:SS') AND o.BL_PICKUP = 1 - AND o.ORDER_STATUS IN (3, 4, 5, 6, 7, 8, 11) + + AND o.ORDER_STATUS IN + + #{st} + + + + AND o.ORDER_STATUS IN (3, 4, 5, 6, 7, 8, 11) + AND o.ORDER_ID = #{query.orderId} diff --git a/bms-front/src/views/monitor/orderSource/components/OrderSourceSyncDialog.vue b/bms-front/src/views/monitor/orderSource/components/OrderSourceSyncDialog.vue index b0d36897..d393b902 100644 --- a/bms-front/src/views/monitor/orderSource/components/OrderSourceSyncDialog.vue +++ b/bms-front/src/views/monitor/orderSource/components/OrderSourceSyncDialog.vue @@ -213,6 +213,7 @@ function submit(skipConfirm) { orderId: q.orderId || undefined, orgOrderId: q.orgOrderId || undefined, transferOrderId: q.transferOrderId || undefined, + orderStatuses: Array.isArray(q.orderStatuses) && q.orderStatuses.length ? q.orderStatuses : undefined, batchSize: 100 }).then(res => { const asyncTaskId = res.data?.asyncTaskId || res.data diff --git a/bms-front/src/views/monitor/orderSource/index.vue b/bms-front/src/views/monitor/orderSource/index.vue index 6f8d8253..b95e5cea 100644 --- a/bms-front/src/views/monitor/orderSource/index.vue +++ b/bms-front/src/views/monitor/orderSource/index.vue @@ -18,11 +18,11 @@ ref="tableRef" :columns="columns" :search-columns="searchColumns" + :default-params="defaultParams" :query="queryList" row-key="orderId" :auto-load="false" selection - search-action-align="center" :search-per-row="4" :page-sizes="[100, 200, 300, 400]" :page-size="100" @@ -83,6 +83,31 @@ + @@ -130,6 +155,27 @@ const syncFloat = ref(null) /** 比对回填搜索模式:走专用转单号接口,不影响普通列表 */ const transferFillMode = ref(false) +const orderStatusMap = { + 0: '预报订单', + 1: '确认订单', + 2: '已中转', + 3: '已收货', + 4: '已装箱', + 5: '已出库', + 6: '转运中', + 7: '已上网', + 8: '已签收', + 9: '已退件', + 10: '已删除', + 11: '已复核' +} + +const orderStatusOptions = Object.keys(orderStatusMap).map(k => ({ label: orderStatusMap[k], value: Number(k) })) + +const defaultParams = { + orderStatuses: [3, 4, 5, 6, 7, 8, 11] +} + const searchColumns = [ { // 客户名称或客户代码混合录入,一行一个 @@ -164,7 +210,20 @@ const searchColumns = [ clearable: true, defaultTime: [new Date(2000, 0, 1, 0, 0, 0), new Date(2000, 0, 1, 23, 59, 59)] } - } + }, + { + label: '订单状态', + prop: 'orderStatuses', + component: 'select', + options: orderStatusOptions, + placeholder: '请选择', + props: { + multiple: true, + clearable: true, + collapseTags: true, + collapseTagsTooltip: true + } + }, ] const columns = [ @@ -186,21 +245,6 @@ const columns = [ // { label: '操作', prop: 'action', align: 'center', width: 120, fixed: 'right', slot: 'action', showInToolbar: false } ] -const orderStatusMap = { - 0: '预报订单', - 1: '确认订单', - 2: '已中转', - 3: '已收货', - 4: '已装箱', - 5: '已出库', - 6: '转运中', - 7: '已上网', - 8: '已签收', - 9: '已退件', - 10: '已删除', - 11: '已复核' -} - const syncFloatVisible = computed(() => { const p = syncFloat.value return !!(p && (p.loading || p.finished)) @@ -220,6 +264,30 @@ const syncFloatSummary = computed(() => { }) const syncFloatTooltip = computed(() => syncFloat.value?.message || '点击查看详情') + +const orderStatusAllValues = computed(() => orderStatusOptions.map(o => o.value)) + +function selectedOrderStatuses(model) { + return Array.isArray(model?.orderStatuses) ? model.orderStatuses : [] +} + +function isAllOrderStatusSelected(model) { + const selected = selectedOrderStatuses(model) + const all = orderStatusAllValues.value + return all.length > 0 && selected.length === all.length +} + +function isOrderStatusIndeterminate(model) { + const selected = selectedOrderStatuses(model) + const all = orderStatusAllValues.value + return selected.length > 0 && selected.length < all.length +} + +function toggleAllOrderStatus(model, checked) { + if (!model) return + model.orderStatuses = checked ? [...orderStatusAllValues.value] : [] +} + function orderStatusLabel(status) { if (status === null || status === undefined || status === '') return '-' const key = Number(status)