|
|
@@ -128,6 +128,10 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
|
|
|
private static final String JY_INVOICING_COMMISSION_LOCK = "JY_INVOICING_COMMISSION_LOCK:";
|
|
|
// 驾意险跟单费结算所
|
|
|
private static final String JY_INVOICING_OTHER_LOCK = "JY_INVOICING_OTHER_LOCK:";
|
|
|
+ // 平台车险结算锁
|
|
|
+ private static final String PT_INVOICING_COMMISSION_LOCK = "PT_INVOICING_COMMISSION_LOCK:";
|
|
|
+ // 平台非车险结算锁
|
|
|
+ private static final String PT_INVOICING_OTHER_LOCK = "PT_INVOICING_OTHER_LOCK:";
|
|
|
|
|
|
|
|
|
// @Override
|
|
|
@@ -473,6 +477,34 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
|
|
|
return invoiceIds;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 开票前计算应收金额等信息
|
|
|
+ *
|
|
|
+ * @param invoicingVo 获取订单编号等信息
|
|
|
+ * @author lipf
|
|
|
+ * @date 2026/5/26 10:45
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public InsPlyIncomeInvoiceVO calBeforeInvoice(InvoicingVo invoicingVo) {
|
|
|
+ log.info("开票前校验并计算应收金额等金额。 invoicingVO=[{}]", JSONUtil.toJsonStr(invoicingVo));
|
|
|
+ InsPlyIncomeInvoiceVO invoice = new InsPlyIncomeInvoiceVO();
|
|
|
+ boolean b = this.invoicingCheck(invoicingVo);
|
|
|
+ if(!b){
|
|
|
+ List<String> invoiceIds = this.queryIncomeBindInvoice(invoicingVo);
|
|
|
+ invoice.setCanInvoice(false);
|
|
|
+ invoice.setErrMsg("订单已开票。发票序号是"+ invoiceIds.toString());
|
|
|
+ return invoice;
|
|
|
+ }
|
|
|
+ invoice.setCanInvoice(true);
|
|
|
+ BigDecimal receivableAmount = this.getReceivableAmount(invoicingVo);
|
|
|
+ log.info("根据订单号[{}]计算得到的应收金额是[{}]",JSONUtil.toJsonStr(invoicingVo),receivableAmount);
|
|
|
+ invoice.setReceivableSupervisePremium(receivableAmount);
|
|
|
+ invoice.setCompanyId(invoicingVo.getCompanyId());
|
|
|
+ invoice.setInvoiceTime(LocalDateTime.now());
|
|
|
+ invoice.setInvoiceType(invoicingVo.getInvoiceType());
|
|
|
+ return invoice;
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 开票重复校验
|
|
|
* 功能:DB+Redis双重校验,防止并发重复开票
|
|
|
@@ -495,12 +527,15 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
+ // 开票类型 1、手续费 2、跟单费 3、驾意险手续费 4、驾意险跟单费 5、平台应收-车险 6、平台应收-非车险
|
|
|
// 3. 根据开票类型获取Redis锁前缀
|
|
|
String redisKeyPrefix = switch (invoicingVo.getInvoiceType()) {
|
|
|
case "1" -> CAR_INVOICING_COMMISSION_LOCK;
|
|
|
case "2" -> CAR_INVOICING_OTHER_LOCK;
|
|
|
case "3" -> JY_INVOICING_COMMISSION_LOCK;
|
|
|
case "4" -> JY_INVOICING_OTHER_LOCK;
|
|
|
+ case "5" -> PT_INVOICING_COMMISSION_LOCK;
|
|
|
+ case "6" -> PT_INVOICING_OTHER_LOCK;
|
|
|
default -> throw new SystemException("不支持的开票类型");
|
|
|
};
|
|
|
|
|
|
@@ -567,6 +602,7 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
|
|
|
|
|
|
@Override
|
|
|
public BigDecimal getReceivableAmount(InvoicingVo invoicingVo) {
|
|
|
+ log.info("获取订单的应收金额:invoicingVo=[{}]", JSONUtil.toJsonStr(invoicingVo));
|
|
|
String invoiceType = invoicingVo.getInvoiceType();
|
|
|
List<String> orderNos = invoicingVo.getOrderNos();
|
|
|
orderNos = orderNos.stream()
|
|
|
@@ -596,6 +632,12 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
|
|
|
} else if (invoiceType.equals("4")) {
|
|
|
// 驾意险的总跟单费(jy_follow_premium)
|
|
|
return jyFollowPremium;
|
|
|
+ } else if (invoiceType.equals("5")) {
|
|
|
+ // 交强的总手续费(jq_commission_premium) + 商业的总手续费(sy_commission_premium) + 交强的总跟单费(jq_follow_premium) + 商业的总跟单费(sy_follow_premium)
|
|
|
+ return jqCommissionPremium.add(syCommissionPremium).add(jqFollowPremium).add(syFollowPremium);
|
|
|
+ } else if (invoiceType.equals("6")) {
|
|
|
+ // 驾意险的总手续费(jy_commission_premium) + 驾意险的总跟单费(jy_follow_premium)
|
|
|
+ return jyCommissionPremium.add(jyFollowPremium);
|
|
|
}
|
|
|
return null;
|
|
|
}
|
|
|
@@ -603,34 +645,34 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
|
|
|
/**
|
|
|
* 添加发票
|
|
|
*
|
|
|
- * @param invoicingVo
|
|
|
- * @return
|
|
|
+ * @param invoicingVo 开票相关的信息
|
|
|
+ * @return InvoiceingResult 开票的结果
|
|
|
*/
|
|
|
@Override
|
|
|
@Transactional
|
|
|
- public InvoiceingResult addInvoicing(InvoicingVo invoicingVo) {
|
|
|
+ public InvoiceingResult addInvoicing(InsPlyIncomeInvoiceVO invoicingVo) {
|
|
|
+ log.info("开票:invoicingVo=[{}]", JSONUtil.toJsonStr(invoicingVo));
|
|
|
try {
|
|
|
- invoicingVo.setReceivablePremium(this.getReceivableAmount(invoicingVo));
|
|
|
-
|
|
|
InvoiceingResult result = new InvoiceingResult();
|
|
|
InsPlyIncomeInvoice invoice = new InsPlyIncomeInvoice();
|
|
|
+ BeanUtils.copyProperties(invoicingVo, invoice);
|
|
|
invoice.setId(IdGenerate.nextId());
|
|
|
invoice.setCompanyId(invoicingVo.getCompanyId());
|
|
|
invoice.setInvoiceType(invoicingVo.getInvoiceType());
|
|
|
- // 开票类型 1 手续费 2 跟单费 3 驾意险手续费 4 驾意险跟单费
|
|
|
+ // 开票类型 1、手续费 2、跟单费 3、驾意险手续费 4、驾意险跟单费 5、平台应收-车险 6、平台应收-非车险
|
|
|
if("1".equals(invoicingVo.getInvoiceType()) || "2".equals(invoicingVo.getInvoiceType())){
|
|
|
invoice.setInvoiceRiskType("10");
|
|
|
+ }else if("5".equals(invoicingVo.getInvoiceType()) || "6".equals(invoicingVo.getInvoiceType())){
|
|
|
+ invoice.setInvoiceRiskType("30");
|
|
|
}else{
|
|
|
invoice.setInvoiceRiskType("20");
|
|
|
}
|
|
|
invoice.setInvoiceParty(invoicingVo.getInvoiceParty());
|
|
|
invoice.setOverinflatedAmount(invoicingVo.getOverinflatedAmount());
|
|
|
- invoice.setReceivableSupervisePremium(invoicingVo.getReceivablePremium());
|
|
|
+ invoice.setReceivableSupervisePremium(invoicingVo.getReceivableSupervisePremium());
|
|
|
invoice.setTaxPoint(invoicingVo.getTaxPoint());
|
|
|
insPlyIncomeInvoiceMapper.insert(invoice);
|
|
|
-
|
|
|
- List<InsPlyIncomeInvoiceLink> invoicingLinkList = new ArrayList();
|
|
|
-
|
|
|
+ List<InsPlyIncomeInvoiceLink> invoicingLinkList = new ArrayList<InsPlyIncomeInvoiceLink>();
|
|
|
invoicingVo.getIncomeIds().forEach(incomeId -> {
|
|
|
InsPlyIncomeInvoiceLink link = new InsPlyIncomeInvoiceLink();
|
|
|
link.setId(IdGenerate.nextId());
|
|
|
@@ -641,7 +683,7 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
|
|
|
});
|
|
|
insPlyIncomeInvoiceLinkMapper.insert(invoicingLinkList);
|
|
|
result.setInvoiceId(invoice.getId());
|
|
|
- result.setSumPrice(null != invoicingVo.getReceivablePremium() ? invoicingVo.getReceivablePremium().toString() : null);
|
|
|
+ result.setSumPrice(null != invoicingVo.getReceivableSupervisePremium() ? invoicingVo.getReceivableSupervisePremium().toString() : null);
|
|
|
return result;
|
|
|
} catch (Exception e) {
|
|
|
log.info("开票异常.invoicingVo=[{}]",JSONUtil.toJsonStr(invoicingVo), e);
|
|
|
@@ -691,12 +733,141 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
|
|
|
.in(InsPlyIncome::getId, invoiceIds)
|
|
|
.set(InsPlyIncome::getJyOtherSettlement, "1"));
|
|
|
break;
|
|
|
+ case "5":
|
|
|
+ result = baseMapper.update(new LambdaUpdateWrapper<InsPlyIncome>()
|
|
|
+ .in(InsPlyIncome::getId, invoiceIds)
|
|
|
+ .set(InsPlyIncome::getPlatformSuperviseSettlement, "1").set(InsPlyIncome::getSettlementStatus, "1"));
|
|
|
+ break;
|
|
|
+ case "6":
|
|
|
+ result = baseMapper.update(new LambdaUpdateWrapper<InsPlyIncome>()
|
|
|
+ .in(InsPlyIncome::getId, invoiceIds)
|
|
|
+ .set(InsPlyIncome::getPlatformOtherSettlement, "1").set(InsPlyIncome::getSettlementStatus, "1"));
|
|
|
+ break;
|
|
|
default:
|
|
|
result = 0;
|
|
|
}
|
|
|
return result > 0;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 开票并结算
|
|
|
+ *
|
|
|
+ * @param settlementVo 开票信息和结算信息
|
|
|
+ * @author lipf
|
|
|
+ * @date 2026/5/26 11:44
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public HttpResult<String> invoiceAndSettlement(InvoiceAndSettlementVo settlementVo) {
|
|
|
+ log.info("开票并结算: settlementVo=[{}]", JSONUtil.toJsonStr(settlementVo));
|
|
|
+ InvoiceingResult result = this.addInvoicing(settlementVo.getInvoiceVO());
|
|
|
+ if (Objects.nonNull(result)){
|
|
|
+ SettlementVo settlementVo1 = new SettlementVo();
|
|
|
+ BeanUtils.copyProperties(settlementVo, settlementVo1);
|
|
|
+ settlementVo1.setInvoicingId(result.getInvoiceId());
|
|
|
+ boolean settlement = this.settlement(settlementVo1);
|
|
|
+ if(settlement){
|
|
|
+ return HttpResult.ok("开票并结算成功");
|
|
|
+ }else{
|
|
|
+ return HttpResult.error("开票成功但结算失败");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return HttpResult.error("开票失败");
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public boolean platformSettlement(PlatformSettlementVo platformSettlementVo) {
|
|
|
+ SettlementVo settlementVo = platformSettlementVo.getSettlementVo();
|
|
|
+ InvoicingVo invoicingVo = platformSettlementVo.getInvoicingVo();
|
|
|
+
|
|
|
+ log.info("平台结算:platformSettlement=[{}]", JSONUtil.toJsonStr(platformSettlementVo));
|
|
|
+ try {
|
|
|
+ // ============================开票逻辑============================
|
|
|
+ invoicingVo.setReceivablePremium(this.getReceivableAmount(invoicingVo));
|
|
|
+
|
|
|
+ InvoiceingResult result = new InvoiceingResult();
|
|
|
+ InsPlyIncomeInvoice invoice = new InsPlyIncomeInvoice();
|
|
|
+ invoice.setId(IdGenerate.nextId());
|
|
|
+ invoice.setCompanyId(invoicingVo.getCompanyId());
|
|
|
+ invoice.setInvoiceType(invoicingVo.getInvoiceType());
|
|
|
+ // 开票类型 1、手续费 2、跟单费 3、驾意险手续费 4、驾意险跟单费 5、平台应收-车险 6、平台应收-非车险
|
|
|
+ if("1".equals(invoicingVo.getInvoiceType()) || "2".equals(invoicingVo.getInvoiceType())){
|
|
|
+ invoice.setInvoiceRiskType("10");
|
|
|
+ }else if("5".equals(invoicingVo.getInvoiceType()) || "6".equals(invoicingVo.getInvoiceType())){
|
|
|
+ invoice.setInvoiceRiskType("30");
|
|
|
+ }else{
|
|
|
+ invoice.setInvoiceRiskType("20");
|
|
|
+ }
|
|
|
+ invoice.setInvoiceParty(invoicingVo.getInvoiceParty());
|
|
|
+ invoice.setOverinflatedAmount(invoicingVo.getOverinflatedAmount());
|
|
|
+ invoice.setReceivableSupervisePremium(invoicingVo.getReceivablePremium());
|
|
|
+ invoice.setTaxPoint(invoicingVo.getTaxPoint());
|
|
|
+
|
|
|
+ List<InsPlyIncomeInvoiceLink> invoicingLinkList = new ArrayList();
|
|
|
+
|
|
|
+ invoicingVo.getIncomeIds().forEach(incomeId -> {
|
|
|
+ InsPlyIncomeInvoiceLink link = new InsPlyIncomeInvoiceLink();
|
|
|
+ link.setId(IdGenerate.nextId());
|
|
|
+ link.setInvoiceId(invoice.getId());
|
|
|
+ link.setIncomeId(incomeId);
|
|
|
+ link.setInvoiceType(invoicingVo.getInvoiceType());
|
|
|
+ invoicingLinkList.add(link);
|
|
|
+ });
|
|
|
+ insPlyIncomeInvoiceLinkMapper.insert(invoicingLinkList);
|
|
|
+ result.setInvoiceId(invoice.getId());
|
|
|
+ result.setSumPrice(null != invoicingVo.getReceivablePremium() ? invoicingVo.getReceivablePremium().toString() : null);
|
|
|
+
|
|
|
+ // ============================结算逻辑============================
|
|
|
+ // 实际已经收了的金额
|
|
|
+ BigDecimal actualReceivedAmount = this.getInvoicingAmount(settlementVo.getInvoicingId());
|
|
|
+
|
|
|
+ // 所有需要结算的金额
|
|
|
+ BigDecimal allToSettlement = invoice.getReceivableSupervisePremium().add(invoice.getOverinflatedAmount());
|
|
|
+ // 剩余的金额
|
|
|
+ BigDecimal surplusPremium = allToSettlement.subtract(actualReceivedAmount);
|
|
|
+ log.info("invoiceId=[{}],一共需要结算的金额[{}],实际已经结算的金额[{}],本次计划结算的金额[{}]",
|
|
|
+ settlementVo.getInvoicingId(), allToSettlement,actualReceivedAmount,settlementVo.getActualReceivedAmount());
|
|
|
+ // 校验是否超出了剩余的金额
|
|
|
+ AssertionUtils.isFail(surplusPremium.compareTo(settlementVo.getActualReceivedAmount()) < 0, "已超出应收金额,请核对!");
|
|
|
+
|
|
|
+ // 处理结算数据
|
|
|
+ // 未完全结算完成
|
|
|
+ InsPlyIncomeInvoiceSettlement settlement = new InsPlyIncomeInvoiceSettlement(invoice.getId(), settlementVo.getActualReceivedAmount(),
|
|
|
+ DateTime.now(), settlementVo.getPaymentDifference(), settlementVo.getPaymentReason());
|
|
|
+ insPlyIncomeInvoiceSettlementMapper.insert(settlement);
|
|
|
+
|
|
|
+ if (CollectionUtils.isNotEmpty(settlementVo.getAttachmentIds())) {
|
|
|
+ // 添加发票附件
|
|
|
+ List<InsPlyIncomeInvoiceSettlementFile> files = new ArrayList<>();
|
|
|
+ for (String fileId : settlementVo.getAttachmentIds()) {
|
|
|
+ InsPlyIncomeInvoiceSettlementFile file = new InsPlyIncomeInvoiceSettlementFile();
|
|
|
+ file.setId(IdGenerate.nextId());
|
|
|
+ file.setSettlementId(settlement.getId());
|
|
|
+ file.setFileId(fileId);
|
|
|
+ files.add(file);
|
|
|
+ }
|
|
|
+ insPlyIncomeInvoiceSettlementFileMapper.insert(files);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 判断是否已经结算完成
|
|
|
+ if (surplusPremium.compareTo(settlementVo.getActualReceivedAmount()) == 0) {
|
|
|
+ log.info("序号为[{}]的发票已经结算完成",invoice.getId());
|
|
|
+ // 更新发票状态
|
|
|
+ invoice.setStatus("1");
|
|
|
+ insPlyIncomeInvoiceMapper.insert(invoice);
|
|
|
+ // 判断是需要更新哪个字段
|
|
|
+ this.updateIncomeSettlementStatus(invoice.getInvoiceType(), invoicingVo.getIncomeIds());
|
|
|
+ }else{
|
|
|
+ log.info("invoiceId=[{}], 还剩[{}]钱没有结算",settlementVo.getInvoicingId(), surplusPremium.subtract(settlementVo.getActualReceivedAmount()));
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("平台结算异常. settlementVo=[{}]",JSONUtil.toJsonStr(settlementVo), e);
|
|
|
+ TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
|
|
|
+ throw new RuntimeException(e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
@Override
|
|
|
@Transactional(rollbackFor = Exception.class)
|
|
|
public boolean settlement(SettlementVo settlementVo) {
|
|
|
@@ -705,15 +876,15 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
|
|
|
// 获取应收的金额
|
|
|
InsPlyIncomeInvoice insPlyIncomeInvoice = insPlyIncomeInvoiceMapper.selectById(settlementVo.getInvoicingId());
|
|
|
AssertionUtils.isFail(Objects.isNull(insPlyIncomeInvoice), "发票数据不存在");
|
|
|
- // 实际已经收的了金额
|
|
|
- BigDecimal ctualReceivedAmount = this.getInvoicingAmount(settlementVo.getInvoicingId());
|
|
|
+ // 实际已经收了的金额
|
|
|
+ BigDecimal actualReceivedAmount = this.getInvoicingAmount(settlementVo.getInvoicingId());
|
|
|
|
|
|
// 所有需要结算的金额
|
|
|
BigDecimal allToSettlement = insPlyIncomeInvoice.getReceivableSupervisePremium().add(insPlyIncomeInvoice.getOverinflatedAmount());
|
|
|
// 剩余的金额
|
|
|
- BigDecimal surplusPremium = allToSettlement.subtract(ctualReceivedAmount);
|
|
|
+ BigDecimal surplusPremium = allToSettlement.subtract(actualReceivedAmount);
|
|
|
log.info("invoiceId=[{}],一共需要结算的金额[{}],实际已经结算的金额[{}],本次计划结算的金额[{}]",
|
|
|
- settlementVo.getInvoicingId(), allToSettlement,ctualReceivedAmount,settlementVo.getActualReceivedAmount());
|
|
|
+ settlementVo.getInvoicingId(), allToSettlement,actualReceivedAmount,settlementVo.getActualReceivedAmount());
|
|
|
// 校验是否超出了剩余的金额
|
|
|
AssertionUtils.isFail(surplusPremium.compareTo(settlementVo.getActualReceivedAmount()) < 0, "已超出应收金额,请核对!");
|
|
|
|
|
|
@@ -724,6 +895,7 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
|
|
|
insPlyIncomeInvoiceSettlementMapper.insert(settlement);
|
|
|
|
|
|
if (CollectionUtils.isNotEmpty(settlementVo.getAttachmentIds())) {
|
|
|
+ log.info("结算的凭证是:settlementVo.getAttachmentIds()=[{}]", JSONUtil.toJsonStr(settlementVo.getAttachmentIds()));
|
|
|
// 添加发票附件
|
|
|
List<InsPlyIncomeInvoiceSettlementFile> files = new ArrayList<>();
|
|
|
for (String fileId : settlementVo.getAttachmentIds()) {
|
|
|
@@ -779,7 +951,7 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
|
|
|
List<SuperviseExcelVo> dataList = listener.getDataList();
|
|
|
return dataList;
|
|
|
} catch (Exception e) {
|
|
|
- e.printStackTrace();
|
|
|
+ log.error("导入excel异常。",e);
|
|
|
return null;
|
|
|
}
|
|
|
}
|
|
|
@@ -1080,7 +1252,8 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
|
|
|
// 数据库已存在 → 继续后续校验
|
|
|
// 判断已开票 / 已结算
|
|
|
if ("1".equals(existIncome.getSuperviseSettlement()) || "1".equals(existIncome.getOtherSettlement())
|
|
|
- || "1".equals(existIncome.getJySuperviseSettlement()) || "1".equals(existIncome.getJyOtherSettlement())) {
|
|
|
+ || "1".equals(existIncome.getJySuperviseSettlement()) || "1".equals(existIncome.getJyOtherSettlement())
|
|
|
+ || "1".equals(existIncome.getPlatformSuperviseSettlement()) || "1".equals(existIncome.getPlatformOtherSettlement())) {
|
|
|
failedNumber++;
|
|
|
vo.setErrorMessage("应收数据已结算");
|
|
|
failedExcel.add(vo);
|
|
|
@@ -1450,6 +1623,8 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
|
|
|
case "2" -> dto.setInvoiceType("跟单费");
|
|
|
case "3" -> dto.setInvoiceType("驾意险手续费");
|
|
|
case "4" -> dto.setInvoiceType("驾意险跟单费");
|
|
|
+ case "5" -> dto.setInvoiceType("平台协议车险应收");
|
|
|
+ case "6" -> dto.setInvoiceType("平台协议非车险应收");
|
|
|
}
|
|
|
dto.setInvoiceTypeName(Constant.invoiceRiskTypeMap.get(Objects.toString(dto.getInvoiceType())));
|
|
|
LambdaQueryWrapper<InsPlyIncomeInvoiceSettlementFile> wrapper = new LambdaQueryWrapper<InsPlyIncomeInvoiceSettlementFile>();
|