From 762cad2c0d6efab8c6c4e87f7c1a36910caeedd1 Mon Sep 17 00:00:00 2001 From: caojia <1301869380@qq.com> Date: Fri, 30 Oct 2026 15:22:50 +0800 Subject: [PATCH] =?UTF-8?q?:sparkles:=20=E6=96=B0=E5=A2=9E=E5=BA=94?= =?UTF-8?q?=E6=94=B6=E8=B4=A6=E5=8D=95=E6=97=A5=E6=9C=9F=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=E7=AD=9B=E9=80=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bms/ar/domain/vo/ArBillGenerateQuery.java | 3 ++ .../ar/domain/vo/ArBillGenerateRequest.java | 2 + .../java/com/bms/ar/enums/ArBillDateType.java | 39 +++++++++++++++++++ .../ar/service/impl/ArBillServiceImpl.java | 30 ++++++++++---- .../bms/price/mapper/PrcOrderBillMapper.java | 10 ++--- .../mapper/price/PrcOrderBillMapper.xml | 38 +++++++++++++++--- .../ar/bill/components/GenerateBillDialog.vue | 22 +++++++---- 7 files changed, 117 insertions(+), 27 deletions(-) create mode 100644 bms-back/bms-system/src/main/java/com/bms/ar/enums/ArBillDateType.java diff --git a/bms-back/bms-system/src/main/java/com/bms/ar/domain/vo/ArBillGenerateQuery.java b/bms-back/bms-system/src/main/java/com/bms/ar/domain/vo/ArBillGenerateQuery.java index bc36a885..ceda9d17 100644 --- a/bms-back/bms-system/src/main/java/com/bms/ar/domain/vo/ArBillGenerateQuery.java +++ b/bms-back/bms-system/src/main/java/com/bms/ar/domain/vo/ArBillGenerateQuery.java @@ -24,6 +24,9 @@ public class ArBillGenerateQuery @JsonDeserialize(using = StrictDateDeserializer.class) private Date billPeriodEnd; + /** 截止日筛选字段:BIZ_DATE=计费时间,PICKUP_DATE=收货时间;历史请求默认计费时间。 */ + private String dateType = "BIZ_DATE"; + private String currency; /** 订单号、运单号或转单号;支持换行、逗号、分号或空格分隔多个号码。 */ diff --git a/bms-back/bms-system/src/main/java/com/bms/ar/domain/vo/ArBillGenerateRequest.java b/bms-back/bms-system/src/main/java/com/bms/ar/domain/vo/ArBillGenerateRequest.java index bdf6e9b9..106c21ca 100644 --- a/bms-back/bms-system/src/main/java/com/bms/ar/domain/vo/ArBillGenerateRequest.java +++ b/bms-back/bms-system/src/main/java/com/bms/ar/domain/vo/ArBillGenerateRequest.java @@ -26,6 +26,8 @@ public class ArBillGenerateRequest @JsonFormat(pattern = "yyyy-MM-dd") @JsonDeserialize(using = StrictDateDeserializer.class) private Date billPeriodEnd; + /** 截止日筛选字段:BIZ_DATE=计费时间,PICKUP_DATE=收货时间;历史任务默认计费时间。 */ + private String dateType = "BIZ_DATE"; /** 手动模式选中的来源订单 ID;全选模式为空。 */ private List sourceBillIds; /** 选择模式:EXPLICIT 手动选择,ALL_MATCHED 全选查询结果。 */ diff --git a/bms-back/bms-system/src/main/java/com/bms/ar/enums/ArBillDateType.java b/bms-back/bms-system/src/main/java/com/bms/ar/enums/ArBillDateType.java new file mode 100644 index 00000000..cd522945 --- /dev/null +++ b/bms-back/bms-system/src/main/java/com/bms/ar/enums/ArBillDateType.java @@ -0,0 +1,39 @@ +package com.bms.ar.enums; + +/** 应收账单生成时用于截止日筛选的来源订单日期字段。 */ +public enum ArBillDateType +{ + /** 计费时间,对应 prc_order_bill.biz_date。 */ + BIZ_DATE("BIZ_DATE"), + /** 收货时间,对应 prc_order_bill.pickup_date。 */ + PICKUP_DATE("PICKUP_DATE"); + + private final String code; + + ArBillDateType(String code) + { + this.code = code; + } + + public String getCode() + { + return code; + } + + /** 历史请求未携带日期类型时按计费时间处理。 */ + public static ArBillDateType of(String code) + { + if (code == null || code.trim().isEmpty()) + { + return BIZ_DATE; + } + for (ArBillDateType type : values()) + { + if (type.code.equalsIgnoreCase(code.trim())) + { + return type; + } + } + return null; + } +} diff --git a/bms-back/bms-system/src/main/java/com/bms/ar/service/impl/ArBillServiceImpl.java b/bms-back/bms-system/src/main/java/com/bms/ar/service/impl/ArBillServiceImpl.java index 890d047c..dc1acbb4 100644 --- a/bms-back/bms-system/src/main/java/com/bms/ar/service/impl/ArBillServiceImpl.java +++ b/bms-back/bms-system/src/main/java/com/bms/ar/service/impl/ArBillServiceImpl.java @@ -55,6 +55,7 @@ import com.bms.ar.domain.ArExportTemplate; import com.bms.ar.event.ArBillExportTaskEvent; import com.bms.ar.event.ArBillGenerateTaskEvent; import com.bms.ar.enums.ArBillGenerateTaskStatus; +import com.bms.ar.enums.ArBillDateType; import com.bms.ar.enums.ArBillGenerationStatus; import com.bms.ar.enums.ArBillSelectionMode; import com.bms.ar.enums.ArBillStatus; @@ -319,7 +320,7 @@ public class ArBillServiceImpl implements IArBillService { List excludeOrderIdentifiers = normalizeOrderIdentifiers(query.getExcludeOrderOrTrackingNo()); List result = sourceBillMapper.selectPrcOrderBillByCustomerPeriod(query.getCustomerId(), query.getCustomerCode(), orderIdentifiers, - excludeOrderIdentifiers, query.getBillPeriodEnd(), query.getCurrency(), + excludeOrderIdentifiers, query.getBillPeriodEnd(), query.getDateType(), query.getCurrency(), eligibleOrderBillStatuses(), ArIncomeBillFeeStatus.UNBILLED.getCode(), null); log.debug("应收账单生成范围预览查询完成,customerId={}, billPeriodEnd={}, currency={}, resultCount={}, costMs={}", query.getCustomerId(), query.getBillPeriodEnd(), safeLogValue(query.getCurrency()), @@ -349,7 +350,7 @@ public class ArBillServiceImpl implements IArBillService { List excludeOrderIdentifiers = normalizeOrderIdentifiers(query.getExcludeOrderOrTrackingNo()); BigDecimal total = nvl(sourceBillMapper.sumPrcOrderBillIncomeByCustomerPeriod(query.getCustomerId(), query.getCustomerCode(), orderIdentifiers, - excludeOrderIdentifiers, query.getBillPeriodEnd(), query.getCurrency(), + excludeOrderIdentifiers, query.getBillPeriodEnd(), query.getDateType(), query.getCurrency(), eligibleOrderBillStatuses(), ArIncomeBillFeeStatus.UNBILLED.getCode())); log.debug("应收账单生成范围金额汇总完成,customerId={}, billPeriodEnd={}, currency={}, costMs={}", query.getCustomerId(), query.getBillPeriodEnd(), safeLogValue(query.getCurrency()), @@ -604,7 +605,7 @@ public class ArBillServiceImpl implements IArBillService { int totalCount = sourceBillMapper.countPrcOrderBillByCustomerPeriod( request.getCustomerId(), request.getCustomerCode(), normalizeOrderIdentifiers(request.getOrderOrTrackingNo()), - request.getBillPeriodEnd(), request.getCurrency(), eligibleOrderBillStatuses(), + request.getBillPeriodEnd(), request.getDateType(), request.getCurrency(), eligibleOrderBillStatuses(), ArIncomeBillFeeStatus.UNBILLED.getCode(), task.getSnapshotCreateTime(), null, excludedSourceBillIds, excludedOrderIdentifiers); if (totalCount <= 0) { @@ -731,7 +732,8 @@ public class ArBillServiceImpl implements IArBillService { List sources = sourceBillMapper.selectPrcOrderBillByCustomerPeriodCursor( request.getCustomerId(), request.getCustomerCode(), normalizeOrderIdentifiers(request.getOrderOrTrackingNo()), - request.getBillPeriodEnd(), StringUtils.isEmpty(request.getCurrency()) ? "CNY" : request.getCurrency(), + request.getBillPeriodEnd(), request.getDateType(), + StringUtils.isEmpty(request.getCurrency()) ? "CNY" : request.getCurrency(), eligibleOrderBillStatuses(), ArIncomeBillFeeStatus.UNBILLED.getCode(), task.getSnapshotCreateTime(), task.getLastSourceBillId(), explicitIds, selectionMode == ArBillSelectionMode.ALL_MATCHED ? excludedSourceBillIds : null, @@ -836,7 +838,7 @@ public class ArBillServiceImpl implements IArBillService { } int processedCount = (task.getProcessedCount() == null ? 0 : task.getProcessedCount()) + sources.size(); BigDecimal totalAmount = nvl(task.getTotalAmount()).add(batchAmount); - Date periodStart = earliestBizDate(sources); + Date periodStart = earliestDate(sources, request.getDateType()); billMapper.updateArBillProgress(bill.getArBillId(), processedCount, totalAmount, totalAmount, periodStart, task.getCreateBy()); String lastSourceBillId = sources.get(sources.size() - 1).getBillId(); @@ -2181,6 +2183,7 @@ public class ArBillServiceImpl implements IArBillService { if (StringUtils.isNotEmpty(request.getRemark()) && request.getRemark().trim().length() > 500) { throw new ServiceException("备注不能超过500个字符"); } + request.setDateType(normalizeDateType(request.getDateType())); // 生成任务会保存原始请求快照,先在入任务前校验号码数量,避免后台任务创建后才失败。 normalizeOrderIdentifiers(request.getOrderOrTrackingNo()); } @@ -2190,6 +2193,7 @@ public class ArBillServiceImpl implements IArBillService { || query.getBillPeriodEnd() == null) { throw new ServiceException("客户和账单截止日不能为空"); } + query.setDateType(normalizeDateType(query.getDateType())); int identifierCount = normalizeOrderIdentifiers(query.getOrderOrTrackingNo()).size() + normalizeOrderIdentifiers(query.getExcludeOrderOrTrackingNo()).size(); if (identifierCount > ORDER_IDENTIFIER_LIMIT) { @@ -2203,16 +2207,26 @@ public class ArBillServiceImpl implements IArBillService { return Arrays.asList(ArOrderBillStatus.UNBILLED.getCode(), ArOrderBillStatus.PARTIAL.getCode()); } - private Date earliestBizDate(List sources) { + private Date earliestDate(List sources, String dateType) { + boolean usePickupDate = ArBillDateType.PICKUP_DATE.getCode().equals(dateType); Date earliest = null; for (PrcOrderBill source : sources) { - if (source.getBizDate() != null && (earliest == null || source.getBizDate().before(earliest))) { - earliest = source.getBizDate(); + Date sourceDate = usePickupDate ? source.getPickupDate() : source.getBizDate(); + if (sourceDate != null && (earliest == null || sourceDate.before(earliest))) { + earliest = sourceDate; } } return earliest == null ? new Date() : earliest; } + private String normalizeDateType(String dateType) { + ArBillDateType type = ArBillDateType.of(dateType); + if (type == null) { + throw new ServiceException("账单日期类型无效"); + } + return type.getCode(); + } + private List normalizeSourceBillIds(List sourceBillIds) { LinkedHashSet uniqueIds = new LinkedHashSet<>(); if (sourceBillIds != null) { diff --git a/bms-back/bms-system/src/main/java/com/bms/price/mapper/PrcOrderBillMapper.java b/bms-back/bms-system/src/main/java/com/bms/price/mapper/PrcOrderBillMapper.java index fa61b7bf..6bc1fe72 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/mapper/PrcOrderBillMapper.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/mapper/PrcOrderBillMapper.java @@ -63,7 +63,7 @@ public interface PrcOrderBillMapper public List selectPrcOrderBillByCustomerPeriod(@Param("customerId") Long customerId, @Param("customerCode") String customerCode, @Param("orderIdentifiers") List orderIdentifiers, @Param("excludeOrderIdentifiers") List excludeOrderIdentifiers, - @Param("cutoffDate") Date cutoffDate, @Param("currency") String currency, + @Param("cutoffDate") Date cutoffDate, @Param("dateType") String dateType, @Param("currency") String currency, @Param("arBillStatuses") List arBillStatuses, @Param("feeArBillStatus") String feeArBillStatus, @Param("excludedBillIds") List excludedBillIds); @@ -71,13 +71,13 @@ public interface PrcOrderBillMapper BigDecimal sumPrcOrderBillIncomeByCustomerPeriod(@Param("customerId") Long customerId, @Param("customerCode") String customerCode, @Param("orderIdentifiers") List orderIdentifiers, @Param("excludeOrderIdentifiers") List excludeOrderIdentifiers, - @Param("cutoffDate") Date cutoffDate, @Param("currency") String currency, + @Param("cutoffDate") Date cutoffDate, @Param("dateType") String dateType, @Param("currency") String currency, @Param("arBillStatuses") List arBillStatuses, @Param("feeArBillStatus") String feeArBillStatus); /** 异步生成账单按 bill_id 游标读取一批来源订单。 */ List selectPrcOrderBillByCustomerPeriodCursor(@Param("customerId") Long customerId, @Param("customerCode") String customerCode, @Param("orderIdentifiers") List orderIdentifiers, - @Param("cutoffDate") Date cutoffDate, @Param("currency") String currency, + @Param("cutoffDate") Date cutoffDate, @Param("dateType") String dateType, @Param("currency") String currency, @Param("arBillStatuses") List arBillStatuses, @Param("feeArBillStatus") String feeArBillStatus, @Param("snapshotCreateTime") Date snapshotCreateTime, @Param("lastSourceBillId") String lastSourceBillId, @Param("billIds") List billIds, @@ -86,7 +86,7 @@ public interface PrcOrderBillMapper int countPrcOrderBillByCustomerPeriod(@Param("customerId") Long customerId, @Param("customerCode") String customerCode, @Param("orderIdentifiers") List orderIdentifiers, - @Param("cutoffDate") Date cutoffDate, @Param("currency") String currency, + @Param("cutoffDate") Date cutoffDate, @Param("dateType") String dateType, @Param("currency") String currency, @Param("arBillStatuses") List arBillStatuses, @Param("feeArBillStatus") String feeArBillStatus, @Param("snapshotCreateTime") Date snapshotCreateTime, @Param("billIds") List billIds, @Param("excludedBillIds") List excludedBillIds, @@ -95,7 +95,7 @@ public interface PrcOrderBillMapper /** 按生成账单时用户勾选的订单读取,并再次校验账单筛选条件。 */ public List selectPrcOrderBillByCustomerCutoffAndIds(@Param("customerId") Long customerId, @Param("customerCode") String customerCode, @Param("orderIdentifiers") List orderIdentifiers, - @Param("cutoffDate") Date cutoffDate, + @Param("cutoffDate") Date cutoffDate, @Param("dateType") String dateType, @Param("currency") String currency, @Param("billIds") List billIds, @Param("arBillStatuses") List arBillStatuses, @Param("feeArBillStatus") String feeArBillStatus); diff --git a/bms-back/bms-system/src/main/resources/mapper/price/PrcOrderBillMapper.xml b/bms-back/bms-system/src/main/resources/mapper/price/PrcOrderBillMapper.xml index 32b9ada4..b94d1c4b 100644 --- a/bms-back/bms-system/src/main/resources/mapper/price/PrcOrderBillMapper.xml +++ b/bms-back/bms-system/src/main/resources/mapper/price/PrcOrderBillMapper.xml @@ -639,6 +639,18 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ) + + + + + and p.pickup_date < DATE_ADD(#{cutoffDate}, INTERVAL 1 DAY) + + + and p.biz_date < DATE_ADD(#{cutoffDate}, INTERVAL 1 DAY) + + + + where p.customer_id = #{customerId} - and p.biz_date < DATE_ADD(#{cutoffDate}, INTERVAL 1 DAY) + and p.ar_bill_status in #{status} @@ -800,7 +819,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" and p.currency = #{currency} - order by p.biz_date, p.order_no, p.bill_id + + + order by p.pickup_date, p.order_no, p.bill_id + + + order by p.biz_date, p.order_no, p.bill_id + + diff --git a/bms-front/src/views/ar/bill/components/GenerateBillDialog.vue b/bms-front/src/views/ar/bill/components/GenerateBillDialog.vue index eb1e7094..cff109e9 100644 --- a/bms-front/src/views/ar/bill/components/GenerateBillDialog.vue +++ b/bms-front/src/views/ar/bill/components/GenerateBillDialog.vue @@ -3,10 +3,10 @@ - - - - + + +
+
@@ -69,7 +69,7 @@ - + @@ -109,7 +109,7 @@ - + @@ -200,7 +200,7 @@ const bankAccount = ref(null) const generateRequestId = ref('') const generateFormRef = ref() const billNameFormRef = ref() -const generateForm = reactive({ customerId: '', customerCode: '', customerName: '', cutoffDate: '', currency: 'CNY', orderOrTrackingNo: '' }) +const generateForm = reactive({ customerId: '', customerCode: '', customerName: '', cutoffDate: '', dateType: 'BIZ_DATE', currency: 'CNY', orderOrTrackingNo: '' }) const billNameForm = reactive({ billName: '' }) const generateRules = { customerId: [{ required: true, message: '客户不能为空', trigger: 'change' }], @@ -209,6 +209,8 @@ const generateRules = { } const billNameRules = { billName: [{ required: true, message: '请输入账单名称', trigger: 'blur' }] } const selectedAmount = computed(() => selectedRows.value.reduce((sum, row) => sum + (Number(row.incomeTotal) || 0), 0)) +const dateColumnProp = computed(() => generateForm.dateType === 'PICKUP_DATE' ? 'pickupDate' : 'bizDate') +const dateColumnLabel = computed(() => generateForm.dateType === 'PICKUP_DATE' ? '收货时间' : '计费时间') const allSelected = computed(() => selectionMode.value === AR_BILL_SELECTION_MODE.ALL_MATCHED) const displaySelectedCount = computed(() => selectionMode.value === AR_BILL_SELECTION_MODE.ALL_MATCHED ? Math.max(previewTotal.value - confirmedExcludeCount.value, 0) : selectedRows.value.length) @@ -223,7 +225,7 @@ watch(() => props.modelValue, visible => { // 每次打开生成弹窗都重新建立一次查询快照,避免复用上一次的选中订单。 function openGenerate() { - Object.assign(generateForm, { customerId: '', customerCode: '', customerName: '', cutoffDate: '', currency: 'CNY', orderOrTrackingNo: '' }) + Object.assign(generateForm, { customerId: '', customerCode: '', customerName: '', cutoffDate: '', dateType: 'BIZ_DATE', currency: 'CNY', orderOrTrackingNo: '' }) Object.assign(billNameForm, { billName: '' }) billNameOpen.value = false resetPreview() @@ -288,6 +290,7 @@ function buildGenerateQuery() { customerCode: generateForm.customerCode?.trim() || undefined, customerName: generateForm.customerName?.trim() || undefined, billPeriodEnd: generateForm.cutoffDate, + dateType: generateForm.dateType || 'BIZ_DATE', currency: generateForm.currency || undefined, orderOrTrackingNo: generateForm.orderOrTrackingNo?.trim() || undefined } @@ -535,6 +538,9 @@ function createRequestId() { return globalThis.crypto?.randomUUID?.() || `ar-${D .generate-dialog :deep(.el-dialog__body) { padding: 18px 24px 10px; } .generate-form { padding: 4px 6px 0; border: 1px solid var(--el-border-color-lighter); border-radius: 8px; background: var(--el-fill-color-blank); } .generate-form :deep(.el-form-item) { margin-bottom: 16px; } +.cutoff-date-controls { display: flex; align-items: center; width: 100%; gap: 8px; } +.cutoff-date-type { flex: 0 0 120px; } +.cutoff-date-picker { flex: 1 1 auto; min-width: 180px; } .order-identifier-input { position: relative; width: 100%; } .order-identifier-input :deep(.el-textarea__inner) { padding-right: 48px; } .order-identifier-clear { position: absolute; top: 4px; right: 6px; z-index: 1; padding: 2px 4px; }