Commit 309dd01b8a4457e01569443ea726fa3e88f2f124

Authored by yeqianyong
1 parent a1eb252c

楚江erp:1、台账报表统计逻辑调整;2、定时任务更新台账欠款状态

... ... @@ -114,7 +114,7 @@ public class ReceiptLedgerReportBo {
114 114 /**
115 115 * 授时状态
116 116 */
117   - @ApiModelProperty("总欠款")
  117 + @ApiModelProperty("授时状态")
118 118 private String timingStatus;
119 119
120 120 /**
... ...
... ... @@ -179,7 +179,7 @@ public class ReceiptLedgerInfoController extends DefaultBaseController {
179 179 /**
180 180 * 重新生成新的台账数据
181 181 */
182   - @ApiOperation("自动生成台账明细数据")
  182 + @ApiOperation("重新生成新的台账数据")
183 183 @GetMapping("/againGenerate")
184 184 @Scheduled(cron = "0 30 2 1 * ?")
185 185 public InvokeResult<Void> againGenerate() {
... ... @@ -263,11 +263,23 @@ public class ReceiptLedgerInfoController extends DefaultBaseController {
263 263 /**
264 264 * 冻结欠款客户订货单、草稿要车单数据
265 265 */
266   - @ApiOperation("自动生成台账明细数据")
  266 + @ApiOperation("自动冻结")
267 267 @GetMapping("/autoFreeze")
268 268 @Scheduled(cron = "0 50 2 * * ?")
269 269 public InvokeResult<Void> autoFreeze() {
270 270 receiptLedgerInfoService.autoFreeze(null);
271 271 return InvokeResultBuilder.success();
272 272 }
  273 +
  274 +
  275 + /**
  276 + * 更新欠款状态
  277 + */
  278 + @ApiOperation("更新欠款状态")
  279 + @GetMapping("/autoUpdateDebtStatus")
  280 + @Scheduled(cron = "0 50 1 * * ?")
  281 + public InvokeResult<Void> autoUpdateDebtStatus() {
  282 + receiptLedgerInfoService.autoUpdateDebtStatus();
  283 + return InvokeResultBuilder.success();
  284 + }
273 285 }
... ...
... ... @@ -49,10 +49,13 @@ import java.math.BigDecimal;
49 49 import java.math.RoundingMode;
50 50 import java.time.LocalDate;
51 51 import java.time.LocalDateTime;
  52 +import java.time.YearMonth;
52 53 import java.time.temporal.ChronoUnit;
53 54 import java.time.temporal.TemporalAdjusters;
54 55 import java.util.*;
55 56 import java.util.function.Function;
  57 +import java.util.regex.Matcher;
  58 +import java.util.regex.Pattern;
56 59 import java.util.stream.Collectors;
57 60
58 61
... ... @@ -495,13 +498,17 @@ public class ReceiptLedgerInfoServiceImpl extends BaseMpServiceImpl<ReceiptLedge
495 498 return result;
496 499 }
497 500 List<String> shortNames = dataList.stream().map(ReceiptLedgerReportBo::getCustomerShortName).distinct().collect(Collectors.toList());
  501 + // 根据简称获取台账明细数据
  502 + Map<String, List<ReceiptLedgerInfo>> agreementDataMap = getLedgerInfoByShortName(shortNames, Boolean.FALSE);
  503 + Map<String, List<ReceiptLedgerInfo>> overdueDataMap = getLedgerInfoByShortName(shortNames, Boolean.TRUE);
498 504 // 只统计约定内、一次、二次协调、清欠阶段
499 505 List<String> debtStatusList = new ArrayList<>();
500 506 debtStatusList.add("AGREEMENT");
501 507 debtStatusList.add("FIRST_COORDINATE");
502 508 debtStatusList.add("SECOND_COORDINATE");
503 509 debtStatusList.add("CLEAR_DEBTS");
504   - List<Map<String, Object>> debtAmountList = getBaseMapper().statisticsDeptByShortName(shortNames, debtStatusList);
  510 + debtStatusList.add("DEPOSIT");
  511 + List<Map<String, Object>> debtAmountList = getBaseMapper().statisticsDebtByShortName(shortNames, debtStatusList, "INSIDE");
505 512 if (CollectionUtils.isEmpty(debtAmountList)) {
506 513 return result;
507 514 }
... ... @@ -525,12 +532,8 @@ public class ReceiptLedgerInfoServiceImpl extends BaseMpServiceImpl<ReceiptLedge
525 532 if (CollectionUtils.isEmpty(list)) {
526 533 continue;
527 534 }
528   - BigDecimal debtTotal = BigDecimal.ZERO;
529   - BigDecimal agreementTotal = BigDecimal.ZERO;
530   - BigDecimal firstCoordinateTotal = BigDecimal.ZERO;
531   - BigDecimal secondCoordinateTotal = BigDecimal.ZERO;
532   - BigDecimal clearDebtTotal = BigDecimal.ZERO;
533 535 long waitDeliveredOrderTotal = 0;
  536 + List<String> creditStatusList = new ArrayList<>();
534 537 List<String> debtStates = new ArrayList<>();
535 538 Map<String, ReceiptLedgerReportDetail> reportDetailMap = new LinkedHashMap<>();
536 539 for (Map<String, Object> map : list) {
... ... @@ -545,24 +548,31 @@ public class ReceiptLedgerInfoServiceImpl extends BaseMpServiceImpl<ReceiptLedge
545 548 }
546 549 reportDetail.setCustomerName(customerName);
547 550 reportDetail.setCreditStatus(debtStatus);
548   - if ("AGREEMENT".equals(debtStatus)) {
549   - reportDetail.setAgreement(valueConvert(debtAmount));
550   - agreementTotal = agreementTotal.add(debtAmount);
  551 + if ("AGREEMENT".equals(debtStatus) || "DEPOSIT".equals(debtStatus)) {
  552 + BigDecimal agreement = reportDetail.getAgreement();
  553 + if (agreement == null) {
  554 + agreement = debtAmount;
  555 + } else {
  556 + agreement = agreement.add(debtAmount);
  557 + }
  558 + reportDetail.setAgreement(valueConvert(agreement));
551 559 reportDetail.setCreditStatus("约定内");
552 560 } else if ("FIRST_COORDINATE".equals(debtStatus)) {
553 561 reportDetail.setFirstCoordinate(valueConvert(debtAmount));
554   - firstCoordinateTotal = firstCoordinateTotal.add(debtAmount);
555 562 reportDetail.setCreditStatus("超期1");
556 563 } else if ("SECOND_COORDINATE".equals(debtStatus)) {
557 564 reportDetail.setSecondCoordinate(valueConvert(debtAmount));
558   - secondCoordinateTotal = secondCoordinateTotal.add(debtAmount);
559 565 reportDetail.setCreditStatus("超期2");
560 566 } else if ("CLEAR_DEBTS".equals(debtStatus)) {
561 567 reportDetail.setClearDebt(valueConvert(debtAmount));
562   - clearDebtTotal = clearDebtTotal.add(debtAmount);
563 568 reportDetail.setCreditStatus("超期3");
564 569 }
565   - debtTotal = debtTotal.add(debtAmount);
  570 + // 计算超额数据(授信状态)
  571 + String creditStatus = calculateExcess(debtAmount, report.getQuota());
  572 + if (StringUtils.isNotBlank(creditStatus)) {
  573 + report.setCreditStatus(creditStatus);
  574 + creditStatusList.add(creditStatus);
  575 + }
566 576 // 统计待交付订单数
567 577 Long count = orderCountMap.get(customerName);
568 578 if (count != null) {
... ... @@ -575,14 +585,15 @@ public class ReceiptLedgerInfoServiceImpl extends BaseMpServiceImpl<ReceiptLedge
575 585 List<ReceiptLedgerReportDetail> details = new ArrayList<>(reportDetailMap.values());
576 586 report.setDetailList(details);
577 587
578   - report.setDebtTotal(valueConvert(debtTotal));
579   - report.setAgreementTotal(valueConvert(agreementTotal));
580   - report.setFirstCoordinateTotal(valueConvert(firstCoordinateTotal));
581   - report.setSecondCoordinateTotal(valueConvert(secondCoordinateTotal));
582   - report.setClearDebtTotal(valueConvert(clearDebtTotal));
583   - report.setCreditStatus(getHighestPriorityStatus(debtStates));
584   - // 处理超额逻辑
  588 + // 处理约定内、一次协调、二次协调、清欠小计数据
  589 + handleSubtotal(agreementDataMap, overdueDataMap, report);
  590 + // 授时状态
  591 + report.setTimingStatus(getHighestPriorityStatus(debtStates));
  592 + // 授信状态
  593 + report.setCreditStatus(findMaxPercentageString(creditStatusList));
585 594 report.setWaitDeliveredOrderTotal(waitDeliveredOrderTotal);
  595 + BigDecimal debtTotal = report.getDebtTotal();
  596 + report.setDebtTotal(valueConvert(debtTotal));
586 597 }
587 598 return result;
588 599 }
... ... @@ -852,6 +863,36 @@ public class ReceiptLedgerInfoServiceImpl extends BaseMpServiceImpl<ReceiptLedge
852 863 shipmentsPlanDetailService.delByOrderIds(needFreezeOrderIds);
853 864 }
854 865
  866 + @Override
  867 + public void autoUpdateDebtStatus() {
  868 + // 获取当月所有台账明细数据
  869 + QueryReceiptLedgerInfoVo ledgerInfoVo = new QueryReceiptLedgerInfoVo();
  870 + LocalDateTime startTime = YearMonth.now()
  871 + .atDay(1)
  872 + .atStartOfDay();
  873 + LocalDateTime endTime = YearMonth.now()
  874 + .atEndOfMonth()
  875 + .atTime(23, 59, 59);
  876 + ledgerInfoVo.setCreateTimeStart(startTime.toString());
  877 + ledgerInfoVo.setCreateTimeEnd(endTime.toString());
  878 + List<ReceiptLedgerInfo> ledgerInfoList = getBaseMapper().query(ledgerInfoVo);
  879 + if (CollectionUtils.isEmpty(ledgerInfoList)) {
  880 + return;
  881 + }
  882 + for (ReceiptLedgerInfo info : ledgerInfoList) {
  883 + BigDecimal endAccountReceivable = info.getEndAccountReceivable();
  884 + LocalDate processedDate = info.getProcessedDate();
  885 + if (processedDate != null) {
  886 + // 更新欠款状态
  887 + String debtStatus = getSettlementStatus(endAccountReceivable, processedDate);
  888 + LambdaUpdateWrapper<ReceiptLedgerInfo> updateWrapper = Wrappers.lambdaUpdate(ReceiptLedgerInfo.class);
  889 + updateWrapper.set(ReceiptLedgerInfo::getDebtStatus, debtStatus)
  890 + .eq(ReceiptLedgerInfo::getId, info.getId());
  891 + getBaseMapper().update(updateWrapper);
  892 + }
  893 + }
  894 + }
  895 +
