| @@ -14,7 +14,9 @@ open class Warehouse : BaseEntity<Long>() { | |||||
| @NotNull | @NotNull | ||||
| @Column(name = "code", nullable = false, length = 30) | @Column(name = "code", nullable = false, length = 30) | ||||
| open var code: String? = null | open var code: String? = null | ||||
| @NotNull | |||||
| @Column(name = "order", nullable = false, length = 30) | |||||
| open var order: String? = null | |||||
| @NotNull | @NotNull | ||||
| @Column(name = "name", nullable = false, length = 30) | @Column(name = "name", nullable = false, length = 30) | ||||
| open var name: String? = null | open var name: String? = null | ||||
| @@ -4520,6 +4520,169 @@ open fun getLotDetailsByDoPickOrderRecordId(doPickOrderRecordId: Long): Map<Stri | |||||
| "pickOrders" to pickOrders | "pickOrders" to pickOrders | ||||
| ) | ) | ||||
| } | } | ||||
| private fun numToBigDecimal(n: Number?): BigDecimal { | |||||
| return when (n) { | |||||
| null -> BigDecimal.ZERO | |||||
| is BigDecimal -> n | |||||
| else -> BigDecimal.valueOf(n.toDouble()) | |||||
| } | |||||
| } | |||||
| open fun getLotDetailsByDoPickOrderRecordId2(doPickOrderRecordId: Long): Map<String, Any?> { | |||||
| // 1) 头信息(来自 record 表) | |||||
| val dpor = doPickOrderRecordRepository.findById(doPickOrderRecordId).orElse(null) | |||||
| ?: return mapOf("fgInfo" to null, "pickOrders" to emptyList<Any>()) | |||||
| val fgInfo = mapOf( | |||||
| "doPickOrderId" to dpor.id, | |||||
| "ticketNo" to dpor.ticketNo, | |||||
| "storeId" to dpor.storeId, | |||||
| "shopCode" to dpor.shopCode, | |||||
| "shopName" to dpor.shopName, | |||||
| "truckLanceCode" to dpor.truckLanceCode, | |||||
| "departureTime" to dpor.truckDepartureTime | |||||
| ) | |||||
| // 2) 取该 record 下所有 pick orders(通过行记录聚合) | |||||
| val lineRecords = doPickOrderLineRecordRepository.findByDoPickOrderIdAndDeletedFalse(dpor.id!!) | |||||
| val pickOrderIds = lineRecords.mapNotNull { it.pickOrderId }.distinct() | |||||
| if (pickOrderIds.isEmpty()) { | |||||
| return mapOf("fgInfo" to fgInfo, "pickOrders" to emptyList<Any>()) | |||||
| } | |||||
| val pickOrders = pickOrderRepository.findAllById(pickOrderIds) | |||||
| // 3) 逐个 pick order 组装行与批次/出库行 | |||||
| val pickOrderDtos = pickOrders.map { po -> | |||||
| val lines = po.pickOrderLines | |||||
| val lineDtos = lines.map { pol -> | |||||
| val item = pol.item | |||||
| val uom = pol.uom | |||||
| // 建议批次 | |||||
| val lots = pol.suggestedPickLots.mapNotNull { spl -> | |||||
| val ill = spl.suggestedLotLine ?: return@mapNotNull null | |||||
| val il = ill.inventoryLot | |||||
| val w = ill.warehouse | |||||
| val today = LocalDate.now() | |||||
| val isExpired = il?.expiryDate?.let { exp -> exp.isBefore(today) } == true | |||||
| mapOf( | |||||
| "id" to ill.id, | |||||
| "lotNo" to il?.lotNo, | |||||
| "expiryDate" to il?.expiryDate, | |||||
| "location" to w?.name, | |||||
| "stockUnit" to (ill.stockUom?.uom?.udfudesc ?: uom?.udfudesc ?: "N/A"), | |||||
| "availableQty" to ((ill.inQty ?: BigDecimal.ZERO) | |||||
| .minus(ill.outQty ?: BigDecimal.ZERO) | |||||
| .minus(ill.holdQty ?: BigDecimal.ZERO)), | |||||
| "requiredQty" to spl.qty, | |||||
| "actualPickQty" to null, // 稍后回填 | |||||
| "inQty" to ill.inQty, | |||||
| "outQty" to ill.outQty, | |||||
| "holdQty" to ill.holdQty, | |||||
| "lotStatus" to ill.status?.value, | |||||
| "lotAvailability" to when { | |||||
| isExpired -> "expired" | |||||
| ill.status?.value == "unavailable" -> "status_unavailable" | |||||
| ((ill.inQty ?: BigDecimal.ZERO) | |||||
| .minus(ill.outQty ?: BigDecimal.ZERO) | |||||
| .minus(ill.holdQty ?: BigDecimal.ZERO)) <= BigDecimal.ZERO -> "insufficient_stock" | |||||
| else -> "available" | |||||
| }, | |||||
| "processingStatus" to "pending", | |||||
| "suggestedPickLotId" to spl.id, | |||||
| "stockOutLineId" to null, | |||||
| "stockOutLineStatus" to null, | |||||
| "stockOutLineQty" to null, | |||||
| "router" to mapOf( | |||||
| "id" to null, | |||||
| "index" to w?.order, | |||||
| "route" to w?.code, | |||||
| "area" to w?.code | |||||
| ) | |||||
| ) | |||||
| } | |||||
| // 出库行(投影):支持 inventoryLotLineId 为空 | |||||
| val stockOutLines = pol.id?.let { | |||||
| // 使用你已有的方法;若该方法返回投影类型(如 StockOutLineInfo),则以下基于字段名访问 | |||||
| stockOutLIneRepository.findAllByPickOrderLineIdAndDeletedFalse(it) | |||||
| } ?: emptyList() | |||||
| // 如果是投影,通常字段:id, qty(Double?), status(String?), inventoryLotLineId(Long?) | |||||
| // 计算每个 ILL 的已拣数量(BigDecimal) | |||||
| val actualQtyByIllId: Map<Long, BigDecimal> = stockOutLines | |||||
| .mapNotNull { sol -> | |||||
| val illId = sol.inventoryLotLineId ?: return@mapNotNull null | |||||
| val qtyBD = numToBigDecimal(sol.qty as Number?) | |||||
| illId to qtyBD | |||||
| } | |||||
| .groupBy({ it.first }, { it.second }) | |||||
| .mapValues { (_, list) -> list.fold(BigDecimal.ZERO) { acc, v -> acc + v } } | |||||
| val lotsWithActual = lots.map { lot -> | |||||
| val illId = lot["id"] as? Long | |||||
| val actual = illId?.let { actualQtyByIllId[it] } | |||||
| lot.toMutableMap().apply { if (actual != null) put("actualPickQty", actual) } | |||||
| } | |||||
| // 构建 stockouts,若有 lotLineId 则加载 ILL 以补充 lotNo/location/availableQty | |||||
| val stockouts = stockOutLines.map { sol -> | |||||
| val illId = sol.inventoryLotLineId | |||||
| val ill = illId?.let { inventoryLotLineRepository.findById(it).orElse(null) } | |||||
| val il = ill?.inventoryLot | |||||
| val w = ill?.warehouse | |||||
| val available = if (ill == null) null else | |||||
| (ill.inQty ?: BigDecimal.ZERO) | |||||
| .minus(ill.outQty ?: BigDecimal.ZERO) | |||||
| .minus(ill.holdQty ?: BigDecimal.ZERO) | |||||
| mapOf( | |||||
| "id" to sol.id, | |||||
| "status" to sol.status, | |||||
| "qty" to numToBigDecimal(sol.qty as Number?), | |||||
| "lotId" to ill?.id, | |||||
| "lotNo" to (il?.lotNo ?: ""), | |||||
| "location" to (w?.name ?: ""), | |||||
| "availableQty" to available, | |||||
| "noLot" to (ill == null) | |||||
| ) | |||||
| } | |||||
| mapOf( | |||||
| "id" to pol.id, | |||||
| "requiredQty" to pol.qty, | |||||
| "status" to pol.status?.value, | |||||
| "item" to mapOf( | |||||
| "id" to item?.id, | |||||
| "code" to item?.code, | |||||
| "name" to item?.name, | |||||
| "uomCode" to uom?.code, | |||||
| "uomDesc" to uom?.udfudesc, | |||||
| "uomShortDesc" to uom?.udfShortDesc | |||||
| ), | |||||
| "lots" to lotsWithActual, | |||||
| "stockouts" to stockouts | |||||
| ) | |||||
| } | |||||
| mapOf( | |||||
| "pickOrderId" to po.id, | |||||
| "pickOrderCode" to po.code, | |||||
| "doOrderId" to po.deliveryOrder?.id, | |||||
| "deliveryOrderCode" to po.deliveryOrder?.code, | |||||
| "consoCode" to po.consoCode, | |||||
| "status" to po.status?.value, | |||||
| "targetDate" to po.targetDate?.toLocalDate(), | |||||
| "pickOrderLines" to lineDtos | |||||
| ) | |||||
| } | |||||
| return mapOf( | |||||
| "fgInfo" to fgInfo, | |||||
| "pickOrders" to pickOrderDtos | |||||
| ) | |||||
| } | |||||
| // ✅ 新增:从 do_pick_order_record 表查询(用于已完成的 pick orders) | // ✅ 新增:从 do_pick_order_record 表查询(用于已完成的 pick orders) | ||||
| open fun getFgPickOrdersFromRecordByPickOrderId(pickOrderId: Long): List<Map<String, Any?>> { | open fun getFgPickOrdersFromRecordByPickOrderId(pickOrderId: Long): List<Map<String, Any?>> { | ||||
| try { | try { | ||||
| @@ -163,7 +163,7 @@ class PickOrderController( | |||||
| } | } | ||||
| @GetMapping("/lot-details-by-do-pick-order-record/{doPickOrderRecordId}") | @GetMapping("/lot-details-by-do-pick-order-record/{doPickOrderRecordId}") | ||||
| fun getLotDetailsByDoPickOrderRecordId(@PathVariable doPickOrderRecordId: Long): Map<String, Any?> { | fun getLotDetailsByDoPickOrderRecordId(@PathVariable doPickOrderRecordId: Long): Map<String, Any?> { | ||||
| return pickOrderService.getLotDetailsByDoPickOrderRecordId(doPickOrderRecordId) | |||||
| return pickOrderService.getLotDetailsByDoPickOrderRecordId2(doPickOrderRecordId) | |||||
| } | } | ||||
| @PostMapping("/groups") | @PostMapping("/groups") | ||||
| @@ -584,7 +584,7 @@ open class ProductProcessService( | |||||
| open fun UpdateProductProcessLineOperatorIdOrEquipmentId(request: UpdateProductProcessLineOperatorIdOrEquipmentIdRequest): MessageResponse { | open fun UpdateProductProcessLineOperatorIdOrEquipmentId(request: UpdateProductProcessLineOperatorIdOrEquipmentIdRequest): MessageResponse { | ||||
| val productProcessLine = productProcessLineRepository.findById(request.productProcessLineId).orElse(null) | val productProcessLine = productProcessLineRepository.findById(request.productProcessLineId).orElse(null) | ||||
| val equipmentId = request.equipmentId | val equipmentId = request.equipmentId | ||||
| val user = userRepository.findById(request.operatorId).orElse(null) | |||||
| val user = userRepository.findById(request.operatorId?:0L).orElse(null) | |||||
| val bomProcess= bomProcessRepository.findById(productProcessLine?.bomProcess?.id?:0L).orElse(null) | val bomProcess= bomProcessRepository.findById(productProcessLine?.bomProcess?.id?:0L).orElse(null) | ||||
| val bomProcessEquipment=bomProcess?.equipment | val bomProcessEquipment=bomProcess?.equipment | ||||
| if(equipmentId != null &&( equipmentId==bomProcessEquipment?.id)) { | if(equipmentId != null &&( equipmentId==bomProcessEquipment?.id)) { | ||||
| @@ -596,7 +596,7 @@ open class ProductProcessService( | |||||
| else | else | ||||
| { | { | ||||
| println("not match") | |||||
| println("not match equipment id${equipmentId} and ${bomProcessEquipment?.id}") | |||||
| } | } | ||||
| if(user != null) { | if(user != null) { | ||||
| productProcessLine.operator = user | productProcessLine.operator = user | ||||
| @@ -613,4 +613,50 @@ open class ProductProcessService( | |||||
| errorPosition = null, | errorPosition = null, | ||||
| ) | ) | ||||
| } | } | ||||
| open fun UpdateProductProcessLineHandlerId(request: UpdateProductProcessLineHandlerIdRequest): MessageResponse { | |||||
| val productProcessLine = productProcessLineRepository.findById(request.productProcessLineId).orElse(null) | |||||
| val handlerId = request.handlerId | |||||
| val user = userRepository.findById(handlerId?:0L).orElse(null) | |||||
| if(user != null) { | |||||
| productProcessLine.handler = user | |||||
| productProcessLineRepository.save(productProcessLine) | |||||
| } | |||||
| return MessageResponse( | |||||
| id = null, | |||||
| code = null, | |||||
| name = null, | |||||
| type = null, | |||||
| message = null, | |||||
| errorPosition = null, | |||||
| ) | |||||
| } | |||||
| open fun getJobOrderProcessLineDetail(productProcessLineId: Long): JobOrderProcessLineDetailResponse { | |||||
| val productProcessLine = productProcessLineRepository.findById(productProcessLineId).orElse(null) | |||||
| return JobOrderProcessLineDetailResponse( | |||||
| id = productProcessLine.id?:0, | |||||
| productProcessId = productProcessLine.productProcess ?.id?:0, | |||||
| bomProcessId = productProcessLine.bomProcess?.id?:0, | |||||
| operatorId = productProcessLine.operator?.id?:0, | |||||
| operatorName = productProcessLine.operator?.name?:"", | |||||
| handlerId = productProcessLine.handler?.id?:0, | |||||
| seqNo = productProcessLine.seqNo?:0, | |||||
| name = productProcessLine.name?:"", | |||||
| description = productProcessLine.description?:"", | |||||
| equipmentType = productProcessLine.equipmentType?:"", | |||||
| equipment = productProcessLine.equipment?.name?:"", | |||||
| startTime = productProcessLine.startTime?:LocalDateTime.now(), | |||||
| endTime = productProcessLine.endTime?:LocalDateTime.now(), | |||||
| status = productProcessLine.status?:"", | |||||
| outputFromProcessQty = productProcessLine.outputFromProcessQty?:0, | |||||
| outputFromProcessUom = productProcessLine.outputFromProcessUom?:"", | |||||
| defectQty = productProcessLine.defectQty?:0, | |||||
| defectUom = productProcessLine.defectUom?:"", | |||||
| scrapQty = productProcessLine.scrapQty?:0, | |||||
| scrapUom = productProcessLine.scrapUom?:"", | |||||
| byproductId = productProcessLine.byproduct?.id?:0, | |||||
| byproductName = productProcessLine.byproduct?.name?:"", | |||||
| byproductQty = productProcessLine.byproductQty?:0, | |||||
| byproductUom = productProcessLine.byproductUom?:"" | |||||
| ) | |||||
| } | |||||
| } | } | ||||
| @@ -167,4 +167,8 @@ class ProductProcessController( | |||||
| fun demoupdate(@RequestBody request: UpdateProductProcessLineOperatorIdOrEquipmentIdRequest): MessageResponse { | fun demoupdate(@RequestBody request: UpdateProductProcessLineOperatorIdOrEquipmentIdRequest): MessageResponse { | ||||
| return productProcessService.UpdateProductProcessLineOperatorIdOrEquipmentId(request) | return productProcessService.UpdateProductProcessLineOperatorIdOrEquipmentId(request) | ||||
| } | } | ||||
| @PostMapping("/Demo/update/handler") | |||||
| fun demoupdatehandler(@RequestBody request: UpdateProductProcessLineHandlerIdRequest): MessageResponse { | |||||
| return productProcessService.UpdateProductProcessLineHandlerId(request) | |||||
| } | |||||
| } | } | ||||
| @@ -11,6 +11,10 @@ data class UpdateProductProcessLineOperatorIdOrEquipmentIdRequest( | |||||
| val operatorId: Long?, | val operatorId: Long?, | ||||
| val equipmentId: Long? | val equipmentId: Long? | ||||
| ) | ) | ||||
| data class UpdateProductProcessLineHandlerIdRequest( | |||||
| val productProcessLineId: Long, | |||||
| val handlerId: Long? | |||||
| ) | |||||
| data class ProductionProcessIssueResponse( | data class ProductionProcessIssueResponse( | ||||
| val id: Long, | val id: Long, | ||||
| val productProcessId: Long?, | val productProcessId: Long?, | ||||
| @@ -89,4 +93,31 @@ data class UpdateLineOutputRequest( | |||||
| val byproductName: String?, | val byproductName: String?, | ||||
| val byproductQty: Int?, | val byproductQty: Int?, | ||||
| val byproductUom: String? | val byproductUom: String? | ||||
| ) | |||||
| ) | |||||
| data class JobOrderProcessLineDetailResponse( | |||||
| val id: Long, | |||||
| val productProcessId: Long?, | |||||
| val bomProcessId: Long?, | |||||
| val operatorId: Long?, | |||||
| val equipmentType: String?, | |||||
| val operatorName: String?, | |||||
| val handlerId: Long?, | |||||
| val seqNo: Long?, | |||||
| val name: String?, | |||||
| val description: String?, | |||||
| val equipment: String?, | |||||
| val startTime: LocalDateTime?, | |||||
| val endTime: LocalDateTime?, | |||||
| val status: String, | |||||
| val outputFromProcessQty: Int?, | |||||
| val outputFromProcessUom: String?, | |||||
| val defectQty: Int?, | |||||
| val defectUom: String?, | |||||
| val scrapQty: Int?, | |||||
| val scrapUom: String?, | |||||
| val byproductId: Long?, | |||||
| val byproductName: String?, | |||||
| val byproductQty: Int?, | |||||
| val byproductUom: String? | |||||
| ) | |||||