Commit 3bfbbe395856c1da840a5c7061ec365de3f035c2

Authored by 杨鸣坤
1 parent 22cd48f8

楚江ERP:定时发送锁规延期消息

... ... @@ -33,6 +33,7 @@ import io.swagger.annotations.ApiOperation;
33 33 import org.apache.commons.collections4.CollectionUtils;
34 34 import org.apache.commons.lang3.StringUtils;
35 35 import org.springframework.beans.factory.annotation.Autowired;
  36 +import org.springframework.scheduling.annotation.Scheduled;
36 37 import org.springframework.validation.annotation.Validated;
37 38 import org.springframework.web.bind.annotation.*;
38 39
... ... @@ -263,4 +264,12 @@ public class SpecLockDelayApplicationController extends DefaultBaseController {
263 264
264 265 return InvokeResultBuilder.success();
265 266 }
  267 +
  268 + @ApiOperation("发送锁规延期消息")
  269 + @GetMapping("/sendSpecLockDelayMsg")
  270 + @Scheduled(cron = "0 30 0 * * ?")
  271 + public InvokeResult<Void> sendSpecLockDelayMsg() {
  272 + specLockDelayApplicationService.sendDelaySpecLockMessage();
  273 + return InvokeResultBuilder.success();
  274 + }
266 275 }
... ...
... ... @@ -80,7 +80,7 @@ public class HolidaysServiceImpl extends BaseMpServiceImpl<HolidaysMapper, Holid
80 80 .collect(Collectors.toList());
81 81
82 82 int workingDays = 0;
83   - LocalDate currentDate = startDate.plusDays(1); // 从签订日第二天开始计算
  83 + LocalDate currentDate = startDate; // 从签订日当天开始计算
