| @@ -13,7 +13,7 @@ import com.ffii.fpsms.modules.pickOrder.enums.PickOrderStatus | |||||
| import org.springframework.stereotype.Service | import org.springframework.stereotype.Service | ||||
| import org.springframework.transaction.annotation.Transactional | import org.springframework.transaction.annotation.Transactional | ||||
| import java.time.LocalDate | import java.time.LocalDate | ||||
| import com.ffii.fpsms.modules.stock.entity.enum.InventoryLotLineStatus | |||||
| import java.time.LocalDateTime | import java.time.LocalDateTime | ||||
| import com.ffii.core.support.JdbcDao | import com.ffii.core.support.JdbcDao | ||||
| import com.ffii.fpsms.modules.jobOrder.web.model.SecondScanSubmitRequest | import com.ffii.fpsms.modules.jobOrder.web.model.SecondScanSubmitRequest | ||||
| @@ -24,7 +24,11 @@ import com.ffii.fpsms.modules.pickOrder.entity.PickExecutionIssueRepository | |||||
| import java.math.BigDecimal | import java.math.BigDecimal | ||||
| import com.ffii.fpsms.modules.pickOrder.entity.HandleStatus | import com.ffii.fpsms.modules.pickOrder.entity.HandleStatus | ||||
| import com.ffii.fpsms.modules.pickOrder.entity.IssueCategory | import com.ffii.fpsms.modules.pickOrder.entity.IssueCategory | ||||
| import com.ffii.fpsms.modules.pickOrder.entity.PickOrderLineRepository | |||||
| import com.ffii.fpsms.modules.stock.entity.SuggestPickLotRepository | |||||
| import com.ffii.fpsms.modules.stock.entity.InventoryLotLineRepository | |||||
| import com.ffii.fpsms.modules.stock.entity.InventoryLotRepository | |||||
| import com.ffii.fpsms.modules.stock.entity.StockOutLIneRepository | |||||
| @Service | @Service | ||||
| open class JoPickOrderService( | open class JoPickOrderService( | ||||
| private val joPickOrderRepository: JoPickOrderRepository, | private val joPickOrderRepository: JoPickOrderRepository, | ||||
| @@ -33,7 +37,12 @@ open class JoPickOrderService( | |||||
| private val userService: UserService, | private val userService: UserService, | ||||
| private val pickOrderRepository: PickOrderRepository, | private val pickOrderRepository: PickOrderRepository, | ||||
| private val jdbcDao: JdbcDao, | private val jdbcDao: JdbcDao, | ||||
| private val pickExecutionIssueRepository: PickExecutionIssueRepository | |||||
| private val pickExecutionIssueRepository: PickExecutionIssueRepository, | |||||
| private val pickOrderLineRepository: PickOrderLineRepository, | |||||
| private val suggestPickLotRepository: SuggestPickLotRepository, | |||||
| private val inventoryLotLineRepository: InventoryLotLineRepository, | |||||
| private val inventoryLotRepository: InventoryLotRepository, | |||||
| private val stockOutLineRepository: StockOutLIneRepository | |||||
| ) { | ) { | ||||
| open fun save(record: JoPickOrder): JoPickOrder { | open fun save(record: JoPickOrder): JoPickOrder { | ||||
| @@ -209,10 +218,8 @@ open class JoPickOrderService( | |||||
| println("🔍 DEBUG: Found ${allAssignedPickOrders.size} job order pick orders assigned to user $userId") | println("🔍 DEBUG: Found ${allAssignedPickOrders.size} job order pick orders assigned to user $userId") | ||||
| val visiblePickOrders = allAssignedPickOrders | |||||
| // Filter based on assignment and status | // Filter based on assignment and status | ||||
| val filteredPickOrders = if (visiblePickOrders.isNotEmpty()) { | |||||
| val filteredPickOrders = if (allAssignedPickOrders.isNotEmpty()) { | |||||
| // Check if there are any RELEASED orders assigned to this user (active work) | // Check if there are any RELEASED orders assigned to this user (active work) | ||||
| val assignedReleasedOrders = allAssignedPickOrders.filter { | val assignedReleasedOrders = allAssignedPickOrders.filter { | ||||
| it.status == PickOrderStatus.RELEASED && it.assignTo?.id == userId | it.status == PickOrderStatus.RELEASED && it.assignTo?.id == userId | ||||
| @@ -248,223 +255,201 @@ open class JoPickOrderService( | |||||
| ) | ) | ||||
| } | } | ||||
| // 修复:简化 SQL 查询,移除不存在的字段 | |||||
| val pickOrderIdsStr = pickOrderIds.joinToString(",") | |||||
| 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.type as pickOrderType, | |||||
| po.status as pickOrderStatus, | |||||
| po.assignTo as pickOrderAssignTo, | |||||
| -- 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, | |||||
| -- Simplified Router Information using warehouse | |||||
| w.`order` as routerIndex, | |||||
| w.code as routerRoute, | |||||
| w.code 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, | |||||
| // 使用 Repository 获取数据 | |||||
| try { | |||||
| val pickOrders = pickOrderRepository.findAllByIdIn(pickOrderIds) | |||||
| .filter { it.deleted == false && it.assignTo?.id == userId } | |||||
| -- Stock out line information | |||||
| sol.id as stockOutLineId, | |||||
| sol.status as stockOutLineStatus, | |||||
| COALESCE(sol.qty, 0) as stockOutLineQty, | |||||
| if (pickOrders.isEmpty()) { | |||||
| return mapOf( | |||||
| "pickOrder" to null as Any?, | |||||
| "pickOrderLines" to emptyList<Map<String, Any>>() as Any? | |||||
| ) | |||||
| } | |||||
| -- Additional detailed fields | |||||
| COALESCE(ill.inQty, 0) as inQty, | |||||
| COALESCE(ill.outQty, 0) as outQty, | |||||
| COALESCE(ill.holdQty, 0) as holdQty, | |||||
| COALESCE(spl.suggestedLotLineId, ill.id) as debugSuggestedLotLineId, | |||||
| ill.inventoryLotId as debugInventoryLotId, | |||||
| val pickOrder = pickOrders.first() // 取第一个(应该只有一个) | |||||
| val jobOrder = pickOrder.jobOrder ?: return mapOf( | |||||
| "pickOrder" to null as Any?, | |||||
| "pickOrderLines" to emptyList<Map<String, Any>>() as Any? | |||||
| ) | |||||
| -- 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, | |||||
| // 获取 pick order lines | |||||
| val pickOrderLines = pickOrderLineRepository.findAllByPickOrderId(pickOrder.id!!) | |||||
| .filter { it.deleted == false } | |||||
| -- Calculate remaining available quantity correctly | |||||
| (COALESCE(ill.inQty, 0) - COALESCE(ill.outQty, 0) - COALESCE(ill.holdQty, 0)) as remainingAfterAllPickOrders, | |||||
| // 获取所有 pick order line IDs | |||||
| val pickOrderLineIds = pickOrderLines.map { it.id!! } | |||||
| -- 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, | |||||
| // 获取 suggested pick lots | |||||
| val suggestedPickLots = if (pickOrderLineIds.isNotEmpty()) { | |||||
| suggestPickLotRepository.findAllByPickOrderLineIdIn(pickOrderLineIds) | |||||
| .filter { it.deleted == false } | |||||
| } else { | |||||
| emptyList() | |||||
| } | |||||
| -- 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, | |||||
| // 获取所有 inventory lot line IDs | |||||
| val inventoryLotLineIds = suggestedPickLots.mapNotNull { it.suggestedLotLine?.id } | |||||
| -- JoPickOrder second scan status | |||||
| jpo.match_status as match_status, | |||||
| jpo.match_by as match_by, | |||||
| jpo.match_qty as match_qty, | |||||
| jpo.ticketReleaseTime as ticketReleaseTime, | |||||
| jpo.ticketCompleteTime as ticketCompleteTime | |||||
| // 获取 inventory lot lines | |||||
| val inventoryLotLines = if (inventoryLotLineIds.isNotEmpty()) { | |||||
| inventoryLotLineRepository.findAllByIdIn(inventoryLotLineIds) | |||||
| .filter { it.deleted == false } | |||||
| } else { | |||||
| emptyList() | |||||
| } | |||||
| 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.inventory_lot il ON il.id = ill.inventoryLotId | |||||
| LEFT JOIN fpsmsdb.warehouse w ON w.id = ill.warehouseId -- 直接关联 warehouse | |||||
| 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 IN ($pickOrderIdsStr) | |||||
| AND pol.deleted = false | |||||
| AND po.status IN ('PENDING', 'RELEASED', 'COMPLETED') | |||||
| AND po.assignTo = :userId | |||||
| 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(w.`order`, 999999) ASC, -- 使用 warehouse.order 排序 | |||||
| po.code ASC, | |||||
| i.code ASC, | |||||
| il.expiryDate ASC, | |||||
| il.lotNo ASC | |||||
| """.trimIndent() | |||||
| println("🔍 Executing SQL for job order hierarchical structure: $sql") | |||||
| println("🔍 With parameters: userId = $userId, pickOrderIds = $pickOrderIdsStr") | |||||
| // 修复:直接执行 SQL 查询并构建分层结构 | |||||
| try { | |||||
| val results = jdbcDao.queryForList(sql, mapOf("userId" to userId)) | |||||
| // 获取 inventory lots | |||||
| val inventoryLotIds = inventoryLotLines.mapNotNull { it.inventoryLot?.id }.distinct() | |||||
| val inventoryLots = if (inventoryLotIds.isNotEmpty()) { | |||||
| inventoryLotRepository.findAllByIdIn(inventoryLotIds) | |||||
| .filter { it.deleted == false } | |||||
| } else { | |||||
| emptyList() | |||||
| } | |||||
| if (results.isEmpty()) { | |||||
| return mapOf( | |||||
| "pickOrder" to null as Any?, | |||||
| "pickOrderLines" to emptyList<Map<String, Any>>() as Any? | |||||
| ) | |||||
| // 获取 stock out lines | |||||
| val stockOutLines = if (pickOrderLineIds.isNotEmpty() && inventoryLotLineIds.isNotEmpty()) { | |||||
| pickOrderLineIds.flatMap { polId -> | |||||
| inventoryLotLineIds.flatMap { illId -> | |||||
| stockOutLineRepository.findByPickOrderLineIdAndInventoryLotLineIdAndDeletedFalse(polId, illId) | |||||
| } | |||||
| } | |||||
| } else { | |||||
| emptyList() | |||||
| } | } | ||||
| // 取得所有 stock out line(含無 lot 情況) | |||||
| val stockOutLinesByPickOrderLine = pickOrderLineIds.associateWith { polId -> | |||||
| stockOutLineRepository.findAllByPickOrderLineIdAndDeletedFalse(polId) | |||||
| } | |||||
| // 获取 jo_pick_order 记录 | |||||
| val joPickOrders = joPickOrderRepository.findByPickOrderId(pickOrder.id!!) | |||||
| // 构建分层结构 | |||||
| val pickOrderInfo = results.firstOrNull()?.let { firstRow: Map<String, Any?> -> | |||||
| mapOf( | |||||
| "id" to firstRow["pickOrderId"], | |||||
| "code" to firstRow["pickOrderCode"], | |||||
| "consoCode" to firstRow["pickOrderConsoCode"], | |||||
| "targetDate" to firstRow["pickOrderTargetDate"], | |||||
| "type" to firstRow["pickOrderType"], | |||||
| "status" to firstRow["pickOrderStatus"], | |||||
| "assignTo" to firstRow["pickOrderAssignTo"], | |||||
| "jobOrder" to mapOf( | |||||
| "id" to firstRow["jobOrderId"], | |||||
| "code" to firstRow["jobOrderCode"], | |||||
| "name" to "Job Order ${firstRow["jobOrderCode"]}" // 使用生成的名称 | |||||
| ) | |||||
| // 构建 pick order info | |||||
| val pickOrderInfo = mapOf( | |||||
| "id" to pickOrder.id, | |||||
| "code" to pickOrder.code, | |||||
| "consoCode" to pickOrder.consoCode, | |||||
| "targetDate" to pickOrder.targetDate?.let { | |||||
| "${it.year}-${String.format("%02d", it.monthValue)}-${String.format("%02d", it.dayOfMonth)}" | |||||
| }, | |||||
| "type" to pickOrder.type?.value, | |||||
| "status" to pickOrder.status?.value, | |||||
| "assignTo" to pickOrder.assignTo?.id, | |||||
| "jobOrder" to mapOf( | |||||
| "id" to jobOrder.id, | |||||
| "code" to jobOrder.code, | |||||
| "name" to "Job Order ${jobOrder.code}" | |||||
| ) | ) | ||||
| } | |||||
| ) | |||||
| // 按 pick order line 分组 | |||||
| val groupedByLine = results.groupBy { row: Map<String, Any?> -> row["pickOrderLineId"] } | |||||
| val pickOrderLines = groupedByLine.map { (lineId: Any?, lineRows: List<Map<String, Any?>>) -> | |||||
| val firstLineRow = lineRows.first() | |||||
| mapOf( | |||||
| "id" to lineId, | |||||
| "itemId" to firstLineRow["itemId"], | |||||
| "itemCode" to firstLineRow["itemCode"], | |||||
| "itemName" to firstLineRow["itemName"], | |||||
| "requiredQty" to firstLineRow["pickOrderLineRequiredQty"], | |||||
| "uomCode" to firstLineRow["uomCode"], | |||||
| "uomDesc" to firstLineRow["uomDesc"], | |||||
| "lots" to lineRows.map { row: Map<String, Any?> -> | |||||
| mapOf( | |||||
| "lotId" to row["lotId"], | |||||
| "lotNo" to row["lotNo"], | |||||
| "expiryDate" to row["expiryDate"], | |||||
| "location" to row["location"], | |||||
| "availableQty" to row["availableQty"], | |||||
| "requiredQty" to row["requiredQty"], | |||||
| "actualPickQty" to row["actualPickQty"], | |||||
| "processingStatus" to row["processingStatus"], | |||||
| "lotAvailability" to row["lotAvailability"], | |||||
| "pickOrderId" to row["pickOrderId"], | |||||
| "pickOrderCode" to row["pickOrderCode"], | |||||
| "pickOrderConsoCode" to row["pickOrderConsoCode"], | |||||
| "pickOrderLineId" to row["pickOrderLineId"], | |||||
| "stockOutLineId" to row["stockOutLineId"], | |||||
| "suggestedPickLotId" to row["suggestedPickLotId"], | |||||
| "stockOutLineQty" to row["stockOutLineQty"], | |||||
| "stockOutLineStatus" to row["stockOutLineStatus"], | |||||
| "routerIndex" to row["routerIndex"], | |||||
| "routerArea" to row["routerArea"], | |||||
| "routerRoute" to row["routerRoute"], | |||||
| "uomShortDesc" to row["uomShortDesc"], | |||||
| "matchStatus" to row["match_status"], | |||||
| "matchBy" to row["match_by"], | |||||
| "matchQty" to row["match_qty"] | |||||
| ) | |||||
| // 构建 pick order lines with lots | |||||
| val pickOrderLinesResult = pickOrderLines.map { pol -> | |||||
| val item = pol.item | |||||
| val uom = pol.uom | |||||
| val lineId = pol.id!! | |||||
| val suggestions = suggestedPickLots.filter { it.pickOrderLine?.id == lineId } | |||||
| val stockoutsForLine = stockOutLinesByPickOrderLine[lineId].orEmpty() | |||||
| // 获取该 line 的 suggested pick lots | |||||
| val lineSuggestedLots = suggestedPickLots.filter { it.pickOrderLine?.id == pol.id } | |||||
| // 构建 lots 数据 | |||||
| val lots = lineSuggestedLots.mapNotNull { spl -> | |||||
| val ill = spl.suggestedLotLine | |||||
| if (ill == null || ill.deleted == true) return@mapNotNull null | |||||
| val il = ill.inventoryLot | |||||
| if (il == null || il.deleted == true) return@mapNotNull null | |||||
| val warehouse = ill.warehouse | |||||
| // 获取对应的 stock out line | |||||
| val sol = stockOutLines.firstOrNull { | |||||
| it.pickOrderLine?.id == pol.id && it.inventoryLotLine?.id == ill.id | |||||
| } | |||||
| // 获取对应的 jo_pick_order | |||||
| val jpo = joPickOrders.firstOrNull { it.itemId == item?.id } | |||||
| // 计算 available quantity | |||||
| val availableQty = if (sol?.status == "rejected") { | |||||
| null | |||||
| } else { | |||||
| (ill.inQty ?: BigDecimal.ZERO) - (ill.outQty ?: BigDecimal.ZERO) - (ill.holdQty ?: BigDecimal.ZERO) | |||||
| } | |||||
| // 计算 total picked by all pick orders | |||||
| val totalPickedByAllPickOrders = stockOutLines | |||||
| .filter { it.inventoryLotLine?.id == ill.id && it.deleted == false } | |||||
| .filter { it.status in listOf("pending", "checked", "partially_completed", "completed") } | |||||
| .sumOf { it.qty?.toBigDecimal() ?: BigDecimal.ZERO } | |||||
| // 计算 lot availability | |||||
| val lotAvailability = when { | |||||
| il.expiryDate != null && il.expiryDate!!.isBefore(LocalDate.now()) -> "expired" | |||||
| sol?.status == "rejected" -> "rejected" | |||||
| availableQty != null && availableQty <= BigDecimal.ZERO -> "insufficient_stock" | |||||
| ill.status == InventoryLotLineStatus.UNAVAILABLE -> "status_unavailable" | |||||
| else -> "available" | |||||
| } | |||||
| // 计算 processing status | |||||
| val processingStatus = when (sol?.status) { | |||||
| "completed" -> "completed" | |||||
| "rejected" -> "rejected" | |||||
| "created" -> "pending" | |||||
| else -> "pending" | |||||
| } | } | ||||
| mapOf( | |||||
| "lotId" to ill.id, | |||||
| "lotNo" to il.lotNo, | |||||
| "expiryDate" to il.expiryDate?.let { | |||||
| "${it.year}-${String.format("%02d", it.monthValue)}-${String.format("%02d", it.dayOfMonth)}" | |||||
| }, | |||||
| "location" to warehouse?.name, | |||||
| "availableQty" to availableQty?.toDouble(), | |||||
| "requiredQty" to (spl.qty?.toDouble() ?: 0.0), | |||||
| "actualPickQty" to (sol?.qty ?: 0.0), | |||||
| "processingStatus" to processingStatus, | |||||
| "lotAvailability" to lotAvailability, | |||||
| "pickOrderId" to pickOrder.id, | |||||
| "pickOrderCode" to pickOrder.code, | |||||
| "pickOrderConsoCode" to pickOrder.consoCode, | |||||
| "pickOrderLineId" to pol.id, | |||||
| "stockOutLineId" to sol?.id, | |||||
| "suggestedPickLotId" to spl.id, | |||||
| "stockOutLineQty" to (sol?.qty ?: 0.0), | |||||
| "stockOutLineStatus" to sol?.status, | |||||
| "routerIndex" to warehouse?.order, | |||||
| "routerArea" to warehouse?.code, | |||||
| "routerRoute" to warehouse?.code, | |||||
| "uomShortDesc" to uom?.udfShortDesc, | |||||
| "matchStatus" to jpo?.matchStatus?.value, | |||||
| "matchBy" to jpo?.matchBy, | |||||
| "matchQty" to jpo?.matchQty | |||||
| ) | |||||
| } | |||||
| mapOf( | |||||
| "id" to pol.id, | |||||
| "itemId" to item?.id, | |||||
| "itemCode" to item?.code, | |||||
| "itemName" to item?.name, | |||||
| "requiredQty" to pol.qty?.toDouble(), | |||||
| "uomCode" to uom?.code, | |||||
| "uomDesc" to uom?.udfudesc, | |||||
| "lots" to lots | |||||
| ) | ) | ||||
| } | } | ||||
| return mapOf( | return mapOf( | ||||
| "pickOrder" to pickOrderInfo as Any?, | "pickOrder" to pickOrderInfo as Any?, | ||||
| "pickOrderLines" to pickOrderLines as Any? | |||||
| "pickOrderLines" to pickOrderLinesResult as Any? | |||||
| ) | ) | ||||
| } catch (e: Exception) { | } catch (e: Exception) { | ||||
| println("❌ Error executing Job Order SQL: ${e.message}") | |||||
| println("❌ Error executing Job Order hierarchical query: ${e.message}") | |||||
| e.printStackTrace() | e.printStackTrace() | ||||
| return mapOf( | return mapOf( | ||||
| "pickOrder" to null as Any?, | "pickOrder" to null as Any?, | ||||
| @@ -19,6 +19,7 @@ import org.springframework.web.bind.annotation.RequestBody | |||||
| import org.springframework.web.bind.annotation.RequestMapping | import org.springframework.web.bind.annotation.RequestMapping | ||||
| import org.springframework.web.bind.annotation.RestController | import org.springframework.web.bind.annotation.RestController | ||||
| import com.ffii.fpsms.modules.jobOrder.service.JoPickOrderService | import com.ffii.fpsms.modules.jobOrder.service.JoPickOrderService | ||||
| import com.ffii.fpsms.modules.productProcess.service.ProductProcessService | |||||
| import com.ffii.fpsms.modules.jobOrder.web.model.* | import com.ffii.fpsms.modules.jobOrder.web.model.* | ||||
| import com.ffii.fpsms.modules.jobOrder.web.model.ExportPickRecordRequest | import com.ffii.fpsms.modules.jobOrder.web.model.ExportPickRecordRequest | ||||
| import com.ffii.fpsms.modules.jobOrder.web.model.PrintPickRecordRequest | import com.ffii.fpsms.modules.jobOrder.web.model.PrintPickRecordRequest | ||||
| @@ -40,7 +41,8 @@ class JobOrderController( | |||||
| private val jobOrderService: JobOrderService, | private val jobOrderService: JobOrderService, | ||||
| private val jobOrderBomMaterialService: JobOrderBomMaterialService, | private val jobOrderBomMaterialService: JobOrderBomMaterialService, | ||||
| private val jobOrderProcessService: JobOrderProcessService, | private val jobOrderProcessService: JobOrderProcessService, | ||||
| private val joPickOrderService: JoPickOrderService | |||||
| private val joPickOrderService: JoPickOrderService, | |||||
| private val productProcessService: ProductProcessService | |||||
| ) { | ) { | ||||
| @GetMapping("/getRecordByPage") | @GetMapping("/getRecordByPage") | ||||
| @@ -87,7 +89,7 @@ class JobOrderController( | |||||
| } | } | ||||
| jobOrderBomMaterialService.createJobOrderBomMaterialsByJoId(jo.id) | jobOrderBomMaterialService.createJobOrderBomMaterialsByJoId(jo.id) | ||||
| jobOrderProcessService.createJobOrderProcessesByJoId(jo.id) | jobOrderProcessService.createJobOrderProcessesByJoId(jo.id) | ||||
| productProcessService.createProductProcessByJobOrderId(jo.id) | |||||
| return jo | return jo | ||||
| } | } | ||||
| @GetMapping("/all-lots-hierarchical/{userId}") | @GetMapping("/all-lots-hierarchical/{userId}") | ||||
| @@ -39,4 +39,18 @@ interface ProductionScheduleLineRepository : AbstractRepository<ProductionSchedu | |||||
| group by psl.id, bm.id, i.id, pp.proportion | group by psl.id, bm.id, i.id, pp.proportion | ||||
| """) | """) | ||||
| fun getBomMaterials(id: Long): List<DetailedProdScheduleLineBomMaterialInterface>? | fun getBomMaterials(id: Long): List<DetailedProdScheduleLineBomMaterialInterface>? | ||||
| @Query(""" | |||||
| SELECT psl FROM ProductionScheduleLine psl | |||||
| JOIN psl.productionSchedule ps | |||||
| WHERE psl.item.id = :itemId | |||||
| AND ps.produceAt = :produceAt | |||||
| AND psl.type = :type | |||||
| AND ps.deleted = false | |||||
| ORDER BY psl.itemPriority ASC | |||||
| """) | |||||
| fun findByItemIdAndProduceAtAndType( | |||||
| itemId: Long, | |||||
| produceAt: LocalDateTime, | |||||
| type: String | |||||
| ): ProductionScheduleLine? | |||||
| } | } | ||||
| @@ -24,16 +24,24 @@ data class ProductProcessInfo( | |||||
| val isDark: String?, | val isDark: String?, | ||||
| val isDense: Int?, | val isDense: Int?, | ||||
| val isFloat: String?, | val isFloat: String?, | ||||
| val itemId: Long?, | |||||
| val itemCode: String?, | |||||
| val itemName: String?, | |||||
| val outputQtyUom: String?, | val outputQtyUom: String?, | ||||
| val outputQty: Int?, | val outputQty: Int?, | ||||
| val productProcessLines: List<ProductProcessLineInfo>? | |||||
| val productionPriority: String?, | |||||
| val productProcessLines: List<ProductProcessLineInfo>?, | |||||
| val totalStockQty: Int?, | |||||
| val insufficientStockQty: Int?, | |||||
| val sufficientStockQty: Int?, | |||||
| val jobOrderLines: List<jobOrderLineInfo>? | |||||
| ) | ) | ||||
| data class ProductProcessLineInfo( | data class ProductProcessLineInfo( | ||||
| val id:Long?, | val id:Long?, | ||||
| val bomprocessId: Long?, | val bomprocessId: Long?, | ||||
| val operatorId: Long?, | val operatorId: Long?, | ||||
| val operatorName: String?, | |||||
| val equipmentId: Long?, | val equipmentId: Long?, | ||||
| val handlerId: Long?, | val handlerId: Long?, | ||||
| val seqNo: Long?, | val seqNo: Long?, | ||||
| @@ -50,8 +58,22 @@ data class ProductProcessLineInfo( | |||||
| val defectUom: String?, | val defectUom: String?, | ||||
| val outputFromProcessQty: Int?, | val outputFromProcessQty: Int?, | ||||
| val outputFromProcessUom: String?, | val outputFromProcessUom: String?, | ||||
| val durationInMinutes: Int?, | |||||
| val prepTimeInMinutes: Int?, | |||||
| val postProdTimeInMinutes: Int?, | |||||
| @JsonFormat(pattern = "yyyy-MM-dd") | @JsonFormat(pattern = "yyyy-MM-dd") | ||||
| val startTime: LocalDateTime?, | val startTime: LocalDateTime?, | ||||
| @JsonFormat(pattern = "yyyy-MM-dd") | @JsonFormat(pattern = "yyyy-MM-dd") | ||||
| val endTime: LocalDateTime? | val endTime: LocalDateTime? | ||||
| ) | |||||
| data class jobOrderLineInfo( | |||||
| val id: Long?, | |||||
| val itemId: Long?, | |||||
| val itemCode: String?, | |||||
| val itemName: String?, | |||||
| val reqQty: Int?, | |||||
| val stockQty: Int?, | |||||
| val uom: String?, | |||||
| val shortUom: String?, | |||||
| val availableStatus: String? | |||||
| ) | ) | ||||
| @@ -7,6 +7,7 @@ import com.ffii.fpsms.modules.productProcess.enums.ProductProcessStatus | |||||
| import com.ffii.fpsms.modules.productProcess.web.model.* | import com.ffii.fpsms.modules.productProcess.web.model.* | ||||
| import org.springframework.data.domain.Page | import org.springframework.data.domain.Page | ||||
| import org.springframework.data.domain.Pageable | import org.springframework.data.domain.Pageable | ||||
| import com.ffii.fpsms.modules.productProcess.entity.projections.jobOrderLineInfo | |||||
| import org.springframework.stereotype.Service | import org.springframework.stereotype.Service | ||||
| import org.springframework.transaction.annotation.Transactional | import org.springframework.transaction.annotation.Transactional | ||||
| import java.time.LocalDate | import java.time.LocalDate | ||||
| @@ -27,6 +28,14 @@ import com.ffii.fpsms.modules.master.entity.Equipment | |||||
| import com.ffii.fpsms.modules.master.entity.BomProcess | import com.ffii.fpsms.modules.master.entity.BomProcess | ||||
| import com.ffii.fpsms.modules.master.entity.Bom | import com.ffii.fpsms.modules.master.entity.Bom | ||||
| import com.ffii.fpsms.modules.master.web.models.MessageResponse | import com.ffii.fpsms.modules.master.web.models.MessageResponse | ||||
| import com.ffii.fpsms.modules.jobOrder.entity.JobOrderBomMaterialRepository | |||||
| import com.ffii.fpsms.modules.master.service.ProductionScheduleService | |||||
| import com.ffii.fpsms.modules.stock.entity.InventoryLotLineRepository | |||||
| import com.ffii.fpsms.modules.master.entity.ProductionScheduleLineRepository | |||||
| import com.ffii.fpsms.modules.stock.entity.enum.InventoryLotLineStatus | |||||
| import com.ffii.fpsms.modules.jobOrder.enums.JobOrderStatus | |||||
| import com.ffii.fpsms.modules.stock.service.StockInLineService | |||||
| import com.ffii.fpsms.modules.stock.web.model.SaveStockInLineRequest | |||||
| @Service | @Service | ||||
| @Transactional | @Transactional | ||||
| open class ProductProcessService( | open class ProductProcessService( | ||||
| @@ -40,6 +49,10 @@ open class ProductProcessService( | |||||
| private val userRepository: UserRepository, | private val userRepository: UserRepository, | ||||
| private val processRepository: ProcessRepository, | private val processRepository: ProcessRepository, | ||||
| private val equipmentRepository: EquipmentRepository, | private val equipmentRepository: EquipmentRepository, | ||||
| private val jobOrderBomMaterialRepository: JobOrderBomMaterialRepository, | |||||
| private val inventoryLotLineRepository: InventoryLotLineRepository, | |||||
| private val productionScheduleLineRepository: ProductionScheduleLineRepository, | |||||
| private val stockInLineService: StockInLineService, | |||||
| ) { | ) { | ||||
| open fun findAll(pageable: Pageable): Page<ProductProcess> { | open fun findAll(pageable: Pageable): Page<ProductProcess> { | ||||
| @@ -457,6 +470,62 @@ open class ProductProcessService( | |||||
| val productProcesses = productProcessRepository.findByJobOrder_Id(joid) | val productProcesses = productProcessRepository.findByJobOrder_Id(joid) | ||||
| val jobOrder = jobOrderRepository.findById(joid).orElse(null) | val jobOrder = jobOrderRepository.findById(joid).orElse(null) | ||||
| val bom = bomRepository.findById(jobOrder?.bom?.id?:0L).orElse(null) | val bom = bomRepository.findById(jobOrder?.bom?.id?:0L).orElse(null) | ||||
| val bomProcess = bomProcessRepository.findByBomId(jobOrder?.bom?.id?:0L) | |||||
| // get bom materials | |||||
| val bomMaterials = jobOrderBomMaterialRepository.findAllByJobOrderId(jobOrder?.id?:0) | |||||
| val itemIds = bomMaterials.mapNotNull { it.item?.id } | |||||
| // calculate each item's available stock | |||||
| val stockQtyMap = bomMaterials.mapNotNull { material -> | |||||
| val itemId = material.item?.id ?: return@mapNotNull null | |||||
| val availableLots = inventoryLotLineRepository | |||||
| .findAllByInventoryLotItemIdAndStatus(itemId, InventoryLotLineStatus.AVAILABLE) | |||||
| val stockQty = availableLots.sumOf { lot -> | |||||
| (lot.inQty ?: BigDecimal.ZERO) | |||||
| .minus(lot.outQty ?: BigDecimal.ZERO) | |||||
| .minus(lot.holdQty ?: BigDecimal.ZERO) | |||||
| } | |||||
| itemId to stockQty | |||||
| }.toMap() | |||||
| // calculate statistics | |||||
| val totalStockQty = stockQtyMap.values.sumOf { it.toInt() } | |||||
| val insufficientStockQty = bomMaterials | |||||
| .filter { material -> | |||||
| val itemId = material.item?.id ?: 0L | |||||
| val stockQty = stockQtyMap[itemId] ?: BigDecimal.ZERO | |||||
| stockQty < (material.reqQty ?: BigDecimal.ZERO) | |||||
| } | |||||
| .sumOf { material -> | |||||
| val itemId = material.item?.id ?: 0L | |||||
| stockQtyMap[itemId]?.toInt() ?: 0 | |||||
| } | |||||
| val sufficientStockQty = bomMaterials | |||||
| .filter { material -> | |||||
| val itemId = material.item?.id ?: 0L | |||||
| val stockQty = stockQtyMap[itemId] ?: BigDecimal.ZERO | |||||
| stockQty >= (material.reqQty ?: BigDecimal.ZERO) | |||||
| } | |||||
| .sumOf { material -> | |||||
| val itemId = material.item?.id ?: 0L | |||||
| stockQtyMap[itemId]?.toInt() ?: 0 | |||||
| } | |||||
| // 获取 productionPriority | |||||
| val itemId = jobOrder?.bom?.item?.id | |||||
| val planEndDate = jobOrder?.planEnd?.toLocalDate() | |||||
| val productionPriority = if (itemId != null && planEndDate != null) { | |||||
| val scheduleLine = productionScheduleLineRepository | |||||
| .findByItemIdAndProduceAtAndType( | |||||
| itemId, | |||||
| planEndDate.atStartOfDay(), | |||||
| "detailed" | |||||
| ) | |||||
| scheduleLine?.itemPriority?.toString() ?: "0" | |||||
| } else { | |||||
| "0" | |||||
| } | |||||
| fun calculateColourScore(value: Int?): String { | fun calculateColourScore(value: Int?): String { | ||||
| return when (value) { | return when (value) { | ||||
| 0 -> "淺" | 0 -> "淺" | ||||
| @@ -471,13 +540,16 @@ open class ProductProcessService( | |||||
| else -> "" | else -> "" | ||||
| } | } | ||||
| } | } | ||||
| //val processId = productProcess.id ?: 0 | |||||
| return productProcesses.map { process -> | return productProcesses.map { process -> | ||||
| ProductProcessInfo( | ProductProcessInfo( | ||||
| id = process.id?:0, | id = process.id?:0, | ||||
| bomId = process.bom?.id?:0, | bomId = process.bom?.id?:0, | ||||
| jobOrderId = process.jobOrder?.id?:0, | jobOrderId = process.jobOrder?.id?:0, | ||||
| jobOrderCode = jobOrder?.code?:"", | jobOrderCode = jobOrder?.code?:"", | ||||
| itemId = bom?.item?.id?:0, | |||||
| itemCode = bom?.item?.code?:"", | |||||
| itemName = bom?.item?.name?:"", | |||||
| 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), | ||||
| @@ -488,11 +560,16 @@ open class ProductProcessService( | |||||
| startTime = process.startTime?:LocalDateTime.now(), | startTime = process.startTime?:LocalDateTime.now(), | ||||
| endTime = process.endTime?:LocalDateTime.now(), | endTime = process.endTime?:LocalDateTime.now(), | ||||
| date = process.date?:LocalDate.now(), | date = process.date?:LocalDate.now(), | ||||
| productionPriority = productionPriority, // 已经是 String,不需要 ?:0 | |||||
| totalStockQty = totalStockQty, | |||||
| insufficientStockQty = insufficientStockQty, | |||||
| sufficientStockQty = sufficientStockQty, | |||||
| productProcessLines = productProcessLineRepository.findByProductProcess_Id(process.id?:0).map { line -> | productProcessLines = productProcessLineRepository.findByProductProcess_Id(process.id?:0).map { line -> | ||||
| ProductProcessLineInfo( | ProductProcessLineInfo( | ||||
| id = line.id?:0, | id = line.id?:0, | ||||
| bomprocessId = line.bomProcess?.id?:0, | bomprocessId = line.bomProcess?.id?:0, | ||||
| operatorId = line.operator?.id?:0, | operatorId = line.operator?.id?:0, | ||||
| operatorName = line.operator?.name?:"", | |||||
| equipmentId = line.equipment?.id?:0, | equipmentId = line.equipment?.id?:0, | ||||
| handlerId = line.handler?.id?:0, | handlerId = line.handler?.id?:0, | ||||
| seqNo = line.seqNo?:0, | seqNo = line.seqNo?:0, | ||||
| @@ -500,6 +577,9 @@ open class ProductProcessService( | |||||
| description = line.description?:"", | description = line.description?:"", | ||||
| equipment_name = line.equipmentType?:"", | equipment_name = line.equipmentType?:"", | ||||
| status = line.status?:"", | status = line.status?:"", | ||||
| durationInMinutes = line.bomProcess?.durationInMinute?:0, | |||||
| prepTimeInMinutes = line.bomProcess?.prepTimeInMinute?:0, | |||||
| postProdTimeInMinutes = line.bomProcess?.postProdTimeInMinute?:0, | |||||
| byproductId = line.byproduct?.id?:0, | byproductId = line.byproduct?.id?:0, | ||||
| byproductName = line.byproduct?.name?:"", | byproductName = line.byproduct?.name?:"", | ||||
| byproductQty = line.byproductQty?:0, | byproductQty = line.byproductQty?:0, | ||||
| @@ -512,54 +592,36 @@ open class ProductProcessService( | |||||
| startTime = line.startTime, | startTime = line.startTime, | ||||
| endTime = line.endTime | endTime = line.endTime | ||||
| ) | ) | ||||
| }, | |||||
| jobOrderLines = bomMaterials.map { line -> | |||||
| val itemId = line.item?.id ?: 0L | |||||
| val stockQty = stockQtyMap[itemId]?.toInt() ?: 0 | |||||
| val uom = line.uom | |||||
| val shortUom = uom?.udfShortDesc ?: uom?.udfudesc ?: "" | |||||
| // 计算 availableStatus | |||||
| val availableStatus = if (stockQty >= (line.reqQty?.toInt() ?: 0)) { | |||||
| "available" | |||||
| } else { | |||||
| "insufficient" | |||||
| } | |||||
| jobOrderLineInfo( | |||||
| id = line.id?:0, | |||||
| itemId = itemId, | |||||
| itemCode = line.item?.code?:"", | |||||
| itemName = line.item?.name?:"", | |||||
| reqQty = line.reqQty?.toInt() ?: 0, | |||||
| stockQty = stockQty, | |||||
| uom = uom?.udfudesc ?: "", | |||||
| shortUom = shortUom, | |||||
| availableStatus = availableStatus | |||||
| ) | |||||
| } | } | ||||
| ) | ) | ||||
| } | } | ||||
| } | } | ||||
| /* | |||||
| open fun productProcessDetailfindbyidtest(id: Long): ProductProcessInfo { | |||||
| val zero = BigDecimal.ZERO | |||||
| val productProcess = productProcessRepository.findById(id).orElse(null) | |||||
| val processId = productProcess.id ?: 0 | |||||
| val productProcessLines = productProcessLineRepository.findByProductProcess_Id(processId) | |||||
| return ProductProcessInfo( | |||||
| id = productProcess.id?:0, | |||||
| bomId = productProcess.bom?.id?:0, | |||||
| jobOrderId = productProcess.jobOrder?.id?:0, | |||||
| productProcessCode = productProcess.productProcessCode?:"", | |||||
| status = productProcess.status?:ProductProcessStatus.PENDING, | |||||
| startTime = productProcess.startTime?:LocalDateTime.now(), | |||||
| endTime = productProcess.endTime?:LocalDateTime.now(), | |||||
| date = productProcess.date?:LocalDate.now(), | |||||
| productProcessLines = productProcessLines.map { line -> | |||||
| ProductProcessLineInfo( | |||||
| id = line.id?:0, | |||||
| bomprocessId = line.bomProcess?.id?:0, | |||||
| operatorId = line.operator?.id?:0, | |||||
| equipmentId = line.equipment?.id?:0, | |||||
| handlerId = line.handler?.id?:0, | |||||
| seqNo = line.seqNo?:0, | |||||
| name = line.name?:"", | |||||
| description = line.description?:"", | |||||
| equipment_name = line.equipment?.name?:"", | |||||
| status = line.status?:"", | |||||
| byproductId = line.byproduct?.id?:0, | |||||
| byproductName = line.byproduct?.name?:"", | |||||
| byproductQty = line.byproductQty?:0, | |||||
| byproductUom = line.byproductUom?:"", | |||||
| scrapQty = line.scrapQty?:0, | |||||
| defectQty = line.defectQty?:0, | |||||
| defectUom = line.defectUom?:"", | |||||
| outputFromProcessQty = line.outputFromProcessQty?:0, | |||||
| outputFromProcessUom = line.outputFromProcessUom?:"", | |||||
| startTime = line.startTime?:LocalDateTime.now(), | |||||
| endTime = line.endTime?:LocalDateTime.now() | |||||
| ) | |||||
| } | |||||
| ) | |||||
| } | |||||
| */ | |||||
| open fun createProductProcessByJobOrderId(jobOrderId: Long): MessageResponse { | open fun createProductProcessByJobOrderId(jobOrderId: Long): MessageResponse { | ||||
| val jobOrder = jobOrderRepository.findById(jobOrderId).orElse(null) | val jobOrder = jobOrderRepository.findById(jobOrderId).orElse(null) | ||||
| val bom = bomRepository.findById(jobOrder?.bom?.id ?: 0L).orElse(null) | val bom = bomRepository.findById(jobOrder?.bom?.id ?: 0L).orElse(null) | ||||
| @@ -792,6 +854,7 @@ open fun updateProductProcessLineQty(request: UpdateProductProcessLineQtyRequest | |||||
| productProcessLine.byproductUom = byproductUom | productProcessLine.byproductUom = byproductUom | ||||
| } | } | ||||
| productProcessLineRepository.save(productProcessLine) | productProcessLineRepository.save(productProcessLine) | ||||
| CompleteProductProcessLine(request.productProcessLineId) | |||||
| return MessageResponse( | return MessageResponse( | ||||
| id = request.productProcessLineId, | id = request.productProcessLineId, | ||||
| code = "200", | code = "200", | ||||
| @@ -806,11 +869,14 @@ open fun updateProductProcessLineQty(request: UpdateProductProcessLineQtyRequest | |||||
| val productProcesses = productProcessRepository.findAllByDeletedIsFalse() | val productProcesses = productProcessRepository.findAllByDeletedIsFalse() | ||||
| val productProcessIds = productProcesses.map { it.id } | val productProcessIds = productProcesses.map { it.id } | ||||
| return productProcesses.map { productProcesses -> | return productProcesses.map { productProcesses -> | ||||
| val productProcessLines = productProcessLineRepository.findByProductProcess_Id(productProcesses.id?:0L) | val productProcessLines = productProcessLineRepository.findByProductProcess_Id(productProcesses.id?:0L) | ||||
| val jobOrder = jobOrderRepository.findById(productProcesses.jobOrder?.id?:0L).orElse(null) | val jobOrder = jobOrderRepository.findById(productProcesses.jobOrder?.id?:0L).orElse(null) | ||||
| 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 stockInLineId = stockInLine?.id | |||||
| //val silHandlerId = stockInLine?.escalationLog?.firstOrNull { it.status == "pending" }?.handler?.id | |||||
| AllJoborderProductProcessInfoResponse( | AllJoborderProductProcessInfoResponse( | ||||
| id = productProcesses.id ?: 0L, | id = productProcesses.id ?: 0L, | ||||
| productProcessCode = productProcesses.productProcessCode, | productProcessCode = productProcesses.productProcessCode, | ||||
| @@ -821,6 +887,7 @@ open fun updateProductProcessLineQty(request: UpdateProductProcessLineQtyRequest | |||||
| bomId = productProcesses.bom?.id, | bomId = productProcesses.bom?.id, | ||||
| itemName = productProcesses.item?.name, | itemName = productProcesses.item?.name, | ||||
| jobOrderId = productProcesses.jobOrder?.id, | jobOrderId = productProcesses.jobOrder?.id, | ||||
| stockInLineId = stockInLineId, | |||||
| jobOrderCode = jobOrder?.code, | jobOrderCode = jobOrder?.code, | ||||
| productProcessLineCount = productProcessLines.size, | productProcessLineCount = productProcessLines.size, | ||||
| FinishedProductProcessLineCount = FinishedProductProcessLineCount, | FinishedProductProcessLineCount = FinishedProductProcessLineCount, | ||||
| @@ -936,10 +1003,30 @@ open fun updateProductProcessLineQty(request: UpdateProductProcessLineQtyRequest | |||||
| updateProductProcessLineEndTime(productProcessLineId) | updateProductProcessLineEndTime(productProcessLineId) | ||||
| updateProductProcessLineStatus(productProcessLineId, "Completed") | updateProductProcessLineStatus(productProcessLineId, "Completed") | ||||
| val productProcessLine = productProcessLineRepository.findById(productProcessLineId).orElse(null) | val productProcessLine = productProcessLineRepository.findById(productProcessLineId).orElse(null) | ||||
| val allproductProcessLines=productProcessLineRepository.findByProductProcess_Id(productProcessLine.productProcess?.id?:0L) | |||||
| val productProcessId = productProcessLine?.productProcess?.id ?: 0L | |||||
| val allproductProcessLines=productProcessLineRepository.findByProductProcess_Id(productProcessId) | |||||
| if(allproductProcessLines.all { it.status == "Completed" }) { | if(allproductProcessLines.all { it.status == "Completed" }) { | ||||
| updateProductProcessEndTime(productProcessLine.id) | |||||
| updateProductProcessStatus(productProcessLine.id, ProductProcessStatus.COMPLETED) | |||||
| updateProductProcessEndTime(productProcessId) | |||||
| updateProductProcessStatus(productProcessId, ProductProcessStatus.COMPLETED) | |||||
| val productProcess = productProcessRepository.findById(productProcessId).orElse(null) | |||||
| val jobOrder = jobOrderRepository.findById(productProcess?.jobOrder?.id?:0L).orElse(null) | |||||
| if(jobOrder != null) { | |||||
| jobOrder.status = JobOrderStatus.STORING | |||||
| jobOrderRepository.save(jobOrder) | |||||
| stockInLineService.create( | |||||
| SaveStockInLineRequest( | |||||
| itemId = productProcess?.item?.id?:0L, | |||||
| acceptedQty = jobOrder?.reqQty?:BigDecimal.ZERO, | |||||
| productLotNo = jobOrder?.code, | |||||
| productionDate = LocalDate.now(), | |||||
| jobOrderId = jobOrder.id, | |||||
| acceptQty =jobOrder?.reqQty?:BigDecimal.ZERO , | |||||
| expiryDate=null, | |||||
| status="", | |||||
| ) | |||||
| ) | |||||
| } | |||||
| } | } | ||||
| return MessageResponse( | return MessageResponse( | ||||
| id = productProcessLine.id, | id = productProcessLine.id, | ||||
| @@ -147,7 +147,7 @@ data class AllJoborderProductProcessInfoResponse( | |||||
| val jobOrderCode: String?, | val jobOrderCode: String?, | ||||
| val productProcessLineCount: Int, | val productProcessLineCount: Int, | ||||
| val FinishedProductProcessLineCount: Int, | val FinishedProductProcessLineCount: Int, | ||||
| val stockInLineId: Long?, | |||||
| val lines: List<ProductProcessInfoResponse> | val lines: List<ProductProcessInfoResponse> | ||||
| ) | ) | ||||
| data class ProductProcessInfoResponse( | data class ProductProcessInfoResponse( | ||||
| @@ -15,4 +15,5 @@ interface InventoryLotRepository: AbstractRepository<InventoryLot, Long> { | |||||
| select il.lotNo from InventoryLot il where il.lotNo like :prefix% order by il.lotNo desc limit 1 | select il.lotNo from InventoryLot il where il.lotNo like :prefix% order by il.lotNo desc limit 1 | ||||
| """) | """) | ||||
| fun findLatestLotNoByPrefix(prefix: String): String? | fun findLatestLotNoByPrefix(prefix: String): String? | ||||
| fun findAllByIdIn(ids: List<Long>): List<InventoryLot> | |||||
| } | } | ||||
| @@ -21,4 +21,5 @@ interface StockOutLIneRepository: AbstractRepository<StockOutLine, Long> { | |||||
| inventoryLotLineId: Long | inventoryLotLineId: Long | ||||
| ): List<StockOutLine> | ): List<StockOutLine> | ||||
| fun existsByPickOrderLineIdAndInventoryLotLineIdAndDeletedFalse(pickOrderLineId: Long, inventoryLotLineId: Long): Boolean | fun existsByPickOrderLineIdAndInventoryLotLineIdAndDeletedFalse(pickOrderLineId: Long, inventoryLotLineId: Long): Boolean | ||||
| //fun findAllByPickOrderLineIdAndDeletedFalse(pickOrderLineId: Long): List<StockOutLine> | |||||
| } | } | ||||