| @@ -77,7 +77,7 @@ open class JoPickOrderService( | |||||
| } | } | ||||
| // Update JoPickOrder status to released | // Update JoPickOrder status to released | ||||
| open fun updateHandledByForPickOrder(pickOrderId: Long, userId: Long): List<JoPickOrder> { | |||||
| open fun updateHandledByForPickOrder(pickOrderId: Long, userId: Long?): List<JoPickOrder> { | |||||
| val joPickOrders = joPickOrderRepository.findByPickOrderId(pickOrderId) | val joPickOrders = joPickOrderRepository.findByPickOrderId(pickOrderId) | ||||
| // Get pick order details to populate new fields | // Get pick order details to populate new fields | ||||
| @@ -111,7 +111,7 @@ open class JoPickOrderService( | |||||
| } | } | ||||
| // Update JoPickOrderRecord status to released | // Update JoPickOrderRecord status to released | ||||
| open fun updateRecordHandledByForPickOrder(pickOrderId: Long, userId: Long): List<JoPickOrderRecord> { | |||||
| open fun updateRecordHandledByForPickOrder(pickOrderId: Long, userId: Long?): List<JoPickOrderRecord> { | |||||
| val joPickOrderRecords = joPickOrderRecordRepository.findByPickOrderId(pickOrderId) | val joPickOrderRecords = joPickOrderRecordRepository.findByPickOrderId(pickOrderId) | ||||
| // Get pick order details to populate new fields | // Get pick order details to populate new fields | ||||
| @@ -957,6 +957,47 @@ open fun assignJobOrderPickOrderToUser(pickOrderId: Long, userId: Long): Message | |||||
| ) | ) | ||||
| } | } | ||||
| } | } | ||||
| open fun unAssignJobOrderPickOrderToUser(pickOrderId: Long): MessageResponse { | |||||
| println("=== unAssignJobOrderPickOrderToUser ===") | |||||
| println("pickOrderId: $pickOrderId") | |||||
| return try { | |||||
| val pickOrder = pickOrderRepository.findById(pickOrderId).orElse(null) | |||||
| if (pickOrder == null) { | |||||
| return MessageResponse( | |||||
| id = null, | |||||
| code = null, | |||||
| name = null, | |||||
| type = null, | |||||
| message = "Pick order not found", | |||||
| errorPosition = null | |||||
| ) | |||||
| } | |||||
| pickOrder.assignTo = null | |||||
| pickOrderRepository.save(pickOrder) | |||||
| this.updateHandledByForPickOrder(pickOrderId, null) | |||||
| this.updateRecordHandledByForPickOrder(pickOrderId, null) | |||||
| MessageResponse( | |||||
| id = pickOrder.id, | |||||
| code = pickOrder.code, | |||||
| name = pickOrder.jobOrder?.bom?.name, | |||||
| type = null, | |||||
| message = "Successfully unassigned", | |||||
| errorPosition = null | |||||
| ) | |||||
| } catch (e: Exception) { | |||||
| println("❌ Error in unAssignJobOrderPickOrderToUser: ${e.message}") | |||||
| e.printStackTrace() | |||||
| MessageResponse( | |||||
| id = null, | |||||
| code = null, | |||||
| name = null, | |||||
| type = null, | |||||
| message = "Error occurred: ${e.message}", | |||||
| errorPosition = null | |||||
| ) | |||||
| } | |||||
| } | |||||
| // Fix the updateMatchStatus method | // Fix the updateMatchStatus method | ||||
| open fun updateMatchStatus(pickOrderId: Long, itemId: Long, userId: Long, qty: Int): MessageResponse { | open fun updateMatchStatus(pickOrderId: Long, itemId: Long, userId: Long, qty: Int): MessageResponse { | ||||
| try { | try { | ||||
| @@ -1494,66 +1535,70 @@ open fun getCompletedJobOrderPickOrderLotDetails(pickOrderId: Long): List<Map<St | |||||
| } | } | ||||
| // ... existing code ... | // ... existing code ... | ||||
| open fun getCompletedJobOrderPickOrders(userId: Long): List<Map<String, Any?>> { | |||||
| 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 | |||||
| open fun getCompletedJobOrderPickOrders(userId: Long): List<Map<String, Any?>> { | |||||
| println("=== getCompletedJobOrderPickOrders ===") | |||||
| println("userId: $userId") | |||||
| println("Found ${completedPickOrders.size} completed job order pick orders for user $userId") | |||||
| return try { | |||||
| // 修复:先查找所有 COMPLETED 状态的 job order pick orders(不限制 assignTo) | |||||
| val allCompletedPickOrders = pickOrderRepository.findAllByStatusIn( | |||||
| listOf(PickOrderStatus.COMPLETED) | |||||
| ).filter { | |||||
| it.jobOrder != null && // 只查找有 job order 的 | |||||
| (it.assignTo?.id == userId || it.assignTo == null) // 分配给当前用户或未分配 | |||||
| } | |||||
| println("Found ${allCompletedPickOrders.size} completed job order pick orders (including unassigned)") | |||||
| val completedJobOrderPickOrders = completedPickOrders.mapNotNull { pickOrder -> | |||||
| val jobOrder = pickOrder.jobOrder | |||||
| if (jobOrder != null) { | |||||
| // Get JoPickOrder records for this pick order | |||||
| val joPickOrders = findByPickOrderId(pickOrder.id!!) | |||||
| val completedJobOrderPickOrders = allCompletedPickOrders.mapNotNull { pickOrder -> | |||||
| val jobOrder = pickOrder.jobOrder | |||||
| if (jobOrder != null) { | |||||
| // Get JoPickOrder records for this pick order | |||||
| val joPickOrders = findByPickOrderId(pickOrder.id!!) | |||||
| println("Pick Order ${pickOrder.code}: joPickOrders.size=${joPickOrders.size}") | |||||
| // Calculate second scan completion status | |||||
| val secondScanCompleted = joPickOrders.isNotEmpty() && | |||||
| joPickOrders.all { it.matchStatus == JoPickOrderStatus.completed } | |||||
| // Calculate second scan completion status | |||||
| val secondScanCompleted = joPickOrders.isNotEmpty() && | |||||
| joPickOrders.all { it.matchStatus == 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.matchStatus == JoPickOrderStatus.completed } | |||||
| ) | |||||
| } else { | |||||
| println("❌ Pick order ${pickOrder.id} has no job order, skipping.") | |||||
| null | |||||
| } | |||||
| 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.matchStatus == 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() | |||||
| } | } | ||||
| 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 ... | // ... rest of the code ... | ||||
| @@ -182,10 +182,15 @@ open class JobOrderService( | |||||
| } | } | ||||
| .filter { info -> | .filter { info -> | ||||
| // Filter by jobTypeName if provided | // Filter by jobTypeName if provided | ||||
| request.jobTypeName == null || | |||||
| request.jobTypeName.isBlank() || | |||||
| info.jobTypeName?.equals(request.jobTypeName, ignoreCase = true) == true || | |||||
| info.jobTypeName?.contains(request.jobTypeName, ignoreCase = true) == true | |||||
| val jobTypeNameMatch = request.jobTypeName == null || | |||||
| request.jobTypeName.isBlank() || | |||||
| info.jobTypeName?.equals(request.jobTypeName, ignoreCase = true) == true || | |||||
| info.jobTypeName?.contains(request.jobTypeName, ignoreCase = true) == true | |||||
| val notCompletedPutaway = info.stockInLineStatus != "completed" | |||||
| jobTypeNameMatch && notCompletedPutaway | |||||
| } | } | ||||
| // 修复:使用 response.totalElements,这是过滤后的总数 | // 修复:使用 response.totalElements,这是过滤后的总数 | ||||
| @@ -127,7 +127,12 @@ class JobOrderController( | |||||
| ): MessageResponse { | ): MessageResponse { | ||||
| return joPickOrderService.assignJobOrderPickOrderToUser(pickOrderId, userId) | return joPickOrderService.assignJobOrderPickOrderToUser(pickOrderId, userId) | ||||
| } | } | ||||
| @PostMapping("/unassign-job-order-pick-order/{pickOrderId}") | |||||
| fun unAssignJobOrderPickOrderToUser( | |||||
| @PathVariable pickOrderId: Long | |||||
| ): MessageResponse { | |||||
| return joPickOrderService.unAssignJobOrderPickOrderToUser(pickOrderId) | |||||
| } | |||||
| @PostMapping("/update-match-status") | @PostMapping("/update-match-status") | ||||
| fun updateMatchStatus(@RequestBody request: UpdateMatchStatusRequest): MessageResponse { | fun updateMatchStatus(@RequestBody request: UpdateMatchStatusRequest): MessageResponse { | ||||
| return joPickOrderService.updateMatchStatus( | return joPickOrderService.updateMatchStatus( | ||||
| @@ -28,10 +28,8 @@ open class Bom : BaseEntity<Long>() { | |||||
| @Column | @Column | ||||
| open var timeSequence: Int? = null | open var timeSequence: Int? = null | ||||
| @Column | @Column | ||||
| open var complexity: Int? = null | open var complexity: Int? = null | ||||
| @JsonBackReference | @JsonBackReference | ||||
| @OneToOne | @OneToOne | ||||
| @JoinColumn(name = "itemId") | @JoinColumn(name = "itemId") | ||||
| @@ -10,4 +10,5 @@ interface BomCombo { | |||||
| @get:Value("#{target.code} - #{target.name} - #{target.item.itemUoms.^[salesUnit == true && deleted == false]?.uom.udfudesc}") | @get:Value("#{target.code} - #{target.name} - #{target.item.itemUoms.^[salesUnit == true && deleted == false]?.uom.udfudesc}") | ||||
| val label: String; | val label: String; | ||||
| val outputQty: BigDecimal; | val outputQty: BigDecimal; | ||||
| val outputQtyUom: String?; | |||||
| } | } | ||||
| @@ -81,4 +81,5 @@ fun findAllByStatusAndAssignToIsNullAndDeletedFalse(status: PickOrderStatus): Li | |||||
| //fun findAllByJoid(jobOrderId: Long): List<PickOrder> | //fun findAllByJoid(jobOrderId: Long): List<PickOrder> | ||||
| fun findAllByJobOrder_Id(jobOrderId: Long): List<PickOrder> | fun findAllByJobOrder_Id(jobOrderId: Long): List<PickOrder> | ||||
| fun findTopByJobOrder_IdOrderByCreatedDesc(jobOrderId: Long): PickOrder? | fun findTopByJobOrder_IdOrderByCreatedDesc(jobOrderId: Long): PickOrder? | ||||
| fun findAllByStatusIn(statuses: List<PickOrderStatus>): List<PickOrder> | |||||
| } | } | ||||
| @@ -33,6 +33,8 @@ data class ProductProcessInfo( | |||||
| val itemName: String?, | val itemName: String?, | ||||
| val outputQtyUom: String?, | val outputQtyUom: String?, | ||||
| val outputQty: Int?, | val outputQty: Int?, | ||||
| val timeSequence: Int?, | |||||
| val complexity: Int?, | |||||
| val productionPriority: Int?, | val productionPriority: Int?, | ||||
| val productProcessLines: List<ProductProcessLineInfo>?, | val productProcessLines: List<ProductProcessLineInfo>?, | ||||
| val totalStockQty: Int?, | val totalStockQty: Int?, | ||||
| @@ -42,7 +42,7 @@ import com.ffii.fpsms.modules.master.entity.BomProcessMaterialRepository | |||||
| import com.ffii.fpsms.modules.master.entity.BomMaterialRepository | import com.ffii.fpsms.modules.master.entity.BomMaterialRepository | ||||
| import com.ffii.fpsms.modules.productProcess.entity.ProductionProcessIssue | import com.ffii.fpsms.modules.productProcess.entity.ProductionProcessIssue | ||||
| import com.ffii.fpsms.modules.jobOrder.entity.JobTypeRepository | import com.ffii.fpsms.modules.jobOrder.entity.JobTypeRepository | ||||
| import com.ffii.fpsms.modules.pickOrder.entity.PickOrderRepository | |||||
| import java.time.ZoneOffset | import java.time.ZoneOffset | ||||
| @Service | @Service | ||||
| @Transactional | @Transactional | ||||
| @@ -65,6 +65,7 @@ open class ProductProcessService( | |||||
| private val bomMaterialRepository: BomMaterialRepository, | private val bomMaterialRepository: BomMaterialRepository, | ||||
| private val equipmentDetailRepository: EquipmentDetailRepository, | private val equipmentDetailRepository: EquipmentDetailRepository, | ||||
| private val jobTypeRepository: JobTypeRepository, | private val jobTypeRepository: JobTypeRepository, | ||||
| private val pickOrderRepository: PickOrderRepository, | |||||
| ) { | ) { | ||||
| open fun findAll(pageable: Pageable): Page<ProductProcess> { | open fun findAll(pageable: Pageable): Page<ProductProcess> { | ||||
| @@ -589,6 +590,8 @@ open class ProductProcessService( | |||||
| itemId = bom?.item?.id?:0, | itemId = bom?.item?.id?:0, | ||||
| itemCode = bom?.item?.code?:"", | itemCode = bom?.item?.code?:"", | ||||
| itemName = bom?.item?.name?:"", | itemName = bom?.item?.name?:"", | ||||
| timeSequence = bom?.timeSequence?:0, | |||||
| complexity = bom?.complexity?:0, | |||||
| isDark = calculateColourScore(bom?.isDark?:0), | isDark = calculateColourScore(bom?.isDark?:0), | ||||
| isDense = bom?.isDense?:0, | isDense = bom?.isDense?:0, | ||||
| isFloat = calculateFloatScore(bom?.isFloat?:0), | isFloat = calculateFloatScore(bom?.isFloat?:0), | ||||
| @@ -1094,6 +1097,8 @@ open class ProductProcessService( | |||||
| val FinishedProductProcessLineCount = productProcessLineRepository.findByProductProcess_Id(productProcesses.id?:0L).count { it.status == "Completed" } | val FinishedProductProcessLineCount = productProcessLineRepository.findByProductProcess_Id(productProcesses.id?:0L).count { it.status == "Completed" } | ||||
| val stockInLine = jobOrder?.stockInLines?.firstOrNull() | val stockInLine = jobOrder?.stockInLines?.firstOrNull() | ||||
| val stockInLineId = stockInLine?.id | val stockInLineId = stockInLine?.id | ||||
| val pickOrder = pickOrderRepository.findAllByJobOrder_Id(jobOrder?.id?:0L).firstOrNull() | |||||
| //val silHandlerId = stockInLine?.escalationLog?.firstOrNull { it.status == "pending" }?.handler?.id | //val silHandlerId = stockInLine?.escalationLog?.firstOrNull { it.status == "pending" }?.handler?.id | ||||
| AllJoborderProductProcessInfoResponse( | AllJoborderProductProcessInfoResponse( | ||||
| @@ -1105,7 +1110,9 @@ open class ProductProcessService( | |||||
| RequiredQty = jobOrder?.reqQty?.toInt() ?: 0, | RequiredQty = jobOrder?.reqQty?.toInt() ?: 0, | ||||
| date = productProcesses.date, | date = productProcesses.date, | ||||
| bomId = productProcesses.bom?.id, | bomId = productProcesses.bom?.id, | ||||
| assignedTo = pickOrder?.assignTo?.id, | |||||
| itemName = productProcesses.item?.name, | itemName = productProcesses.item?.name, | ||||
| pickOrderId = pickOrder?.id, | |||||
| jobOrderId = productProcesses.jobOrder?.id, | jobOrderId = productProcesses.jobOrder?.id, | ||||
| stockInLineId = stockInLineId, | stockInLineId = stockInLineId, | ||||
| jobOrderCode = jobOrder?.code, | jobOrderCode = jobOrder?.code, | ||||
| @@ -1125,6 +1132,11 @@ open class ProductProcessService( | |||||
| ) | ) | ||||
| } | } | ||||
| ) | ) | ||||
| }.filter { response -> | |||||
| // 过滤掉已完成上架的 job order | |||||
| val jobOrder = jobOrderRepository.findById(response.jobOrderId ?: 0L).orElse(null) | |||||
| val stockInLineStatus = jobOrder?.stockInLines?.firstOrNull()?.status | |||||
| stockInLineStatus != "completed" | |||||
| } | } | ||||
| } | } | ||||
| @@ -166,6 +166,8 @@ data class AllJoborderProductProcessInfoResponse( | |||||
| val RequiredQty: Int?, | val RequiredQty: Int?, | ||||
| val jobOrderId: Long?, | val jobOrderId: Long?, | ||||
| val jobOrderCode: String?, | val jobOrderCode: String?, | ||||
| val assignedTo: Long?, | |||||
| val pickOrderId: Long?, | |||||
| val productProcessLineCount: Int, | val productProcessLineCount: Int, | ||||
| val FinishedProductProcessLineCount: Int, | val FinishedProductProcessLineCount: Int, | ||||
| val stockInLineId: Long?, | val stockInLineId: Long?, | ||||