From 34981c30a78e8bbd7791131059a9210f9928b62c Mon Sep 17 00:00:00 2001
From: 刘光辉 <347230014@qq.com>
Date: 星期四, 17 九月 2026 09:24:09 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/master' into master
---
jnpf-lims/jnpf-lims-biz/src/main/java/jnpf/limsService/impl/LimsBusinessReminderServiceImpl.java | 290 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 290 insertions(+), 0 deletions(-)
diff --git a/jnpf-lims/jnpf-lims-biz/src/main/java/jnpf/limsService/impl/LimsBusinessReminderServiceImpl.java b/jnpf-lims/jnpf-lims-biz/src/main/java/jnpf/limsService/impl/LimsBusinessReminderServiceImpl.java
new file mode 100644
index 0000000..5642ef6
--- /dev/null
+++ b/jnpf-lims/jnpf-lims-biz/src/main/java/jnpf/limsService/impl/LimsBusinessReminderServiceImpl.java
@@ -0,0 +1,290 @@
+package jnpf.limsService.impl;
+
+import jnpf.limsEntity.*;
+import jnpf.limsMapper.LimsBusinessReminderMapper;
+import jnpf.limsMapper.LimsMessageAudienceMapper;
+import jnpf.limsService.LimsBusinessReminderService;
+import jnpf.limsService.LimsMessageService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Collections;
+import java.util.Date;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedHashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class LimsBusinessReminderServiceImpl implements LimsBusinessReminderService {
+ private static final DateTimeFormatter DATE = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+ private static final DateTimeFormatter KEY_DATE = DateTimeFormatter.ofPattern("yyyyMMdd");
+
+ private final LimsBusinessReminderMapper reminderMapper;
+ private final LimsMessageAudienceMapper audienceMapper;
+ private final LimsMessageService messageService;
+
+ @Value("${lims.message.enabled:false}")
+ private boolean messageEnabled;
+
+ @Scheduled(cron = "${lims.message.business-reminder-cron:0 10 8 * * ?}")
+ public void cronTrigger() {
+ if (!messageEnabled) {
+ log.info("[lims-business-reminder] skipped because lims.message.enabled=false");
+ return;
+ }
+ scanAndRemind(false);
+ }
+
+ @Override
+ public Map<String, Map<String, Integer>> scanAndRemind(boolean dryRun) {
+ Map<String, Map<String, Integer>> stats = new LinkedHashMap<>();
+ stats.put("equipmentCalibration", remindEquipment(dryRun));
+ stats.put("equipmentVerification", remindEquipmentVerification(dryRun));
+ stats.put("retainObservation", remindRetainObservation(dryRun));
+ stats.put("environmentSampling", remindEnvironmentSampling(dryRun));
+ stats.put("consumableExpiry", remindConsumableExpiry(dryRun));
+ stats.put("retainDestruction", remindRetainDestruction(dryRun));
+ stats.put("stabilityPeriod", remindStabilityPeriod(dryRun));
+ log.info("[lims-business-reminder] done, dryRun={}, stats={}", dryRun, stats);
+ return stats;
+ }
+
+ private Map<String, Integer> remindEquipment(boolean dryRun) {
+ List<LimsEquipmentCalibrationReminderRow> rows = reminderMapper.selectEquipmentCalibrationDue();
+ int sent = 0;
+ for (LimsEquipmentCalibrationReminderRow row : rows) {
+ Map<String, Object> parameters = new LinkedHashMap<>();
+ parameters.put("bizId", row.getId());
+ parameters.put("equipmentName", value(row.getName()));
+ parameters.put("equipmentCode", value(row.getCode()));
+ parameters.put("reminderDate", format(row.getReminderDate()));
+ parameters.put("dueDate", format(row.getDueDate()));
+ LimsMessageSendResult result = messageService.send(LimsMessageRequest.builder()
+ .event(LimsMessageEvent.EQUIPMENT_CALIBRATION_DUE)
+ .tenantId(row.getTenantId())
+ .bizId(row.getId())
+ .remindStage("DUE")
+ .occurrenceKey(LimsMessageEvent.EQUIPMENT_CALIBRATION_DUE.getCode() + ":"
+ + row.getId() + ":" + keyDate(row.getDueDate()))
+ .recipients(Collections.singletonList(LimsRecipientRef.user(row.getRecipientUserId())))
+ .parameters(parameters)
+ .dryRun(dryRun)
+ .build());
+ if (isComplete(result)) {
+ sent++;
+ }
+ }
+ return stat(rows.size(), sent);
+ }
+
+ private Map<String, Integer> remindRetainObservation(boolean dryRun) {
+ List<LimsRetainObservationReminderRow> rows = reminderMapper.selectRetainObservationDue();
+ int sent = 0;
+ for (LimsRetainObservationReminderRow row : rows) {
+ Map<String, Object> parameters = new LinkedHashMap<>();
+ parameters.put("bizId", row.getId());
+ parameters.put("planId", value(row.getPlanId()));
+ parameters.put("sampleName", value(row.getSampleName()));
+ parameters.put("sampleCode", value(row.getSampleCode()));
+ parameters.put("batchNo", value(row.getBatchNo()));
+ parameters.put("observationDate", format(row.getObservationDate()));
+ LimsMessageSendResult result = messageService.send(LimsMessageRequest.builder()
+ .event(LimsMessageEvent.RETAIN_SAMPLE_OBSERVATION_DUE)
+ .tenantId(row.getTenantId())
+ .bizId(row.getId())
+ .remindStage("DUE")
+ .occurrenceKey(LimsMessageEvent.RETAIN_SAMPLE_OBSERVATION_DUE.getCode() + ":"
+ + row.getId() + ":" + keyDate(row.getObservationDate()))
+ .recipients(Collections.singletonList(LimsRecipientRef.user(row.getRecipientUserId())))
+ .parameters(parameters)
+ .dryRun(dryRun)
+ .build());
+ if (isComplete(result)) {
+ sent++;
+ }
+ }
+ return stat(rows.size(), sent);
+ }
+
+ private Map<String, Integer> remindEquipmentVerification(boolean dryRun) {
+ List<LimsEquipmentCalibrationReminderRow> rows = reminderMapper.selectEquipmentVerificationDue();
+ int sent = 0;
+ for (LimsEquipmentCalibrationReminderRow row : rows) {
+ Map<String, Object> parameters = new LinkedHashMap<>();
+ parameters.put("bizId", row.getId());
+ parameters.put("equipmentName", value(row.getName()));
+ parameters.put("equipmentCode", value(row.getCode()));
+ parameters.put("reminderDate", format(row.getReminderDate()));
+ parameters.put("dueDate", format(row.getDueDate()));
+ LimsMessageSendResult result = send(LimsMessageEvent.EQUIPMENT_VERIFICATION_DUE,
+ row.getTenantId(), row.getId(), "DUE", keyDate(row.getDueDate()),
+ Collections.singletonList(LimsRecipientRef.user(row.getRecipientUserId())),
+ parameters, dryRun);
+ if (isComplete(result)) {
+ sent++;
+ }
+ }
+ return stat(rows.size(), sent);
+ }
+
+ private Map<String, Integer> remindEnvironmentSampling(boolean dryRun) {
+ List<LimsEnvironmentSamplingReminderRow> rows = reminderMapper.selectEnvironmentSamplingDue();
+ int sent = 0;
+ for (LimsEnvironmentSamplingReminderRow row : rows) {
+ Map<String, Object> parameters = new LinkedHashMap<>();
+ parameters.put("bizId", row.getPlanId());
+ parameters.put("planName", value(row.getPlanName()));
+ parameters.put("planType", value(row.getPlanType()));
+ parameters.put("plannedDate", format(row.getPlannedDate()));
+ parameters.put("monitoringArea", value(row.getMonitoringArea()));
+ parameters.put("cleanlinessLevel", value(row.getCleanlinessLevel()));
+ parameters.put("monitoringItems", value(row.getMonitoringItems()));
+ LimsMessageSendResult result = send(LimsMessageEvent.ENVIRONMENT_SAMPLING_DUE,
+ row.getTenantId(), row.getPlanId(), "DUE", keyDate(row.getPlannedDate()),
+ Collections.singletonList(LimsRecipientRef.roleEnCode("ROLE.004")),
+ parameters, dryRun);
+ if (isComplete(result)) {
+ sent++;
+ }
+ }
+ return stat(rows.size(), sent);
+ }
+
+ private Map<String, Integer> remindConsumableExpiry(boolean dryRun) {
+ List<LimsConsumableExpiryReminderRow> rows = reminderMapper.selectConsumableExpiryDue();
+ int sent = 0;
+ for (LimsConsumableExpiryReminderRow row : rows) {
+ Map<String, Object> parameters = new LinkedHashMap<>();
+ parameters.put("bizId", row.getId());
+ parameters.put("batchCode", value(row.getBatchCode()));
+ parameters.put("barcode", value(row.getBarcode()));
+ parameters.put("consumableName", value(row.getName()));
+ parameters.put("specification", value(row.getSpecification()));
+ parameters.put("remainingQuantity", value(row.getRemainingQuantity()));
+ parameters.put("unit", value(row.getUnit()));
+ parameters.put("storageLocation", value(row.getStorageLocation()));
+ parameters.put("expiryDate", format(row.getExpiryDate()));
+ parameters.put("reminderStage", row.getReminderStage());
+ parameters.put("remainingDays", row.getRemainingDays());
+ LimsMessageSendResult result = send(LimsMessageEvent.CONSUMABLE_BATCH_EXPIRY_DUE,
+ row.getTenantId(), row.getId(), row.getReminderStage(),
+ keyDate(row.getExpiryDate()) + ":" + row.getReminderStage(),
+ Collections.singletonList(LimsRecipientRef.roleEnCode("ROLE.005")),
+ parameters, dryRun);
+ if (isComplete(result)) {
+ sent++;
+ }
+ }
+ return stat(rows.size(), sent);
+ }
+
+ private Map<String, Integer> remindRetainDestruction(boolean dryRun) {
+ List<LimsRetainDestructionReminderRow> rows = reminderMapper.selectRetainDestructionDue();
+ int sent = 0;
+ for (LimsRetainDestructionReminderRow row : rows) {
+ Map<String, Object> parameters = new LinkedHashMap<>();
+ parameters.put("bizId", row.getId());
+ parameters.put("sampleName", value(row.getSampleName()));
+ parameters.put("sampleCode", value(row.getSampleCode()));
+ parameters.put("batchNo", value(row.getBatchNo()));
+ parameters.put("currentQuantity", value(row.getCurrentQuantity()));
+ parameters.put("unit", value(row.getUnit()));
+ parameters.put("storageLocation", value(row.getStorageLocation()));
+ parameters.put("retentionDeadline", format(row.getRetentionDeadline()));
+ LimsMessageSendResult result = send(LimsMessageEvent.RETAIN_SAMPLE_DESTRUCTION_DUE,
+ row.getTenantId(), row.getId(), "DUE", keyDate(row.getRetentionDeadline()),
+ Collections.singletonList(LimsRecipientRef.roleEnCode("ROLE.005")),
+ parameters, dryRun);
+ if (isComplete(result)) {
+ sent++;
+ }
+ }
+ return stat(rows.size(), sent);
+ }
+
+ private Map<String, Integer> remindStabilityPeriod(boolean dryRun) {
+ List<LimsStabilityPeriodReminderRow> rows = reminderMapper.selectStabilityPeriodDue();
+ int sent = 0;
+ for (LimsStabilityPeriodReminderRow row : rows) {
+ LinkedHashSet<String> users = new LinkedHashSet<>();
+ if (value(row.getOrganizationIds()).length() > 0) {
+ Arrays.stream(row.getOrganizationIds().split(","))
+ .map(String::trim).filter(item -> !item.isEmpty())
+ .forEach(organizationId -> users.addAll(audienceMapper.selectOrganizationRoleUsers(
+ row.getTenantId(), organizationId, "ROLE.004")));
+ }
+ List<LimsRecipientRef> recipients = new ArrayList<>();
+ users.forEach(userId -> recipients.add(LimsRecipientRef.user(userId)));
+ Map<String, Object> parameters = new LinkedHashMap<>();
+ parameters.put("bizId", row.getId());
+ parameters.put("planId", row.getPlanId());
+ parameters.put("planCode", value(row.getPlanCode()));
+ parameters.put("planName", value(row.getPlanName()));
+ parameters.put("sampleName", value(row.getSampleName()));
+ parameters.put("batchNo", value(row.getBatchNo()));
+ parameters.put("period", row.getPeriod());
+ parameters.put("periodUnit", value(row.getPeriodUnit()));
+ parameters.put("plannedDate", format(row.getPlannedDate()));
+ parameters.put("inspectionItems", value(row.getInspectionItems()));
+ LimsMessageSendResult result = send(LimsMessageEvent.STABILITY_PERIOD_DUE,
+ row.getTenantId(), row.getId(), "DUE", keyDate(row.getPlannedDate()),
+ recipients, parameters, dryRun);
+ if (isComplete(result)) {
+ sent++;
+ }
+ }
+ return stat(rows.size(), sent);
+ }
+
+ private LimsMessageSendResult send(LimsMessageEvent event, String tenantId, String bizId,
+ String stage, String keySuffix, List<LimsRecipientRef> recipients,
+ Map<String, Object> parameters, boolean dryRun) {
+ return messageService.send(LimsMessageRequest.builder().event(event).tenantId(tenantId)
+ .bizId(bizId).remindStage(stage)
+ .occurrenceKey(event.getCode() + ":" + bizId + ":" + keySuffix)
+ .recipients(recipients).parameters(parameters).dryRun(dryRun).build());
+ }
+
+ private boolean isComplete(LimsMessageSendResult result) {
+ return result.isAccepted() && result.getRecipientCount() > 0
+ && result.getSentCount() == result.getRecipientCount() && result.getFailedCount() == 0;
+ }
+
+ private Map<String, Integer> stat(int hit, int sent) {
+ Map<String, Integer> stats = new LinkedHashMap<>();
+ stats.put("hit", hit);
+ stats.put("sent", sent);
+ stats.put("skipped", hit - sent);
+ return stats;
+ }
+
+ private String format(LocalDateTime value) {
+ return value == null ? "" : value.format(DATE);
+ }
+
+ private String format(Date value) {
+ return value == null ? "" : new java.text.SimpleDateFormat("yyyy-MM-dd").format(value);
+ }
+
+ private String keyDate(LocalDateTime value) {
+ return value == null ? "NO_DATE" : value.format(KEY_DATE);
+ }
+
+ private String keyDate(Date value) {
+ return value == null ? "NO_DATE" : new java.text.SimpleDateFormat("yyyyMMdd").format(value);
+ }
+
+ private String value(String value) {
+ return value == null ? "" : value;
+ }
+}
--
Gitblit v1.8.0