84 84
85 85 while (!currentDate.isAfter(endDate)) {
86 86 if (restHolidaysList.contains(currentDate)) {
... ... @@ -99,6 +99,19 @@ public class HolidaysServiceImpl extends BaseMpServiceImpl<HolidaysMapper, Holid
99 99 return workingDays <= maxWorkdays;
100 100 }
101 101
  102 + @Override
  103 + public boolean checkWorkdayToday() {
  104 + LocalDate today = LocalDate.now();
  105 + Holidays query = new Holidays();
  106 + query.setHolidayDate(today);
  107 + List<Holidays> holidays = query(query);
  108 + if (CollectionUtils.isNotEmpty(holidays)) {
  109 + return BooleanUtils.isFalse(holidays.get(0).getRest());
  110 + }
  111 +
  112 + return today.getDayOfWeek().getValue() <= 5;
  113 + }
  114 +
102 115 private List<Holidays> getHolidaysForYear(int year) throws Exception {
103 116 Holidays query = new Holidays();
104 117 query.setYear(year);
... ...
... ... @@ -11,6 +11,7 @@ import com.lframework.starter.bpm.vo.flow.task.QueryTodoTaskListVo;
11 11 import com.lframework.starter.common.exceptions.impl.DefaultClientException;
12 12 import com.lframework.starter.common.utils.Assert;
13 13 import com.lframework.starter.common.utils.ObjectUtil;
  14 +import com.lframework.starter.mq.core.service.MqProducerService;
14 15 import com.lframework.starter.web.core.annotations.oplog.OpLog;
15 16 import com.lframework.starter.web.core.components.resp.PageResult;
16 17 import com.lframework.starter.web.core.components.security.SecurityUtil;
... ... @@ -20,6 +21,8 @@ import com.lframework.starter.web.core.utils.OpLogUtil;
20 21 import com.lframework.starter.web.core.utils.PageHelperUtil;
21 22 import com.lframework.starter.web.core.utils.PageResultUtil;
22 23 import com.lframework.starter.web.inner.components.oplog.OtherOpLogType;
  24 +import com.lframework.starter.web.inner.dto.message.SysSiteMessageDto;
  25 +import com.lframework.starter.web.inner.service.system.SysUserRoleService;
23 26 import com.lframework.xingyun.sc.entity.ContractDistributorStandard;
24 27 import com.lframework.xingyun.sc.entity.SpecLockDelayApplication;
25 28 import com.lframework.xingyun.sc.enums.CustomerDevelopStatus;
... ... @@ -30,6 +33,7 @@ import com.lframework.xingyun.sc.service.contract.SpecLockDelayApplicationServic
30 33 import com.lframework.xingyun.sc.vo.contract.createVo.CreateSpecLockDelayApplicationVo;
31 34 import com.lframework.xingyun.sc.vo.contract.queryVo.QuerySpecLockDelayApplicationVo;
32 35 import com.lframework.xingyun.sc.vo.contract.updateVo.UpdateSpecLockDelayApplicationVo;
  36 +import lombok.extern.slf4j.Slf4j;
33 37 import org.apache.commons.collections.CollectionUtils;
34 38 import org.apache.commons.lang3.StringUtils;
35 39 import org.springframework.beans.factory.annotation.Autowired;
... ... @@ -38,13 +42,16 @@ import org.springframework.cache.annotation.Cacheable;
38 42 import org.springframework.stereotype.Service;
39 43 import org.springframework.transaction.annotation.Transactional;
40 44
  45 +import javax.annotation.Resource;
41 46 import java.io.Serializable;
42 47 import java.time.LocalDate;
43 48 import java.time.LocalDateTime;
44   -import java.util.List;
  49 +import java.util.*;
  50 +import java.util.function.Function;
45 51 import java.util.stream.Collectors;
46 52
47 53 @Service
  54 +@Slf4j
48 55 public class SpecLockDelayApplicationServiceImpl extends BaseMpServiceImpl<SpecLockDelayApplicationMapper, SpecLockDelayApplication> implements SpecLockDelayApplicationService {
49 56
50 57 private static final String SPEC_LOCK_DELAY_FLAY = "SPEC_LOCK_DELAY"; // 未锁规格申请单审批
... ... @@ -57,6 +64,10 @@ public class SpecLockDelayApplicationServiceImpl extends BaseMpServiceImpl<SpecL
57 64 private ContractDistributorStandardService contractDistributorStandardService;
58 65 @Autowired
59 66 private HolidaysService holidaysService;
  67 + @Autowired
  68 + private MqProducerService mqProducerService;
  69 + @Resource
  70 + private SysUserRoleService sysUserRoleService;
60 71
61 72 @Override
62 73 public PageResult<SpecLockDelayApplication> query(Integer pageIndex, Integer pageSize, QuerySpecLockDelayApplicationVo vo) {
... ... @@ -238,4 +249,141 @@ public class SpecLockDelayApplicationServiceImpl extends BaseMpServiceImpl<SpecL
238 249 public void cleanCacheByKey(Serializable key) {
239 250
240 251 }
  252 +
  253 + public void sendDelaySpecLockMessage() {
  254 + log.info("开始执行延迟锁规消息发送任务");
  255 +
  256 + // 检查工作日
  257 + if (!holidaysService.checkWorkdayToday()) {
  258 + log.info("今日非工作日,跳过执行");
  259 + return;
  260 + }
  261 +
  262 + log.info("今日为工作日,继续执行");
  263 +
  264 + // 构建查询条件
  265 + Wrapper<ContractDistributorStandard> wrapper = Wrappers.lambdaUpdate(ContractDistributorStandard.class)
  266 + .in(ContractDistributorStandard::getType, Arrays.asList("INTL_OPEN_SPEC_AGMT", "DRAFT_DIST_AGMT"))
  267 + .eq(ContractDistributorStandard::getStatus, "FORMAL")
  268 + .and(w -> w.isNull(ContractDistributorStandard::getPriceSpecLocked)
  269 + .or()
  270 + .eq(ContractDistributorStandard::getPriceSpecLocked, false));
  271 +
  272 + log.info("查询条件构建完成:类型为INTL_OPEN_SPEC_AGMT或DRAFT_DIST_AGMT,状态为FORMAL,价格规格锁定为空或false");
  273 +
  274 + List<ContractDistributorStandard> contractDistributorStandardList = contractDistributorStandardService.list(wrapper);
  275 +
  276 + if (org.apache.commons.collections4.CollectionUtils.isEmpty(contractDistributorStandardList)) {
  277 + log.info("未查询到符合条件的合同,任务结束");
  278 + return;
  279 + }
  280 +
  281 + log.info("查询到符合条件的合同数量:{}", contractDistributorStandardList.size());
  282 +
  283 + // 提取合同ID列表
  284 + List<String> contractIdList = contractDistributorStandardList.stream()
  285 + .map(ContractDistributorStandard::getId)
  286 + .collect(Collectors.toList());
  287 + log.info("提取合同ID列表完成,共{}个合同ID", contractIdList.size());
  288 +
  289 + // 查询最新的锁规延迟申请
  290 + log.info("开始查询最新的锁规延迟申请记录");
  291 + List<SpecLockDelayApplication> latestPassedByContractIds = this.getBaseMapper().selectLatestPassedByContractIds(contractIdList);
  292 +
  293 + if (org.apache.commons.collections4.CollectionUtils.isEmpty(latestPassedByContractIds)) {
  294 + log.info("未查询到任何锁规延迟申请记录");
  295 + } else {
  296 + log.info("查询到{}条锁规延迟申请记录", latestPassedByContractIds.size());
  297 + }
  298 +
  299 + Map<String, SpecLockDelayApplication> latestPassedMap = org.apache.commons.collections4.CollectionUtils.emptyIfNull(latestPassedByContractIds)
  300 + .stream().collect(Collectors.toMap(SpecLockDelayApplication::getContractId, Function.identity()));
  301 + log.info("锁规延迟申请记录映射表构建完成");
  302 +
  303 + // 处理每个合同
  304 + log.info("开始逐个处理合同消息发送");
  305 + int totalCount = contractDistributorStandardList.size();
  306 + int processedCount = 0;
  307 + int sentCount = 0;
  308 + int errorCount = 0;
  309 +
  310 + for (ContractDistributorStandard contractDistributorStandard : contractDistributorStandardList) {
  311 + processedCount++;
  312 + String contractId = contractDistributorStandard.getId();
  313 + String contractCode = contractDistributorStandard.getCode();
  314 +
  315 + log.info("正在处理合同[{}/{}],合同ID:{},合同号:{}", processedCount, totalCount, contractId, contractCode);
  316 +
  317 + try {
  318 + SpecLockDelayApplication latestPassed = latestPassedMap.get(contractId);
  319 + boolean needSendMsg;
  320 +
  321 + if (latestPassed != null) {
  322 + log.info("合同{}存在锁规延迟申请,锁规日期:{}", contractCode, latestPassed.getSpecLockDate());
  323 + if (latestPassed.getSpecLockDate().isBefore(LocalDate.now())) {
  324 + needSendMsg = true;
  325 + log.info("合同{}锁规日期已过,需要发送消息", contractCode);
  326 + } else {
  327 + needSendMsg = false;
  328 + log.info("合同{}锁规日期未到,不需要发送消息", contractCode);
  329 + }
  330 + } else {
  331 + log.info("合同{}无锁规延迟申请记录,检查工作日限制", contractCode);
  332 + boolean withinWorkdayLimit = holidaysService.isWithinWorkdayLimit(
  333 + contractDistributorStandard.getOrderDate(), LocalDate.now(), 5);
  334 + needSendMsg = !withinWorkdayLimit;
  335 + log.info("合同{}工作日检查结果:withinWorkdayLimit={}, needSendMsg={}",
  336 + contractCode, withinWorkdayLimit, needSendMsg);
  337 + }
  338 +
  339 + if (!needSendMsg) {
  340 + log.info("合同{}不需要发送消息,跳过", contractCode);
  341 + continue;
  342 + }
  343 +
  344 + // 获取用户列表
  345 + log.info("开始获取需要通知的用户列表");
  346 + List<String> userIdList = sysUserRoleService.listUserIdByRoleCodes(Arrays.asList("bsczg", "jybzg"));
  347 + userIdList.add(contractDistributorStandard.getCreateById());
  348 + log.info("合同{}需要通知的用户数量:{}", contractCode, userIdList.size());
  349 +
  350 + // 构建消息内容
  351 + StringBuilder sb = new StringBuilder();
  352 + sb.append("您的");
  353 + if ("DRAFT_DIST_AGMT".equals(contractDistributorStandard.getType())) {
  354 + sb.append("经销未锁规合同,");
  355 + log.info("合同{}类型为经销合同", contractCode);
  356 + } else {
  357 + sb.append("外贸未锁规格合同,");
  358 + log.info("合同{}类型为外贸合同", contractCode);
  359 + }
  360 + sb.append("合同号:").append(contractDistributorStandard.getCode());
  361 + sb.append("。锁规已经延期,请及时进行规格锁定!");
  362 +
  363 + String messageContent = sb.toString();
  364 + log.info("合同{}消息内容构建完成:{}", contractCode, messageContent);
  365 +
  366 + // 发送消息
  367 + SysSiteMessageDto messageDto = new SysSiteMessageDto();
  368 + messageDto.setUserIdList(userIdList);
  369 + messageDto.setTitle("合同锁规延期通知");
  370 + messageDto.setContent(messageContent);
  371 + messageDto.setBizKey(IdUtil.getId());
  372 + messageDto.setCreateUserId(null);
  373 +
  374 + log.info("准备发送站内信给合同{},用户数量:{}", contractCode, userIdList.size());
  375 + mqProducerService.createSysSiteMessage(messageDto);
  376 + sentCount++;
  377 + log.info("合同{}站内信发送成功", contractCode);
  378 +
  379 + } catch (Exception e) {
  380 + errorCount++;
  381 + log.error("处理合同{}时发生异常,合同号:{}", contractId, contractCode, e);
  382 + // 根据业务需求决定是否继续处理其他合同
  383 + }
  384 + }
  385 +
  386 + log.info("延迟锁规消息发送任务执行完成:总共处理{}个合同,成功发送{}条消息,失败{}个",
  387 + totalCount, sentCount, errorCount);
  388 + }
241 389 }
... ...
... ... @@ -21,4 +21,6 @@ public interface SpecLockDelayApplicationMapper extends BaseMapper<SpecLockDelay
21 21 * @return
22 22 */
23 23 List<SpecLockDelayApplication> query(@Param("vo") QuerySpecLockDelayApplicationVo vo);
  24 +
  25 + List<SpecLockDelayApplication> selectLatestPassedByContractIds(@Param("contractIds") List<String> contractIds);
24 26 }
... ...
... ... @@ -44,4 +44,11 @@ public interface HolidaysService extends BaseMpService<Holidays> {
44 44 * @return true表示没有超过,false表示超过了
45 45 */
46 46 boolean isWithinWorkdayLimit(LocalDate startDate, LocalDate endDate, int maxWorkdays) throws Exception;
  47 +
  48 + /**
  49 + * 判断今天是否为工作日
  50 + *
  51 + * @return true 工作日,false 休息日
  52 + */
  53 + boolean checkWorkdayToday();
47 54 }
... ...
... ... @@ -67,5 +67,9 @@ public interface SpecLockDelayApplicationService extends BaseMpService<SpecLockD
67 67 */
68 68 void cancelApplication(String id);
69 69
  70 + /**
  71 + * 锁规合同发送延期消息
  72 + */
  73 + void sendDelaySpecLockMessage();
70 74 }
71 75
... ...
... ... @@ -54,4 +54,21 @@
54 54 </if>
55 55 </where>
56 56 </select>
  57 +
  58 + <select id="selectLatestPassedByContractIds" resultMap="SpecLockDelayApplication">
  59 + SELECT t1.*
  60 + FROM `tbl_spec_lock_delay_application` t1
  61 + INNER JOIN (
  62 + SELECT `contract_id`, MAX(`spec_lock_date`) as max_date
  63 + FROM `tbl_spec_lock_delay_application`
  64 + WHERE `contract_id` IN
  65 + <foreach collection="contractIds" item="contractId" open="(" close=")" separator=",">
  66 + #{contractId}
  67 + </foreach>
  68 + AND `approval_status` = 'PASS'
  69 + GROUP BY `contract_id`
  70 + ) t2 ON t1.`contract_id` = t2.`contract_id`
  71 + AND t1.`spec_lock_date` = t2.max_date
  72 + AND t1.`approval_status` = 'PASS'
  73 + </select>
57 74 </mapper>
... ...