diff --git a/src/main/java/com/ffii/fpsms/modules/jobOrder/entity/JobOrderRepository.kt b/src/main/java/com/ffii/fpsms/modules/jobOrder/entity/JobOrderRepository.kt index 73d8562..9ca0d35 100644 --- a/src/main/java/com/ffii/fpsms/modules/jobOrder/entity/JobOrderRepository.kt +++ b/src/main/java/com/ffii/fpsms/modules/jobOrder/entity/JobOrderRepository.kt @@ -69,7 +69,7 @@ interface JobOrderRepository : AbstractRepository { left join picked_lot_no pln on pln.itemId = jobm.itemId and pln.joId = jo.id where jo.id = :id group by jo.id, uc2.udfudesc, uc2.udfShortDesc - group by jo.id, uc2.udfudesc, uc2.udfShortDesc + limit 1 """ ) diff --git a/src/main/java/com/ffii/fpsms/modules/jobOrder/service/JoPickOrderService.kt b/src/main/java/com/ffii/fpsms/modules/jobOrder/service/JoPickOrderService.kt index 0fa1d51..40f7c05 100644 --- a/src/main/java/com/ffii/fpsms/modules/jobOrder/service/JoPickOrderService.kt +++ b/src/main/java/com/ffii/fpsms/modules/jobOrder/service/JoPickOrderService.kt @@ -1251,4 +1251,214 @@ open fun getCompletedJobOrderPickOrderLotDetails(pickOrderId: Long): List> { + println("=== getCompletedJobOrderPickOrders ===") + println("userId: $userId") + + return try { + // Get all completed pick orders assigned to user that have joId + val completedPickOrders = pickOrderRepository.findAllByAssignToIdAndStatusIn( + userId, + listOf(PickOrderStatus.COMPLETED) + ).filter { it.jobOrder != null } // Only pick orders with joId + + println("Found ${completedPickOrders.size} completed job order pick orders for user $userId") + + val completedJobOrderPickOrders = completedPickOrders.mapNotNull { pickOrder -> + val jobOrder = pickOrder.jobOrder + if (jobOrder != null) { + // Get JoPickOrder records for this pick order + val joPickOrders = findByPickOrderId(pickOrder.id!!) + + // Calculate second scan completion status + val secondScanCompleted = joPickOrders.isNotEmpty() && + joPickOrders.all { it.second_qr_scan_status == JoPickOrderStatus.completed } + + mapOf( + "id" to pickOrder.id, + "pickOrderId" to pickOrder.id, + "pickOrderCode" to pickOrder.code, + "pickOrderConsoCode" to pickOrder.consoCode, + "pickOrderTargetDate" to pickOrder.targetDate?.let { + "${it.year}-${String.format("%02d", it.monthValue)}-${String.format("%02d", it.dayOfMonth)}" + }, + "pickOrderStatus" to pickOrder.status, + "completedDate" to pickOrder.completeDate?.let { + "${it.year}-${String.format("%02d", it.monthValue)}-${String.format("%02d", it.dayOfMonth)}" + }, + "jobOrderId" to jobOrder.id, + "jobOrderCode" to jobOrder.code, + "jobOrderName" to jobOrder.bom?.name, + "reqQty" to jobOrder.reqQty, + "uom" to jobOrder.bom?.uom?.code, + "planStart" to jobOrder.planStart, + "planEnd" to jobOrder.planEnd, + "secondScanCompleted" to secondScanCompleted, + "totalItems" to joPickOrders.size, + "completedItems" to joPickOrders.count { it.second_qr_scan_status == JoPickOrderStatus.completed } + ) + } else { + println("❌ Pick order ${pickOrder.id} has no job order, skipping.") + null + } + } + + println("Returning ${completedJobOrderPickOrders.size} completed job order pick orders") + completedJobOrderPickOrders + } catch (e: Exception) { + println("❌ Error in getCompletedJobOrderPickOrders: ${e.message}") + e.printStackTrace() + emptyList() + } + } + +// ... rest of the code ... + +open fun getCompletedJobOrderPickOrderLotDetailsForCompletedPick(pickOrderId: Long): List> { + println("=== getCompletedJobOrderPickOrderLotDetailsForCompletedPick ===") + println("pickOrderId: $pickOrderId") + + return try { + val sql = """ + SELECT + -- Pick Order Information + po.id as pickOrderId, + po.code as pickOrderCode, + po.consoCode as pickOrderConsoCode, + DATE_FORMAT(po.targetDate, '%Y-%m-%d') as pickOrderTargetDate, + po.status as pickOrderStatus, + + -- Job Order Information + jo.id as jobOrderId, + jo.code as jobOrderCode, + + -- Pick Order Line Information + pol.id as pickOrderLineId, + pol.qty as pickOrderLineRequiredQty, + pol.status as pickOrderLineStatus, + + -- Item Information + i.id as itemId, + i.code as itemCode, + i.name as itemName, + uc.code as uomCode, + uc.udfudesc as uomDesc, + uc.udfShortDesc as uomShortDesc, + + -- Lot Information + ill.id as lotId, + il.lotNo, + DATE_FORMAT(il.expiryDate, '%Y-%m-%d') as expiryDate, + w.name as location, + COALESCE(uc.udfudesc, 'N/A') as stockUnit, + + -- Router Information + r.id as routerId, + r.index as routerIndex, + r.route as routerRoute, + r.area as routerArea, + + -- Set quantities to NULL for rejected lots + CASE + WHEN sol.status = 'rejected' THEN NULL + ELSE (COALESCE(ill.inQty, 0) - COALESCE(ill.outQty, 0) - COALESCE(ill.holdQty, 0)) + END as availableQty, + + -- Required quantity for this lot + COALESCE(spl.qty, 0) as requiredQty, + + -- Actual picked quantity + COALESCE(sol.qty, 0) as actualPickQty, + + -- Suggested pick lot information + spl.id as suggestedPickLotId, + ill.status as lotStatus, + + -- Stock out line information + sol.id as stockOutLineId, + sol.status as stockOutLineStatus, + COALESCE(sol.qty, 0) as stockOutLineQty, + + -- Additional detailed fields + COALESCE(ill.inQty, 0) as inQty, + COALESCE(ill.outQty, 0) as outQty, + COALESCE(ill.holdQty, 0) as holdQty, + + -- Calculate total picked quantity by ALL pick orders for this lot + COALESCE(( + SELECT SUM(sol_all.qty) + FROM fpsmsdb.stock_out_line sol_all + WHERE sol_all.inventoryLotLineId = ill.id + AND sol_all.deleted = false + AND sol_all.status IN ('pending', 'checked', 'partially_completed', 'completed') + ), 0) as totalPickedByAllPickOrders, + + -- Calculate remaining available quantity correctly + (COALESCE(ill.inQty, 0) - COALESCE(ill.outQty, 0) - COALESCE(ill.holdQty, 0)) as remainingAfterAllPickOrders, + + -- Lot availability status + CASE + WHEN (il.expiryDate IS NOT NULL AND il.expiryDate < CURDATE()) THEN 'expired' + WHEN sol.status = 'rejected' THEN 'rejected' + WHEN (COALESCE(ill.inQty, 0) - COALESCE(ill.outQty, 0) - COALESCE(ill.holdQty, 0)) <= 0 THEN 'insufficient_stock' + WHEN ill.status = 'unavailable' THEN 'status_unavailable' + ELSE 'available' + END as lotAvailability, + + -- Processing status + CASE + WHEN sol.status = 'completed' THEN 'completed' + WHEN sol.status = 'rejected' THEN 'rejected' + WHEN sol.status = 'created' THEN 'pending' + ELSE 'pending' + END as processingStatus, + + -- JoPickOrder second scan status + jpo.second_qr_scan_status as secondQrScanStatus, + jpo.second_qr_scan_by as secondQrScanBy, + jpo.second_qr_scan_qty as secondQrScanQty + + FROM fpsmsdb.pick_order po + JOIN fpsmsdb.job_order jo ON jo.id = po.joId + JOIN fpsmsdb.pick_order_line pol ON pol.poId = po.id + JOIN fpsmsdb.items i ON i.id = pol.itemId + LEFT JOIN fpsmsdb.uom_conversion uc ON uc.id = pol.uomId + LEFT JOIN fpsmsdb.suggested_pick_lot spl ON pol.id = spl.pickOrderLineId + LEFT JOIN fpsmsdb.inventory_lot_line ill ON spl.suggestedLotLineId = ill.id + LEFT JOIN fpsmsdb.router r ON r.inventoryLotId = ill.id AND r.deleted = false + LEFT JOIN fpsmsdb.inventory_lot il ON il.id = ill.inventoryLotId + LEFT JOIN fpsmsdb.warehouse w ON w.id = ill.warehouseId + LEFT JOIN fpsmsdb.stock_out_line sol ON sol.pickOrderLineId = pol.id AND sol.inventoryLotLineId = ill.id AND sol.deleted = false + LEFT JOIN fpsmsdb.jo_pick_order jpo ON jpo.pick_order_id = po.id AND jpo.item_id = pol.itemId + WHERE po.deleted = false + AND po.id = :pickOrderId + AND pol.deleted = false + AND po.status = 'COMPLETED' + AND ill.deleted = false + AND il.deleted = false + AND (spl.pickOrderLineId IS NOT NULL OR sol.pickOrderLineId IS NOT NULL) + ORDER BY + CASE WHEN sol.status = 'rejected' THEN 0 ELSE 1 END, + COALESCE(r.index, 0) ASC, + po.code ASC, + i.code ASC, + il.expiryDate ASC, + il.lotNo ASC + """.trimIndent() + + println("🔍 Executing SQL for completed pick order lot details: $sql") + println("🔍 With parameters: pickOrderId = $pickOrderId") + + val results = jdbcDao.queryForList(sql, mapOf("pickOrderId" to pickOrderId)) + + println("Found ${results.size} lot details for completed pick order $pickOrderId") + results + } catch (e: Exception) { + println("❌ Error in getCompletedJobOrderPickOrderLotDetailsForCompletedPick: ${e.message}") + e.printStackTrace() + emptyList() + } +} } diff --git a/src/main/java/com/ffii/fpsms/modules/jobOrder/web/JobOrderController.kt b/src/main/java/com/ffii/fpsms/modules/jobOrder/web/JobOrderController.kt index 1483543..fbe4bde 100644 --- a/src/main/java/com/ffii/fpsms/modules/jobOrder/web/JobOrderController.kt +++ b/src/main/java/com/ffii/fpsms/modules/jobOrder/web/JobOrderController.kt @@ -148,4 +148,13 @@ class JobOrderController( fun getCompletedJobOrderPickOrderLotDetails(@PathVariable pickOrderId: Long): List> { return joPickOrderService.getCompletedJobOrderPickOrderLotDetails(pickOrderId) } + @GetMapping("/completed-job-order-pick-orders-only/{userId}") + fun getCompletedJobOrderPickOrders(@PathVariable userId: Long): List> { + return joPickOrderService.getCompletedJobOrderPickOrders(userId) + } + + @GetMapping("/completed-job-order-pick-order-lot-details-completed-pick/{pickOrderId}") + fun getCompletedJobOrderPickOrderLotDetailsForCompletedPick(@PathVariable pickOrderId: Long): List> { + return joPickOrderService.getCompletedJobOrderPickOrderLotDetailsForCompletedPick(pickOrderId) + } } \ No newline at end of file