Commit 309dd01b8a4457e01569443ea726fa3e88f2f124

Authored by yeqianyong
1 parent a1eb252c

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

@@ -114,7 +114,7 @@ public class ReceiptLedgerReportBo { @@ -114,7 +114,7 @@ public class ReceiptLedgerReportBo {
114 /** 114 /**
115 * 授时状态 115 * 授时状态
116 */ 116 */
117 - @ApiModelProperty("总欠款") 117 + @ApiModelProperty("授时状态")
118 private String timingStatus; 118 private String timingStatus;
119 119
120 /** 120 /**
@@ -179,7 +179,7 @@ public class ReceiptLedgerInfoController extends DefaultBaseController { @@ -179,7 +179,7 @@ public class ReceiptLedgerInfoController extends DefaultBaseController {
179 /** 179 /**
180 * 重新生成新的台账数据 180 * 重新生成新的台账数据
181 */ 181 */
182 - @ApiOperation("自动生成台账明细数据") 182 + @ApiOperation("重新生成新的台账数据")
183 @GetMapping("/againGenerate") 183 @GetMapping("/againGenerate")
184 @Scheduled(cron = "0 30 2 1 * ?") 184 @Scheduled(cron = "0 30 2 1 * ?")
185 public InvokeResult<Void> againGenerate() { 185 public InvokeResult<Void> againGenerate() {
@@ -263,11 +263,23 @@ public class ReceiptLedgerInfoController extends DefaultBaseController { @@ -263,11 +263,23 @@ public class ReceiptLedgerInfoController extends DefaultBaseController {
263 /** 263 /**
264 * 冻结欠款客户订货单、草稿要车单数据 264 * 冻结欠款客户订货单、草稿要车单数据
265 */ 265 */
266 - @ApiOperation("自动生成台账明细数据") 266 + @ApiOperation("自动冻结")
267 @GetMapping("/autoFreeze") 267 @GetMapping("/autoFreeze")
268 @Scheduled(cron = "0 50 2 * * ?") 268 @Scheduled(cron = "0 50 2 * * ?")
269 public InvokeResult<Void> autoFreeze() { 269 public InvokeResult<Void> autoFreeze() {
270 receiptLedgerInfoService.autoFreeze(null); 270 receiptLedgerInfoService.autoFreeze(null);
271 return InvokeResultBuilder.success(); 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,10 +49,13 @@ import java.math.BigDecimal;
49 import java.math.RoundingMode; 49 import java.math.RoundingMode;
50 import java.time.LocalDate; 50 import java.time.LocalDate;
51 import java.time.LocalDateTime; 51 import java.time.LocalDateTime;
  52 +import java.time.YearMonth;
52 import java.time.temporal.ChronoUnit; 53 import java.time.temporal.ChronoUnit;
53 import java.time.temporal.TemporalAdjusters; 54 import java.time.temporal.TemporalAdjusters;
54 import java.util.*; 55 import java.util.*;
55 import java.util.function.Function; 56 import java.util.function.Function;
  57 +import java.util.regex.Matcher;
  58 +import java.util.regex.Pattern;
56 import java.util.stream.Collectors; 59 import java.util.stream.Collectors;
57 60
58 61
@@ -495,13 +498,17 @@ public class ReceiptLedgerInfoServiceImpl extends BaseMpServiceImpl<ReceiptLedge @@ -495,13 +498,17 @@ public class ReceiptLedgerInfoServiceImpl extends BaseMpServiceImpl<ReceiptLedge
495 return result; 498 return result;
496 } 499 }
497 List<String> shortNames = dataList.stream().map(ReceiptLedgerReportBo::getCustomerShortName).distinct().collect(Collectors.toList()); 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 List<String> debtStatusList = new ArrayList<>(); 505 List<String> debtStatusList = new ArrayList<>();
500 debtStatusList.add("AGREEMENT"); 506 debtStatusList.add("AGREEMENT");
501 debtStatusList.add("FIRST_COORDINATE"); 507 debtStatusList.add("FIRST_COORDINATE");
502 debtStatusList.add("SECOND_COORDINATE"); 508 debtStatusList.add("SECOND_COORDINATE");
503 debtStatusList.add("CLEAR_DEBTS"); 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 if (CollectionUtils.isEmpty(debtAmountList)) { 512 if (CollectionUtils.isEmpty(debtAmountList)) {
506 return result; 513 return result;
507 } 514 }
@@ -525,12 +532,8 @@ public class ReceiptLedgerInfoServiceImpl extends BaseMpServiceImpl<ReceiptLedge @@ -525,12 +532,8 @@ public class ReceiptLedgerInfoServiceImpl extends BaseMpServiceImpl<ReceiptLedge
525 if (CollectionUtils.isEmpty(list)) { 532 if (CollectionUtils.isEmpty(list)) {
526 continue; 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 long waitDeliveredOrderTotal = 0; 535 long waitDeliveredOrderTotal = 0;
  536 + List<String> creditStatusList = new ArrayList<>();
534 List<String> debtStates = new ArrayList<>(); 537 List<String> debtStates = new ArrayList<>();
535 Map<String, ReceiptLedgerReportDetail> reportDetailMap = new LinkedHashMap<>(); 538 Map<String, ReceiptLedgerReportDetail> reportDetailMap = new LinkedHashMap<>();
536 for (Map<String, Object> map : list) { 539 for (Map<String, Object> map : list) {
@@ -545,24 +548,31 @@ public class ReceiptLedgerInfoServiceImpl extends BaseMpServiceImpl<ReceiptLedge @@ -545,24 +548,31 @@ public class ReceiptLedgerInfoServiceImpl extends BaseMpServiceImpl<ReceiptLedge
545 } 548 }
546 reportDetail.setCustomerName(customerName); 549 reportDetail.setCustomerName(customerName);
547 reportDetail.setCreditStatus(debtStatus); 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 reportDetail.setCreditStatus("约定内"); 559 reportDetail.setCreditStatus("约定内");
552 } else if ("FIRST_COORDINATE".equals(debtStatus)) { 560 } else if ("FIRST_COORDINATE".equals(debtStatus)) {
553 reportDetail.setFirstCoordinate(valueConvert(debtAmount)); 561 reportDetail.setFirstCoordinate(valueConvert(debtAmount));
554 - firstCoordinateTotal = firstCoordinateTotal.add(debtAmount);  
555 reportDetail.setCreditStatus("超期1"); 562 reportDetail.setCreditStatus("超期1");
556 } else if ("SECOND_COORDINATE".equals(debtStatus)) { 563 } else if ("SECOND_COORDINATE".equals(debtStatus)) {
557 reportDetail.setSecondCoordinate(valueConvert(debtAmount)); 564 reportDetail.setSecondCoordinate(valueConvert(debtAmount));
558 - secondCoordinateTotal = secondCoordinateTotal.add(debtAmount);  
559 reportDetail.setCreditStatus("超期2"); 565 reportDetail.setCreditStatus("超期2");
560 } else if ("CLEAR_DEBTS".equals(debtStatus)) { 566 } else if ("CLEAR_DEBTS".equals(debtStatus)) {
561 reportDetail.setClearDebt(valueConvert(debtAmount)); 567 reportDetail.setClearDebt(valueConvert(debtAmount));
562 - clearDebtTotal = clearDebtTotal.add(debtAmount);  
563 reportDetail.setCreditStatus("超期3"); 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 Long count = orderCountMap.get(customerName); 577 Long count = orderCountMap.get(customerName);
568 if (count != null) { 578 if (count != null) {
@@ -575,14 +585,15 @@ public class ReceiptLedgerInfoServiceImpl extends BaseMpServiceImpl<ReceiptLedge @@ -575,14 +585,15 @@ public class ReceiptLedgerInfoServiceImpl extends BaseMpServiceImpl<ReceiptLedge
575 List<ReceiptLedgerReportDetail> details = new ArrayList<>(reportDetailMap.values()); 585 List<ReceiptLedgerReportDetail> details = new ArrayList<>(reportDetailMap.values());
576 report.setDetailList(details); 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 report.setWaitDeliveredOrderTotal(waitDeliveredOrderTotal); 594 report.setWaitDeliveredOrderTotal(waitDeliveredOrderTotal);
  595 + BigDecimal debtTotal = report.getDebtTotal();
  596 + report.setDebtTotal(valueConvert(debtTotal));
586 } 597 }
587 return result; 598 return result;
588 } 599 }
@@ -852,6 +863,36 @@ public class ReceiptLedgerInfoServiceImpl extends BaseMpServiceImpl<ReceiptLedge @@ -852,6 +863,36 @@ public class ReceiptLedgerInfoServiceImpl extends BaseMpServiceImpl<ReceiptLedge
852 shipmentsPlanDetailService.delByOrderIds(needFreezeOrderIds); 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,4 +952,96 @@ public class ReceiptLedgerInfoServiceImpl extends BaseMpServiceImpl<ReceiptLedge
911 OpLogUtil.setVariable("id", data.getId()); 952 OpLogUtil.setVariable("id", data.getId());
912 OpLogUtil.setExtra(vo); 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,5 +56,16 @@ public interface ReceiptLedgerInfoMapper extends BaseMapper<ReceiptLedgerInfo> {
56 * @param shortNames 客户简称 56 * @param shortNames 客户简称
57 * @return List<Map<String, BigDecimal>> 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,4 +143,9 @@ public interface ReceiptLedgerInfoService extends BaseMpService<ReceiptLedgerInf
143 * 冻结欠款客户,管控发货 143 * 冻结欠款客户,管控发货
144 */ 144 */
145 void autoFreeze(String customerId); 145 void autoFreeze(String customerId);
  146 +
  147 + /**
  148 + * 更新欠款状态
  149 + */
  150 + void autoUpdateDebtStatus();
146 } 151 }
@@ -238,6 +238,7 @@ @@ -238,6 +238,7 @@
238 left join customer_credit cc on tb.customer_id = cc.company_id 238 left join customer_credit cc on tb.customer_id = cc.company_id
239 left join receipt_ledger_info rl on tb.id = rl.customer_short_id 239 left join receipt_ledger_info rl on tb.id = rl.customer_short_id
240 <where> 240 <where>
  241 + and rl.type = 'INSIDE'
241 <if test="vo.customerType != null and vo.customerType != ''"> 242 <if test="vo.customerType != null and vo.customerType != ''">
242 and tb.type = #{vo.customerType} 243 and tb.type = #{vo.customerType}
243 </if> 244 </if>
@@ -258,7 +259,7 @@ @@ -258,7 +259,7 @@
258 </if> 259 </if>
259 </select> 260 </select>
260 261
261 - <select id="statisticsDeptByShortName" resultType="java.util.Map"> 262 + <select id="statisticsDebtByShortName" resultType="java.util.Map">
262 select c.name, 263 select c.name,
263 cs.short_name, 264 cs.short_name,
264 tb.debt_status, 265 tb.debt_status,
@@ -266,15 +267,53 @@ @@ -266,15 +267,53 @@
266 from receipt_ledger_info tb 267 from receipt_ledger_info tb
267 inner join base_data_customer_short cs on tb.customer_id = cs.customer_id 268 inner join base_data_customer_short cs on tb.customer_id = cs.customer_id
268 inner join base_data_customer c on tb.customer_id = c.id 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 and tb.debt_status is not null 283 and tb.debt_status is not null
278 group by c.name,cs.short_name,tb.debt_status 284 group by c.name,cs.short_name,tb.debt_status
279 </select> 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 </mapper> 319 </mapper>