855 896
856 897 /**
857 898 * 从多个状态中获取最高优先级的状态
... ... @@ -911,4 +952,96 @@ public class ReceiptLedgerInfoServiceImpl extends BaseMpServiceImpl<ReceiptLedge
911 952 OpLogUtil.setVariable("id", data.getId());
912 953 OpLogUtil.setExtra(vo);
913 954 }
  955 +
  956 +
  957 + /**
  958 + * 计算超额比例
  959 + *
  960 + * @param amount 欠款金额
  961 + * @param quota 额度
  962 + * @return String
  963 + */
  964 + private String calculateExcess(BigDecimal amount, BigDecimal quota) {
  965 + if (amount == null || amount.compareTo(BigDecimal.ZERO) <= 0
  966 + || quota == null || quota.compareTo(BigDecimal.ZERO) <= 0) {
  967 + return null;
  968 + }
  969 + // 万元转换成元
  970 + quota = quota.multiply(new BigDecimal(10000));
  971 + if (amount.compareTo(quota) <= 0) {
  972 + return null;
  973 + }
  974 + BigDecimal result = amount.subtract(quota)
  975 + .divide(quota, 2, RoundingMode.HALF_UP)
  976 + .multiply(new BigDecimal(100))
  977 + .divide(new BigDecimal("5"), 0, RoundingMode.CEILING)
  978 + .multiply(new BigDecimal("5"));
  979 +
  980 + return "超额" + result + "%";
  981 + }
  982 +
  983 +
  984 + /**
  985 + * 获取最大值对应的完整字符串
  986 + */
  987 + public static String findMaxPercentageString(List<String> dataList) {
  988 + if (CollectionUtils.isEmpty(dataList)) {
  989 + return null;
  990 + }
  991 + String maxString = null;
  992 + int maxValue = 0;
  993 + for (String str : dataList) {
  994 + // 提取数字
  995 + Pattern pattern = Pattern.compile("(\\d+)%");
  996 + Matcher matcher = pattern.matcher(str);
  997 + if (matcher.find()) {
  998 + int value = Integer.parseInt(matcher.group(1));
  999 + if (value > maxValue) {
  1000 + maxValue = value;
  1001 + maxString = str;
  1002 + }
  1003 + }
  1004 + }
  1005 + return maxString;
  1006 + }
  1007 +
  1008 +
  1009 + /**
  1010 + * 处理“小计”数据
  1011 + *
  1012 + * @param agreementDataMap 约定内数据集合
  1013 + * @param overdueDataMap 逾期数据集合
  1014 + * @param report 报表数据
  1015 + */
  1016 + private void handleSubtotal(Map<String, List<ReceiptLedgerInfo>> agreementDataMap, Map<String, List<ReceiptLedgerInfo>> overdueDataMap
  1017 + , ReceiptLedgerReportBo report) {
  1018 + String customerShortName = report.getCustomerShortName();
  1019 + }
  1020 +
  1021 +
  1022 + /**
  1023 + * 获取台账明细数据
  1024 + * 根据客户简称、状态分组
  1025 + *
  1026 + * @param shortNames 客户简称集合
  1027 + * @param overdue 是否逾期
  1028 + * @return Map<String, List<ReceiptLedgerInfo>>
  1029 + */
  1030 + private Map<String, List<ReceiptLedgerInfo>> getLedgerInfoByShortName(List<String> shortNames, Boolean overdue) {
  1031 + // 根据简称获取台账明细
  1032 + List<ReceiptLedgerInfo> ledgerInfoList = getBaseMapper().queryByShortName(shortNames, "INSIDE", overdue);
  1033 + if (CollectionUtils.isEmpty(ledgerInfoList)) {
  1034 + return Collections.emptyMap();
  1035 + }
  1036 + // 根据欠款状态分组
  1037 + Map<String, List<ReceiptLedgerInfo>> ledgerInfoMap = new HashMap<>();
  1038 + for (ReceiptLedgerInfo ledgerInfo : ledgerInfoList) {
  1039 + String debtStatus = ledgerInfo.getDebtStatus();
  1040 + String shortName = ledgerInfo.getCustomerShortName();
  1041 + String key = shortName + "_" + debtStatus;
  1042 + List<ReceiptLedgerInfo> list = ledgerInfoMap.computeIfAbsent(key, k -> new ArrayList<>());
  1043 + list.add(ledgerInfo);
  1044 + }
  1045 + return ledgerInfoMap;
  1046 + }
