增加可修改计费重功能
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
package com.bms.price.domain;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/** Async charge-weight import progress (Redis). */
|
||||
public class ChargeWeightImportTask 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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.bms.price.domain.vo;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import com.bms.common.annotation.Excel;
|
||||
import lombok.Data;
|
||||
|
||||
/** Excel row for batch charge_weight update. */
|
||||
@Data
|
||||
public class ChargeWeightImportRow implements Serializable
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Excel(name = "订单号")
|
||||
private String orderNo;
|
||||
|
||||
@Excel(name = "客户")
|
||||
private String customer;
|
||||
|
||||
@Excel(name = "人工修改计费重")
|
||||
private BigDecimal chargeWeight;
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package com.bms.price.domain.vo;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
|
||||
/** Download charge-weight import template; optionally fill order/customer by list filters. */
|
||||
@Data
|
||||
public class ChargeWeightTemplateRequest implements Serializable
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** true = fill orderNo/customer from current list filters */
|
||||
private boolean fillByFilter;
|
||||
|
||||
private List<String> orderNos;
|
||||
private List<String> trackingNos;
|
||||
private List<String> transferNos;
|
||||
private List<String> customerCodes;
|
||||
private List<String> productCodes;
|
||||
private String creditArrearsStatus;
|
||||
private String beginBizDate;
|
||||
private String endBizDate;
|
||||
}
|
||||
@@ -35,6 +35,6 @@ public class TmsPriceQuoteRequest implements Serializable
|
||||
/** yyyy-MM-dd or yyyy-MM-dd HH:mm:ss; quote defaults today; bill required */
|
||||
private String bizDate;
|
||||
private Integer tmsId;
|
||||
/** Header X-Api-Code 优先;Body 兜底 */
|
||||
/** Header X-Api-Code first; body as fallback */
|
||||
private String apiCode;
|
||||
}
|
||||
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package com.bms.price.domain.vo;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import jakarta.validation.constraints.DecimalMin;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
/** Single-bill update for charge_weight (manual override; weight kept). */
|
||||
@Data
|
||||
public class UpdateChargeWeightRequest implements Serializable
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@NotBlank(message = "billId is required")
|
||||
private String billId;
|
||||
|
||||
@NotNull(message = "chargeWeight is required")
|
||||
@DecimalMin(value = "0.001", message = "chargeWeight must be > 0")
|
||||
private BigDecimal chargeWeight;
|
||||
}
|
||||
@@ -4,9 +4,12 @@ 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.ChargeWeightImportTask;
|
||||
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.ChargeWeightImportRow;
|
||||
import com.bms.price.domain.vo.ChargeWeightTemplateRequest;
|
||||
import com.bms.price.domain.vo.UpdateIncomeBillFeeRequest;
|
||||
import com.bms.price.domain.vo.TmsPriceBillRequest;
|
||||
import com.bms.price.domain.vo.TmsPriceQuoteResult;
|
||||
@@ -77,4 +80,35 @@ public interface IPrcOrderBillService
|
||||
* @return 更新后的计费结果
|
||||
*/
|
||||
TmsPriceQuoteResult updateCreditArrearsStatus(String billId);
|
||||
|
||||
/**
|
||||
* Update charge_weight (manual override), keep weight, and rebill.
|
||||
* Applies data-scope check.
|
||||
*
|
||||
* @param billId bill id
|
||||
* @param chargeWeight new charge weight (kg)
|
||||
*/
|
||||
TmsPriceQuoteResult updateChargeWeight(String billId, BigDecimal chargeWeight);
|
||||
|
||||
/**
|
||||
* Update charge_weight without data-scope check (pre-validated async import).
|
||||
*/
|
||||
TmsPriceQuoteResult updateChargeWeightByBillId(String billId, BigDecimal chargeWeight);
|
||||
|
||||
/**
|
||||
* Submit async import of charge_weight updates; returns taskId.
|
||||
*
|
||||
* @param rows excel rows
|
||||
* @return taskId
|
||||
*/
|
||||
String submitImportChargeWeight(List<ChargeWeightImportRow> rows);
|
||||
|
||||
/** Poll Redis progress for charge-weight import task. */
|
||||
ChargeWeightImportTask getChargeWeightImportTask(String taskId);
|
||||
|
||||
/**
|
||||
* Build import-template rows. Empty when fillByFilter=false;
|
||||
* otherwise fill orderNo/customer from list filters (data-scoped).
|
||||
*/
|
||||
List<ChargeWeightImportRow> buildChargeWeightTemplateRows(ChargeWeightTemplateRequest request);
|
||||
}
|
||||
|
||||
+359
-3
@@ -43,11 +43,16 @@ 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.ChargeWeightImportTask;
|
||||
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.ChargeWeightImportRow;
|
||||
import com.bms.price.domain.vo.ChargeWeightTemplateRequest;
|
||||
import com.bms.price.domain.vo.UpdateIncomeBillFeeRequest;
|
||||
import com.bms.price.task.PrcBatchAddIncomeFeeAsyncRunner;
|
||||
import com.bms.price.task.PrcChargeWeightImportAsyncRunner;
|
||||
import com.bms.price.task.PrcChargeWeightImportAsyncRunner.ChargeWeightImportWorkItem;
|
||||
import com.bms.price.domain.vo.TmsPriceBillRequest;
|
||||
import com.bms.price.domain.vo.TmsOrderBillStatusResult;
|
||||
import com.bms.price.domain.vo.TmsPriceQuoteFeeLine;
|
||||
@@ -128,8 +133,12 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService
|
||||
@Autowired
|
||||
private PrcBatchAddIncomeFeeAsyncRunner batchAddIncomeFeeAsyncRunner;
|
||||
|
||||
@Autowired
|
||||
private PrcChargeWeightImportAsyncRunner chargeWeightImportAsyncRunner;
|
||||
|
||||
private static final int BATCH_ADD_FEE_MAX = 5000;
|
||||
private static final int BATCH_ADD_FEE_PREVIEW_LIMIT = 20;
|
||||
private static final int CHARGE_WEIGHT_IMPORT_MAX = 5000;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@@ -148,9 +157,12 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService
|
||||
}
|
||||
Date bizDate = resolveBizDate(request.getBizDate());
|
||||
assertOrderBillEditable(request.getOrderNo());
|
||||
BigDecimal weight = request.getWeight();
|
||||
PrcOrderBill existed = orderBillMapper.selectPrcOrderBillByOrderNo(request.getOrderNo());
|
||||
BigDecimal systemWeight = request.getWeight();
|
||||
BigDecimal calcWeight = resolveCalcWeight(existed, systemWeight);
|
||||
request.setWeight(calcWeight);
|
||||
TmsPriceQuoteResult result = tmsPriceQuoteService.calculate(request);
|
||||
persistBill(request, weight, bizDate, result);
|
||||
persistBill(request, systemWeight, bizDate, result);
|
||||
return result;
|
||||
}
|
||||
catch (RuntimeException e)
|
||||
@@ -1097,6 +1109,7 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService
|
||||
bill.setProductName(result.getProductName());
|
||||
bill.setCountryCode(result.getCountryCode());
|
||||
bill.setCountryName(result.getCountryName());
|
||||
// weight = system/original; charge_weight = effective (may be manual override)
|
||||
bill.setWeight(weight);
|
||||
bill.setBizDate(bizDate);
|
||||
bill.setTmsId(request.getTmsId() == null ? null : Long.valueOf(request.getTmsId()));
|
||||
@@ -1115,7 +1128,7 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService
|
||||
bill.setWeightMax(result.getWeightMax());
|
||||
bill.setWeightLabel(result.getWeightLabel());
|
||||
bill.setEffectiveDate(result.getEffectiveDate());
|
||||
bill.setChargeWeight(result.getChargeWeight());
|
||||
bill.setChargeWeight(resolvePersistChargeWeight(weight, result.getChargeWeight()));
|
||||
bill.setFreightRate(result.getFreightRate());
|
||||
bill.setBaseFreightRate(result.getBaseFreightRate());
|
||||
bill.setDiscountPercent(result.getDiscountPercent());
|
||||
@@ -1754,6 +1767,349 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public TmsPriceQuoteResult updateChargeWeight(String billId, BigDecimal chargeWeight)
|
||||
{
|
||||
if (StringUtils.isEmpty(billId))
|
||||
{
|
||||
throw new ServiceException(MessageUtils.message("price.bill.billIdRequired"));
|
||||
}
|
||||
// data-scope check via list query
|
||||
self.getBill(billId.trim());
|
||||
return self.updateChargeWeightByBillId(billId.trim(), chargeWeight);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public TmsPriceQuoteResult updateChargeWeightByBillId(String billId, BigDecimal chargeWeight)
|
||||
{
|
||||
if (StringUtils.isEmpty(billId))
|
||||
{
|
||||
throw new ServiceException(MessageUtils.message("price.bill.billIdRequired"));
|
||||
}
|
||||
PrcOrderBill bill = orderBillMapper.selectPrcOrderBillById(billId.trim());
|
||||
if (bill == null)
|
||||
{
|
||||
throw new ServiceException(MessageUtils.message("price.bill.notFound"));
|
||||
}
|
||||
assertOrderBillEditable(bill);
|
||||
if (BillRefundStatus.REFUNDED.getCode().equalsIgnoreCase(bill.getRefundStatus()))
|
||||
{
|
||||
throw new ServiceException("订单已退费,不可修改计费重");
|
||||
}
|
||||
if (chargeWeight == null || chargeWeight.compareTo(BigDecimal.ZERO) <= 0)
|
||||
{
|
||||
throw new ServiceException("人工修改计费重必须大于 0");
|
||||
}
|
||||
BigDecimal cw = chargeWeight.setScale(3, RoundingMode.HALF_UP);
|
||||
TmsPriceBillRequest req = buildBillRequestFromBill(bill);
|
||||
req.setWeight(cw);
|
||||
Date bizDate = bill.getBizDate();
|
||||
if (bizDate == null)
|
||||
{
|
||||
throw new ServiceException(MessageUtils.message("price.bill.bizDateRequired"));
|
||||
}
|
||||
TmsPriceQuoteResult result = tmsPriceQuoteService.calculate(req);
|
||||
// keep original system weight; charge_weight becomes the manual override
|
||||
persistBill(req, bill.getWeight(), bizDate, result);
|
||||
return toResult(bill.getBillId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String submitImportChargeWeight(List<ChargeWeightImportRow> rows)
|
||||
{
|
||||
if (rows == null || rows.isEmpty())
|
||||
{
|
||||
throw new ServiceException("导入数据不能为空");
|
||||
}
|
||||
java.util.Map<String, ChargeWeightImportRow> dedup = new java.util.LinkedHashMap<String, ChargeWeightImportRow>();
|
||||
int lineNo = 1;
|
||||
int initialFail = 0;
|
||||
StringBuilder preFailTips = new StringBuilder();
|
||||
for (ChargeWeightImportRow row : rows)
|
||||
{
|
||||
lineNo++;
|
||||
if (row == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
String orderNo = row.getOrderNo() == null ? "" : row.getOrderNo().trim();
|
||||
if (orderNo.isEmpty())
|
||||
{
|
||||
initialFail++;
|
||||
if (preFailTips.length() < 800)
|
||||
{
|
||||
if (preFailTips.length() > 0)
|
||||
{
|
||||
preFailTips.append("; ");
|
||||
}
|
||||
preFailTips.append("第").append(lineNo).append("行:订单号为空");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
dedup.put(orderNo, row);
|
||||
}
|
||||
List<ChargeWeightImportWorkItem> items = new ArrayList<ChargeWeightImportWorkItem>();
|
||||
for (java.util.Map.Entry<String, ChargeWeightImportRow> entry : dedup.entrySet())
|
||||
{
|
||||
String orderNo = entry.getKey();
|
||||
ChargeWeightImportRow row = entry.getValue();
|
||||
try
|
||||
{
|
||||
if (row.getChargeWeight() == null || row.getChargeWeight().compareTo(BigDecimal.ZERO) <= 0)
|
||||
{
|
||||
throw new ServiceException("人工修改计费重必须大于 0");
|
||||
}
|
||||
String customer = row.getCustomer() == null ? "" : row.getCustomer().trim();
|
||||
if (customer.isEmpty())
|
||||
{
|
||||
throw new ServiceException("客户不能为空");
|
||||
}
|
||||
PrcOrderBill bill = orderBillMapper.selectPrcOrderBillByOrderNo(orderNo);
|
||||
if (bill == null)
|
||||
{
|
||||
throw new ServiceException("订单不存在");
|
||||
}
|
||||
// data-scope in request thread
|
||||
self.getBill(bill.getBillId());
|
||||
if (!customerMatches(bill, customer))
|
||||
{
|
||||
throw new ServiceException("客户与订单不匹配");
|
||||
}
|
||||
if (BillRefundStatus.REFUNDED.getCode().equalsIgnoreCase(bill.getRefundStatus()))
|
||||
{
|
||||
throw new ServiceException("订单已退费");
|
||||
}
|
||||
items.add(new ChargeWeightImportWorkItem(bill.getBillId(), orderNo,
|
||||
row.getChargeWeight().setScale(3, RoundingMode.HALF_UP)));
|
||||
}
|
||||
catch (RuntimeException e)
|
||||
{
|
||||
initialFail++;
|
||||
if (preFailTips.length() < 800)
|
||||
{
|
||||
String tip = e.getMessage() == null ? e.getClass().getSimpleName() : e.getMessage();
|
||||
if (preFailTips.length() > 0)
|
||||
{
|
||||
preFailTips.append("; ");
|
||||
}
|
||||
preFailTips.append(orderNo).append(":").append(tip);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (items.isEmpty() && initialFail == 0)
|
||||
{
|
||||
throw new ServiceException("导入数据不能为空");
|
||||
}
|
||||
if (items.size() > CHARGE_WEIGHT_IMPORT_MAX)
|
||||
{
|
||||
throw new ServiceException("导入行数超限,最多 "
|
||||
+ CHARGE_WEIGHT_IMPORT_MAX + " 条");
|
||||
}
|
||||
String taskId = IdUtils.fastSimpleUUID();
|
||||
int total = items.size() + initialFail;
|
||||
chargeWeightImportAsyncRunner.put(taskId, ChargeWeightImportTask.STATUS_PENDING, 0, "queued",
|
||||
preFailTips.length() > 0 ? preFailTips.toString() : null, total, 0, initialFail);
|
||||
chargeWeightImportAsyncRunner.run(taskId, items, initialFail);
|
||||
return taskId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChargeWeightImportTask getChargeWeightImportTask(String taskId)
|
||||
{
|
||||
if (StringUtils.isEmpty(taskId) || chargeWeightImportAsyncRunner == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return chargeWeightImportAsyncRunner.get(taskId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ChargeWeightImportRow> buildChargeWeightTemplateRows(ChargeWeightTemplateRequest request)
|
||||
{
|
||||
if (request == null || !request.isFillByFilter())
|
||||
{
|
||||
return new ArrayList<ChargeWeightImportRow>();
|
||||
}
|
||||
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 beginBizDate = StringUtils.isEmpty(request.getBeginBizDate()) ? null
|
||||
: request.getBeginBizDate().trim();
|
||||
String endBizDate = StringUtils.isEmpty(request.getEndBizDate()) ? null
|
||||
: request.getEndBizDate().trim();
|
||||
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(beginBizDate)
|
||||
|| StringUtils.isNotEmpty(endBizDate);
|
||||
if (!hasFilter)
|
||||
{
|
||||
throw new ServiceException("\u8bf7\u5148\u8bbe\u7f6e\u5217\u8868\u7b5b\u9009\u6761\u4ef6");
|
||||
}
|
||||
PrcOrderBill query = new PrcOrderBill();
|
||||
query.setOrderNos(orderNos);
|
||||
query.setTrackingNos(trackingNos);
|
||||
query.setTransferNos(transferNos);
|
||||
query.setCustomerCodes(customerCodes);
|
||||
query.setProductCodes(productCodes);
|
||||
query.setCreditArrearsStatus(creditArrearsStatus);
|
||||
if (beginBizDate != null)
|
||||
{
|
||||
query.getParams().put("beginBizDate", beginBizDate);
|
||||
}
|
||||
if (endBizDate != null)
|
||||
{
|
||||
query.getParams().put("endBizDate", endBizDate);
|
||||
}
|
||||
List<PrcOrderBill> list = self.selectBillList(query);
|
||||
if (list == null || list.isEmpty())
|
||||
{
|
||||
throw new ServiceException("\u5f53\u524d\u7b5b\u9009\u6761\u4ef6\u4e0b\u6ca1\u6709\u53ef\u5bfc\u51fa\u7684\u8ba2\u5355");
|
||||
}
|
||||
if (list.size() > CHARGE_WEIGHT_IMPORT_MAX)
|
||||
{
|
||||
throw new ServiceException("\u7b5b\u9009\u7ed3\u679c\u8d85\u8fc7 "
|
||||
+ CHARGE_WEIGHT_IMPORT_MAX + " \u6761\uff0c\u8bf7\u7f29\u5c0f\u7b5b\u9009\u8303\u56f4");
|
||||
}
|
||||
List<ChargeWeightImportRow> rows = new ArrayList<ChargeWeightImportRow>(list.size());
|
||||
for (PrcOrderBill bill : list)
|
||||
{
|
||||
if (bill == null || StringUtils.isEmpty(bill.getOrderNo()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (BillRefundStatus.REFUNDED.getCode().equalsIgnoreCase(bill.getRefundStatus()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
ChargeWeightImportRow row = new ChargeWeightImportRow();
|
||||
row.setOrderNo(bill.getOrderNo());
|
||||
String customer = StringUtils.isNotEmpty(bill.getCustomerCode()) ? bill.getCustomerCode()
|
||||
: bill.getCustomerName();
|
||||
row.setCustomer(customer);
|
||||
row.setChargeWeight(null);
|
||||
rows.add(row);
|
||||
}
|
||||
if (rows.isEmpty())
|
||||
{
|
||||
throw new ServiceException("\u5f53\u524d\u7b5b\u9009\u6761\u4ef6\u4e0b\u6ca1\u6709\u53ef\u5bfc\u51fa\u7684\u8ba2\u5355");
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
private TmsPriceQuoteResult toResult(String billId)
|
||||
{
|
||||
PrcOrderBill bill = orderBillMapper.selectPrcOrderBillById(billId);
|
||||
if (bill == null)
|
||||
{
|
||||
throw new ServiceException(MessageUtils.message("price.bill.notFound"));
|
||||
}
|
||||
return toResult(bill, incomeBillFeeMapper.selectByBillId(bill.getBillId()),
|
||||
payBillFeeMapper.selectByBillId(bill.getBillId()));
|
||||
}
|
||||
|
||||
/** charge_weight differs from weight => treated as manual override. */
|
||||
private static boolean isManualChargeWeight(PrcOrderBill bill)
|
||||
{
|
||||
if (bill == null || bill.getChargeWeight() == null || bill.getWeight() == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return bill.getChargeWeight().compareTo(bill.getWeight()) != 0;
|
||||
}
|
||||
|
||||
/** Prefer manual charge_weight when present; otherwise system weight. */
|
||||
private static BigDecimal resolveCalcWeight(PrcOrderBill existed, BigDecimal systemWeight)
|
||||
{
|
||||
if (isManualChargeWeight(existed))
|
||||
{
|
||||
return existed.getChargeWeight();
|
||||
}
|
||||
return systemWeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Persist charge_weight: keep manual override when calc weight != system weight,
|
||||
* or when existing bill already had a manual override.
|
||||
*/
|
||||
private static BigDecimal resolvePersistChargeWeight(BigDecimal systemWeight, BigDecimal resultChargeWeight)
|
||||
{
|
||||
// calc weight != system weight => keep result as manual charge_weight
|
||||
if (systemWeight != null && resultChargeWeight != null
|
||||
&& systemWeight.compareTo(resultChargeWeight) != 0)
|
||||
{
|
||||
return resultChargeWeight;
|
||||
}
|
||||
return resultChargeWeight;
|
||||
}
|
||||
|
||||
private static boolean customerMatches(PrcOrderBill bill, String customer)
|
||||
{
|
||||
if (bill == null || StringUtils.isEmpty(customer))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
String code = bill.getCustomerCode() == null ? "" : bill.getCustomerCode().trim();
|
||||
String name = bill.getCustomerName() == null ? "" : bill.getCustomerName().trim();
|
||||
return customer.equalsIgnoreCase(code) || customer.equals(name);
|
||||
}
|
||||
|
||||
private TmsPriceBillRequest buildBillRequestFromBill(PrcOrderBill bill)
|
||||
{
|
||||
TmsPriceBillRequest req = new TmsPriceBillRequest();
|
||||
req.setOrderNo(bill.getOrderNo());
|
||||
req.setTrackingNo(bill.getTrackingNo());
|
||||
req.setTransferNo(bill.getTransferNo());
|
||||
req.setBelongSaler(bill.getBelongSaler());
|
||||
req.setBelongSalerCode(bill.getBelongSalerCode());
|
||||
req.setSettlementMan(bill.getSettlementMan());
|
||||
req.setSettlementManCode(bill.getSettlementManCode());
|
||||
req.setServiceMan(bill.getServiceMan());
|
||||
req.setServiceManCode(bill.getServiceManCode());
|
||||
req.setCustomerId(bill.getCustomerId());
|
||||
req.setCustomerCode(bill.getCustomerCode());
|
||||
req.setCustomerName(bill.getCustomerName());
|
||||
req.setProductCode(bill.getProductCode());
|
||||
req.setCountryCode(bill.getCountryCode());
|
||||
req.setCountryName(bill.getCountryName());
|
||||
req.setDestPostcode(bill.getDestPostcode());
|
||||
req.setPieces(bill.getPieces());
|
||||
req.setActualWeight(bill.getActualWeight());
|
||||
req.setReceiveWeight(bill.getReceiveWeight());
|
||||
req.setVolume(bill.getVolume());
|
||||
req.setVolumeWeight(bill.getVolumeWeight());
|
||||
req.setPkgLength(bill.getPkgLength());
|
||||
req.setPkgWidth(bill.getPkgWidth());
|
||||
req.setPkgHeight(bill.getPkgHeight());
|
||||
req.setShipperName(bill.getShipperName());
|
||||
req.setConsigneeName(bill.getConsigneeName());
|
||||
req.setWarehouseCode(bill.getWarehouseCode());
|
||||
req.setOrderTime(bill.getOrderTime());
|
||||
req.setOrderRemark(bill.getOrderRemark());
|
||||
if (bill.getTmsId() != null)
|
||||
{
|
||||
req.setTmsId(Integer.valueOf(bill.getTmsId().intValue()));
|
||||
}
|
||||
if (bill.getBizDate() != null)
|
||||
{
|
||||
req.setBizDate(DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", bill.getBizDate()));
|
||||
}
|
||||
BigDecimal w = bill.getChargeWeight() != null ? bill.getChargeWeight() : bill.getWeight();
|
||||
req.setWeight(w);
|
||||
return req;
|
||||
}
|
||||
|
||||
|
||||
private Date resolveBizDate(String bizDate)
|
||||
{
|
||||
if (StringUtils.isEmpty(bizDate))
|
||||
|
||||
+195
@@ -0,0 +1,195 @@
|
||||
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.ChargeWeightImportTask;
|
||||
import com.bms.price.service.IPrcOrderBillService;
|
||||
|
||||
/**
|
||||
* Async runner: import charge_weight updates and rebill each order.
|
||||
*/
|
||||
@Component
|
||||
public class PrcChargeWeightImportAsyncRunner
|
||||
{
|
||||
private static final Logger log = LoggerFactory.getLogger(PrcChargeWeightImportAsyncRunner.class);
|
||||
|
||||
public static final String CACHE_KEY_PREFIX = "price:billing:chargeWeight:import:task:";
|
||||
public static final int TTL_MINUTES = 60;
|
||||
|
||||
@Autowired
|
||||
@Lazy
|
||||
private IPrcOrderBillService orderBillService;
|
||||
|
||||
@Autowired
|
||||
private RedisCache redisCache;
|
||||
|
||||
/**
|
||||
* @param items pre-validated rows with billId filled in remark field unused;
|
||||
* use orderNo + chargeWeight; billId stored in customer field as billId carrier
|
||||
* -- better use a dedicated work item. See run(List of Object[]).
|
||||
*/
|
||||
@Async("threadPoolTaskExecutor")
|
||||
public void run(String taskId, List<ChargeWeightImportWorkItem> items, int initialFail)
|
||||
{
|
||||
int total = (items == null ? 0 : items.size()) + Math.max(initialFail, 0);
|
||||
int success = 0;
|
||||
int fail = Math.max(initialFail, 0);
|
||||
StringBuilder failTips = new StringBuilder();
|
||||
try
|
||||
{
|
||||
put(taskId, ChargeWeightImportTask.STATUS_RUNNING, 1, "running", null, total, 0, fail);
|
||||
int workSize = items == null ? 0 : items.size();
|
||||
if (workSize == 0)
|
||||
{
|
||||
if (fail > 0)
|
||||
{
|
||||
put(taskId, ChargeWeightImportTask.STATUS_SUCCESS, 100,
|
||||
"success=0, fail=" + fail, "all rows failed validation", total, 0, fail);
|
||||
}
|
||||
else
|
||||
{
|
||||
put(taskId, ChargeWeightImportTask.STATUS_FAIL, 100, "failed", "no rows", 0, 0, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < workSize; i++)
|
||||
{
|
||||
ChargeWeightImportWorkItem item = items.get(i);
|
||||
try
|
||||
{
|
||||
orderBillService.updateChargeWeightByBillId(item.getBillId(), item.getChargeWeight());
|
||||
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(item.getOrderNo()).append(":").append(tip);
|
||||
}
|
||||
log.warn("charge weight import failed taskId={} orderNo={}", taskId, item.getOrderNo(), e);
|
||||
}
|
||||
int done = i + 1 + Math.max(initialFail, 0);
|
||||
int percent = Math.min(99, (int) Math.floor(100.0 * done / Math.max(total, 1)));
|
||||
put(taskId, ChargeWeightImportTask.STATUS_RUNNING, percent,
|
||||
"processing " + done + "/" + total, null, total, success, fail);
|
||||
}
|
||||
String msg = "success=" + success + ", fail=" + fail;
|
||||
if (fail > 0 && failTips.length() > 0)
|
||||
{
|
||||
put(taskId, ChargeWeightImportTask.STATUS_SUCCESS, 100, msg, failTips.toString(),
|
||||
total, success, fail);
|
||||
}
|
||||
else
|
||||
{
|
||||
put(taskId, ChargeWeightImportTask.STATUS_SUCCESS, 100, msg, null, total, success, fail);
|
||||
}
|
||||
log.info("charge weight import done taskId={} total={} success={} fail={}",
|
||||
taskId, total, success, fail);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
log.error("charge weight import aborted taskId={}", taskId, e);
|
||||
put(taskId, ChargeWeightImportTask.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)
|
||||
{
|
||||
ChargeWeightImportTask task = new ChargeWeightImportTask();
|
||||
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 ChargeWeightImportTask 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;
|
||||
}
|
||||
|
||||
/** Pre-validated work item for async import. */
|
||||
public static class ChargeWeightImportWorkItem implements java.io.Serializable
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
private String billId;
|
||||
private String orderNo;
|
||||
private BigDecimal chargeWeight;
|
||||
|
||||
public ChargeWeightImportWorkItem()
|
||||
{
|
||||
}
|
||||
|
||||
public ChargeWeightImportWorkItem(String billId, String orderNo, BigDecimal chargeWeight)
|
||||
{
|
||||
this.billId = billId;
|
||||
this.orderNo = orderNo;
|
||||
this.chargeWeight = chargeWeight;
|
||||
}
|
||||
|
||||
public String getBillId()
|
||||
{
|
||||
return billId;
|
||||
}
|
||||
|
||||
public void setBillId(String billId)
|
||||
{
|
||||
this.billId = billId;
|
||||
}
|
||||
|
||||
public String getOrderNo()
|
||||
{
|
||||
return orderNo;
|
||||
}
|
||||
|
||||
public void setOrderNo(String orderNo)
|
||||
{
|
||||
this.orderNo = orderNo;
|
||||
}
|
||||
|
||||
public BigDecimal getChargeWeight()
|
||||
{
|
||||
return chargeWeight;
|
||||
}
|
||||
|
||||
public void setChargeWeight(BigDecimal chargeWeight)
|
||||
{
|
||||
this.chargeWeight = chargeWeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user