Implement batch fee management features in BillingController, including preview, submission, and task retrieval. Update related services and mappers to support batch processing. Add necessary error messages in properties file and enhance front-end API for batch operations.

This commit is contained in:
wuweihua
2026-10-09 10:28:29 +08:00
parent 95df65b4f6
commit 5b4cbaffd6
15 changed files with 1014 additions and 23 deletions
@@ -1,7 +1,9 @@
package com.bms.web.controller.price;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
@@ -20,10 +22,13 @@ import com.bms.common.core.domain.AjaxResult;
import com.bms.common.core.page.TableDataInfo;
import com.bms.common.enums.BusinessType;
import com.bms.common.utils.DateUtils;
import com.bms.common.utils.MessageUtils;
import com.bms.common.utils.StringUtils;
import com.bms.price.domain.BatchAddIncomeBillFeeTask;
import com.bms.price.domain.PrcOrderBill;
import com.bms.price.domain.PrcQuote;
import com.bms.price.domain.vo.AddIncomeBillFeeRequest;
import com.bms.price.domain.vo.BatchAddIncomeBillFeeRequest;
import com.bms.price.domain.vo.UpdateIncomeBillFeeRequest;
import com.bms.price.domain.vo.TmsPriceBillRequest;
import com.bms.price.domain.vo.TmsPriceQuoteRequest;
@@ -207,6 +212,38 @@ public class BillingController extends BaseController
return success(prcOrderBillService.addIncomeFee(request));
}
/** Preview matched bills for batch add fee (filter: customer / transferNo / country). */
@PreAuthorize("@ss.hasPermi('price:billing:feeAdd')")
@PostMapping("/bill/fee/batch/preview")
public AjaxResult previewBatchAddIncomeFee(@RequestBody BatchAddIncomeBillFeeRequest request)
{
return success(prcOrderBillService.previewBatchAddIncomeFee(request));
}
/** Submit async batch add fee; poll /bill/fee/batch/task/{taskId}. */
@PreAuthorize("@ss.hasPermi('price:billing:feeAdd')")
@Log(title = "Billing batch income fee", businessType = BusinessType.INSERT)
@PostMapping("/bill/fee/batch")
public AjaxResult submitBatchAddIncomeFee(@Validated @RequestBody BatchAddIncomeBillFeeRequest request)
{
String taskId = prcOrderBillService.submitBatchAddIncomeFee(request);
Map<String, Object> payload = new HashMap<String, Object>();
payload.put("taskId", taskId);
return success(payload);
}
@PreAuthorize("@ss.hasPermi('price:billing:feeAdd')")
@GetMapping("/bill/fee/batch/task/{taskId}")
public AjaxResult getBatchAddIncomeFeeTask(@PathVariable String taskId)
{
BatchAddIncomeBillFeeTask task = prcOrderBillService.getBatchAddIncomeFeeTask(taskId);
if (task == null)
{
return error(MessageUtils.message("price.bill.fee.batch.taskNotExists"));
}
return success(task);
}
@PreAuthorize("@ss.hasPermi('price:billing:feeEdit')")
@Log(title = "Billing income fee", businessType = BusinessType.UPDATE)
@PutMapping("/bill/fee")
@@ -175,6 +175,12 @@ price.bill.packageZonePriceNotHit=已匹配分区,但套餐版本无该分区/
price.bill.packagePriceNotHit=套餐版本无匹配的国家/重量段价格
price.bill.productNotInPackage=产品不在客户套餐版本中,无法计费
price.bill.fee.scIdRequired=附加费不能为空
price.bill.fee.batch.taskNotExists=批量增加费用任务不存在或已过期
price.bill.fee.batch.tooMany=匹配订单超过上限 {0} 条,请缩小筛选范围
price.bill.fee.batch.noMatch=未查询到匹配的计费订单,无法批量增加费用
price.bill.fee.batch.filterRequired=请先在计费列表设置查询条件
price.bill.fee.batch.selectedRequired=请勾选要增加费用的订单
price.bill.fee.batch.scopeRequired=请选择添加范围
price.bill.fee.surchargeNotFound=附加费配置不存在或已停用
price.bill.fee.notFound=费用明细不存在
price.bill.fee.notManual=仅手动增加的费用可编辑或删除
@@ -0,0 +1,103 @@
package com.bms.price.domain;
import java.io.Serializable;
/** Async batch add income fee progress (Redis). */
public class BatchAddIncomeBillFeeTask implements Serializable
{
private static final long serialVersionUID = 1L;
public static final String STATUS_PENDING = "PENDING";
public static final String STATUS_RUNNING = "RUNNING";
public static final String STATUS_SUCCESS = "SUCCESS";
public static final String STATUS_FAIL = "FAIL";
private String taskId;
private String status;
private int percent;
private String message;
private String error;
private int total;
private int success;
private int fail;
public String getTaskId()
{
return taskId;
}
public void setTaskId(String taskId)
{
this.taskId = taskId;
}
public String getStatus()
{
return status;
}
public void setStatus(String status)
{
this.status = status;
}
public int getPercent()
{
return percent;
}
public void setPercent(int percent)
{
this.percent = percent;
}
public String getMessage()
{
return message;
}
public void setMessage(String message)
{
this.message = message;
}
public String getError()
{
return error;
}
public void setError(String error)
{
this.error = error;
}
public int getTotal()
{
return total;
}
public void setTotal(int total)
{
this.total = total;
}
public int getSuccess()
{
return success;
}
public void setSuccess(int success)
{
this.success = success;
}
public int getFail()
{
return fail;
}
public void setFail(int fail)
{
this.fail = fail;
}
}
@@ -16,6 +16,8 @@ public class PrcOrderBill extends BaseEntity
private static final long serialVersionUID = 1L;
private String billId;
/** 批量查询:多个账单ID精确匹配(仅查询用,非表字段) */
private List<String> billIds;
private String billKey;
private String orderNo;
/** 批量查询:多个订单号精确匹配(仅查询用,非表字段) */
@@ -0,0 +1,18 @@
package com.bms.price.domain.vo;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import com.bms.price.domain.PrcOrderBill;
import lombok.Data;
/** Preview matched bills before async batch add fee. */
@Data
public class BatchAddIncomeBillFeePreview implements Serializable
{
private static final long serialVersionUID = 1L;
private int matchCount;
/** First N rows for UI preview. */
private List<PrcOrderBill> samples = new ArrayList<PrcOrderBill>();
}
@@ -0,0 +1,50 @@
package com.bms.price.domain.vo;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.List;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
/**
* Batch add receivable fee lines.
* scopeMode=SELECTED uses billIds; scopeMode=ALL uses list query filters.
*/
@Data
public class BatchAddIncomeBillFeeRequest implements Serializable
{
private static final long serialVersionUID = 1L;
/** ALL = list filters; SELECTED = billIds only. */
private String scopeMode;
/** Selected bill ids when scopeMode=SELECTED. */
private List<String> billIds;
/** Same filters as billing list search. */
private List<String> orderNos;
private List<String> trackingNos;
private List<String> transferNos;
private List<String> customerCodes;
private List<String> productCodes;
private String countryCode;
private String creditArrearsStatus;
/** Surcharge config id (prc_surcharge.sc_id). */
@NotNull(message = "scId required")
private Long scId;
/** Dict bms_fee_type; empty = use surcharge.feeType. */
private String feeType;
/**
* Fixed amount for every matched bill.
* Empty = calculate per bill from surcharge chargeType / weight / freight.
*/
private BigDecimal amount;
/** Default CNY. */
private String currency;
private String remark;
}
@@ -17,6 +17,10 @@ public interface PrcIncomeBillFeeMapper
public PrcIncomeBillFee selectByFeeId(String feeId);
/** Lookup by unique key uk_bill_fee_item (bill_id, fee_type, sc_id). */
public PrcIncomeBillFee selectByBillIdAndFeeTypeAndScId(@Param("billId") String billId,
@Param("feeType") String feeType, @Param("scId") Long scId);
/** Count fees of a bill under given ar_bill_status and fee_type (e.g. BILLED + BASIC_FREIGHT). */
public int countByBillIdAndArBillStatusAndFeeType(@Param("billId") String billId,
@Param("arBillStatus") String arBillStatus, @Param("feeType") String feeType);
@@ -3,7 +3,10 @@ package com.bms.price.service;
import java.math.BigDecimal;
import java.util.List;
import com.bms.price.domain.PrcOrderBill;
import com.bms.price.domain.BatchAddIncomeBillFeeTask;
import com.bms.price.domain.vo.AddIncomeBillFeeRequest;
import com.bms.price.domain.vo.BatchAddIncomeBillFeePreview;
import com.bms.price.domain.vo.BatchAddIncomeBillFeeRequest;
import com.bms.price.domain.vo.UpdateIncomeBillFeeRequest;
import com.bms.price.domain.vo.TmsPriceBillRequest;
import com.bms.price.domain.vo.TmsPriceQuoteResult;
@@ -45,6 +48,15 @@ public interface IPrcOrderBillService
/** Delete manual UNBILLED income fee; refresh receivable totals. */
TmsPriceQuoteResult deleteIncomeFee(String feeId);
/** Preview matched bills for batch add fee (data-scoped). */
BatchAddIncomeBillFeePreview previewBatchAddIncomeFee(BatchAddIncomeBillFeeRequest request);
/** Submit async batch add fee; returns taskId. */
String submitBatchAddIncomeFee(BatchAddIncomeBillFeeRequest request);
/** Poll Redis progress for batch add fee task. */
BatchAddIncomeBillFeeTask getBatchAddIncomeFeeTask(String taskId);
/** 提供给 TMS 判断订单是否可以继续处理的客户状态查询。 */
TmsOrderBillStatusResult queryTmsOrderBillStatus(String identifier);
@@ -30,6 +30,7 @@ import com.bms.common.utils.MessageUtils;
import com.bms.common.utils.SecurityUtils;
import com.bms.common.utils.StringUtils;
import com.bms.common.utils.sign.Md5Utils;
import com.bms.common.utils.uuid.IdUtils;
import com.bms.customer.customerinfo.domain.BmsCustomer;
import com.bms.customer.customerinfo.mapper.BmsCustomerMapper;
import com.bms.system.mapper.SysUserMapper;
@@ -40,8 +41,12 @@ import com.bms.price.domain.PrcOrderBillExt;
import com.bms.price.domain.PrcPayBill;
import com.bms.price.domain.PrcPayBillFee;
import com.bms.price.domain.PrcSurcharge;
import com.bms.price.domain.BatchAddIncomeBillFeeTask;
import com.bms.price.domain.vo.AddIncomeBillFeeRequest;
import com.bms.price.domain.vo.BatchAddIncomeBillFeePreview;
import com.bms.price.domain.vo.BatchAddIncomeBillFeeRequest;
import com.bms.price.domain.vo.UpdateIncomeBillFeeRequest;
import com.bms.price.task.PrcBatchAddIncomeFeeAsyncRunner;
import com.bms.price.domain.vo.TmsPriceBillRequest;
import com.bms.price.domain.vo.TmsOrderBillStatusResult;
import com.bms.price.domain.vo.TmsPriceQuoteFeeLine;
@@ -118,6 +123,12 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService
@Autowired
private PrcCreditArrearsClearAsyncRunner creditArrearsClearAsyncRunner;
@Autowired
private PrcBatchAddIncomeFeeAsyncRunner batchAddIncomeFeeAsyncRunner;
private static final int BATCH_ADD_FEE_MAX = 5000;
private static final int BATCH_ADD_FEE_PREVIEW_LIMIT = 20;
@Override
@Transactional(rollbackFor = Exception.class)
public TmsPriceQuoteResult bill(TmsPriceBillRequest request)
@@ -387,20 +398,48 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService
amount = BigDecimal.ZERO;
}
PrcIncomeBillFee fee = new PrcIncomeBillFee();
fee.setFeeId(UUID.randomUUID().toString());
fee.setBillId(bill.getBillId());
fee.setIncomeBillId(incomeBill == null ? null : incomeBill.getIncomeBillId());
fee.setFeeType(feeType);
fee.setFeeName(surcharge.getScName());
fee.setScId(surcharge.getScId());
fee.setAmount(amount);
fee.setCurrency(currency);
fee.setRoundMode(StringUtils.isEmpty(surcharge.getRoundMode()) ? bill.getRoundMode() : surcharge.getRoundMode());
fee.setRemark(request.getRemark());
fee.setArBillStatus(ArIncomeBillFeeStatus.UNBILLED.getCode());
fee.setManualFlag("1");
incomeBillFeeMapper.insertPrcIncomeBillFee(fee);
// uk_bill_fee_item (bill_id, fee_type, sc_id): overwrite when exists
PrcIncomeBillFee existing = incomeBillFeeMapper.selectByBillIdAndFeeTypeAndScId(
bill.getBillId(), feeType, surcharge.getScId());
if (existing != null)
{
if (ArIncomeBillFeeStatus.BILLED.getCode().equals(existing.getArBillStatus()))
{
throw new ServiceException(MessageUtils.message("price.bill.fee.alreadyBilled"));
}
existing.setFeeType(feeType);
existing.setFeeName(surcharge.getScName());
existing.setScId(surcharge.getScId());
existing.setAmount(amount);
existing.setCurrency(currency);
existing.setRoundMode(StringUtils.isEmpty(surcharge.getRoundMode()) ? bill.getRoundMode()
: surcharge.getRoundMode());
existing.setRemark(request.getRemark());
existing.setManualFlag("1");
if (incomeBill != null && StringUtils.isEmpty(existing.getIncomeBillId()))
{
existing.setIncomeBillId(incomeBill.getIncomeBillId());
}
incomeBillFeeMapper.updatePrcIncomeBillFee(existing);
}
else
{
PrcIncomeBillFee fee = new PrcIncomeBillFee();
fee.setFeeId(UUID.randomUUID().toString());
fee.setBillId(bill.getBillId());
fee.setIncomeBillId(incomeBill == null ? null : incomeBill.getIncomeBillId());
fee.setFeeType(feeType);
fee.setFeeName(surcharge.getScName());
fee.setScId(surcharge.getScId());
fee.setAmount(amount);
fee.setCurrency(currency);
fee.setRoundMode(StringUtils.isEmpty(surcharge.getRoundMode()) ? bill.getRoundMode()
: surcharge.getRoundMode());
fee.setRemark(request.getRemark());
fee.setArBillStatus(ArIncomeBillFeeStatus.UNBILLED.getCode());
fee.setManualFlag("1");
incomeBillFeeMapper.insertPrcIncomeBillFee(fee);
}
return refreshBillIncomeTotals(bill);
}
@@ -472,6 +511,125 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService
return refreshBillIncomeTotals(bill);
}
@Override
public BatchAddIncomeBillFeePreview previewBatchAddIncomeFee(BatchAddIncomeBillFeeRequest request)
{
List<PrcOrderBill> bills = resolveBatchAddFeeBills(request);
BatchAddIncomeBillFeePreview preview = new BatchAddIncomeBillFeePreview();
preview.setMatchCount(bills.size());
int limit = Math.min(bills.size(), BATCH_ADD_FEE_PREVIEW_LIMIT);
preview.setSamples(bills.subList(0, limit));
return preview;
}
@Override
public String submitBatchAddIncomeFee(BatchAddIncomeBillFeeRequest request)
{
if (request == null || request.getScId() == null)
{
throw new ServiceException(MessageUtils.message("price.bill.fee.scIdRequired"));
}
requireActiveSurcharge(request.getScId());
List<PrcOrderBill> bills = resolveBatchAddFeeBills(request);
if (bills.isEmpty())
{
throw new ServiceException(MessageUtils.message("price.bill.fee.batch.noMatch"));
}
if (bills.size() > BATCH_ADD_FEE_MAX)
{
throw new ServiceException(MessageUtils.message("price.bill.fee.batch.tooMany",
Integer.valueOf(BATCH_ADD_FEE_MAX)));
}
List<String> billIds = new ArrayList<String>();
for (PrcOrderBill bill : bills)
{
if (bill != null && StringUtils.isNotEmpty(bill.getBillId()))
{
billIds.add(bill.getBillId());
}
}
if (billIds.isEmpty())
{
throw new ServiceException(MessageUtils.message("price.bill.fee.batch.noMatch"));
}
String taskId = IdUtils.fastSimpleUUID();
batchAddIncomeFeeAsyncRunner.put(taskId, BatchAddIncomeBillFeeTask.STATUS_PENDING, 0, "queued", null,
billIds.size(), 0, 0);
batchAddIncomeFeeAsyncRunner.run(taskId, billIds, request.getScId(), request.getFeeType(),
request.getAmount(), request.getCurrency(), request.getRemark());
return taskId;
}
@Override
public BatchAddIncomeBillFeeTask getBatchAddIncomeFeeTask(String taskId)
{
if (StringUtils.isEmpty(taskId) || batchAddIncomeFeeAsyncRunner == null)
{
return null;
}
return batchAddIncomeFeeAsyncRunner.get(taskId);
}
/**
* Resolve matched bills with data scope.
* scopeMode required: SELECTED uses billIds; ALL uses list filters (at least one required).
*/
private List<PrcOrderBill> resolveBatchAddFeeBills(BatchAddIncomeBillFeeRequest request)
{
if (request == null)
{
throw new ServiceException(MessageUtils.message("price.bill.fee.batch.filterRequired"));
}
String scopeMode = StringUtils.nvl(request.getScopeMode(), "").trim().toUpperCase();
if (!"ALL".equals(scopeMode) && !"SELECTED".equals(scopeMode))
{
throw new ServiceException(MessageUtils.message("price.bill.fee.batch.scopeRequired"));
}
List<String> orderNos = normalizeCodeList(request.getOrderNos());
List<String> trackingNos = normalizeCodeList(request.getTrackingNos());
List<String> transferNos = normalizeCodeList(request.getTransferNos());
List<String> customerCodes = normalizeCodeList(request.getCustomerCodes());
List<String> productCodes = normalizeCodeList(request.getProductCodes());
String creditArrearsStatus = StringUtils.isEmpty(request.getCreditArrearsStatus()) ? null
: request.getCreditArrearsStatus().trim();
String countryCode = StringUtils.isEmpty(request.getCountryCode()) ? null
: request.getCountryCode().trim().toUpperCase();
boolean hasFilter = (orderNos != null && !orderNos.isEmpty())
|| (trackingNos != null && !trackingNos.isEmpty())
|| (transferNos != null && !transferNos.isEmpty())
|| (customerCodes != null && !customerCodes.isEmpty())
|| (productCodes != null && !productCodes.isEmpty())
|| StringUtils.isNotEmpty(creditArrearsStatus)
|| StringUtils.isNotEmpty(countryCode);
if (!hasFilter)
{
throw new ServiceException(MessageUtils.message("price.bill.fee.batch.filterRequired"));
}
PrcOrderBill query = new PrcOrderBill();
if ("SELECTED".equals(scopeMode))
{
List<String> billIds = normalizeCodeList(request.getBillIds());
if (billIds == null || billIds.isEmpty())
{
throw new ServiceException(MessageUtils.message("price.bill.fee.batch.selectedRequired"));
}
query.setBillIds(billIds);
}
else
{
query.setOrderNos(orderNos);
query.setTrackingNos(trackingNos);
query.setTransferNos(transferNos);
query.setCustomerCodes(customerCodes);
query.setProductCodes(productCodes);
query.setCreditArrearsStatus(creditArrearsStatus);
query.setCountryCode(countryCode);
}
// Use self proxy so @DataScope applies
List<PrcOrderBill> list = self.selectBillList(query);
return list == null ? new ArrayList<PrcOrderBill>() : list;
}
private PrcSurcharge requireActiveSurcharge(Long scId)
{
PrcSurcharge surcharge = surchargeService.selectPrcSurchargeById(scId);
@@ -0,0 +1,137 @@
package com.bms.price.task;
import java.math.BigDecimal;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import com.bms.common.core.redis.RedisCache;
import com.bms.common.utils.StringUtils;
import com.bms.price.domain.BatchAddIncomeBillFeeTask;
import com.bms.price.domain.vo.AddIncomeBillFeeRequest;
import com.bms.price.service.IPrcOrderBillService;
/**
* Async runner: add the same manual income fee to many order bills.
*/
@Component
public class PrcBatchAddIncomeFeeAsyncRunner
{
private static final Logger log = LoggerFactory.getLogger(PrcBatchAddIncomeFeeAsyncRunner.class);
public static final String CACHE_KEY_PREFIX = "price:billing:fee:batch:task:";
public static final int TTL_MINUTES = 60;
@Autowired
@Lazy
private IPrcOrderBillService orderBillService;
@Autowired
private RedisCache redisCache;
@Async("threadPoolTaskExecutor")
public void run(String taskId, List<String> billIds, Long scId, String feeType, BigDecimal amount,
String currency, String remark)
{
int total = billIds == null ? 0 : billIds.size();
int success = 0;
int fail = 0;
StringBuilder failTips = new StringBuilder();
try
{
put(taskId, BatchAddIncomeBillFeeTask.STATUS_RUNNING, 1, "running", null, total, 0, 0);
if (total == 0)
{
put(taskId, BatchAddIncomeBillFeeTask.STATUS_FAIL, 100, "failed", "no bills", 0, 0, 0);
return;
}
for (int i = 0; i < total; i++)
{
String billId = billIds.get(i);
try
{
AddIncomeBillFeeRequest req = new AddIncomeBillFeeRequest();
req.setBillId(billId);
req.setScId(scId);
req.setFeeType(feeType);
req.setAmount(amount);
req.setCurrency(currency);
req.setRemark(remark);
orderBillService.addIncomeFee(req);
success++;
}
catch (Exception e)
{
fail++;
if (failTips.length() < 800)
{
String tip = e.getMessage();
if (StringUtils.isEmpty(tip))
{
tip = e.getClass().getSimpleName();
}
if (failTips.length() > 0)
{
failTips.append("; ");
}
failTips.append(billId).append(":").append(tip);
}
log.warn("batch add fee failed taskId={} billId={}", taskId, billId, e);
}
int percent = Math.min(99, (int) Math.floor(100.0 * (i + 1) / total));
put(taskId, BatchAddIncomeBillFeeTask.STATUS_RUNNING, percent,
"processing " + (i + 1) + "/" + total, null, total, success, fail);
}
String msg = "success=" + success + ", fail=" + fail;
if (fail > 0 && failTips.length() > 0)
{
put(taskId, BatchAddIncomeBillFeeTask.STATUS_SUCCESS, 100, msg, failTips.toString(),
total, success, fail);
}
else
{
put(taskId, BatchAddIncomeBillFeeTask.STATUS_SUCCESS, 100, msg, null, total, success, fail);
}
log.info("batch add fee done taskId={} total={} success={} fail={}", taskId, total, success, fail);
}
catch (Exception e)
{
log.error("batch add fee aborted taskId={}", taskId, e);
put(taskId, BatchAddIncomeBillFeeTask.STATUS_FAIL, 100, "failed", errorMessage(e), total, success, fail);
}
}
public void put(String taskId, String status, int percent, String message, String error,
int total, int success, int fail)
{
BatchAddIncomeBillFeeTask task = new BatchAddIncomeBillFeeTask();
task.setTaskId(taskId);
task.setStatus(status);
task.setPercent(percent);
task.setMessage(message);
task.setError(error);
task.setTotal(total);
task.setSuccess(success);
task.setFail(fail);
redisCache.setCacheObject(CACHE_KEY_PREFIX + taskId, task, TTL_MINUTES, TimeUnit.MINUTES);
}
public BatchAddIncomeBillFeeTask get(String taskId)
{
return redisCache.getCacheObject(CACHE_KEY_PREFIX + taskId);
}
private static String errorMessage(Exception e)
{
String msg = e.getMessage();
if (StringUtils.isEmpty(msg))
{
msg = e.getClass().getSimpleName();
}
return msg;
}
}
@@ -60,6 +60,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
where fee_id = #{feeId}
</select>
<select id="selectByBillIdAndFeeTypeAndScId" resultMap="PrcIncomeBillFeeResult">
select fee_id, bill_id, income_bill_id, fee_type, fee_name, sc_id, amount, product_amount, redline_amount, currency, round_mode, remark,
ar_bill_status, manual_flag, create_time
from prc_income_bill_fee
where bill_id = #{billId}
and fee_type = #{feeType}
and sc_id = #{scId}
limit 1
</select>
<select id="countByBillIdAndArBillStatusAndFeeType" resultType="int">
select count(1)
from prc_income_bill_fee
@@ -101,7 +111,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
redline_amount = #{redlineAmount},
currency = #{currency},
round_mode = #{roundMode},
remark = #{remark}
remark = #{remark},
income_bill_id = #{incomeBillId},
manual_flag = #{manualFlag}
where fee_id = #{feeId}
</update>
@@ -240,6 +240,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="billId != null and billId != ''">
AND p.bill_id = #{billId}
</if>
<if test="billIds != null and billIds.size() > 0">
AND p.bill_id IN
<foreach collection="billIds" item="bid" open="(" separator="," close=")">
#{bid}
</foreach>
</if>
<if test="orderNo != null and orderNo != ''">
AND p.order_no like concat('%', #{orderNo}, '%')
</if>