914 1047 }
... ...
... ... @@ -56,5 +56,16 @@ public interface ReceiptLedgerInfoMapper extends BaseMapper<ReceiptLedgerInfo> {
56 56 * @param shortNames 客户简称
57 57 * @return List<Map<String, BigDecimal>>
58 58 */
59   - List<Map<String, Object>> statisticsDeptByShortName(@Param("shortNames") List<String> shortNames, @Param("debtStatusList") List<String> debtStatusList);
  59 + List<Map<String, Object>> statisticsDebtByShortName(@Param("shortNames") List<String> shortNames, @Param("debtStatusList") List<String> debtStatusList
  60 + , @Param("type") String type);
  61 +
  62 + /**
  63 + * 根据客户简称获取台账明细数据
  64 + *
  65 + * @param shortNames 客户简称集合
  66 + * @param type 类型(内贸、外贸)
  67 + * @param overdue 是否逾期
  68 + * @return List<ReceiptLedgerInfo>
  69 + */
  70 + List<ReceiptLedgerInfo> queryByShortName(@Param("shortNames") List<String> shortNames, @Param("type") String type, @Param("overdue") Boolean overdue);
60 71 }
... ...
... ... @@ -143,4 +143,9 @@ public interface ReceiptLedgerInfoService extends BaseMpService<ReceiptLedgerInf
143 143 * 冻结欠款客户,管控发货
144 144 */
145 145 void autoFreeze(String customerId);
  146 +
  147 + /**
  148 + * 更新欠款状态
  149 + */
  150 + void autoUpdateDebtStatus();
