|
|
@@ -397,6 +397,15 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
|
|
|
*/
|
|
|
List<InsPlyIncome> fillOtherInfo(List<InsPlyIncome> records){
|
|
|
if(CollUtil.isNotEmpty(records)){
|
|
|
+ List<String> incomeIds = records.stream().map(InsPlyIncome::getId).toList();
|
|
|
+ InvoicingVo invoicingVo = new InvoicingVo();
|
|
|
+ invoicingVo.setIncomeIds(incomeIds);
|
|
|
+ List<InsPlyIncomeInvoiceLink> links = baseMapper.queryIncomeBindInvoice(invoicingVo);
|
|
|
+ Map<String, String> income2InvoceIdMap = links.stream()
|
|
|
+ .filter(action -> StrUtil.isNotEmpty(action.getIncomeId()))
|
|
|
+ .collect(Collectors.toMap(InsPlyIncomeInvoiceLink::getIncomeId, InsPlyIncomeInvoiceLink::getInvoiceId, (oleItem, newItem) -> oleItem));
|
|
|
+
|
|
|
+
|
|
|
Map<String, String> typeAttrMaps = sysUserJzgInfoSalesmanService.queryYwyTypeAttrMap();
|
|
|
records.forEach(insPlyIncome -> {
|
|
|
if("0".equals(insPlyIncome.getSettlementStatus())){
|
|
|
@@ -413,6 +422,10 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
|
|
|
// 费用信息
|
|
|
List<InsFeeOrders> insFeeOrderByOrderNo = insFeeOrdersClient.getInsFeeOrderByOrderNo(insPlyIncome.getOrderNo());
|
|
|
insPlyIncome.setInsFeeOrders(CollUtil.getFirst(insFeeOrderByOrderNo));
|
|
|
+
|
|
|
+ String invoiceId = income2InvoceIdMap.get(insPlyIncome.getId());
|
|
|
+ insPlyIncome.setInvoiceStatusName(StrUtil.isEmpty(invoiceId)? "未开票":"已开票");
|
|
|
+ insPlyIncome.setInvoiceId(invoiceId);
|
|
|
});
|
|
|
}
|
|
|
return records;
|
|
|
@@ -423,65 +436,147 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
|
|
|
return baseMapper.getReceivableList(receivableQueryVo);
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 查询订单绑定的发票信息
|
|
|
+ *
|
|
|
+ * @param invoicingVo
|
|
|
+ * @return List<String> 订单绑定的发票号
|
|
|
+ * @author lipf
|
|
|
+ * @date 2026/5/21 11:59
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public List<String> queryIncomeBindInvoice(InvoicingVo invoicingVo) {
|
|
|
+ log.info("查询订单绑定的发票信息:invoicingVo=[{}]", JSONUtil.toJsonStr(invoicingVo));
|
|
|
+ List<InsPlyIncomeInvoiceLink> links = baseMapper.queryIncomeBindInvoice(invoicingVo);
|
|
|
+ List<String> invoiceIds = links.stream().map(InsPlyIncomeInvoiceLink::getInvoiceId).distinct().toList();
|
|
|
+ log.info("查询订单绑定的发票信息:invoicingVo=[{}].invoiceIds=[{}]", JSONUtil.toJsonStr(invoicingVo), JSONUtil.toJsonStr(invoiceIds));
|
|
|
+ return invoiceIds;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 开票重复校验
|
|
|
+ * 功能:DB+Redis双重校验,防止并发重复开票
|
|
|
+ *
|
|
|
+ * @param invoicingVo 开票参数
|
|
|
+ * @return true=允许开票,false=禁止开票
|
|
|
+ */
|
|
|
@Override
|
|
|
public boolean invoicingCheck(InvoicingVo invoicingVo) {
|
|
|
+ // 1. 基础参数校验
|
|
|
+ if (invoicingVo == null || CollUtil.isEmpty(invoicingVo.getIncomeIds()) || StrUtil.isBlank(invoicingVo.getInvoiceType())) {
|
|
|
+ log.error("开票校验参数不能为空");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 数据库校验:是否已存在开票记录
|
|
|
Integer count = baseMapper.invoicingCheck(invoicingVo);
|
|
|
- RKeys keys = redissonClient.getKeys();
|
|
|
- Iterable<String> allKeys = null;
|
|
|
- String redisKey = null;
|
|
|
- if (invoicingVo.getInvoiceType().equals("1")) {
|
|
|
- redisKey = CAR_INVOICING_COMMISSION_LOCK;
|
|
|
- } else if (invoicingVo.getInvoiceType().equals("2")) {
|
|
|
- redisKey = CAR_INVOICING_OTHER_LOCK;
|
|
|
- } else if (invoicingVo.getInvoiceType().equals("3")) {
|
|
|
- redisKey = JY_INVOICING_COMMISSION_LOCK;
|
|
|
- } else if (invoicingVo.getInvoiceType().equals("4")) {
|
|
|
- redisKey = JY_INVOICING_OTHER_LOCK;
|
|
|
+ if (count > 0) {
|
|
|
+ log.info("数据库已存在开票记录,直接禁止");
|
|
|
+ return false;
|
|
|
}
|
|
|
- allKeys = keys.getKeysByPattern(redisKey + "*");
|
|
|
- //提取所有redis的key 然后遍历是否存在重复的id
|
|
|
- for (String key : allKeys) {
|
|
|
- // 过滤掉自己的redis key
|
|
|
- if (!key.equals(key + baseController.getUserName())) {
|
|
|
- RBucket<Object> bucket = redissonClient.getBucket(key);
|
|
|
- String incomeIds = bucket.get().toString();
|
|
|
- incomeIds = incomeIds.substring(1, incomeIds.length() - 1);
|
|
|
- List<String> incomeIdList = Arrays.stream(incomeIds.split(",")).collect(Collectors.toList());
|
|
|
- boolean hasDuplicate = invoicingVo.getIncomeIds().stream().anyMatch(incomeIdList::contains);
|
|
|
- if (hasDuplicate) {
|
|
|
- return false;
|
|
|
- }
|
|
|
+
|
|
|
+ // 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;
|
|
|
+ default -> throw new SystemException("不支持的开票类型");
|
|
|
+ };
|
|
|
+
|
|
|
+ // 4. 当前用户的Redis Key
|
|
|
+ String currentUserName = baseController.getUserName();
|
|
|
+ String currentRedisKey = redisKeyPrefix + currentUserName;
|
|
|
+
|
|
|
+ // 5. Redis校验:同类型下,是否有其他用户占用了相同incomeId
|
|
|
+ // 把锁key存入同一个set,避免使用keys命令
|
|
|
+ RKeys keys = redissonClient.getKeys();
|
|
|
+ Iterable<String> allLockKeys = keys.getKeysByPattern(redisKeyPrefix + "*");
|
|
|
+
|
|
|
+ for (String lockKey : allLockKeys) {
|
|
|
+ // 正确过滤自己的key
|
|
|
+ if (currentRedisKey.equals(lockKey)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 安全获取缓存值
|
|
|
+ RBucket<Object> bucket = redissonClient.getBucket(lockKey);
|
|
|
+ Object cacheObj = bucket.get();
|
|
|
+ if (cacheObj == null) {
|
|
|
+ continue;
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- if (count == 0) {
|
|
|
- // 设置缓存
|
|
|
- RBucket<Object> bucket = redissonClient.getBucket(redisKey + baseController.getUserName());
|
|
|
- bucket.set(invoicingVo.getIncomeIds(), 10, TimeUnit.MINUTES);
|
|
|
+ // 解析缓存中的incomeId集合
|
|
|
+ List<String> cacheIncomeIds = this.parseIncomeIdsFromRedis(cacheObj.toString());
|
|
|
+ // 校验重复
|
|
|
+ boolean duplicate = invoicingVo.getIncomeIds().stream().anyMatch(cacheIncomeIds::contains);
|
|
|
+ if (duplicate) {
|
|
|
+ log.info("Redis校验重复,lockKey:{}", lockKey);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- return count == 0;
|
|
|
+ // 6. 校验通过,存入Redis锁(10分钟自动过期)
|
|
|
+ RBucket<Object> bucket = redissonClient.getBucket(currentRedisKey);
|
|
|
+ bucket.set(invoicingVo.getIncomeIds(), 10, TimeUnit.MINUTES);
|
|
|
+ log.info("开票校验通过,Redis加锁成功,key:{}", currentRedisKey);
|
|
|
+
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 从Redis字符串解析收入ID集合(安全解析,防止异常)
|
|
|
+ */
|
|
|
+ private List<String> parseIncomeIdsFromRedis(String incomeIdsStr) {
|
|
|
+ try {
|
|
|
+ if (StrUtil.isBlank(incomeIdsStr) || !incomeIdsStr.startsWith("[") || !incomeIdsStr.endsWith("]")) {
|
|
|
+ return Collections.emptyList();
|
|
|
+ }
|
|
|
+ String content = incomeIdsStr.substring(1, incomeIdsStr.length() - 1).trim();
|
|
|
+ if (StrUtil.isBlank(content)) {
|
|
|
+ return Collections.emptyList();
|
|
|
+ }
|
|
|
+ return Arrays.stream(content.split(","))
|
|
|
+ .map(String::trim)
|
|
|
+ .collect(Collectors.toList());
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("解析Redis收入ID异常", e);
|
|
|
+ return Collections.emptyList();
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public BigDecimal getReceivableAmount(InvoicingVo invoicingVo) {
|
|
|
String invoiceType = invoicingVo.getInvoiceType();
|
|
|
+ List<String> orderNos = invoicingVo.getOrderNos();
|
|
|
+ orderNos = orderNos.stream()
|
|
|
+ .filter(s -> s != null && !s.trim().isEmpty())
|
|
|
+ .map(String::trim)
|
|
|
+ .distinct() // 可选,去重
|
|
|
+ .collect(Collectors.toList());
|
|
|
+ // 修改后(返回总手续费 = 交强险+商业险+驾意险 手续费之和)
|
|
|
+ Map<String, Object> map = baseMapper.getJqSumReceivable(orderNos);
|
|
|
+ BigDecimal jqCommissionPremium = (BigDecimal) Optional.ofNullable(map.get("jqCommissionPremium")).orElse(BigDecimal.ZERO);
|
|
|
+ BigDecimal syCommissionPremium = (BigDecimal) Optional.ofNullable(map.get("syCommissionPremium")).orElse(BigDecimal.ZERO);
|
|
|
+ BigDecimal jyCommissionPremium = (BigDecimal) Optional.ofNullable(map.get("jyCommissionPremium")).orElse(BigDecimal.ZERO);
|
|
|
+ BigDecimal jqFollowPremium = (BigDecimal) Optional.ofNullable(map.get("jqFollowPremium")).orElse(BigDecimal.ZERO);
|
|
|
+ BigDecimal syFollowPremium = (BigDecimal) Optional.ofNullable(map.get("syFollowPremium")).orElse(BigDecimal.ZERO);
|
|
|
+ BigDecimal jyFollowPremium = (BigDecimal) Optional.ofNullable(map.get("jyFollowPremium")).orElse(BigDecimal.ZERO);
|
|
|
+
|
|
|
// 私有手续费 应收金额
|
|
|
+ // 交强的总手续费(jq_commission_premium) + 商业的总手续费(sy_commission_premium)
|
|
|
if (invoiceType.equals("1")) {
|
|
|
- List<String> orderNos = invoicingVo.getOrderNos();
|
|
|
- orderNos = orderNos.stream()
|
|
|
- .filter(s -> s != null && !s.trim().isEmpty())
|
|
|
- .map(String::trim)
|
|
|
- .distinct() // 可选,去重
|
|
|
- .collect(Collectors.toList());
|
|
|
- String jqSumReceivable = baseMapper.getJqSumReceivable(orderNos);
|
|
|
- return new BigDecimal(jqSumReceivable);
|
|
|
+ return jqCommissionPremium.add(syCommissionPremium);
|
|
|
} else if (invoiceType.equals("2")) {
|
|
|
-
|
|
|
+ // 交强的总跟单费(jq_follow_premium) + 商业的总跟单费(sy_follow_premium)
|
|
|
+ return jqFollowPremium.add(syFollowPremium);
|
|
|
} else if (invoiceType.equals("3")) {
|
|
|
-
|
|
|
+ // 驾意险的总手续费(jy_commission_premium)
|
|
|
+ return jyCommissionPremium;
|
|
|
} else if (invoiceType.equals("4")) {
|
|
|
-
|
|
|
+ // 驾意险的总跟单费(jy_follow_premium)
|
|
|
+ return jyFollowPremium;
|
|
|
}
|
|
|
return null;
|
|
|
}
|
|
|
@@ -522,11 +617,12 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
|
|
|
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(invoicingVo.getReceivablePremium().toString());
|
|
|
+ result.setSumPrice(null != invoicingVo.getReceivablePremium() ? invoicingVo.getReceivablePremium().toString() : null);
|
|
|
return result;
|
|
|
} catch (Exception e) {
|
|
|
log.info("开票异常.invoicingVo=[{}]",JSONUtil.toJsonStr(invoicingVo), e);
|