实现扣减额度功能
This commit is contained in:
@@ -141,6 +141,7 @@ price.quote.hitCustomerFixedPackageDetail=命中客户套餐固定价格明细
|
||||
price.bill.orderNoRequired=订单号为空
|
||||
price.bill.billIdRequired=计费ID为空
|
||||
price.bill.notFound=计费记录不存在
|
||||
price.bill.customerRequired=订单同步缺少有效客户
|
||||
price.bill.bizDateRequired=业务日期为空
|
||||
|
||||
price.set.version.effectiveTime.empty=版本生效时间不能为空
|
||||
|
||||
+12
-8
@@ -246,8 +246,8 @@ public class CustomerAccountApiImpl implements ICustomerAccountApi
|
||||
validateUsageCommand(command);
|
||||
Long customerId = resolveCustomerId(command);
|
||||
String currency = resolveCurrency(command.getCurrency());
|
||||
String username = SecurityUtils.getUsername();
|
||||
Long userId = SecurityUtils.getUserId();
|
||||
String username = currentUsername();
|
||||
Long userId = currentUserId();
|
||||
CustomerAccount account = lockAccountForUsage(customerId, currency, username);
|
||||
if (account == null)
|
||||
{
|
||||
@@ -281,8 +281,8 @@ public class CustomerAccountApiImpl implements ICustomerAccountApi
|
||||
validateUsageCommand(command);
|
||||
Long customerId = resolveCustomerId(command);
|
||||
String currency = resolveCurrency(command.getCurrency());
|
||||
String username = SecurityUtils.getUsername();
|
||||
Long userId = SecurityUtils.getUserId();
|
||||
String username = currentUsername();
|
||||
Long userId = currentUserId();
|
||||
CustomerAccount account = lockAccountForUsage(customerId, currency, username);
|
||||
if (account == null)
|
||||
{
|
||||
@@ -635,19 +635,23 @@ public class CustomerAccountApiImpl implements ICustomerAccountApi
|
||||
|
||||
private String bizTypeLabel(String bizType)
|
||||
{
|
||||
if (CustomerFundBizType.RECEIPT.equals(bizType))
|
||||
{
|
||||
return "\u6536\u6b3e";
|
||||
}
|
||||
if (CustomerFundBizType.AR_BILL.equals(bizType))
|
||||
{
|
||||
return "应收账单";
|
||||
return "\u5e94\u6536\u8d26\u5355";
|
||||
}
|
||||
if (CustomerFundBizType.ORDER.equals(bizType))
|
||||
{
|
||||
return "计费订单";
|
||||
return "\u8ba1\u8d39\u8ba2\u5355";
|
||||
}
|
||||
if (CustomerFundBizType.BILL_PAY.equals(bizType))
|
||||
{
|
||||
return "账单核销";
|
||||
return "\u8d26\u5355\u6838\u9500";
|
||||
}
|
||||
return "业务";
|
||||
return "\u4e1a\u52a1";
|
||||
}
|
||||
|
||||
/** 临时额度是否已过期:有失效日期且今天已晚于失效日(失效日当天仍有效) */
|
||||
|
||||
@@ -8,6 +8,8 @@ public final class EsLogType
|
||||
{
|
||||
public static final String BILL = "BILL";
|
||||
public static final String QUOTE = "QUOTE";
|
||||
/** Order credit occupy/release */
|
||||
public static final String CREDIT = "CREDIT";
|
||||
|
||||
private EsLogType()
|
||||
{
|
||||
|
||||
+103
@@ -28,6 +28,9 @@ import com.ruoyi.price.mapper.PrcPayBillFeeMapper;
|
||||
import com.ruoyi.price.search.EsBizLogSupport;
|
||||
import com.ruoyi.price.search.EsLogType;
|
||||
import com.ruoyi.price.search.IBillSearchStore;
|
||||
import com.ruoyi.customer.customermoney.api.CreditUsageCommand;
|
||||
import com.ruoyi.customer.customermoney.api.CustomerFundBizType;
|
||||
import com.ruoyi.customer.customermoney.api.ICustomerAccountApi;
|
||||
import com.ruoyi.price.service.IPrcOrderBillService;
|
||||
import com.ruoyi.price.service.ITmsPriceQuoteService;
|
||||
|
||||
@@ -49,6 +52,9 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService
|
||||
@Autowired
|
||||
private IBillSearchStore billSearchStore;
|
||||
|
||||
@Autowired
|
||||
private ICustomerAccountApi customerAccountApi;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public TmsPriceQuoteResult bill(TmsPriceBillRequest request)
|
||||
@@ -121,6 +127,7 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService
|
||||
String orderNo = request.getOrderNo();
|
||||
String billKey = Md5Utils.hash(orderNo);
|
||||
PrcOrderBill existed = orderBillMapper.selectPrcOrderBillByOrderNo(orderNo);
|
||||
BigDecimal previousIncome = existed == null ? BigDecimal.ZERO : nz(existed.getIncomeTotal());
|
||||
PrcOrderBill bill = existed == null ? new PrcOrderBill() : existed;
|
||||
if (existed == null)
|
||||
{
|
||||
@@ -209,9 +216,105 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService
|
||||
{
|
||||
incomeBillFeeMapper.insertBatch(fees);
|
||||
}
|
||||
syncOrderCredit(bill, previousIncome);
|
||||
billSearchStore.save(EsLogType.BILL, orderNo, toRequestJson(request), toResponseJson(result));
|
||||
}
|
||||
|
||||
/**
|
||||
* Occupy/release credit by income total delta (bizType=ORDER).
|
||||
* Always write CREDIT log to ES (SUCCESS / FAIL), then rethrow on failure.
|
||||
*/
|
||||
private void syncOrderCredit(PrcOrderBill bill, BigDecimal previousIncome)
|
||||
{
|
||||
if (bill == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Long customerId = bill.getCustomerId();
|
||||
if (customerId == null || customerId.longValue() <= 0L)
|
||||
{
|
||||
ServiceException ex = new ServiceException(MessageUtils.message("price.bill.customerRequired"));
|
||||
saveCreditEsLog(bill, null, "SKIP", false, EsBizLogSupport.errorText(ex));
|
||||
throw ex;
|
||||
}
|
||||
BigDecimal oldAmt = nz(previousIncome);
|
||||
BigDecimal newAmt = nz(bill.getIncomeTotal());
|
||||
BigDecimal delta = newAmt.subtract(oldAmt);
|
||||
if (delta.compareTo(BigDecimal.ZERO) == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
CreditUsageCommand cmd = new CreditUsageCommand();
|
||||
cmd.setCustomerId(customerId);
|
||||
cmd.setCustomerCode(bill.getCustomerCode());
|
||||
cmd.setCurrency(StringUtils.isEmpty(bill.getCurrency()) ? "CNY" : bill.getCurrency());
|
||||
cmd.setBizType(CustomerFundBizType.ORDER);
|
||||
cmd.setBizNo(bill.getOrderNo());
|
||||
cmd.setCheckAvailable(Boolean.TRUE);
|
||||
String action = delta.compareTo(BigDecimal.ZERO) > 0 ? "OCCUPY" : "RELEASE";
|
||||
try
|
||||
{
|
||||
if (delta.compareTo(BigDecimal.ZERO) > 0)
|
||||
{
|
||||
cmd.setAmount(delta);
|
||||
customerAccountApi.occupyCredit(cmd);
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd.setAmount(delta.abs());
|
||||
customerAccountApi.releaseCredit(cmd);
|
||||
}
|
||||
saveCreditEsLog(bill, cmd, action, true, null);
|
||||
}
|
||||
catch (RuntimeException e)
|
||||
{
|
||||
saveCreditEsLog(bill, cmd, action, false, EsBizLogSupport.errorText(e));
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/** CREDIT ES log; does not set ATTR_FAIL_LOGGED so BILL fail can still be written. */
|
||||
private void saveCreditEsLog(PrcOrderBill bill, CreditUsageCommand cmd, String action, boolean success,
|
||||
String errorMessage)
|
||||
{
|
||||
if (billSearchStore == null || bill == null || StringUtils.isEmpty(bill.getOrderNo()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
JSONObject req = new JSONObject();
|
||||
req.put("orderNo", bill.getOrderNo());
|
||||
req.put("billId", bill.getBillId());
|
||||
req.put("customerId", bill.getCustomerId());
|
||||
req.put("customerCode", bill.getCustomerCode());
|
||||
req.put("currency", bill.getCurrency());
|
||||
req.put("incomeTotal", bill.getIncomeTotal());
|
||||
req.put("action", action);
|
||||
req.put("bizType", CustomerFundBizType.ORDER);
|
||||
if (cmd != null)
|
||||
{
|
||||
req.put("amount", cmd.getAmount());
|
||||
req.put("checkAvailable", cmd.getCheckAvailable());
|
||||
}
|
||||
JSONObject resp = new JSONObject();
|
||||
resp.put("success", Boolean.valueOf(success));
|
||||
if (success)
|
||||
{
|
||||
resp.put("msg", action);
|
||||
}
|
||||
else
|
||||
{
|
||||
resp.put("msg", errorMessage);
|
||||
}
|
||||
String status = success ? EsBizLogSupport.STATUS_SUCCESS : EsBizLogSupport.STATUS_FAIL;
|
||||
String err = success ? null : EsBizLogSupport.cut(errorMessage);
|
||||
billSearchStore.save(EsLogType.CREDIT, bill.getOrderNo(), req.toJSONString(), resp.toJSONString(), status, err);
|
||||
}
|
||||
|
||||
private static BigDecimal nz(BigDecimal v)
|
||||
{
|
||||
return v == null ? BigDecimal.ZERO : v;
|
||||
}
|
||||
|
||||
private List<PrcIncomeBillFee> toFeeRows(String billId, TmsPriceQuoteResult result)
|
||||
{
|
||||
List<PrcIncomeBillFee> fees = new ArrayList<PrcIncomeBillFee>();
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
-- customer fund biz_type dict (CustomerFundBizType)
|
||||
-- dict_type: customer_fund_biz_type
|
||||
|
||||
INSERT INTO sys_dict_type (dict_name, dict_type, status, create_by, create_time, remark)
|
||||
SELECT '客户资金业务类型', 'customer_fund_biz_type', '0', 'admin', sysdate(), 'ICustomerAccountApi bizType'
|
||||
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM sys_dict_type WHERE dict_type = 'customer_fund_biz_type');
|
||||
|
||||
INSERT INTO sys_dict_data (dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, remark)
|
||||
SELECT 1, '收款', 'RECEIPT', 'customer_fund_biz_type', '', 'success', 'N', '0', 'admin', sysdate(), NULL
|
||||
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM sys_dict_data WHERE dict_type = 'customer_fund_biz_type' AND dict_value = 'RECEIPT');
|
||||
|
||||
INSERT INTO sys_dict_data (dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, remark)
|
||||
SELECT 2, '应收账单', 'AR_BILL', 'customer_fund_biz_type', '', 'primary', 'N', '0', 'admin', sysdate(), NULL
|
||||
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM sys_dict_data WHERE dict_type = 'customer_fund_biz_type' AND dict_value = 'AR_BILL');
|
||||
|
||||
INSERT INTO sys_dict_data (dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, remark)
|
||||
SELECT 3, '账单核销', 'BILL_PAY', 'customer_fund_biz_type', '', 'danger', 'N', '0', 'admin', sysdate(), NULL
|
||||
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM sys_dict_data WHERE dict_type = 'customer_fund_biz_type' AND dict_value = 'BILL_PAY');
|
||||
|
||||
INSERT INTO sys_dict_data (dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, remark)
|
||||
SELECT 4, '计费订单', 'ORDER', 'customer_fund_biz_type', '', 'warning', 'Y', '0', 'admin', sysdate(), 'TMS bill sync occupy/release'
|
||||
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM sys_dict_data WHERE dict_type = 'customer_fund_biz_type' AND dict_value = 'ORDER');
|
||||
Reference in New Issue
Block a user