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/LimsHaocaiAlertServiceImpl.java |   90 +++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 90 insertions(+), 0 deletions(-)

diff --git a/jnpf-lims/jnpf-lims-biz/src/main/java/jnpf/limsService/impl/LimsHaocaiAlertServiceImpl.java b/jnpf-lims/jnpf-lims-biz/src/main/java/jnpf/limsService/impl/LimsHaocaiAlertServiceImpl.java
new file mode 100644
index 0000000..aa3cfeb
--- /dev/null
+++ b/jnpf-lims/jnpf-lims-biz/src/main/java/jnpf/limsService/impl/LimsHaocaiAlertServiceImpl.java
@@ -0,0 +1,90 @@
+package jnpf.limsService.impl;
+
+import jnpf.limsEntity.LimsHaocaiAlertRow;
+import jnpf.limsEntity.LimsMessageEvent;
+import jnpf.limsEntity.LimsMessageRequest;
+import jnpf.limsEntity.LimsMessageSendResult;
+import jnpf.limsEntity.LimsRecipientRef;
+import jnpf.limsMapper.LimsHaocaiAlertMapper;
+import jnpf.limsService.LimsHaocaiAlertService;
+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.math.BigDecimal;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class LimsHaocaiAlertServiceImpl implements LimsHaocaiAlertService {
+    private static final String QC_ADMIN_ROLE = "ROLE.005";
+
+    private final LimsHaocaiAlertMapper alertMapper;
+    private final LimsMessageService messageService;
+
+    @Value("${lims.message.enabled:false}")
+    private boolean messageEnabled;
+
+    @Scheduled(cron = "${lims.haocai.alert.cron:0 0 1 * * ?}")
+    public void cronTrigger() {
+        if (!messageEnabled) {
+            log.info("[haocai-alert] skipped because lims.message.enabled=false");
+            return;
+        }
+        log.info("[haocai-alert] cron triggered");
+        scanAndAlert(false);
+    }
+
+    @Override
+    public Map<String, Integer> scanAndAlert(boolean dryRun) {
+        List<LimsHaocaiAlertRow> rows = alertMapper.selectBelowThreshold();
+        int sent = 0;
+        for (LimsHaocaiAlertRow row : rows) {
+            LimsMessageSendResult result = messageService.send(LimsMessageRequest.builder()
+                    .event(LimsMessageEvent.CONSUMABLE_STOCK_LOW)
+                    .tenantId(row.getTenantId())
+                    .bizId(row.getId())
+                    .remindStage("DAILY")
+                    .occurrenceKey(LimsMessageEvent.CONSUMABLE_STOCK_LOW.getCode() + ":" + row.getId()
+                            + ":" + LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE))
+                    .recipients(Arrays.asList(LimsRecipientRef.roleEnCode(QC_ADMIN_ROLE)))
+                    .parameters(parameters(row))
+                    .dryRun(dryRun)
+                    .build());
+            if (result.isAccepted() && result.getRecipientCount() > 0
+                    && result.getSentCount() == result.getRecipientCount()
+                    && result.getFailedCount() == 0) {
+                sent++;
+            }
+        }
+        Map<String, Integer> stats = new LinkedHashMap<>();
+        stats.put("hit", rows.size());
+        stats.put("sent", sent);
+        stats.put("skipped", rows.size() - sent);
+        log.info("[haocai-alert] done, dryRun={}, stats={}", dryRun, stats);
+        return stats;
+    }
+
+    private Map<String, Object> parameters(LimsHaocaiAlertRow row) {
+        Map<String, Object> parameters = new HashMap<>();
+        parameters.put("bizId", row.getId());
+        parameters.put("bizName", row.getMingcheng() == null ? "" : row.getMingcheng());
+        parameters.put("currentStock", plain(row.getJieyuSum()));
+        parameters.put("warningStock", row.getQuehuoYujing() == null ? "" : row.getQuehuoYujing());
+        return parameters;
+    }
+
+    private String plain(BigDecimal value) {
+        return value == null ? "0" : value.stripTrailingZeros().toPlainString();
+    }
+}

--
Gitblit v1.8.0