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:
@@ -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);
|
||||
|
||||
|
||||
+172
-14
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user