146 151 }
... ...
... ... @@ -238,6 +238,7 @@
238 238 left join customer_credit cc on tb.customer_id = cc.company_id
239 239 left join receipt_ledger_info rl on tb.id = rl.customer_short_id
240 240 <where>
  241 + and rl.type = 'INSIDE'
241 242 <if test="vo.customerType != null and vo.customerType != ''">
242 243 and tb.type = #{vo.customerType}
243 244 </if>
... ... @@ -258,7 +259,7 @@
258 259 </if>
259 260 </select>
260 261
261   - <select id="statisticsDeptByShortName" resultType="java.util.Map">
  262 + <select id="statisticsDebtByShortName" resultType="java.util.Map">
262 263 select c.name,
263 264 cs.short_name,
264 265 tb.debt_status,
... ... @@ -266,15 +267,53 @@
266 267 from receipt_ledger_info tb
267 268 inner join base_data_customer_short cs on tb.customer_id = cs.customer_id
268 269 inner join base_data_customer c on tb.customer_id = c.id
269   - where cs.short_name in
270   - <foreach collection="shortNames" open="(" separator="," close=")" item="item">
271   - #{item}
272   - </foreach>
273   - and tb.debt_status in
274   - <foreach collection="debtStatusList" open="(" separator="," close=")" item="item">
275   - #{item}
276   - </foreach>
  270 + <where>
  271 + <if test="type != null and type != ''">
  272 + and tb.type = #{type}
  273 + </if>
  274 + and cs.short_name in
  275 + <foreach collection="shortNames" open="(" separator="," close=")" item="item">
  276 + #{item}
  277 + </foreach>
  278 + and tb.debt_status in
  279 + <foreach collection="debtStatusList" open="(" separator="," close=")" item="item">
  280 + #{item}
  281 + </foreach>
  282 + </where>
