| @@ -2095,15 +2095,11 @@ open fun autoAssignAndReleasePickOrderByStore(userId: Long, storeId: String): Me | |||||
| val zero = BigDecimal.ZERO | val zero = BigDecimal.ZERO | ||||
| val releasedBy = SecurityUtils.getUser().getOrNull() | val releasedBy = SecurityUtils.getUser().getOrNull() | ||||
| val user = userService.find(userId).orElse(null) | val user = userService.find(userId).orElse(null) | ||||
| if (user == null) { | if (user == null) { | ||||
| return MessageResponse( | |||||
| id = null, name = "User not found", code = "ERROR", type = "pickorder", | |||||
| message = "User with ID $userId not found", errorPosition = null | |||||
| ) | |||||
| return MessageResponse(id = null, name = "User not found", code = "ERROR", type = "pickorder", | |||||
| message = "User with ID $userId not found", errorPosition = null) | |||||
| } | } | ||||
| // Get candidate pick order IDs by store from do_pick_order | |||||
| val sql = """ | val sql = """ | ||||
| SELECT DISTINCT dpo.pick_order_id AS pickOrderId | SELECT DISTINCT dpo.pick_order_id AS pickOrderId | ||||
| FROM do_pick_order dpo | FROM do_pick_order dpo | ||||
| @@ -2123,111 +2119,106 @@ open fun autoAssignAndReleasePickOrderByStore(userId: Long, storeId: String): Me | |||||
| println("Candidate pickOrderIds by store $storeId: $pickOrderIdsByStore") | println("Candidate pickOrderIds by store $storeId: $pickOrderIdsByStore") | ||||
| if (pickOrderIdsByStore.isEmpty()) { | if (pickOrderIdsByStore.isEmpty()) { | ||||
| return MessageResponse( | |||||
| id = null, name = "No pick orders", code = "NO_ORDERS", type = "pickorder", | |||||
| message = "No pending pick orders found for store $storeId", errorPosition = null | |||||
| ) | |||||
| return MessageResponse(id = null, name = "No pick orders", code = "NO_ORDERS", type = "pickorder", | |||||
| message = "No pending pick orders found for store $storeId", errorPosition = null) | |||||
| } | } | ||||
| // Filter to available pending DO pick orders by ID and earliest target date | |||||
| val availablePickOrders = pickOrderRepository | val availablePickOrders = pickOrderRepository | ||||
| .findAll() | .findAll() | ||||
| .filter { it.status == PickOrderStatus.PENDING } | |||||
| .filter { it.deliveryOrder != null } | |||||
| .filter { it.id != null && pickOrderIdsByStore.contains(it.id!!) } | .filter { it.id != null && pickOrderIdsByStore.contains(it.id!!) } | ||||
| .filter { it.deliveryOrder != null } | |||||
| .filter { it.assignTo == null } | |||||
| .filter { it.status == PickOrderStatus.PENDING || it.status == PickOrderStatus.RELEASED } | |||||
| .sortedBy { it.targetDate } | .sortedBy { it.targetDate } | ||||
| .take(1) | .take(1) | ||||
| if (availablePickOrders.isEmpty()) { | if (availablePickOrders.isEmpty()) { | ||||
| return MessageResponse( | |||||
| id = null, name = "No available pick orders", code = "NO_ORDERS", type = "pickorder", | |||||
| message = "No pending pick orders available for store $storeId", errorPosition = null | |||||
| ) | |||||
| return MessageResponse(id = null, name = "No available pick orders", code = "NO_ORDERS", type = "pickorder", | |||||
| message = "No unassigned pick orders available for store $storeId", errorPosition = null) | |||||
| } | } | ||||
| val newConsoCode = assignConsoCode() | |||||
| val selected = availablePickOrders.first() | |||||
| val currUser = SecurityUtils.getUser().orElseThrow() | val currUser = SecurityUtils.getUser().orElseThrow() | ||||
| // Create stock out early | |||||
| val stockOut = StockOut().apply { | |||||
| this.type = "job" | |||||
| this.consoPickOrderCode = newConsoCode | |||||
| this.status = StockOutStatus.PENDING.status | |||||
| this.handler = currUser.id | |||||
| } | |||||
| val savedStockOut = stockOutRepository.saveAndFlush(stockOut) | |||||
| // If still PENDING, perform full release flow; if already RELEASED, skip creation duplication | |||||
| if (selected.status == PickOrderStatus.PENDING) { | |||||
| val newConsoCode = assignConsoCode() | |||||
| // Assign and release selected pick order | |||||
| val selected = availablePickOrders.first() | |||||
| selected.apply { | |||||
| this.releasedBy = releasedBy | |||||
| status = PickOrderStatus.RELEASED | |||||
| this.assignTo = user | |||||
| this.consoCode = newConsoCode | |||||
| } | |||||
| val stockOut = StockOut().apply { | |||||
| this.type = "job" | |||||
| this.consoPickOrderCode = newConsoCode | |||||
| this.status = StockOutStatus.PENDING.status | |||||
| this.handler = currUser.id | |||||
| } | |||||
| val savedStockOut = stockOutRepository.saveAndFlush(stockOut) | |||||
| val suggestions = suggestedPickLotService.suggestionForPickOrders( | |||||
| SuggestedPickLotForPoRequest(pickOrders = listOf(selected)) | |||||
| ) | |||||
| val saveSuggestedPickLots = suggestedPickLotService.saveAll(suggestions.suggestedList) | |||||
| pickOrderRepository.saveAndFlush(selected) | |||||
| selected.apply { | |||||
| this.releasedBy = releasedBy | |||||
| status = PickOrderStatus.RELEASED | |||||
| this.consoCode = newConsoCode | |||||
| } | |||||
| // Hold inventory | |||||
| val inventoryLotLines = inventoryLotLineRepository.findAllByIdIn( | |||||
| saveSuggestedPickLots.mapNotNull { it.suggestedLotLine?.id } | |||||
| ) | |||||
| saveSuggestedPickLots.forEach { lot -> | |||||
| val lotLineId = lot.suggestedLotLine?.id | |||||
| if (lotLineId != null) { | |||||
| val idx = inventoryLotLines.indexOf(lot.suggestedLotLine) | |||||
| if (idx >= 0) { | |||||
| val currentHold = inventoryLotLines[idx].holdQty ?: zero | |||||
| val addHold = lot.qty ?: zero | |||||
| inventoryLotLines[idx].holdQty = currentHold.plus(addHold) | |||||
| val suggestions = suggestedPickLotService.suggestionForPickOrders( | |||||
| SuggestedPickLotForPoRequest(pickOrders = listOf(selected)) | |||||
| ) | |||||
| val saveSuggestedPickLots = suggestedPickLotService.saveAll(suggestions.suggestedList) | |||||
| pickOrderRepository.saveAndFlush(selected) | |||||
| val inventoryLotLines = inventoryLotLineRepository.findAllByIdIn( | |||||
| saveSuggestedPickLots.mapNotNull { it.suggestedLotLine?.id } | |||||
| ) | |||||
| saveSuggestedPickLots.forEach { lot -> | |||||
| val lotLineId = lot.suggestedLotLine?.id | |||||
| if (lotLineId != null) { | |||||
| val idx = inventoryLotLines.indexOf(lot.suggestedLotLine) | |||||
| if (idx >= 0) { | |||||
| val currentHold = inventoryLotLines[idx].holdQty ?: zero | |||||
| val addHold = lot.qty ?: zero | |||||
| inventoryLotLines[idx].holdQty = currentHold.plus(addHold) | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| } | |||||
| inventoryLotLineRepository.saveAll(inventoryLotLines) | |||||
| inventoryLotLineRepository.saveAll(inventoryLotLines) | |||||
| // Pre-create stock out lines | |||||
| var precreated = 0 | |||||
| saveSuggestedPickLots.forEach { lot -> | |||||
| val polId = lot.pickOrderLine?.id | |||||
| val illId = lot.suggestedLotLine?.id | |||||
| if (polId != null && illId != null) { | |||||
| val existingLines = stockOutLIneRepository.findByPickOrderLineIdAndInventoryLotLineIdAndDeletedFalse(polId, illId) | |||||
| if (existingLines.isEmpty()) { | |||||
| val pickOrderLine = pickOrderLineRepository.findById(polId).orElse(null) | |||||
| val inventoryLotLine = inventoryLotLineRepository.findById(illId).orElse(null) | |||||
| if (pickOrderLine != null && inventoryLotLine != null) { | |||||
| val line = com.ffii.fpsms.modules.stock.entity.StockOutLine().apply { | |||||
| this.stockOut = savedStockOut | |||||
| this.pickOrderLine = pickOrderLine | |||||
| this.inventoryLotLine = inventoryLotLine | |||||
| this.item = pickOrderLine.item | |||||
| this.status = com.ffii.fpsms.modules.stock.web.model.StockOutLineStatus.PENDING.status | |||||
| this.qty = 0.0 | |||||
| var precreated = 0 | |||||
| saveSuggestedPickLots.forEach { lot -> | |||||
| val polId = lot.pickOrderLine?.id | |||||
| val illId = lot.suggestedLotLine?.id | |||||
| if (polId != null && illId != null) { | |||||
| val existing = stockOutLIneRepository.findByPickOrderLineIdAndInventoryLotLineIdAndDeletedFalse(polId, illId) | |||||
| if (existing.isEmpty()) { | |||||
| val pol = pickOrderLineRepository.findById(polId).orElse(null) | |||||
| val ill = inventoryLotLineRepository.findById(illId).orElse(null) | |||||
| if (pol != null && ill != null) { | |||||
| val line = com.ffii.fpsms.modules.stock.entity.StockOutLine().apply { | |||||
| this.stockOut = savedStockOut | |||||
| this.pickOrderLine = pol | |||||
| this.inventoryLotLine = ill | |||||
| this.item = pol.item | |||||
| this.status = com.ffii.fpsms.modules.stock.web.model.StockOutLineStatus.PENDING.status | |||||
| this.qty = 0.0 | |||||
| } | |||||
| stockOutLIneRepository.save(line) | |||||
| precreated++ | |||||
| } | } | ||||
| stockOutLIneRepository.save(line) | |||||
| precreated++ | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| println("Precreated $precreated stock out lines for store $storeId") | |||||
| } | } | ||||
| println("Precreated $precreated stock out lines for store $storeId") | |||||
| // Assign user (both pending->released and already released) | |||||
| selected.assignTo = user | |||||
| pickOrderRepository.saveAndFlush(selected) | |||||
| return MessageResponse( | return MessageResponse( | ||||
| id = null, | id = null, | ||||
| name = "Pick order assigned and released", | |||||
| name = "Pick order assigned", | |||||
| code = "SUCCESS", | code = "SUCCESS", | ||||
| type = "pickorder", | type = "pickorder", | ||||
| message = "Assigned to user $userId for store $storeId", | message = "Assigned to user $userId for store $storeId", | ||||
| errorPosition = null, | errorPosition = null, | ||||
| entity = mapOf( | |||||
| "consoCode" to newConsoCode, | |||||
| "pickOrderIds" to listOf(selected.id!!), | |||||
| "storeId" to storeId | |||||
| ) | |||||
| entity = mapOf("pickOrderIds" to listOf(selected.id!!), "storeId" to storeId, "status" to selected.status?.value) | |||||
| ) | ) | ||||
| } catch (e: Exception) { | } catch (e: Exception) { | ||||
| e.printStackTrace() | e.printStackTrace() | ||||