From 9bbd43aade3ea9a6c7e8cfcd7a19a61f3b264fe8 Mon Sep 17 00:00:00 2001 From: "CANCERYS\\kw093" Date: Mon, 8 Jun 2026 13:15:30 +0800 Subject: [PATCH] update do is extra same order --- .../DoWorkbenchDopoAssignmentService.kt | 8 +- .../service/DoWorkbenchMainService.kt | 22 +- .../service/DoWorkbenchReleaseService.kt | 346 +++++++++++++----- .../service/WorkbenchReleaseTypeSupport.kt | 61 +++ .../service/HierarchicalFgPayloadAssembler.kt | 1 + .../web/models/SearchPickOrderRequest.kt | 2 + 6 files changed, 325 insertions(+), 115 deletions(-) create mode 100644 src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/WorkbenchReleaseTypeSupport.kt diff --git a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoWorkbenchDopoAssignmentService.kt b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoWorkbenchDopoAssignmentService.kt index 25ef935..4fa089f 100644 --- a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoWorkbenchDopoAssignmentService.kt +++ b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoWorkbenchDopoAssignmentService.kt @@ -145,7 +145,9 @@ open class DoWorkbenchDopoAssignmentService( params["loadingSequence"] = request.loadingSequence } if (isisExtraReleaseType(request.releaseType)) { - sql.append(" AND LOWER(COALESCE(dop.releaseType, '')) = 'isExtra' ") + sql.append(WorkbenchReleaseTypeSupport.legacyIsExtraSql()) + } else { + sql.append(WorkbenchReleaseTypeSupport.assignFilterSql(request.releaseType)) } // Fetch a batch of candidates and try atomic-assign sequentially. // This avoids forcing the frontend to refresh when a single picked candidate is concurrently assigned. @@ -251,7 +253,9 @@ open class DoWorkbenchDopoAssignmentService( params["loadingSequence"] = request.loadingSequence } if (isisExtraReleaseType(request.releaseType)) { - sql.append(" AND LOWER(COALESCE(dop.releaseType, '')) = 'isExtra' ") + sql.append(WorkbenchReleaseTypeSupport.legacyIsExtraSql()) + } else { + sql.append(WorkbenchReleaseTypeSupport.assignFilterSql(request.releaseType)) } val shouldOrderBySequenceV1 = actualStoreId == "2/F" && request.loadingSequence == null if (shouldOrderBySequenceV1) { diff --git a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoWorkbenchMainService.kt b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoWorkbenchMainService.kt index 687a13c..081db78 100644 --- a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoWorkbenchMainService.kt +++ b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoWorkbenchMainService.kt @@ -668,13 +668,7 @@ return MessageResponse( "4/F" -> "4/F" else -> storeId } - val rt = releaseType.lowercase() - val releaseFilterClause = when (rt) { - "batch" -> " AND LOWER(COALESCE(dop.releaseType, '')) = 'batch' " - "single" -> " AND LOWER(COALESCE(dop.releaseType, '')) = 'single' " - "isExtra" -> " AND LOWER(COALESCE(dop.releaseType, '')) = 'isExtra' " - else -> "" - } + val releaseFilterClause = WorkbenchReleaseTypeSupport.summaryFilterSql(releaseType) val sql = """ SELECT dop.truckDepartureTime AS truckDepartureTime, @@ -1068,6 +1062,7 @@ return MessageResponse( dop.deliveryNoteCode AS deliveryNoteCode, dop.cartonQty AS cartonQty, dop.handlerName AS handlerName, + dop.releaseType AS releaseType, GROUP_CONCAT(DISTINCT po.id ORDER BY po.id SEPARATOR ',') AS pickOrderIdsStr, GROUP_CONCAT(DISTINCT po.code ORDER BY po.code SEPARATOR ',') AS pickOrderCodesStr, GROUP_CONCAT(DISTINCT d.id ORDER BY d.id SEPARATOR ',') AS deliveryOrderIdsStr, @@ -1186,6 +1181,7 @@ return MessageResponse( shopAddress = null, fgPickOrders = emptyList(), handlerName = str(row, "handlerName"), + releaseType = str(row, "releaseType"), ) } } @@ -1219,6 +1215,7 @@ return MessageResponse( dop.deliveryNoteCode AS deliveryNoteCode, dop.cartonQty AS cartonQty, dop.handlerName AS handlerName, + dop.releaseType AS releaseType, GROUP_CONCAT(DISTINCT po.id ORDER BY po.id SEPARATOR ',') AS pickOrderIdsStr, GROUP_CONCAT(DISTINCT po.code ORDER BY po.code SEPARATOR ',') AS pickOrderCodesStr, GROUP_CONCAT(DISTINCT d.id ORDER BY d.id SEPARATOR ',') AS deliveryOrderIdsStr, @@ -1336,6 +1333,7 @@ return MessageResponse( shopAddress = null, fgPickOrders = emptyList(), handlerName = str(row, "handlerName"), + releaseType = str(row, "releaseType"), ) } } @@ -1681,9 +1679,7 @@ return MessageResponse( params["shopPat"] = "%${shopName.trim()}%" } val rtNorm = releaseTypeFilter?.trim()?.lowercase().orEmpty() - if (rtNorm == "isExtra") { - sqlBuilder.append(" AND LOWER(COALESCE(dop.releaseType, '')) = 'isExtra' ") - } + sqlBuilder.append(WorkbenchReleaseTypeSupport.summaryFilterSql(rtNorm)) sqlBuilder.append(" ORDER BY dop.requiredDeliveryDate, dop.truckDepartureTime, dop.truckLanceCode, dop.id ") val rows: List> = try { jdbcDao.queryForList(sqlBuilder.toString(), params) @@ -1768,7 +1764,8 @@ return MessageResponse( dop.shopCode as ShopCode, dop.shopName as ShopName, dop.ticketStatus as doTicketStatus, - dop.requiredDeliveryDate as required_delivery_date + dop.requiredDeliveryDate as required_delivery_date, + dop.releaseType as release_type FROM fpsmsdb.delivery_order_pick_order dop WHERE dop.handledBy = :userId @@ -1897,7 +1894,8 @@ return MessageResponse( dop.truckDepartureTime as truck_departure_time, dop.shopCode as ShopCode, dop.shopName as ShopName, - dop.ticketStatus as doTicketStatus + dop.ticketStatus as doTicketStatus, + dop.releaseType as release_type FROM fpsmsdb.delivery_order_pick_order dop WHERE dop.id = :dopoId AND dop.deleted = 0 diff --git a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoWorkbenchReleaseService.kt b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoWorkbenchReleaseService.kt index 5307654..e5d3bda 100644 --- a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoWorkbenchReleaseService.kt +++ b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoWorkbenchReleaseService.kt @@ -359,7 +359,7 @@ open class DoWorkbenchReleaseService( } /** - * `TI-B-yyyyMMdd-2F-001` (batch), `TI-S-yyyyMMdd-2F-001` (single), or `TI-E-yyyyMMdd-2F-001` (Etra), + * `TI-B-yyyyMMdd-2F-001` (batch / isExtrabatch) or `TI-S-yyyyMMdd-2F-001` (single / isExtrasingle), * same suffix rules as [DoReleaseCoordinatorService] / legacy `do_pick_order`. */ private fun nextDeliveryOrderPickOrderTicketNo( @@ -367,8 +367,8 @@ open class DoWorkbenchReleaseService( storeDisplay: String, ticketLetter: String, ): String { - require(ticketLetter == "B" || ticketLetter == "S" || ticketLetter == "E") { - "ticketLetter must be B, S or E" + require(ticketLetter == "B" || ticketLetter == "S") { + "ticketLetter must be B or S" } val ymd = requiredDate.format(DateTimeFormatter.ofPattern("yyyyMMdd")) val floor = storeDisplay.replace("/", "").trim() @@ -400,9 +400,6 @@ open class DoWorkbenchReleaseService( private fun nextDeliveryOrderPickOrderSingleTicketNo(requiredDate: LocalDate, storeDisplay: String): String = nextDeliveryOrderPickOrderTicketNo(requiredDate, storeDisplay, "S") - private fun nextDeliveryOrderPickOrderEtraTicketNo(requiredDate: LocalDate, storeDisplay: String): String = - nextDeliveryOrderPickOrderTicketNo(requiredDate, storeDisplay, "E") - private fun asyncJobType(useV2: Boolean, dopReleaseType: String): String { val single = dopReleaseType.equals("single", ignoreCase = true) return when { @@ -440,120 +437,267 @@ open class DoWorkbenchReleaseService( } } + private fun laneGroupKey(result: ReleaseDoResult): String = + listOf( + result.shopId?.toString() ?: "", + result.estimatedArrivalDate?.toString() ?: "", + result.preferredFloor, + result.truckId?.toString() ?: "", + result.truckDepartureTime?.toString() ?: "", + result.truckLanceCode ?: "", + result.loadingSequence?.toString() ?: "", + ).joinToString("|") + + private fun resolveStoreId(first: ReleaseDoResult): String? { + val isDefaultTruckLane = + first.usedDefaultTruck == true || + first.truckLanceCode?.trim() == WORKBENCH_DEFAULT_TRUCK_LANCE_CODE + if (isDefaultTruckLane) return null + return when (first.preferredFloor) { + "2F" -> "2/F" + "4F" -> "4/F" + else -> "2/F" + } + } + + private fun resolveTicketFloorSegment(storeId: String?, isDefaultTruckLane: Boolean): String = + if (isDefaultTruckLane) { + WORKBENCH_TICKET_FLOOR_SEGMENT_DEFAULT_TRUCK + } else { + (storeId ?: "2/F").replace("/", "").trim() + } + + private data class MergeableWorkbenchTicket(val id: Long, val releaseType: String?) + + /** + * Active batch/single-family ticket for the same lane. Excludes completed tickets and legacy `isExtra`. + */ + private fun findMergeableWorkbenchTicket( + first: ReleaseDoResult, + storeId: String?, + isSingleRelease: Boolean, + ): MergeableWorkbenchTicket? { + if (first.shopId == null || first.estimatedArrivalDate == null) return null + + val familyTypes = if (isSingleRelease) { + WorkbenchReleaseTypeSupport.singleFamilyTypes() + } else { + WorkbenchReleaseTypeSupport.batchFamilyTypes() + } + val typePlaceholders = familyTypes.joinToString(",") { "'${it.lowercase()}'" } + + val sql = StringBuilder( + """ + SELECT id, releaseType + FROM fpsmsdb.delivery_order_pick_order + WHERE deleted = 0 + AND shopId = :shopId + AND requiredDeliveryDate = :requiredDate + AND ticketStatus IN ('pending', 'released') + AND LOWER(COALESCE(releaseType, '')) IN ($typePlaceholders) + """.trimIndent() + ) + val params = mutableMapOf( + "shopId" to first.shopId!!, + "requiredDate" to first.estimatedArrivalDate!!, + ) + if (storeId.isNullOrBlank()) { + sql.append(" AND (storeId IS NULL OR TRIM(COALESCE(storeId, '')) = '') ") + } else { + sql.append(" AND storeId = :storeId ") + params["storeId"] = storeId + } + if (first.truckId != null) { + sql.append(" AND truckId = :truckId ") + params["truckId"] = first.truckId!! + } else { + sql.append(" AND truckId IS NULL ") + } + if (first.truckDepartureTime != null) { + sql.append(" AND truckDepartureTime = :truckDepartureTime ") + params["truckDepartureTime"] = first.truckDepartureTime!! + } else { + sql.append(" AND truckDepartureTime IS NULL ") + } + if (!first.truckLanceCode.isNullOrBlank()) { + sql.append(" AND truckLanceCode = :truckLanceCode ") + params["truckLanceCode"] = first.truckLanceCode!!.trim() + } else { + sql.append(" AND (truckLanceCode IS NULL OR TRIM(truckLanceCode) = '') ") + } + if (first.loadingSequence != null) { + sql.append(" AND loadingSequence = :loadingSequence ") + params["loadingSequence"] = first.loadingSequence!! + } + sql.append(" ORDER BY id ASC ") + + val rows = try { + jdbcDao.queryForList(sql.toString(), params) + } catch (_: Exception) { + emptyList() + } + if (rows.isEmpty()) return null + + fun rowId(row: Map): Long? { + val key = row.keys.find { it.equals("id", true) } ?: return null + return (row[key] as? Number)?.toLong() + } + fun rowReleaseType(row: Map): String? { + val key = row.keys.find { it.equals("releaseType", true) } ?: return null + return row[key]?.toString() + } + + val matched = rows.first() + val id = rowId(matched) ?: return null + return MergeableWorkbenchTicket(id = id, releaseType = rowReleaseType(matched)) + } + + private fun linkPickOrdersToHeader(headerId: Long, group: List) { + group.forEach { r -> + jdbcDao.executeUpdate( + """ + UPDATE fpsmsdb.pick_order + SET deliveryOrderPickOrderId = :headerId + WHERE id = :pickOrderId + """.trimIndent(), + mapOf( + "headerId" to headerId, + "pickOrderId" to r.pickOrderId + ) + ) + } + } + + private fun maybeUpgradeReleaseType( + headerId: Long, + currentReleaseType: String?, + isExtraRelease: Boolean, + isSingleRelease: Boolean, + ) { + val upgraded = WorkbenchReleaseTypeSupport.upgradedReleaseTypeIfNeeded( + currentReleaseType, + isExtraRelease, + isSingleRelease, + ) ?: return + jdbcDao.executeUpdate( + """ + UPDATE fpsmsdb.delivery_order_pick_order + SET releaseType = :releaseType, + modified = :modified, + modifiedBy = :modifiedBy + WHERE id = :id AND deleted = 0 + """.trimIndent(), + mapOf( + "releaseType" to upgraded, + "modified" to LocalDateTime.now(), + "modifiedBy" to "system", + "id" to headerId, + ) + ) + } + + private fun insertNewDeliveryOrderPickOrderHeader( + first: ReleaseDoResult, + storeId: String?, + releaseTypeCol: String, + ticketNo: String, + ): Long? { + val now = LocalDateTime.now() + jdbcDao.executeUpdate( + """ + INSERT INTO fpsmsdb.delivery_order_pick_order ( + truckId, shopId, storeId, requiredDeliveryDate, truckDepartureTime, + truckLanceCode, shopCode, shopName, loadingSequence, ticketNo, + ticketReleaseTime, ticketStatus, releaseType, handledBy, handlerName, + created, createdBy, version, modified, modifiedBy, deleted + ) VALUES ( + :truckId, :shopId, :storeId, :requiredDeliveryDate, :truckDepartureTime, + :truckLanceCode, :shopCode, :shopName, :loadingSequence, :ticketNo, + NULL, 'pending', :releaseType, NULL, NULL, + :created, :createdBy, 0, :modified, :modifiedBy, 0 + ) + """.trimIndent(), + mapOf( + "truckId" to first.truckId, + "shopId" to first.shopId, + "storeId" to storeId, + "requiredDeliveryDate" to (first.estimatedArrivalDate ?: LocalDate.now()), + "truckDepartureTime" to first.truckDepartureTime, + "truckLanceCode" to first.truckLanceCode, + "shopCode" to first.shopCode, + "shopName" to first.shopName, + "loadingSequence" to first.loadingSequence, + "ticketNo" to ticketNo, + "releaseType" to releaseTypeCol, + "created" to now, + "createdBy" to "system", + "modified" to now, + "modifiedBy" to "system", + ) + ) + return jdbcDao.queryForList( + """ + SELECT id + FROM fpsmsdb.delivery_order_pick_order + WHERE ticketNo = :ticketNo + ORDER BY id DESC + LIMIT 1 + """.trimIndent(), + mapOf("ticketNo" to ticketNo) + ).firstOrNull()?.get("id")?.let { (it as Number).toLong() } + } + + /** + * Link released pick orders to [delivery_order_pick_order] headers. + * Normal DOs merge into batch/single-family tickets; isExtra DOs upgrade `batch`→`isExtrabatch` or `single`→`isExtrasingle`. + * Legacy `isExtra` tickets are never merge targets. Completed tickets are skipped (new header created instead). + */ private fun createAndLinkDeliveryOrderPickOrders( results: List, dopReleaseType: String = "batch", ): Int { if (results.isEmpty()) return 0 - val grouped = results.groupBy { - listOf( - it.shopId?.toString() ?: "", - it.estimatedArrivalDate?.toString() ?: "", - it.preferredFloor, - it.truckId?.toString() ?: "", - it.truckDepartureTime?.toString() ?: "", - it.truckLanceCode ?: "", - it.isExtra.toString(), - ).joinToString("|") - } + val isSingleRelease = dopReleaseType.equals("single", ignoreCase = true) + val normalGroups = results.filter { !it.isExtra }.groupBy { laneGroupKey(it) } + val extraGroups = results.filter { it.isExtra }.groupBy { laneGroupKey(it) } var createdHeaders = 0 - grouped.values.forEach { group -> + + fun processGroup(group: List, isExtraRelease: Boolean): Int { + if (group.isEmpty()) return 0 val first = group.first() + val storeId = resolveStoreId(first) val isDefaultTruckLane = first.usedDefaultTruck == true || first.truckLanceCode?.trim() == WORKBENCH_DEFAULT_TRUCK_LANCE_CODE - val storeId: String? = if (isDefaultTruckLane) { - null - } else { - when (first.preferredFloor) { - "2F" -> "2/F" - "4F" -> "4/F" - else -> "2/F" - } - } - val ticketFloorSegment = if (isDefaultTruckLane) { - WORKBENCH_TICKET_FLOOR_SEGMENT_DEFAULT_TRUCK - } else { - (storeId ?: "2/F").replace("/", "").trim() - } + val ticketFloorSegment = resolveTicketFloorSegment(storeId, isDefaultTruckLane) val requiredDate = first.estimatedArrivalDate ?: LocalDate.now() - val releaseTypeCol = if (first.isExtra) { - "isExtra" - } else if (dopReleaseType.equals("single", ignoreCase = true)) { - "single" - } else { - "batch" + + val existing = findMergeableWorkbenchTicket(first, storeId, isSingleRelease) + if (existing != null) { + linkPickOrdersToHeader(existing.id, group) + maybeUpgradeReleaseType(existing.id, existing.releaseType, isExtraRelease, isSingleRelease) + return 0 } - val tempTicket = if (first.isExtra) { - nextDeliveryOrderPickOrderEtraTicketNo(requiredDate, ticketFloorSegment) - } else if (releaseTypeCol == "single") { + + val releaseTypeCol = WorkbenchReleaseTypeSupport.newHeaderReleaseType(isExtraRelease, isSingleRelease) + val ticketNo = if (isSingleRelease) { nextDeliveryOrderPickOrderSingleTicketNo(requiredDate, ticketFloorSegment) } else { nextDeliveryOrderPickOrderBatchTicketNo(requiredDate, ticketFloorSegment) } - val now = LocalDateTime.now() - - // Column names must match Liquibase `01_alter_stock_take.sql` (camelCase), not snake_case. - jdbcDao.executeUpdate( - """ - INSERT INTO fpsmsdb.delivery_order_pick_order ( - truckId, shopId, storeId, requiredDeliveryDate, truckDepartureTime, - truckLanceCode, shopCode, shopName, loadingSequence, ticketNo, - ticketReleaseTime, ticketStatus, releaseType, handledBy, handlerName, - created, createdBy, version, modified, modifiedBy, deleted - ) VALUES ( - :truckId, :shopId, :storeId, :requiredDeliveryDate, :truckDepartureTime, - :truckLanceCode, :shopCode, :shopName, :loadingSequence, :ticketNo, - NULL, 'pending', :releaseType, NULL, NULL, - :created, :createdBy, 0, :modified, :modifiedBy, 0 - ) - """.trimIndent(), - mapOf( - "truckId" to first.truckId, - "shopId" to first.shopId, - "storeId" to storeId, - "requiredDeliveryDate" to (first.estimatedArrivalDate ?: LocalDate.now()), - "truckDepartureTime" to first.truckDepartureTime, - "truckLanceCode" to first.truckLanceCode, - "shopCode" to first.shopCode, - "shopName" to first.shopName, - "loadingSequence" to first.loadingSequence, - "ticketNo" to tempTicket, - "releaseType" to releaseTypeCol, - "created" to now, - "createdBy" to "system", - "modified" to now, - "modifiedBy" to "system", - ) - ) - - val headerId = jdbcDao.queryForList( - """ - SELECT id - FROM fpsmsdb.delivery_order_pick_order - WHERE ticketNo = :ticketNo - ORDER BY id DESC - LIMIT 1 - """.trimIndent(), - mapOf("ticketNo" to tempTicket) - ).firstOrNull()?.get("id")?.let { (it as Number).toLong() } ?: return@forEach + val headerId = insertNewDeliveryOrderPickOrderHeader(first, storeId, releaseTypeCol, ticketNo) + ?: return 0 + linkPickOrdersToHeader(headerId, group) + return 1 + } - group.forEach { r -> - jdbcDao.executeUpdate( - """ - UPDATE fpsmsdb.pick_order - SET deliveryOrderPickOrderId = :headerId - WHERE id = :pickOrderId - """.trimIndent(), - mapOf( - "headerId" to headerId, - "pickOrderId" to r.pickOrderId - ) - ) - } - createdHeaders++ + normalGroups.values.forEach { group -> + createdHeaders += processGroup(group, isExtraRelease = false) + } + extraGroups.values.forEach { group -> + createdHeaders += processGroup(group, isExtraRelease = true) } return createdHeaders diff --git a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/WorkbenchReleaseTypeSupport.kt b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/WorkbenchReleaseTypeSupport.kt new file mode 100644 index 0000000..c775577 --- /dev/null +++ b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/WorkbenchReleaseTypeSupport.kt @@ -0,0 +1,61 @@ +package com.ffii.fpsms.modules.deliveryOrder.service + +/** + * Workbench [delivery_order_pick_order.releaseType] values and SQL filters. + * Legacy `isExtra` tickets are excluded from merge; only used for legacy Etra views. + */ +object WorkbenchReleaseTypeSupport { + const val BATCH = "batch" + const val SINGLE = "single" + const val IS_EXTRA_BATCH = "isExtrabatch" + const val IS_EXTRA_SINGLE = "isExtrasingle" + const val LEGACY_IS_EXTRA = "isExtra" + + fun batchFamilyTypes(): List = listOf(BATCH, IS_EXTRA_BATCH) + + fun singleFamilyTypes(): List = listOf(SINGLE, IS_EXTRA_SINGLE) + + fun summaryFilterSql(releaseType: String, column: String = "dop.releaseType"): String = + when (releaseType.trim().lowercase()) { + "batch" -> batchFamilySql(column) + "single" -> singleFamilySql(column) + "isextra" -> legacyIsExtraSql(column) + else -> "" + } + + fun assignFilterSql(releaseType: String?, column: String = "dop.releaseType"): String { + val n = releaseType?.trim()?.lowercase().orEmpty() + return when (n) { + "batch" -> batchFamilySql(column) + "single" -> singleFamilySql(column) + "isextra" -> legacyIsExtraSql(column) + else -> "" + } + } + + fun batchFamilySql(column: String = "dop.releaseType"): String = + " AND LOWER(COALESCE($column, '')) IN ('batch', 'isextrabatch') " + + fun singleFamilySql(column: String = "dop.releaseType"): String = + " AND LOWER(COALESCE($column, '')) IN ('single', 'isextrasingle') " + + fun legacyIsExtraSql(column: String = "dop.releaseType"): String = + " AND LOWER(COALESCE($column, '')) = 'isextra' " + + fun newHeaderReleaseType(isExtraRelease: Boolean, isSingleRelease: Boolean): String = when { + isExtraRelease && isSingleRelease -> IS_EXTRA_SINGLE + isExtraRelease -> IS_EXTRA_BATCH + isSingleRelease -> SINGLE + else -> BATCH + } + + fun upgradedReleaseTypeIfNeeded(currentType: String?, isExtraRelease: Boolean, isSingleRelease: Boolean): String? { + if (!isExtraRelease) return null + val cur = currentType?.trim()?.lowercase().orEmpty() + return when { + isSingleRelease && cur == SINGLE.lowercase() -> IS_EXTRA_SINGLE + !isSingleRelease && cur == BATCH.lowercase() -> IS_EXTRA_BATCH + else -> null + } + } +} diff --git a/src/main/java/com/ffii/fpsms/modules/pickOrder/service/HierarchicalFgPayloadAssembler.kt b/src/main/java/com/ffii/fpsms/modules/pickOrder/service/HierarchicalFgPayloadAssembler.kt index 170fff1..491e973 100644 --- a/src/main/java/com/ffii/fpsms/modules/pickOrder/service/HierarchicalFgPayloadAssembler.kt +++ b/src/main/java/com/ffii/fpsms/modules/pickOrder/service/HierarchicalFgPayloadAssembler.kt @@ -336,6 +336,7 @@ ORDER BY "shopName" to doPickOrderInfo["ShopName"], "truckLanceCode" to doPickOrderInfo["TruckLanceCode"], "departureTime" to doPickOrderInfo["truck_departure_time"], + "releaseType" to doPickOrderInfo["release_type"], ) val allConsoCodes = pickOrdersInfo.mapNotNull { it["consoCode"] as? String }.distinct() diff --git a/src/main/java/com/ffii/fpsms/modules/pickOrder/web/models/SearchPickOrderRequest.kt b/src/main/java/com/ffii/fpsms/modules/pickOrder/web/models/SearchPickOrderRequest.kt index 104fac3..c8906e7 100644 --- a/src/main/java/com/ffii/fpsms/modules/pickOrder/web/models/SearchPickOrderRequest.kt +++ b/src/main/java/com/ffii/fpsms/modules/pickOrder/web/models/SearchPickOrderRequest.kt @@ -53,6 +53,8 @@ data class CompletedDoPickOrderResponse( val fgPickOrders: List, /** Legacy: `do_pick_order_record.handler_name`; workbench: `delivery_order_pick_order.handlerName`. */ val handlerName: String? = null, + /** Workbench: `delivery_order_pick_order.releaseType` (e.g. isExtrabatch, batch). */ + val releaseType: String? = null, ) data class FgPickOrderSummary(