277 283 and tb.debt_status is not null
278 284 group by c.name,cs.short_name,tb.debt_status
279 285 </select>
  286 +
  287 + <select id="queryByShortName" resultType="com.lframework.xingyun.sc.entity.ReceiptLedgerInfo">
  288 + select tb.*,
  289 + cs.short_name as customer_short_name
  290 + from receipt_ledger_info tb
  291 + left join base_data_customer_short cs on tb.customer_id = cs.customer_id
  292 + <where>
  293 + <if test="type != null and type != ''">
  294 + and tb.type = #{type}
  295 + </if>
  296 + <if test="shortNames != null and shortNames.size() > 0">
  297 + and cs.short_name in
  298 + <foreach collection="shortNames" open="(" separator="," close=")" item="item">
  299 + #{item}
  300 + </foreach>
  301 + </if>
  302 + <if test="overdue != null">
  303 + <choose>
  304 + <when test="overdue == true">
  305 + and tb.processed_date &lt; curdate()
  306 + order by tb.processed_date desc,tb.start_account_receivable asc
  307 + </when>
  308 + <otherwise>
  309 + and (tb.processed_date >= curdate() or tb.end_account_receivable &lt; 0)
  310 + order by
  311 + case when tb.processed_date is null then 1 else 0 end,
  312 + tb.processed_date,
  313 + tb.start_account_receivable
  314 + </otherwise>
  315 + </choose>
  316 + </if>
  317 + </where>
  318 + </select>
280 319 </mapper>
... ...