| @@ -75,6 +75,7 @@ public class SecurityConfig { | |||||
| } | } | ||||
| /** | /** | ||||
| * FP-MTMS Version Checklist | Functions Ref. No. 67 | v1.0.0 | 2026-08-13 | |||||
| * FP-MTMS Version Checklist | Functions Ref. No. 51 | v1.0.1 | 2026-08-06 | * FP-MTMS Version Checklist | Functions Ref. No. 51 | v1.0.1 | 2026-08-06 | ||||
| * FP-MTMS Version Checklist | Functions Ref. No. 3 | v1.0.5 | 2026-08-05 | * FP-MTMS Version Checklist | Functions Ref. No. 3 | v1.0.5 | 2026-08-05 | ||||
| * (stockAdjustment/submit → INVENTORY_ADJUST only) | * (stockAdjustment/submit → INVENTORY_ADJUST only) | ||||
| @@ -128,6 +129,15 @@ public class SecurityConfig { | |||||
| /* 工序「已完成」(Just Pass):僅 ADMIN */ | /* 工序「已完成」(Just Pass):僅 ADMIN */ | ||||
| .requestMatchers(HttpMethod.POST, "/product-process/Demo/ProcessLine/pass/**") | .requestMatchers(HttpMethod.POST, "/product-process/Demo/ProcessLine/pass/**") | ||||
| .hasAuthority("ADMIN") | .hasAuthority("ADMIN") | ||||
| /* M18 手動同步頁:ADMIN 或 M18_SYNC。po-by-code 另允許 PURCHASE(採購單搜尋自動同步)。 */ | |||||
| .requestMatchers(HttpMethod.GET, "/m18/test/po-by-code") | |||||
| .hasAnyAuthority("ADMIN", "M18_SYNC", "PURCHASE") | |||||
| .requestMatchers(HttpMethod.GET, "/m18/test/do-by-code") | |||||
| .hasAnyAuthority("ADMIN", "M18_SYNC") | |||||
| .requestMatchers(HttpMethod.GET, "/m18/test/do-by-code-extra") | |||||
| .hasAnyAuthority("ADMIN", "M18_SYNC") | |||||
| .requestMatchers(HttpMethod.GET, "/m18/test/product-by-code") | |||||
| .hasAnyAuthority("ADMIN", "M18_SYNC") | |||||
| .anyRequest().authenticated()) | .anyRequest().authenticated()) | ||||
| .httpBasic(httpBasic -> httpBasic.authenticationEntryPoint( | .httpBasic(httpBasic -> httpBasic.authenticationEntryPoint( | ||||
| (request, response, authException) -> sendUnauthorizedJson(response, "Unauthorized", "UNAUTHORIZED"))) | (request, response, authException) -> sendUnauthorizedJson(response, "Unauthorized", "UNAUTHORIZED"))) | ||||
| @@ -244,9 +244,10 @@ open class DoWorkbenchMainService( | |||||
| } | } | ||||
| /** | /** | ||||
| * FP-MTMS Version Checklist | Functions Ref. No. 38 | v1.0.2 | 2026-08-13 | |||||
| * Warehouse exclude list for workbench **re-suggest** after scan-pick (shortfall / lot split). | * Warehouse exclude list for workbench **re-suggest** after scan-pick (shortfall / lot split). | ||||
| * - JO: same list as assign ([JoWorkbenchPickConstants.DEFAULT_EXCLUDE_WAREHOUSE_CODES]). | * - JO: same list as assign ([JoWorkbenchPickConstants.DEFAULT_EXCLUDE_WAREHOUSE_CODES]). | ||||
| * - Consumable: hardcoded user [ConsumableWorkbenchPickConstants.HARDCODED_EXCLUDE_USER_ID] → JO list; else `null`. | |||||
| * - Consumable: hardcoded user [ConsumableWorkbenchPickConstants.HARDCODED_EXCLUDE_USER_ID] → JO list; else empty (no limit). | |||||
| * - DO / other: pass through request (`null` → service default excludes). | * - DO / other: pass through request (`null` → service default excludes). | ||||
| */ | */ | ||||
| private fun workbenchResuggestExcludeWarehouseCodes( | private fun workbenchResuggestExcludeWarehouseCodes( | ||||
| @@ -267,7 +268,7 @@ open class DoWorkbenchMainService( | |||||
| } | } | ||||
| /** | /** | ||||
| * FP-MTMS Version Checklist | Functions Ref. No. 38 | v1.0.1 | 2026-08-10 | |||||
| * FP-MTMS Version Checklist | Functions Ref. No. 38 | v1.0.2 | 2026-08-13 | |||||
| * Workbench scan-pick (DO FG): | * Workbench scan-pick (DO FG): | ||||
| * 1) Post outbound on scanned inventory lot line first; on failure return a clear message. | * 1) Post outbound on scanned inventory lot line first; on failure return a clear message. | ||||
| * 2) If the lot runs out before this stock-out line’s chunk is filled and the user did not pass a short [qty], | * 2) If the lot runs out before this stock-out line’s chunk is filled and the user did not pass a short [qty], | ||||
| @@ -2364,6 +2365,7 @@ return MessageResponse( | |||||
| } | } | ||||
| } | } | ||||
| /** FP-MTMS Version Checklist | Functions Ref. No. 38 | v1.0.2 | 2026-08-13 */ | |||||
| private fun runWorkbenchPickDeferredFollowUps( | private fun runWorkbenchPickDeferredFollowUps( | ||||
| solId: Long, | solId: Long, | ||||
| polId: Long, | polId: Long, | ||||
| @@ -2386,12 +2388,17 @@ return MessageResponse( | |||||
| var postMs = 0L | var postMs = 0L | ||||
| try { | try { | ||||
| if (pickOrderId != null) { | if (pickOrderId != null) { | ||||
| // JO assign primes with storeId=null; re-suggest must match or 3F lots are | |||||
| // filtered out after resolveWorkbenchSuggestionStoreId defaults to "2/F". | |||||
| // JO / Consumable prime with storeId=null; re-suggest must match or non-2F lots | |||||
| // are filtered out after resolveWorkbenchSuggestionStoreId defaults to "2/F". | |||||
| val resolvedPoType = pickOrderRepository.findById(pickOrderId).orElse(null)?.type | val resolvedPoType = pickOrderRepository.findById(pickOrderId).orElse(null)?.type | ||||
| val suggestionStoreId = | val suggestionStoreId = | ||||
| if (resolvedPoType == PickOrderType.JOB_ORDER) null | |||||
| else resolveWorkbenchSuggestionStoreId(pickOrderId, requestStoreId) | |||||
| if (resolvedPoType == PickOrderType.JOB_ORDER || | |||||
| resolvedPoType == PickOrderType.Consumable | |||||
| ) { | |||||
| null | |||||
| } else { | |||||
| resolveWorkbenchSuggestionStoreId(pickOrderId, requestStoreId) | |||||
| } | |||||
| val resuggestExcludeWarehouseCodes = workbenchResuggestExcludeWarehouseCodes( | val resuggestExcludeWarehouseCodes = workbenchResuggestExcludeWarehouseCodes( | ||||
| pickOrderId = pickOrderId, | pickOrderId = pickOrderId, | ||||
| poType = resolvedPoType, | poType = resolvedPoType, | ||||
| @@ -2625,7 +2632,7 @@ return MessageResponse( | |||||
| } | } | ||||
| /** | /** | ||||
| * FP-MTMS Version Checklist | Functions Ref. No. 38 | v1.0.1 | 2026-08-10 | |||||
| * FP-MTMS Version Checklist | Functions Ref. No. 38 | v1.0.2 | 2026-08-13 | |||||
| * DO user-audit: Just Complete is reportable only when the item still has pickable stock | * DO user-audit: Just Complete is reportable only when the item still has pickable stock | ||||
| * at complete time (AVAILABLE, not expired, in−out > 0). | * at complete time (AVAILABLE, not expired, in−out > 0). | ||||
| * | * | ||||
| @@ -3,7 +3,7 @@ package com.ffii.fpsms.modules.deliveryOrder.web.models | |||||
| import java.math.BigDecimal | import java.math.BigDecimal | ||||
| /** | /** | ||||
| * FP-MTMS Version Checklist | Functions Ref. No. 38 | v1.0.0 | 2026-08-03 | |||||
| * FP-MTMS Version Checklist | Functions Ref. No. 38 | v1.0.2 | 2026-08-13 | |||||
| * Workbench v1: scan lot and post pick immediately (no separate submit step). | * Workbench v1: scan lot and post pick immediately (no separate submit step). | ||||
| * [qty] optional: when null, posts up to remaining quantity for this stock-out line chunk; when set, may exceed that | * [qty] optional: when null, posts up to remaining quantity for this stock-out line chunk; when set, may exceed that | ||||
| * chunk and is capped only by available quantity on the scanned inventory lot line (overscan / UI edit). | * chunk and is capped only by available quantity on the scanned inventory lot line (overscan / UI edit). | ||||
| @@ -6,13 +6,16 @@ import com.ffii.fpsms.modules.jobOrder.service.JoWorkbenchPickConstants | |||||
| * Temporary consumable workbench exclude list until per-user DB config (Scheme A) lands. | * Temporary consumable workbench exclude list until per-user DB config (Scheme A) lands. | ||||
| * | * | ||||
| * - [HARDCODED_EXCLUDE_USER_ID] → same warehouses as JO ([JoWorkbenchPickConstants]). | * - [HARDCODED_EXCLUDE_USER_ID] → same warehouses as JO ([JoWorkbenchPickConstants]). | ||||
| * - All other users → `null` → DO 2F default excludes in [SuggestedPickLotWorkbenchService]. | |||||
| * - All other users → empty list (no warehouse limit). Do not return null: | |||||
| * [SuggestedPickLotWorkbenchService] treats null as DO default 2F excludes. | |||||
| * Consumable re-suggest keeps storeId null (same as first prime / JO); it does not use DO floor store resolution. | |||||
| */ | */ | ||||
| object ConsumableWorkbenchPickConstants { | object ConsumableWorkbenchPickConstants { | ||||
| const val HARDCODED_EXCLUDE_USER_ID: Long = 246L | const val HARDCODED_EXCLUDE_USER_ID: Long = 246L | ||||
| fun resolveExcludeWarehouseCodes(userId: Long): List<String>? { | |||||
| if (userId != HARDCODED_EXCLUDE_USER_ID) return null | |||||
| /** FP-MTMS Version Checklist | Functions Ref. No. 66 | v1.0.0 | 2026-08-13 */ | |||||
| fun resolveExcludeWarehouseCodes(userId: Long): List<String> { | |||||
| if (userId != HARDCODED_EXCLUDE_USER_ID) return emptyList() | |||||
| return JoWorkbenchPickConstants.DEFAULT_EXCLUDE_WAREHOUSE_CODES.toList() | return JoWorkbenchPickConstants.DEFAULT_EXCLUDE_WAREHOUSE_CODES.toList() | ||||
| } | } | ||||
| } | } | ||||
| @@ -0,0 +1,8 @@ | |||||
| --liquibase formatted sql | |||||
| --changeset fpsms:add_m18_sync_authority | |||||
| --preconditions onFail:MARK_RAN | |||||
| --precondition-sql-check expectedResult:0 SELECT COUNT(*) FROM authority WHERE authority = 'M18_SYNC' | |||||
| --comment: Manual M18 sync page (/m18Syn): ADMIN or M18_SYNC | |||||
| INSERT IGNORE INTO `authority` (`authority`, `name`, `module`, `description`) | |||||
| VALUES ('M18_SYNC', 'M18同步', 'M18', 'Allow manual M18 sync by document or item code'); | |||||