From cb249acbd7ed7f3bc2afa2bc9bee7d69ac8b5e30 Mon Sep 17 00:00:00 2001
From: chen.lin <1442464845@qq.com>
Date: 星期二, 10 三月 2026 14:22:43 +0800
Subject: [PATCH] 空板自动出库定时任务
---
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/LocItemServiceImpl.java | 11 ++++-
version/db/material_auto_config.sql | 3 +
rsf-server/src/main/java/com/vincent/rsf/server/system/constant/GlobalConfigCode.java | 3 +
rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/WcsServiceImpl.java | 39 +++++--------------
rsf-server/src/main/java/com/vincent/rsf/server/manager/schedules/MaterialAutoSchedules.java | 61 +++++++++++++++++++++++++++++-
5 files changed, 84 insertions(+), 33 deletions(-)
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/WcsServiceImpl.java b/rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/WcsServiceImpl.java
index f1dd469..3b01c2f 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/WcsServiceImpl.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/WcsServiceImpl.java
@@ -141,6 +141,11 @@
// 楠岃瘉璁惧绔欑偣
DeviceSite deviceSite = validateDeviceSite(param);
+ // 绌烘澘鍏ュ簱锛氫笌闈炵┖鏉垮悓涓�鍏ュ彛锛屼粎涓嶆牎楠岀粍鎵橈紝鍙仛鍒嗛厤搴撲綅銆佸缓浠诲姟銆佹洿鏂板簱浣�
+ if (param.getIoType() != null && param.getIoType().equals(TaskType.TASK_TYPE_EMPITY_IN.type)) {
+ return createInTaskForEmptyPallet(param.getBarcode(), param.getSourceStaNo(), param.getLocType1());
+ }
+
// 鎻愬墠瀹氫箟 waitPakin / waitPakinItems锛屼緵鍚庣画鍏朵粬鍏ュ簱閫昏緫浣跨敤
WaitPakin waitPakin = null;
List<WaitPakinItem> waitPakinItems = Collections.emptyList();
@@ -621,8 +626,8 @@
}
/**
- * 绌烘澘鍏ュ簱锛歊CS 鐢宠鏃� full=true锛屾棤闇�缁勬墭锛屽垎閰嶅簱浣嶅苟鍒涘缓 TASK_TYPE_EMPITY_IN 浠诲姟銆�
- * 闇�鍦ㄨ澶囩珯鐐逛腑閰嶇疆 type=10锛堢┖鏉垮叆搴擄級鐨勭珯鐐硅矾寰勩��
+ * 绌烘澘鍏ュ簱锛氫笌闈炵┖鏉垮悓涓�娴佺▼锛堟牎楠岀珯鐐广�佸垎閰嶅簱浣嶃�佸缓浠诲姟銆佹洿鏂板簱浣嶏級锛屼粎涓嶆牎楠岀粍鎵樸�佷笉鍐欎换鍔℃槑缁嗐�佷笉鏇存柊缁勬墭鐘舵�併��
+ * 鐢� createInTask 鍦� ioType=绌烘澘鏃惰皟鐢紱闇�鍦ㄨ澶囩珯鐐逛腑閰嶇疆 type=10锛堢┖鏉垮叆搴擄級鐨勭珯鐐硅矾寰勩��
*/
private InTaskMsgDto createInTaskForEmptyPallet(String barcode, String staNo, Integer type) {
TaskInParam param = new TaskInParam();
@@ -1560,36 +1565,14 @@
log.info("========== 寮�濮嬬敵璇峰叆搴撲换鍔★紝鍒嗛厤搴撲綅 ==========");
log.info("鏂欑鐮侊細{}锛屽叆搴撶珯鐐癸細{}锛屽叆搴撶被鍨嬶細{}锛岀┖鏉匡細{}", barcode, staNo, type, full);
- // full=true 鏃惰蛋绌烘澘鍏ュ簱锛堟棤闇�缁勬墭锛夛紱鍚﹀垯璧版櫘閫氬叆搴擄紙闇�缁勬墭鎴栬嚜鍔ㄧ粍鎵橈級
- if (Boolean.TRUE.equals(full)) {
- InTaskMsgDto msgDto = createInTaskForEmptyPallet(barcode, staNo, type);
- JSONObject result = new JSONObject();
- result.put("locNo", msgDto.getLocNo());
- result.put("batchNo", msgDto.getWorkNo());
- result.put("taskNo", msgDto.getWorkNo());
- return R.ok(result);
- }
-
- // 鏋勫缓 TaskInParam 鍙傛暟锛屼笌 /wcs/create/in/task 鎺ュ彛鍙傛暟涓�鑷�
+ // 缁熶竴璧� createInTask锛氱┖鏉�(full=true)浠呬笉鏍¢獙缁勬墭锛屼粛鏍¢獙绔欑偣銆佸垎閰嶅簱浣嶃�佸缓浠诲姟锛涢潪绌烘澘闇�缁勬墭
TaskInParam param = new TaskInParam();
param.setBarcode(barcode);
param.setSourceStaNo(staNo);
- param.setIoType(TaskType.TASK_TYPE_IN.type); // 鍏ュ簱绫诲瀷
- param.setLocType1(type); // 搴撲綅绫诲瀷锛堥珮浣庢娴嬩俊鍙凤級
- param.setUser(1L); // 榛樿鐢ㄦ埛ID锛屽彲浠ユ牴鎹疄闄呴渶姹傝皟鏁�
+ param.setLocType1(type != null ? type : 1);
+ param.setUser(1L);
+ param.setIoType(Boolean.TRUE.equals(full) ? TaskType.TASK_TYPE_EMPITY_IN.type : TaskType.TASK_TYPE_IN.type);
- // 璋冪敤 createInTask 鏂规硶锛屽垱寤哄畬鏁寸殑鍏ュ簱浠诲姟
- // 璇ユ柟娉曚細鎵ц浠ヤ笅娴佺▼锛�
- // 1. 楠岃瘉璁惧绔欑偣
- // 2. 楠岃瘉缁勬嫋鐘舵��
- // 3. 妫�鏌ユ槸鍚︽湁鍖归厤鐨勫叆搴撲换鍔★紙鎷f枡/鐩樼偣鍏ュ簱浼氬尮閰嶇姸鎬�199骞舵洿鏂颁负2锛�
- // 4. 鐢熸垚浠诲姟缂栫爜锛堝鏋滈渶瑕佸垱寤烘柊浠诲姟锛�
- // 5. 鑾峰彇搴撲綅鍙�
- // 6. 鍒涘缓骞朵繚瀛樹换鍔★紙濡傛灉闇�瑕佸垱寤烘柊浠诲姟锛�
- // 7. 鏇存柊搴撲綅鐘舵��
- // 8. 鑾峰彇骞堕獙璇佺粍鎷栨槑缁�
- // 9. 鍒涘缓骞朵繚瀛樹换鍔℃槑缁�
- // 10. 鏇存柊缁勬墭鐘舵��
InTaskMsgDto msgDto = createInTask(param);
// 鏌ヨ浠诲姟褰撳墠鐘舵��
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/schedules/MaterialAutoSchedules.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/schedules/MaterialAutoSchedules.java
index 8ed7634..48ae660 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/manager/schedules/MaterialAutoSchedules.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/schedules/MaterialAutoSchedules.java
@@ -3,11 +3,14 @@
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.vincent.rsf.framework.exception.CoolException;
+import com.vincent.rsf.server.manager.controller.params.LocToTaskParams;
import com.vincent.rsf.server.manager.controller.params.OutStockToTaskParams;
import com.vincent.rsf.server.manager.controller.params.PakinItem;
import com.vincent.rsf.server.manager.controller.params.WaitPakinParam;
import com.vincent.rsf.server.manager.entity.*;
+import com.vincent.rsf.server.common.constant.Constants;
import com.vincent.rsf.server.manager.enums.AsnExceStatus;
+import com.vincent.rsf.server.manager.enums.LocStsType;
import com.vincent.rsf.server.manager.enums.OrderType;
import com.vincent.rsf.server.manager.enums.OrderWorkType;
import com.vincent.rsf.server.manager.enums.TaskStsType;
@@ -31,10 +34,11 @@
import java.util.stream.Collectors;
/**
- * 鎸囧畾鐗╂枡鑷姩鍖栧畾鏃朵换鍔★細鍙厤缃墿鏂欑紪鐮佸悗锛�
+ * 鎸囧畾鐗╂枡/绌烘澘鑷姩鍖栧畾鏃朵换鍔★細鍙厤缃悗
* 1锛夋湁搴撳瓨鏃惰嚜鍔ㄧ敓鎴愬叏鐗堝嚭搴撳崟锛�
* 2锛夎鐗╂枡鍑哄簱鍗曡嚜鍔ㄤ笅鍙戜换鍔★紱
- * 3锛塕CS 鍏ュ簱閫氱煡鏃讹紙鍙�夛級鑷姩缁勬墭锛屾暟閲忓彲閰嶇疆銆�
+ * 3锛塕CS 鍏ュ簱閫氱煡鏃讹紙鍙�夛級鑷姩缁勬墭锛屾暟閲忓彲閰嶇疆锛�
+ * 4锛夌┖鏉�(D)搴撲綅瀹氭椂鑷姩鐢熸垚绌烘澘鍑哄簱浠诲姟骞朵笅鍙� RCS锛圓UTO_EMPTY_OUT_ENABLED锛夈��
*/
@Slf4j
@Component
@@ -229,6 +233,59 @@
}
/**
+ * 瀹氭椂浠诲姟锛氱┖鏉垮簱瀛樿嚜鍔ㄥ嚭搴擄紙姣� 2 鍒嗛挓锛�
+ * 閰嶇疆锛欰UTO_EMPTY_OUT_ENABLED=true 鏃讹紝鎵弿绌烘澘(D)搴撲綅锛岀敓鎴愮┖鏉垮嚭搴撲换鍔″苟涓嬪彂 RCS锛屾祦绋嬩笌 AUTO_FULL_OUT 瀵瑰簲瀹氭椂浠诲姟涓�鑷淬��
+ */
+ @Scheduled(cron = "0 0/2 * * * ?")
+ @Transactional(rollbackFor = Exception.class)
+ public void autoEmptyOutTask() {
+ Config enabledConfig = configService.getOne(new LambdaQueryWrapper<Config>().eq(Config::getFlag, GlobalConfigCode.AUTO_EMPTY_OUT_ENABLED));
+ if (enabledConfig == null || !Boolean.parseBoolean(enabledConfig.getVal())) {
+ return;
+ }
+ List<Loc> emptyLocs = locService.list(new LambdaQueryWrapper<Loc>()
+ .eq(Loc::getUseStatus, LocStsType.LOC_STS_TYPE_D.type));
+ if (emptyLocs.isEmpty()) {
+ return;
+ }
+ List<Task> existingEmptyOut = taskService.list(new LambdaQueryWrapper<Task>()
+ .eq(Task::getTaskType, TaskType.TASK_TYPE_EMPITY_OUT.type)
+ .lt(Task::getTaskStatus, TaskStsType.COMPLETE_OUT.id));
+ Set<String> locCodesInProgress = existingEmptyOut.stream()
+ .map(Task::getOrgLoc).filter(Objects::nonNull).collect(Collectors.toSet());
+ List<Task> created = new ArrayList<>();
+ for (Loc loc : emptyLocs) {
+ if (locCodesInProgress.contains(loc.getCode())) {
+ continue;
+ }
+ try {
+ LocToTaskParams params = new LocToTaskParams();
+ params.setType(Constants.TASK_TYPE_OUT_STOCK_EMPTY)
+ .setOrgLoc(loc.getCode())
+ .setSiteNo(DEFAULT_SITE_NO);
+ Task task = locItemService.generateTaskEmpty(params, SYSTEM_USER_ID);
+ created.add(task);
+ locCodesInProgress.add(loc.getCode());
+ } catch (Exception e) {
+ log.warn("[鑷姩绌烘澘鍑哄簱] 搴撲綅 {} 鐢熸垚浠诲姟澶辫触: {}", loc.getCode(), e.getMessage());
+ }
+ }
+ if (!created.isEmpty()) {
+ List<Task> toPublish = created.stream()
+ .filter(t -> TaskStsType.GENERATE_OUT.id.equals(t.getTaskStatus()))
+ .collect(Collectors.toList());
+ if (!toPublish.isEmpty()) {
+ try {
+ taskService.pubTaskToWcs(toPublish);
+ log.info("[鑷姩绌烘澘鍑哄簱] 宸茬敓鎴愬苟涓嬪彂 {} 涓┖鏉垮嚭搴撲换鍔�", toPublish.size());
+ } catch (Exception e) {
+ log.error("[鑷姩绌烘澘鍑哄簱] 涓嬪彂 RCS 澶辫触", e);
+ }
+ }
+ }
+ }
+
+ /**
* 瀹氭椂浠诲姟锛氶厤缃墿鏂欏嚭搴撲换鍔″湪 RCS 鍥炶皟涓� 199锛堝緟纭锛夊悗鑷姩鎷h揣瀹屾垚锛屾棤闇� PDA 蹇�熸嫞璐х‘璁ゅ嵆鍙洿鏂板簱瀛樸��
* 閰嶇疆锛欰UTO_FULL_OUT_MATNR_CODE锛堢墿鏂欑紪鐮侊紝閰嶇疆浜嗗垯瀵硅鐗╂枡鐢熸晥锛�
*/
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/LocItemServiceImpl.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/LocItemServiceImpl.java
index 0b19e52..1932160 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/LocItemServiceImpl.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/LocItemServiceImpl.java
@@ -26,11 +26,15 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;
@Service("locItemService")
public class LocItemServiceImpl extends ServiceImpl<LocItemMapper, LocItem> implements LocItemService {
+
+ private static final BigDecimal FULL_OUT_QTY_TOLERANCE = new BigDecimal("0.000001");
Logger logger = LoggerFactory.getLogger(LocItemServiceImpl.class);
@@ -167,12 +171,15 @@
Double orgQty = locItems.stream().mapToDouble(LocItem::getAnfme).sum();
List<LocItem> locItemList = listMap.get(key);
Double outQty = locItemList.stream().mapToDouble(LocItem::getOutQty).sum();
+ BigDecimal orgQtyBd = BigDecimal.valueOf(orgQty).setScale(6, RoundingMode.HALF_UP);
+ BigDecimal outQtyBd = BigDecimal.valueOf(outQty).setScale(6, RoundingMode.HALF_UP);
if (map.getType().equals(Constants.TASK_TYPE_OUT_STOCK)
|| map.getType().equals(Constants.TASK_TYPE_ORDER_OUT_STOCK)
|| map.getType().equals(Constants.TASK_TYPE_WAVE_OUT_STOCK)) {
- if (orgQty.compareTo(outQty) > 0) {
- //鎷f枡鍑哄簱 -- 鐩樼偣鍑哄簱
+ // 鍑哄簱閲忚揪鍒板簱浣嶅簱瀛橈紙鍚宸級瑙嗕负鍏ㄧ増鍑哄簱锛岄伩鍏嶆诞鐐硅宸鑷磋鍒や负鎷f枡/閮ㄥ垎鍑哄簱
+ if (orgQtyBd.subtract(outQtyBd).compareTo(FULL_OUT_QTY_TOLERANCE) > 0) {
+ // 鎷f枡鍑哄簱锛堥儴鍒嗗嚭搴擄級
DeviceSite deviceSite = deviceSiteService.getOne(new LambdaQueryWrapper<DeviceSite>()
.eq(DeviceSite::getSite, siteNo)
.eq(!Objects.isNull(loc.getChannel()),DeviceSite::getChannel, loc.getChannel())
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/system/constant/GlobalConfigCode.java b/rsf-server/src/main/java/com/vincent/rsf/server/system/constant/GlobalConfigCode.java
index 1dd2027..efed840 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/system/constant/GlobalConfigCode.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/system/constant/GlobalConfigCode.java
@@ -53,4 +53,7 @@
/** 鑷姩缁勬墭鏁伴噺锛堜笌 AUTO_PAKIN_ON_ASN_ENABLED 閰嶅悎锛屾瘡鏉℃槑缁嗙粍鎵樻暟閲忥級 */
public final static String AUTO_PAKIN_QTY = "AUTO_PAKIN_QTY";
+ /** 鏄惁鍚敤锛氬畾鏃惰嚜鍔ㄧ敓鎴愮┖鏉垮嚭搴撲换鍔″苟涓嬪彂 RCS锛堟瘡 2 鍒嗛挓鎵弿 D 绌烘澘搴撲綅锛� */
+ public final static String AUTO_EMPTY_OUT_ENABLED = "AUTO_EMPTY_OUT_ENABLED";
+
}
diff --git a/version/db/material_auto_config.sql b/version/db/material_auto_config.sql
index 63153fa..6f164a2 100644
--- a/version/db/material_auto_config.sql
+++ b/version/db/material_auto_config.sql
@@ -6,5 +6,6 @@
(UPPER(UUID()), '鍚敤锛氭湁搴撳瓨鏃惰嚜鍔ㄧ敓鎴愬叏鐗堝嚭搴撳崟', 'AUTO_FULL_OUT_ENABLED', 1, 'false', 'true/false', 1, 0, 1, NULL, NOW(), NULL, NOW(), '闇�閰嶇疆 AUTO_FULL_OUT_MATNR_CODE'),
(UPPER(UUID()), '鍚敤锛氳鐗╂枡鍑哄簱鍗曡嚜鍔ㄤ笅鍙戜换鍔�', 'AUTO_FULL_OUT_DISPATCH_ENABLED', 1, 'false', 'true/false', 1, 0, 1, NULL, NOW(), NULL, NOW(), '闇�閰嶇疆 AUTO_FULL_OUT_MATNR_CODE'),
(UPPER(UUID()), '鍚敤锛歊CS鍏ュ簱閫氱煡鏃惰嚜鍔ㄧ粍鎵�', 'AUTO_PAKIN_ON_ASN_ENABLED', 1, 'false', 'true/false', 1, 0, 1, NULL, NOW(), NULL, NOW(), '闇�閰嶇疆 AUTO_FULL_OUT_MATNR_CODE銆丄UTO_PAKIN_QTY'),
-(UPPER(UUID()), '鑷姩缁勬墭鏁伴噺', 'AUTO_PAKIN_QTY', 2, '1', '姣忔潯鍏ュ簱鏄庣粏鑷姩缁勬墭鏁伴噺', 1, 0, 1, NULL, NOW(), NULL, NOW(), '涓� AUTO_PAKIN_ON_ASN_ENABLED 閰嶅悎')
+(UPPER(UUID()), '鑷姩缁勬墭鏁伴噺', 'AUTO_PAKIN_QTY', 2, '1', '姣忔潯鍏ュ簱鏄庣粏鑷姩缁勬墭鏁伴噺', 1, 0, 1, NULL, NOW(), NULL, NOW(), '涓� AUTO_PAKIN_ON_ASN_ENABLED 閰嶅悎'),
+(UPPER(UUID()), '鍚敤锛氬畾鏃惰嚜鍔ㄧ敓鎴愮┖鏉垮嚭搴撲换鍔″苟涓嬪彂RCS', 'AUTO_EMPTY_OUT_ENABLED', 1, 'false', 'true/false锛屾瘡2鍒嗛挓鎵弿绌烘澘(D)搴撲綅骞剁敓鎴愬嚭搴撲换鍔°�佸懠鍙玆CS', 1, 0, 1, NULL, NOW(), NULL, NOW(), '闇�鍦ㄨ澶囩珯鐐归厤缃� type=110 绌烘澘鍑哄簱鐨勭珯鐐癸紙濡�1001锛�')
;
--
Gitblit v1.9.1