✨ 新增应收账单日期类型筛选

This commit is contained in:
caojia
2026-10-30 15:22:50 +08:00
parent 7ef3f40a4f
commit 762cad2c0d
7 changed files with 117 additions and 27 deletions
@@ -24,6 +24,9 @@ public class ArBillGenerateQuery
@JsonDeserialize(using = StrictDateDeserializer.class) @JsonDeserialize(using = StrictDateDeserializer.class)
private Date billPeriodEnd; private Date billPeriodEnd;
/** 截止日筛选字段:BIZ_DATE=计费时间,PICKUP_DATE=收货时间;历史请求默认计费时间。 */
private String dateType = "BIZ_DATE";
private String currency; private String currency;
/** 订单号、运单号或转单号;支持换行、逗号、分号或空格分隔多个号码。 */ /** 订单号、运单号或转单号;支持换行、逗号、分号或空格分隔多个号码。 */
@@ -26,6 +26,8 @@ public class ArBillGenerateRequest
@JsonFormat(pattern = "yyyy-MM-dd") @JsonFormat(pattern = "yyyy-MM-dd")
@JsonDeserialize(using = StrictDateDeserializer.class) @JsonDeserialize(using = StrictDateDeserializer.class)
private Date billPeriodEnd; private Date billPeriodEnd;
/** 截止日筛选字段:BIZ_DATE=计费时间,PICKUP_DATE=收货时间;历史任务默认计费时间。 */
private String dateType = "BIZ_DATE";
/** 手动模式选中的来源订单 ID;全选模式为空。 */ /** 手动模式选中的来源订单 ID;全选模式为空。 */
private List<String> sourceBillIds; private List<String> sourceBillIds;
/** 选择模式:EXPLICIT 手动选择,ALL_MATCHED 全选查询结果。 */ /** 选择模式:EXPLICIT 手动选择,ALL_MATCHED 全选查询结果。 */
@@ -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;
}
}
@@ -55,6 +55,7 @@ import com.bms.ar.domain.ArExportTemplate;
import com.bms.ar.event.ArBillExportTaskEvent; import com.bms.ar.event.ArBillExportTaskEvent;
import com.bms.ar.event.ArBillGenerateTaskEvent; import com.bms.ar.event.ArBillGenerateTaskEvent;
import com.bms.ar.enums.ArBillGenerateTaskStatus; import com.bms.ar.enums.ArBillGenerateTaskStatus;
import com.bms.ar.enums.ArBillDateType;
import com.bms.ar.enums.ArBillGenerationStatus; import com.bms.ar.enums.ArBillGenerationStatus;
import com.bms.ar.enums.ArBillSelectionMode; import com.bms.ar.enums.ArBillSelectionMode;
import com.bms.ar.enums.ArBillStatus; import com.bms.ar.enums.ArBillStatus;
@@ -319,7 +320,7 @@ public class ArBillServiceImpl implements IArBillService {
List<String> excludeOrderIdentifiers = normalizeOrderIdentifiers(query.getExcludeOrderOrTrackingNo()); List<String> excludeOrderIdentifiers = normalizeOrderIdentifiers(query.getExcludeOrderOrTrackingNo());
List<PrcOrderBill> result = sourceBillMapper.selectPrcOrderBillByCustomerPeriod(query.getCustomerId(), List<PrcOrderBill> result = sourceBillMapper.selectPrcOrderBillByCustomerPeriod(query.getCustomerId(),
query.getCustomerCode(), orderIdentifiers, query.getCustomerCode(), orderIdentifiers,
excludeOrderIdentifiers, query.getBillPeriodEnd(), query.getCurrency(), excludeOrderIdentifiers, query.getBillPeriodEnd(), query.getDateType(), query.getCurrency(),
eligibleOrderBillStatuses(), ArIncomeBillFeeStatus.UNBILLED.getCode(), null); eligibleOrderBillStatuses(), ArIncomeBillFeeStatus.UNBILLED.getCode(), null);
log.debug("应收账单生成范围预览查询完成,customerId={}, billPeriodEnd={}, currency={}, resultCount={}, costMs={}", log.debug("应收账单生成范围预览查询完成,customerId={}, billPeriodEnd={}, currency={}, resultCount={}, costMs={}",
query.getCustomerId(), query.getBillPeriodEnd(), safeLogValue(query.getCurrency()), query.getCustomerId(), query.getBillPeriodEnd(), safeLogValue(query.getCurrency()),
@@ -349,7 +350,7 @@ public class ArBillServiceImpl implements IArBillService {
List<String> excludeOrderIdentifiers = normalizeOrderIdentifiers(query.getExcludeOrderOrTrackingNo()); List<String> excludeOrderIdentifiers = normalizeOrderIdentifiers(query.getExcludeOrderOrTrackingNo());
BigDecimal total = nvl(sourceBillMapper.sumPrcOrderBillIncomeByCustomerPeriod(query.getCustomerId(), BigDecimal total = nvl(sourceBillMapper.sumPrcOrderBillIncomeByCustomerPeriod(query.getCustomerId(),
query.getCustomerCode(), orderIdentifiers, query.getCustomerCode(), orderIdentifiers,
excludeOrderIdentifiers, query.getBillPeriodEnd(), query.getCurrency(), excludeOrderIdentifiers, query.getBillPeriodEnd(), query.getDateType(), query.getCurrency(),
eligibleOrderBillStatuses(), ArIncomeBillFeeStatus.UNBILLED.getCode())); eligibleOrderBillStatuses(), ArIncomeBillFeeStatus.UNBILLED.getCode()));
log.debug("应收账单生成范围金额汇总完成,customerId={}, billPeriodEnd={}, currency={}, costMs={}", log.debug("应收账单生成范围金额汇总完成,customerId={}, billPeriodEnd={}, currency={}, costMs={}",
query.getCustomerId(), query.getBillPeriodEnd(), safeLogValue(query.getCurrency()), query.getCustomerId(), query.getBillPeriodEnd(), safeLogValue(query.getCurrency()),
@@ -604,7 +605,7 @@ public class ArBillServiceImpl implements IArBillService {
int totalCount = sourceBillMapper.countPrcOrderBillByCustomerPeriod( int totalCount = sourceBillMapper.countPrcOrderBillByCustomerPeriod(
request.getCustomerId(), request.getCustomerCode(), request.getCustomerId(), request.getCustomerCode(),
normalizeOrderIdentifiers(request.getOrderOrTrackingNo()), normalizeOrderIdentifiers(request.getOrderOrTrackingNo()),
request.getBillPeriodEnd(), request.getCurrency(), eligibleOrderBillStatuses(), request.getBillPeriodEnd(), request.getDateType(), request.getCurrency(), eligibleOrderBillStatuses(),
ArIncomeBillFeeStatus.UNBILLED.getCode(), task.getSnapshotCreateTime(), null, ArIncomeBillFeeStatus.UNBILLED.getCode(), task.getSnapshotCreateTime(), null,
excludedSourceBillIds, excludedOrderIdentifiers); excludedSourceBillIds, excludedOrderIdentifiers);
if (totalCount <= 0) { if (totalCount <= 0) {
@@ -731,7 +732,8 @@ public class ArBillServiceImpl implements IArBillService {
List<PrcOrderBill> sources = sourceBillMapper.selectPrcOrderBillByCustomerPeriodCursor( List<PrcOrderBill> sources = sourceBillMapper.selectPrcOrderBillByCustomerPeriodCursor(
request.getCustomerId(), request.getCustomerCode(), request.getCustomerId(), request.getCustomerCode(),
normalizeOrderIdentifiers(request.getOrderOrTrackingNo()), 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(), eligibleOrderBillStatuses(), ArIncomeBillFeeStatus.UNBILLED.getCode(),
task.getSnapshotCreateTime(), task.getLastSourceBillId(), task.getSnapshotCreateTime(), task.getLastSourceBillId(),
explicitIds, selectionMode == ArBillSelectionMode.ALL_MATCHED ? excludedSourceBillIds : null, 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(); int processedCount = (task.getProcessedCount() == null ? 0 : task.getProcessedCount()) + sources.size();
BigDecimal totalAmount = nvl(task.getTotalAmount()).add(batchAmount); BigDecimal totalAmount = nvl(task.getTotalAmount()).add(batchAmount);
Date periodStart = earliestBizDate(sources); Date periodStart = earliestDate(sources, request.getDateType());
billMapper.updateArBillProgress(bill.getArBillId(), processedCount, totalAmount, totalAmount, billMapper.updateArBillProgress(bill.getArBillId(), processedCount, totalAmount, totalAmount,
periodStart, task.getCreateBy()); periodStart, task.getCreateBy());
String lastSourceBillId = sources.get(sources.size() - 1).getBillId(); 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) { if (StringUtils.isNotEmpty(request.getRemark()) && request.getRemark().trim().length() > 500) {
throw new ServiceException("备注不能超过500个字符"); throw new ServiceException("备注不能超过500个字符");
} }
request.setDateType(normalizeDateType(request.getDateType()));
// 生成任务会保存原始请求快照,先在入任务前校验号码数量,避免后台任务创建后才失败。 // 生成任务会保存原始请求快照,先在入任务前校验号码数量,避免后台任务创建后才失败。
normalizeOrderIdentifiers(request.getOrderOrTrackingNo()); normalizeOrderIdentifiers(request.getOrderOrTrackingNo());
} }
@@ -2190,6 +2193,7 @@ public class ArBillServiceImpl implements IArBillService {
|| query.getBillPeriodEnd() == null) { || query.getBillPeriodEnd() == null) {
throw new ServiceException("客户和账单截止日不能为空"); throw new ServiceException("客户和账单截止日不能为空");
} }
query.setDateType(normalizeDateType(query.getDateType()));
int identifierCount = normalizeOrderIdentifiers(query.getOrderOrTrackingNo()).size() int identifierCount = normalizeOrderIdentifiers(query.getOrderOrTrackingNo()).size()
+ normalizeOrderIdentifiers(query.getExcludeOrderOrTrackingNo()).size(); + normalizeOrderIdentifiers(query.getExcludeOrderOrTrackingNo()).size();
if (identifierCount > ORDER_IDENTIFIER_LIMIT) { if (identifierCount > ORDER_IDENTIFIER_LIMIT) {
@@ -2203,16 +2207,26 @@ public class ArBillServiceImpl implements IArBillService {
return Arrays.asList(ArOrderBillStatus.UNBILLED.getCode(), ArOrderBillStatus.PARTIAL.getCode()); return Arrays.asList(ArOrderBillStatus.UNBILLED.getCode(), ArOrderBillStatus.PARTIAL.getCode());
} }
private Date earliestBizDate(List<PrcOrderBill> sources) { private Date earliestDate(List<PrcOrderBill> sources, String dateType) {
boolean usePickupDate = ArBillDateType.PICKUP_DATE.getCode().equals(dateType);
Date earliest = null; Date earliest = null;
for (PrcOrderBill source : sources) { for (PrcOrderBill source : sources) {
if (source.getBizDate() != null && (earliest == null || source.getBizDate().before(earliest))) { Date sourceDate = usePickupDate ? source.getPickupDate() : source.getBizDate();
earliest = source.getBizDate(); if (sourceDate != null && (earliest == null || sourceDate.before(earliest))) {
earliest = sourceDate;
} }
} }
return earliest == null ? new Date() : earliest; 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<String> normalizeSourceBillIds(List<String> sourceBillIds) { private List<String> normalizeSourceBillIds(List<String> sourceBillIds) {
LinkedHashSet<String> uniqueIds = new LinkedHashSet<>(); LinkedHashSet<String> uniqueIds = new LinkedHashSet<>();
if (sourceBillIds != null) { if (sourceBillIds != null) {
@@ -63,7 +63,7 @@ public interface PrcOrderBillMapper
public List<PrcOrderBill> selectPrcOrderBillByCustomerPeriod(@Param("customerId") Long customerId, public List<PrcOrderBill> selectPrcOrderBillByCustomerPeriod(@Param("customerId") Long customerId,
@Param("customerCode") String customerCode, @Param("orderIdentifiers") List<String> orderIdentifiers, @Param("customerCode") String customerCode, @Param("orderIdentifiers") List<String> orderIdentifiers,
@Param("excludeOrderIdentifiers") List<String> excludeOrderIdentifiers, @Param("excludeOrderIdentifiers") List<String> excludeOrderIdentifiers,
@Param("cutoffDate") Date cutoffDate, @Param("currency") String currency, @Param("cutoffDate") Date cutoffDate, @Param("dateType") String dateType, @Param("currency") String currency,
@Param("arBillStatuses") List<String> arBillStatuses, @Param("feeArBillStatus") String feeArBillStatus, @Param("arBillStatuses") List<String> arBillStatuses, @Param("feeArBillStatus") String feeArBillStatus,
@Param("excludedBillIds") List<String> excludedBillIds); @Param("excludedBillIds") List<String> excludedBillIds);
@@ -71,13 +71,13 @@ public interface PrcOrderBillMapper
BigDecimal sumPrcOrderBillIncomeByCustomerPeriod(@Param("customerId") Long customerId, BigDecimal sumPrcOrderBillIncomeByCustomerPeriod(@Param("customerId") Long customerId,
@Param("customerCode") String customerCode, @Param("orderIdentifiers") List<String> orderIdentifiers, @Param("customerCode") String customerCode, @Param("orderIdentifiers") List<String> orderIdentifiers,
@Param("excludeOrderIdentifiers") List<String> excludeOrderIdentifiers, @Param("excludeOrderIdentifiers") List<String> excludeOrderIdentifiers,
@Param("cutoffDate") Date cutoffDate, @Param("currency") String currency, @Param("cutoffDate") Date cutoffDate, @Param("dateType") String dateType, @Param("currency") String currency,
@Param("arBillStatuses") List<String> arBillStatuses, @Param("feeArBillStatus") String feeArBillStatus); @Param("arBillStatuses") List<String> arBillStatuses, @Param("feeArBillStatus") String feeArBillStatus);
/** 异步生成账单按 bill_id 游标读取一批来源订单。 */ /** 异步生成账单按 bill_id 游标读取一批来源订单。 */
List<PrcOrderBill> selectPrcOrderBillByCustomerPeriodCursor(@Param("customerId") Long customerId, List<PrcOrderBill> selectPrcOrderBillByCustomerPeriodCursor(@Param("customerId") Long customerId,
@Param("customerCode") String customerCode, @Param("orderIdentifiers") List<String> orderIdentifiers, @Param("customerCode") String customerCode, @Param("orderIdentifiers") List<String> orderIdentifiers,
@Param("cutoffDate") Date cutoffDate, @Param("currency") String currency, @Param("cutoffDate") Date cutoffDate, @Param("dateType") String dateType, @Param("currency") String currency,
@Param("arBillStatuses") List<String> arBillStatuses, @Param("feeArBillStatus") String feeArBillStatus, @Param("arBillStatuses") List<String> arBillStatuses, @Param("feeArBillStatus") String feeArBillStatus,
@Param("snapshotCreateTime") Date snapshotCreateTime, @Param("snapshotCreateTime") Date snapshotCreateTime,
@Param("lastSourceBillId") String lastSourceBillId, @Param("billIds") List<String> billIds, @Param("lastSourceBillId") String lastSourceBillId, @Param("billIds") List<String> billIds,
@@ -86,7 +86,7 @@ public interface PrcOrderBillMapper
int countPrcOrderBillByCustomerPeriod(@Param("customerId") Long customerId, int countPrcOrderBillByCustomerPeriod(@Param("customerId") Long customerId,
@Param("customerCode") String customerCode, @Param("orderIdentifiers") List<String> orderIdentifiers, @Param("customerCode") String customerCode, @Param("orderIdentifiers") List<String> orderIdentifiers,
@Param("cutoffDate") Date cutoffDate, @Param("currency") String currency, @Param("cutoffDate") Date cutoffDate, @Param("dateType") String dateType, @Param("currency") String currency,
@Param("arBillStatuses") List<String> arBillStatuses, @Param("feeArBillStatus") String feeArBillStatus, @Param("arBillStatuses") List<String> arBillStatuses, @Param("feeArBillStatus") String feeArBillStatus,
@Param("snapshotCreateTime") Date snapshotCreateTime, @Param("snapshotCreateTime") Date snapshotCreateTime,
@Param("billIds") List<String> billIds, @Param("excludedBillIds") List<String> excludedBillIds, @Param("billIds") List<String> billIds, @Param("excludedBillIds") List<String> excludedBillIds,
@@ -95,7 +95,7 @@ public interface PrcOrderBillMapper
/** 按生成账单时用户勾选的订单读取,并再次校验账单筛选条件。 */ /** 按生成账单时用户勾选的订单读取,并再次校验账单筛选条件。 */
public List<PrcOrderBill> selectPrcOrderBillByCustomerCutoffAndIds(@Param("customerId") Long customerId, public List<PrcOrderBill> selectPrcOrderBillByCustomerCutoffAndIds(@Param("customerId") Long customerId,
@Param("customerCode") String customerCode, @Param("orderIdentifiers") List<String> orderIdentifiers, @Param("customerCode") String customerCode, @Param("orderIdentifiers") List<String> orderIdentifiers,
@Param("cutoffDate") Date cutoffDate, @Param("cutoffDate") Date cutoffDate, @Param("dateType") String dateType,
@Param("currency") String currency, @Param("billIds") List<String> billIds, @Param("currency") String currency, @Param("billIds") List<String> billIds,
@Param("arBillStatuses") List<String> arBillStatuses, @Param("feeArBillStatus") String feeArBillStatus); @Param("arBillStatuses") List<String> arBillStatuses, @Param("feeArBillStatus") String feeArBillStatus);
@@ -639,6 +639,18 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
) )
</sql> </sql>
<!-- 截止日按用户选择的日期类型筛选;字段名固定在 SQL 中,避免动态列名注入。 -->
<sql id="arBillCutoffDateCondition">
<choose>
<when test="dateType != null and dateType == 'PICKUP_DATE'">
and p.pickup_date &lt; DATE_ADD(#{cutoffDate}, INTERVAL 1 DAY)
</when>
<otherwise>
and p.biz_date &lt; DATE_ADD(#{cutoffDate}, INTERVAL 1 DAY)
</otherwise>
</choose>
</sql>
<select id="selectPrcOrderBillByCustomerPeriod" resultMap="PrcOrderBillArSourceResult"> <select id="selectPrcOrderBillByCustomerPeriod" resultMap="PrcOrderBillArSourceResult">
<include refid="selectArBillSourceVo"/> <include refid="selectArBillSourceVo"/>
where p.customer_id = #{customerId} where p.customer_id = #{customerId}
@@ -661,7 +673,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</foreach> </foreach>
) )
</if> </if>
and p.biz_date &lt; DATE_ADD(#{cutoffDate}, INTERVAL 1 DAY) <include refid="arBillCutoffDateCondition"/>
and p.ar_bill_status in and p.ar_bill_status in
<foreach collection="arBillStatuses" item="status" open="(" separator="," close=")"> <foreach collection="arBillStatuses" item="status" open="(" separator="," close=")">
#{status} #{status}
@@ -676,7 +688,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
#{excludedBillId} #{excludedBillId}
</foreach> </foreach>
</if> </if>
order by p.biz_date, p.order_no, p.bill_id <choose>
<when test="dateType != null and dateType == 'PICKUP_DATE'">
order by p.pickup_date, p.order_no, p.bill_id
</when>
<otherwise>
order by p.biz_date, p.order_no, p.bill_id
</otherwise>
</choose>
</select> </select>
<select id="sumPrcOrderBillIncomeByCustomerPeriod" resultType="java.math.BigDecimal"> <select id="sumPrcOrderBillIncomeByCustomerPeriod" resultType="java.math.BigDecimal">
@@ -704,7 +723,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</foreach> </foreach>
) )
</if> </if>
and p.biz_date &lt; DATE_ADD(#{cutoffDate}, INTERVAL 1 DAY) <include refid="arBillCutoffDateCondition"/>
and p.ar_bill_status in and p.ar_bill_status in
<foreach collection="arBillStatuses" item="status" open="(" separator="," close=")"> <foreach collection="arBillStatuses" item="status" open="(" separator="," close=")">
#{status} #{status}
@@ -720,7 +739,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
and p.customer_code like concat('%', #{customerCode}, '%') and p.customer_code like concat('%', #{customerCode}, '%')
</if> </if>
<include refid="orderIdentifierCondition"/> <include refid="orderIdentifierCondition"/>
and p.biz_date &lt; DATE_ADD(#{cutoffDate}, INTERVAL 1 DAY) <include refid="arBillCutoffDateCondition"/>
and p.ar_bill_status in and p.ar_bill_status in
<foreach collection="arBillStatuses" item="status" open="(" separator="," close=")"> <foreach collection="arBillStatuses" item="status" open="(" separator="," close=")">
#{status} #{status}
@@ -783,7 +802,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<select id="selectPrcOrderBillByCustomerCutoffAndIds" resultMap="PrcOrderBillArSourceResult"> <select id="selectPrcOrderBillByCustomerCutoffAndIds" resultMap="PrcOrderBillArSourceResult">
<include refid="selectArBillSourceVo"/> <include refid="selectArBillSourceVo"/>
where p.customer_id = #{customerId} where p.customer_id = #{customerId}
and p.biz_date &lt; DATE_ADD(#{cutoffDate}, INTERVAL 1 DAY) <include refid="arBillCutoffDateCondition"/>
and p.ar_bill_status in and p.ar_bill_status in
<foreach collection="arBillStatuses" item="status" open="(" separator="," close=")"> <foreach collection="arBillStatuses" item="status" open="(" separator="," close=")">
#{status} #{status}
@@ -800,7 +819,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="currency != null and currency != ''"> <if test="currency != null and currency != ''">
and p.currency = #{currency} and p.currency = #{currency}
</if> </if>
order by p.biz_date, p.order_no, p.bill_id <choose>
<when test="dateType != null and dateType == 'PICKUP_DATE'">
order by p.pickup_date, p.order_no, p.bill_id
</when>
<otherwise>
order by p.biz_date, p.order_no, p.bill_id
</otherwise>
</choose>
</select> </select>
<insert id="insertPrcOrderBill" parameterType="PrcOrderBill"> <insert id="insertPrcOrderBill" parameterType="PrcOrderBill">
@@ -3,10 +3,10 @@
<el-dialog v-model="dialogOpen" class="generate-dialog" title="生成应收账单" width="1200px" append-to-body destroy-on-close> <el-dialog v-model="dialogOpen" class="generate-dialog" title="生成应收账单" width="1200px" append-to-body destroy-on-close>
<el-form ref="generateFormRef" :model="generateForm" :rules="generateRules" label-width="110px" class="generate-form"> <el-form ref="generateFormRef" :model="generateForm" :rules="generateRules" label-width="110px" class="generate-form">
<el-row :gutter="16"> <el-row :gutter="16">
<el-col :span="8"><el-form-item label="客户" prop="customerId"><customer-select :fetch-options="listArBillGenerateCustomerOptions" v-model="generateForm.customerId" placeholder="请输入客户名称或代码搜索" :remote-search="true" :page-size="20" @change="handleCustomerChange" /></el-form-item></el-col> <el-col :span="6"><el-form-item label="客户" prop="customerId"><customer-select :fetch-options="listArBillGenerateCustomerOptions" v-model="generateForm.customerId" placeholder="请输入客户名称或代码搜索" :remote-search="true" :page-size="20" @change="handleCustomerChange" /></el-form-item></el-col>
<el-col :span="8"><el-form-item label="币种" prop="currency"><el-select v-model="generateForm.currency" placeholder="请选择币种" style="width: 100%;" @change="handleCurrencyChange"><el-option label="人民币 CNY" value="CNY" /><el-option label="美元 USD" value="USD" /></el-select></el-form-item></el-col> <el-col :span="7"><el-form-item label="币种" prop="currency"><el-select v-model="generateForm.currency" placeholder="请选择币种" style="width: 100%;" @change="handleCurrencyChange"><el-option label="人民币 CNY" value="CNY" /><el-option label="美元 USD" value="USD" /></el-select></el-form-item></el-col>
<el-col :span="8"><el-form-item label="账单截止日" prop="cutoffDate"><el-date-picker v-model="generateForm.cutoffDate" type="date" value-format="YYYY-MM-DD" placeholder="请选择账单截止日" style="width: 100%;" @change="resetPreview" /></el-form-item></el-col> <el-col :span="11"><el-form-item label="账单截止日" prop="cutoffDate"><div class="cutoff-date-controls"><el-select v-model="generateForm.dateType" class="cutoff-date-type" @change="resetPreview"><el-option label="计费时间" value="BIZ_DATE" /><el-option label="收货时间" value="PICKUP_DATE" /></el-select><el-date-picker v-model="generateForm.cutoffDate" class="cutoff-date-picker" type="date" value-format="YYYY-MM-DD" placeholder="请选择账单截止日" @change="resetPreview" /></div></el-form-item></el-col>
<el-col :span="8"> <el-col :span="9">
<el-form-item label="单号"> <el-form-item label="单号">
<div class="order-identifier-input"> <div class="order-identifier-input">
<el-input v-model="generateForm.orderOrTrackingNo" type="textarea" :rows="4" resize="vertical" placeholder="请输入订单号、运单号或转单号" clearable /> <el-input v-model="generateForm.orderOrTrackingNo" type="textarea" :rows="4" resize="vertical" placeholder="请输入订单号、运单号或转单号" clearable />
@@ -69,7 +69,7 @@
<el-table-column prop="trackingNo" label="运单号" min-width="140" show-overflow-tooltip /> <el-table-column prop="trackingNo" label="运单号" min-width="140" show-overflow-tooltip />
<el-table-column prop="transferNo" label="转单号" min-width="240" show-overflow-tooltip /> <el-table-column prop="transferNo" label="转单号" min-width="240" show-overflow-tooltip />
<el-table-column prop="customerName" label="客户" min-width="130" show-overflow-tooltip /> <el-table-column prop="customerName" label="客户" min-width="130" show-overflow-tooltip />
<el-table-column prop="bizDate" label="业务日期" width="170" :formatter="formatDateColumn" /> <el-table-column :prop="dateColumnProp" :label="dateColumnLabel" width="170" :formatter="formatDateColumn" />
<el-table-column prop="productName" label="产品" min-width="140" show-overflow-tooltip /> <el-table-column prop="productName" label="产品" min-width="140" show-overflow-tooltip />
<el-table-column prop="countryName" label="国家/地区" min-width="110" show-overflow-tooltip /> <el-table-column prop="countryName" label="国家/地区" min-width="110" show-overflow-tooltip />
<el-table-column prop="actualWeight" label="实际重(kg)" width="105" align="right" :formatter="formatNumberColumn" /> <el-table-column prop="actualWeight" label="实际重(kg)" width="105" align="right" :formatter="formatNumberColumn" />
@@ -109,7 +109,7 @@
<el-table-column prop="trackingNo" label="运单号" min-width="180" show-overflow-tooltip /> <el-table-column prop="trackingNo" label="运单号" min-width="180" show-overflow-tooltip />
<el-table-column prop="transferNo" label="转单号" min-width="180" show-overflow-tooltip /> <el-table-column prop="transferNo" label="转单号" min-width="180" show-overflow-tooltip />
<el-table-column prop="customerName" label="客户" min-width="150" show-overflow-tooltip /> <el-table-column prop="customerName" label="客户" min-width="150" show-overflow-tooltip />
<el-table-column prop="bizDate" label="业务日期" width="170" :formatter="formatDateColumn" /> <el-table-column :prop="dateColumnProp" :label="dateColumnLabel" width="170" :formatter="formatDateColumn" />
<el-table-column prop="incomeTotal" label="应收金额" width="130" align="right" :formatter="formatNumberColumn" /> <el-table-column prop="incomeTotal" label="应收金额" width="130" align="right" :formatter="formatNumberColumn" />
<el-table-column prop="currency" label="币种" width="80" /> <el-table-column prop="currency" label="币种" width="80" />
</el-table> </el-table>
@@ -200,7 +200,7 @@ const bankAccount = ref(null)
const generateRequestId = ref('') const generateRequestId = ref('')
const generateFormRef = ref() const generateFormRef = ref()
const billNameFormRef = 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 billNameForm = reactive({ billName: '' })
const generateRules = { const generateRules = {
customerId: [{ required: true, message: '客户不能为空', trigger: 'change' }], customerId: [{ required: true, message: '客户不能为空', trigger: 'change' }],
@@ -209,6 +209,8 @@ const generateRules = {
} }
const billNameRules = { billName: [{ required: true, message: '请输入账单名称', trigger: 'blur' }] } const billNameRules = { billName: [{ required: true, message: '请输入账单名称', trigger: 'blur' }] }
const selectedAmount = computed(() => selectedRows.value.reduce((sum, row) => sum + (Number(row.incomeTotal) || 0), 0)) 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 allSelected = computed(() => selectionMode.value === AR_BILL_SELECTION_MODE.ALL_MATCHED)
const displaySelectedCount = 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) ? Math.max(previewTotal.value - confirmedExcludeCount.value, 0) : selectedRows.value.length)
@@ -223,7 +225,7 @@ watch(() => props.modelValue, visible => {
// 每次打开生成弹窗都重新建立一次查询快照,避免复用上一次的选中订单。 // 每次打开生成弹窗都重新建立一次查询快照,避免复用上一次的选中订单。
function openGenerate() { 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: '' }) Object.assign(billNameForm, { billName: '' })
billNameOpen.value = false billNameOpen.value = false
resetPreview() resetPreview()
@@ -288,6 +290,7 @@ function buildGenerateQuery() {
customerCode: generateForm.customerCode?.trim() || undefined, customerCode: generateForm.customerCode?.trim() || undefined,
customerName: generateForm.customerName?.trim() || undefined, customerName: generateForm.customerName?.trim() || undefined,
billPeriodEnd: generateForm.cutoffDate, billPeriodEnd: generateForm.cutoffDate,
dateType: generateForm.dateType || 'BIZ_DATE',
currency: generateForm.currency || undefined, currency: generateForm.currency || undefined,
orderOrTrackingNo: generateForm.orderOrTrackingNo?.trim() || 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-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 { 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; } .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 { position: relative; width: 100%; }
.order-identifier-input :deep(.el-textarea__inner) { padding-right: 48px; } .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; } .order-identifier-clear { position: absolute; top: 4px; right: 6px; z-index: 1; padding: 2px 4px; }