| @@ -18,6 +18,8 @@ import java.time.LocalDateTime | |||||
| @Table(name = "do_pick_order_line_record") | @Table(name = "do_pick_order_line_record") | ||||
| open class DoPickOrderLineRecord: BaseEntity<Long>() { | open class DoPickOrderLineRecord: BaseEntity<Long>() { | ||||
| @Column(name = "record_id") | |||||
| open var recordId: Long? = null | |||||
| @Column(name = "do_pick_order_id", length = 100) | @Column(name = "do_pick_order_id", length = 100) | ||||
| open var doPickOrderId: Long? = null | open var doPickOrderId: Long? = null | ||||
| @@ -14,7 +14,8 @@ class DoPickOrderRecord { | |||||
| @Id | @Id | ||||
| @GeneratedValue(strategy = GenerationType.IDENTITY) | @GeneratedValue(strategy = GenerationType.IDENTITY) | ||||
| var id: Long? = null | var id: Long? = null | ||||
| @Column(name = "record_id") | |||||
| var recordId: Long? = null | |||||
| @Column(name = "store_id", length = 10) | @Column(name = "store_id", length = 10) | ||||
| var storeId: String? = null | var storeId: String? = null | ||||
| @@ -95,6 +96,7 @@ var handlerName: String? = null | |||||
| // Constructor for creating new instances | // Constructor for creating new instances | ||||
| constructor( | constructor( | ||||
| recordId: Long?, | |||||
| storeId: String, | storeId: String, | ||||
| ticketNo: String, | ticketNo: String, | ||||
| ticketStatus: DoPickOrderStatus, | ticketStatus: DoPickOrderStatus, | ||||
| @@ -117,6 +119,7 @@ var handlerName: String? = null | |||||
| deliveryOrderCode: String? = null, | deliveryOrderCode: String? = null, | ||||
| loadingSequence: Int? = null, | loadingSequence: Int? = null, | ||||
| ) { | ) { | ||||
| this.recordId= recordId | |||||
| this.storeId = storeId | this.storeId = storeId | ||||
| this.ticketNo = ticketNo | this.ticketNo = ticketNo | ||||
| this.pickOrderId = pickOrderId | this.pickOrderId = pickOrderId | ||||
| @@ -39,7 +39,7 @@ open class DoPickOrderCompletionService( | |||||
| return savedDoPickOrders | return savedDoPickOrders | ||||
| } | } | ||||
| /* | |||||
| @Transactional | @Transactional | ||||
| fun removeDoPickOrdersForPickOrder(pickOrderId: Long): Int { | fun removeDoPickOrdersForPickOrder(pickOrderId: Long): Int { | ||||
| val doPickOrders = doPickOrderRepository.findByPickOrderId(pickOrderId) | val doPickOrders = doPickOrderRepository.findByPickOrderId(pickOrderId) | ||||
| @@ -48,6 +48,7 @@ open class DoPickOrderCompletionService( | |||||
| doPickOrders.forEach { doPickOrder -> | doPickOrders.forEach { doPickOrder -> | ||||
| // ✅ 第一步:复制 do_pick_order 到 do_pick_order_record | // ✅ 第一步:复制 do_pick_order 到 do_pick_order_record | ||||
| val doPickOrderRecord = DoPickOrderRecord( | val doPickOrderRecord = DoPickOrderRecord( | ||||
| storeId = doPickOrder.storeId ?: "", | storeId = doPickOrder.storeId ?: "", | ||||
| ticketNo = doPickOrder.ticketNo ?: "", | ticketNo = doPickOrder.ticketNo ?: "", | ||||
| ticketStatus = DoPickOrderStatus.completed, | ticketStatus = DoPickOrderStatus.completed, | ||||
| @@ -99,4 +100,5 @@ open class DoPickOrderCompletionService( | |||||
| return deletedCount | return deletedCount | ||||
| } | } | ||||
| */ | |||||
| } | } | ||||
| @@ -176,6 +176,7 @@ open class DoPickOrderService( | |||||
| doPickOrders.forEach { doPickOrder -> | doPickOrders.forEach { doPickOrder -> | ||||
| // ✅ 第一步:复制 do_pick_order 到 do_pick_order_record | // ✅ 第一步:复制 do_pick_order 到 do_pick_order_record | ||||
| val doPickOrderRecord = DoPickOrderRecord( | val doPickOrderRecord = DoPickOrderRecord( | ||||
| recordId = doPickOrder.id, | |||||
| storeId = doPickOrder.storeId?: "", | storeId = doPickOrder.storeId?: "", | ||||
| ticketNo = doPickOrder.ticketNo?: "", | ticketNo = doPickOrder.ticketNo?: "", | ||||
| ticketStatus = DoPickOrderStatus.completed, // 设置为completed状态 | ticketStatus = DoPickOrderStatus.completed, // 设置为completed状态 | ||||
| @@ -203,7 +204,8 @@ open class DoPickOrderService( | |||||
| // ✅ 第二步:复制 do_pick_order_line 到 do_pick_order_line_record | // ✅ 第二步:复制 do_pick_order_line 到 do_pick_order_line_record | ||||
| val doPickOrderLines = doPickOrderLineRepository.findByDoPickOrderIdAndDeletedFalse(doPickOrder.id!!) | val doPickOrderLines = doPickOrderLineRepository.findByDoPickOrderIdAndDeletedFalse(doPickOrder.id!!) | ||||
| doPickOrderLines.forEach { line -> | doPickOrderLines.forEach { line -> | ||||
| val doPickOrderLineRecord = DoPickOrderLineRecord() // ✅ 使用默认构造函数 | |||||
| val doPickOrderLineRecord = DoPickOrderLineRecord() | |||||
| doPickOrderLineRecord.recordId = line.id // ✅ 使用默认构造函数 | |||||
| doPickOrderLineRecord.doPickOrderId = savedRecord.id // ✅ 设置属性 | doPickOrderLineRecord.doPickOrderId = savedRecord.id // ✅ 设置属性 | ||||
| doPickOrderLineRecord.pickOrderId = line.pickOrderId | doPickOrderLineRecord.pickOrderId = line.pickOrderId | ||||
| doPickOrderLineRecord.doOrderId = line.doOrderId | doPickOrderLineRecord.doOrderId = line.doOrderId | ||||
| @@ -540,6 +542,7 @@ open class DoPickOrderService( | |||||
| // 创建 do_pick_order_record | // 创建 do_pick_order_record | ||||
| val doPickOrderRecord = DoPickOrderRecord( | val doPickOrderRecord = DoPickOrderRecord( | ||||
| recordId =doPickOrder.id, | |||||
| storeId = storeId, | storeId = storeId, | ||||
| ticketNo = ticketNumber, | ticketNo = ticketNumber, | ||||
| ticketStatus = DoPickOrderStatus.pending, | ticketStatus = DoPickOrderStatus.pending, | ||||
| @@ -7,4 +7,6 @@ import java.util.Optional | |||||
| @Repository | @Repository | ||||
| interface BomProcessRepository : AbstractRepository<BomProcess, Long> { | interface BomProcessRepository : AbstractRepository<BomProcess, Long> { | ||||
| fun findBySeqNoAndBomIdAndDeletedIsFalse(seqNo: Int, bomId: Long): BomProcess? | fun findBySeqNoAndBomIdAndDeletedIsFalse(seqNo: Int, bomId: Long): BomProcess? | ||||
| fun findByBomIdOrderBySeqNo(bomId: Long): List<BomProcess> | |||||
| fun findByBomId(bomId: Long): List<BomProcess> | |||||
| } | } | ||||
| @@ -1284,6 +1284,7 @@ open class PickOrderService( | |||||
| // 2) 先复制 do_pick_order -> do_pick_order_record | // 2) 先复制 do_pick_order -> do_pick_order_record | ||||
| val dpoRecord = DoPickOrderRecord( | val dpoRecord = DoPickOrderRecord( | ||||
| recordId =dpo.id, | |||||
| storeId = dpo.storeId ?: "", | storeId = dpo.storeId ?: "", | ||||
| ticketNo = dpo.ticketNo ?: "", | ticketNo = dpo.ticketNo ?: "", | ||||
| ticketStatus = DoPickOrderStatus.completed, | ticketStatus = DoPickOrderStatus.completed, | ||||
| @@ -1310,6 +1311,7 @@ open class PickOrderService( | |||||
| val lines = doPickOrderLineRepository.findByDoPickOrderIdAndDeletedFalse(dpo.id!!) | val lines = doPickOrderLineRepository.findByDoPickOrderIdAndDeletedFalse(dpo.id!!) | ||||
| val lineRecords = lines.map { l: DoPickOrderLine -> | val lineRecords = lines.map { l: DoPickOrderLine -> | ||||
| DoPickOrderLineRecord().apply { | DoPickOrderLineRecord().apply { | ||||
| this.recordId=l.id | |||||
| this.doPickOrderId = savedHeader.id | this.doPickOrderId = savedHeader.id | ||||
| this.pickOrderId = l.pickOrderId | this.pickOrderId = l.pickOrderId | ||||
| this.doOrderId = l.doOrderId | this.doOrderId = l.doOrderId | ||||
| @@ -2399,7 +2401,7 @@ open class PickOrderService( | |||||
| ) | ) | ||||
| } | } | ||||
| } | } | ||||
| /* | |||||
| @Transactional(rollbackFor = [java.lang.Exception::class]) | @Transactional(rollbackFor = [java.lang.Exception::class]) | ||||
| open fun autoAssignAndReleasePickOrderByStore(userId: Long, storeId: String): MessageResponse { | open fun autoAssignAndReleasePickOrderByStore(userId: Long, storeId: String): MessageResponse { | ||||
| try { | try { | ||||
| @@ -2622,6 +2624,7 @@ open class PickOrderService( | |||||
| println("🔍 DEBUG: Processing line - Store ID: $determinedStoreId") | println("🔍 DEBUG: Processing line - Store ID: $determinedStoreId") | ||||
| val doPickOrderRecord = DoPickOrderRecord( | val doPickOrderRecord = DoPickOrderRecord( | ||||
| id=dopickorder.id, | |||||
| storeId = determinedStoreId, | storeId = determinedStoreId, | ||||
| ticketNo = nextTicketNumber, | ticketNo = nextTicketNumber, | ||||
| ticketStatus = DoPickOrderStatus.released, | ticketStatus = DoPickOrderStatus.released, | ||||
| @@ -2670,7 +2673,7 @@ open class PickOrderService( | |||||
| ) | ) | ||||
| } | } | ||||
| } | } | ||||
| */ | |||||
| open fun getAllPickOrderLotsWithDetailsWithAutoAssign(userId: Long): List<Map<String, Any>> { | open fun getAllPickOrderLotsWithDetailsWithAutoAssign(userId: Long): List<Map<String, Any>> { | ||||
| println("=== Debug: getAllPickOrderLotsWithDetailsWithAutoAssign ===") | println("=== Debug: getAllPickOrderLotsWithDetailsWithAutoAssign ===") | ||||
| println("today: ${LocalDate.now()}") | println("today: ${LocalDate.now()}") | ||||
| @@ -234,6 +234,7 @@ class PickOrderController( | |||||
| fun autoAssignAndReleasePickOrder(@PathVariable userId: Long): MessageResponse { | fun autoAssignAndReleasePickOrder(@PathVariable userId: Long): MessageResponse { | ||||
| return pickOrderService.autoAssignAndReleasePickOrder(userId) | return pickOrderService.autoAssignAndReleasePickOrder(userId) | ||||
| } | } | ||||
| /* | |||||
| @PostMapping("/auto-assign-release-by-store") | @PostMapping("/auto-assign-release-by-store") | ||||
| fun autoAssignReleaseByStore( | fun autoAssignReleaseByStore( | ||||
| @RequestParam userId: Long, | @RequestParam userId: Long, | ||||
| @@ -241,6 +242,7 @@ class PickOrderController( | |||||
| ): MessageResponse { | ): MessageResponse { | ||||
| return pickOrderService.autoAssignAndReleasePickOrderByStore(userId, storeId) | return pickOrderService.autoAssignAndReleasePickOrderByStore(userId, storeId) | ||||
| } | } | ||||
| */ | |||||
| @GetMapping("/check-pick-completion/{userId}") | @GetMapping("/check-pick-completion/{userId}") | ||||
| fun checkPickOrderCompletion(@PathVariable userId: Long): MessageResponse { | fun checkPickOrderCompletion(@PathVariable userId: Long): MessageResponse { | ||||
| return pickOrderService.checkPickOrderCompletion(userId) | return pickOrderService.checkPickOrderCompletion(userId) | ||||
| @@ -273,7 +275,7 @@ class PickOrderController( | |||||
| fun getAllPickOrderLotsHierarchical(@PathVariable userId: Long): Map<String, Any?> { | fun getAllPickOrderLotsHierarchical(@PathVariable userId: Long): Map<String, Any?> { | ||||
| return pickOrderService.getAllPickOrderLotsWithDetailsHierarchical(userId) | return pickOrderService.getAllPickOrderLotsWithDetailsHierarchical(userId) | ||||
| } | } | ||||
| @PostMapping("/auto-assign-release-by-ticket") | |||||
| /* @PostMapping("/auto-assign-release-by-ticket") | |||||
| fun autoAssignAndReleasePickOrderByTicket( | fun autoAssignAndReleasePickOrderByTicket( | ||||
| @RequestParam storeId: String, | @RequestParam storeId: String, | ||||
| @RequestParam ticketNo: String, | @RequestParam ticketNo: String, | ||||
| @@ -281,6 +283,7 @@ fun autoAssignAndReleasePickOrderByTicket( | |||||
| ): MessageResponse { | ): MessageResponse { | ||||
| return pickOrderService.autoAssignAndReleasePickOrderByStoreAndTicket(storeId, ticketNo, userId) | return pickOrderService.autoAssignAndReleasePickOrderByStoreAndTicket(storeId, ticketNo, userId) | ||||
| } | } | ||||
| */ | |||||
| @GetMapping("/orders-by-store/{storeId}") | @GetMapping("/orders-by-store/{storeId}") | ||||
| fun getPickOrdersByStore(@PathVariable storeId: String): Map<String, Any?> { | fun getPickOrdersByStore(@PathVariable storeId: String): Map<String, Any?> { | ||||
| return pickOrderService.getPickOrdersByDateAndStore(storeId) | return pickOrderService.getPickOrdersByDateAndStore(storeId) | ||||
| @@ -0,0 +1,56 @@ | |||||
| package com.ffii.fpsms.modules.productProcess.entity | |||||
| import com.fasterxml.jackson.annotation.JsonManagedReference | |||||
| import com.ffii.core.entity.BaseEntity | |||||
| import com.ffii.fpsms.modules.jobOrder.entity.JobOrder | |||||
| import com.ffii.fpsms.modules.master.entity.Items | |||||
| import com.ffii.fpsms.modules.productProcess.enums.ProductProcessStatus | |||||
| import com.ffii.fpsms.modules.productProcess.enums.ProductProcessStatusConverter | |||||
| import jakarta.persistence.* | |||||
| import jakarta.validation.constraints.NotNull | |||||
| import jakarta.validation.constraints.Size | |||||
| import java.time.LocalDate | |||||
| import java.time.LocalDateTime | |||||
| import com.ffii.fpsms.modules.master.entity.Bom | |||||
| @Entity | |||||
| @Table(name = "productprocess") | |||||
| open class ProductProcess : BaseEntity<Long>() { | |||||
| @Size(max = 50) | |||||
| @NotNull | |||||
| @Column(name = "productprocesscode", nullable = false, unique = true, length = 50) | |||||
| open var productProcessCode: String? = null | |||||
| @ManyToOne(fetch = FetchType.LAZY) | |||||
| @JoinColumn(name = "jobOrderId") | |||||
| open var jobOrder: JobOrder? = null | |||||
| @ManyToOne(fetch = FetchType.LAZY) | |||||
| @JoinColumn(name = "itemsId") | |||||
| open var item: Items? = null | |||||
| @NotNull | |||||
| @ManyToOne(fetch = FetchType.LAZY) | |||||
| @JoinColumn(name = "bomId", nullable = false) | |||||
| open var bom: Bom? = null | |||||
| @NotNull | |||||
| @Column(name = "status", nullable = false, length = 20) | |||||
| @Convert(converter = ProductProcessStatusConverter::class) | |||||
| open var status: ProductProcessStatus = ProductProcessStatus.PENDING | |||||
| @Column(name = "startTime") | |||||
| open var startTime: LocalDateTime? = null | |||||
| @Column(name = "endTime") | |||||
| open var endTime: LocalDateTime? = null | |||||
| @Column(name = "date") | |||||
| open var date: LocalDate? = null | |||||
| @JsonManagedReference | |||||
| @OneToMany(mappedBy = "productProcess", cascade = [CascadeType.ALL], orphanRemoval = true) | |||||
| open var productionScheduleLines: MutableList<ProductProcessLine> = mutableListOf() | |||||
| } | |||||
| @@ -0,0 +1,106 @@ | |||||
| package com.ffii.fpsms.modules.productProcess.entity | |||||
| import com.fasterxml.jackson.annotation.JsonBackReference | |||||
| import com.ffii.core.entity.BaseEntity | |||||
| import com.ffii.fpsms.modules.master.entity.Equipment | |||||
| import com.ffii.fpsms.modules.master.entity.Items | |||||
| import com.ffii.fpsms.modules.user.entity.User | |||||
| import jakarta.persistence.* | |||||
| import jakarta.validation.constraints.Size | |||||
| import java.time.LocalDateTime | |||||
| import com.ffii.fpsms.modules.master.entity.BomProcess | |||||
| @Entity | |||||
| @Table(name = "productprocessline") | |||||
| open class ProductProcessLine : BaseEntity<Long>() { | |||||
| // ✅ 添加 @ManyToOne | |||||
| @ManyToOne(fetch = FetchType.LAZY) | |||||
| @JoinColumn(name = "operatorId") | |||||
| open var operator: User? = null | |||||
| // ✅ 添加 @ManyToOne | |||||
| @ManyToOne(fetch = FetchType.LAZY) | |||||
| @JoinColumn(name = "equipmentId") | |||||
| open var equipment: Equipment? = null | |||||
| @Size(max = 100) | |||||
| @Column(name = "name", length = 100) | |||||
| open var name: String? = null | |||||
| @Column(name = "description") | |||||
| open var description: String? = null | |||||
| @Size(max = 100) | |||||
| @Column(name = "equipment_name", length = 100) | |||||
| open var equipmentType: String? = null | |||||
| // ✅ 添加 @ManyToOne | |||||
| @ManyToOne(fetch = FetchType.LAZY) | |||||
| @JoinColumn(name = "byproductId") | |||||
| open var byproduct: Items? = null | |||||
| @Column(name = "status") | |||||
| open var status: String? = null | |||||
| @Size(max = 100) | |||||
| @Column(name = "byproductName", length = 100) | |||||
| open var byproductName: String? = null | |||||
| @Column(name = "byproductQty", precision = 16, scale = 2) | |||||
| open var byproductQty: Int? = null | |||||
| @Size(max = 20) | |||||
| @Column(name = "byproductUom", length = 20) | |||||
| open var byproductUom: String? = null | |||||
| @Column(name = "scrapQty", precision = 16, scale = 2) | |||||
| open var scrapQty: Int? = null | |||||
| @Size(max = 20) | |||||
| @Column(name = "scrapUom", length = 20) | |||||
| open var scrapUom: String? = null | |||||
| @Column(name = "defectQty", precision = 16, scale = 2) | |||||
| open var defectQty: Int? = null | |||||
| @Size(max = 20) | |||||
| @Column(name = "defectUom", length = 20) | |||||
| open var defectUom: String? = null | |||||
| @Column(name = "outputFromProcessQty", precision = 16, scale = 2) | |||||
| open var outputFromProcessQty: Int? = null | |||||
| @Size(max = 20) | |||||
| @Column(name = "outputFromProcessUom", length = 20) | |||||
| open var outputFromProcessUom: String? = null | |||||
| @Column(name = "startTime") | |||||
| open var startTime: LocalDateTime? = null | |||||
| @Column(name = "endTime") | |||||
| open var endTime: LocalDateTime? = null | |||||
| @ManyToOne(fetch = FetchType.LAZY) | |||||
| @JoinColumn(name = "bomProcessId") | |||||
| open var bomProcess: BomProcess? = null | |||||
| @Column(name = "seqNo") | |||||
| open var seqNo: Long? = null | |||||
| @ManyToOne(fetch = FetchType.LAZY) | |||||
| @JoinColumn(name = "handlerId") | |||||
| open var handler: User? = null | |||||
| @JsonBackReference | |||||
| @ManyToOne | |||||
| @JoinColumn(name = "productprocessId", nullable = false) | |||||
| open var productProcess: ProductProcess = ProductProcess() | |||||
| data class ProductProcessLineDetail( | |||||
| val id: Long?, | |||||
| val name: String?, | |||||
| val description: String?, | |||||
| val equipmentType: String?, | |||||
| val status: String?, | |||||
| val byproduct: Items?, | |||||
| val byproductName: String?, | |||||
| val byproductQty: Int?, | |||||
| val byproductUom: String?, | |||||
| val scrapQty: Int?, | |||||
| val scrapUom: String?, | |||||
| ) | |||||
| } | |||||
| @@ -0,0 +1,11 @@ | |||||
| package com.ffii.fpsms.modules.productProcess.entity | |||||
| import org.springframework.data.jpa.repository.JpaRepository | |||||
| import org.springframework.stereotype.Repository | |||||
| @Repository | |||||
| interface ProductProcessLineRepository : JpaRepository<ProductProcessLine, Long> { | |||||
| fun findByProductProcess_Id(productProcessId: Long): List<ProductProcessLine> | |||||
| fun findByProductProcess_IdAndHandler_Id(productProcessId: Long, handlerId: Long): List<ProductProcessLine> | |||||
| fun findByHandler_IdAndStartTimeIsNotNullAndEndTimeIsNull(handlerId: Long): List<ProductProcessLine> | |||||
| } | |||||
| @@ -0,0 +1,14 @@ | |||||
| package com.ffii.fpsms.modules.productProcess.entity | |||||
| import org.springframework.data.jpa.repository.JpaRepository | |||||
| import org.springframework.data.jpa.repository.JpaSpecificationExecutor | |||||
| import org.springframework.stereotype.Repository | |||||
| import java.util.* | |||||
| @Repository | |||||
| interface ProductProcessRepository : JpaRepository<ProductProcess, Long>, JpaSpecificationExecutor<ProductProcess> { | |||||
| fun findByProductProcessCode(code: String): Optional<ProductProcess> | |||||
| fun findByJobOrder_Id(jobOrderId: Long): List<ProductProcess> | |||||
| fun findByProductProcessCodeStartingWith(prefix: String): List<ProductProcess> | |||||
| fun findByIdAndDeletedIsFalse(id: Long): Optional<ProductProcess> | |||||
| } | |||||
| @@ -0,0 +1,39 @@ | |||||
| package com.ffii.fpsms.modules.productProcess.entity | |||||
| import com.ffii.core.entity.BaseEntity | |||||
| import com.ffii.fpsms.modules.user.entity.User | |||||
| import jakarta.persistence.* | |||||
| import jakarta.validation.constraints.NotNull | |||||
| import jakarta.validation.constraints.Size | |||||
| import java.time.LocalDateTime | |||||
| @Entity | |||||
| @Table(name = "productionprocessissue") // ✅ 修复:改为正确的表名 | |||||
| open class ProductionProcessIssue : BaseEntity<Long>() { // ✅ 修复:改为正确的类名 | |||||
| @ManyToOne(fetch = FetchType.LAZY) | |||||
| @JoinColumn(name = "productprocessid", nullable = false) | |||||
| open var productProcess: ProductProcess? = null | |||||
| @ManyToOne(fetch = FetchType.LAZY) | |||||
| @JoinColumn(name = "operatorId") | |||||
| open var operator: User? = null | |||||
| @Size(max = 100) | |||||
| @Column(name = "operatorName", length = 100) | |||||
| open var operatorName: String? = null | |||||
| @NotNull | |||||
| @Column(name = "reason", nullable = false) | |||||
| open var reason: String? = null | |||||
| @NotNull | |||||
| @Column(name = "stopTime", nullable = false) | |||||
| open var stopTime: LocalDateTime? = null | |||||
| @Column(name = "resumeTime") | |||||
| open var resumeTime: LocalDateTime? = null | |||||
| @Column(name = "totalTime") | |||||
| open var totalTime: Int? = null // 分钟 | |||||
| } | |||||
| @@ -0,0 +1,9 @@ | |||||
| package com.ffii.fpsms.modules.productProcess.entity | |||||
| import org.springframework.data.jpa.repository.JpaRepository | |||||
| import org.springframework.stereotype.Repository | |||||
| @Repository | |||||
| interface ProductionProcessIssueRepository : JpaRepository<ProductionProcessIssue, Long> { | |||||
| fun findByProductProcess_Id(productProcessId: Long): List<ProductionProcessIssue> | |||||
| } | |||||
| @@ -0,0 +1,48 @@ | |||||
| package com.ffii.fpsms.modules.productProcess.entity.projections | |||||
| import java.time.LocalDateTime | |||||
| import java.time.LocalDate | |||||
| import com.ffii.fpsms.modules.productProcess.enums.ProductProcessStatus | |||||
| import com.fasterxml.jackson.annotation.JsonFormat | |||||
| data class ProductProcessInfo( | |||||
| val id: Long?, | |||||
| val productProcessCode: String?, | |||||
| val status: ProductProcessStatus?, | |||||
| @JsonFormat(pattern = "yyyy-MM-dd") | |||||
| val startTime: LocalDateTime?, | |||||
| @JsonFormat(pattern = "yyyy-MM-dd") | |||||
| val endTime: LocalDateTime?, | |||||
| @JsonFormat(pattern = "yyyy-MM-dd") | |||||
| val date: LocalDate?, | |||||
| val bomId: Long?, | |||||
| val jobOrderId: Long?, | |||||
| val productProcessLines: List<ProductProcessLineInfo>? | |||||
| ) | |||||
| data class ProductProcessLineInfo( | |||||
| val id:Long?, | |||||
| val bomprocessId: Long?, | |||||
| val operatorId: Long?, | |||||
| val equipmentId: Long?, | |||||
| val handlerId: Long?, | |||||
| val seqNo: Long?, | |||||
| val name: String?, | |||||
| val description: String?, | |||||
| val equipment_name: String?, | |||||
| val status: String?, | |||||
| val byproductId: Long?, | |||||
| val byproductName: String?, | |||||
| val byproductQty: Int?, | |||||
| val byproductUom: String?, | |||||
| val scrapQty: Int?, | |||||
| val defectQty: Int?, | |||||
| val defectUom: String?, | |||||
| val outputFromProcessQty: Int?, | |||||
| val outputFromProcessUom: String?, | |||||
| @JsonFormat(pattern = "yyyy-MM-dd") | |||||
| val startTime: LocalDateTime?, | |||||
| @JsonFormat(pattern = "yyyy-MM-dd") | |||||
| val endTime: LocalDateTime? | |||||
| ) | |||||
| @@ -0,0 +1,19 @@ | |||||
| package com.ffii.fpsms.modules.productProcess.enums | |||||
| enum class ProductProcessStatus(val value: String) { | |||||
| PENDING("pending"), | |||||
| IN_PROGRESS("in_progress"), | |||||
| STOPPED("stopped"), | |||||
| COMPLETED("completed"), | |||||
| CANCELLED("cancelled"); | |||||
| companion object { | |||||
| fun fromValue(value: String): ProductProcessStatus { | |||||
| return values().find { it.value == value } | |||||
| ?: throw IllegalArgumentException("Unknown status: $value") | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,15 @@ | |||||
| package com.ffii.fpsms.modules.productProcess.enums | |||||
| import jakarta.persistence.AttributeConverter | |||||
| import jakarta.persistence.Converter | |||||
| @Converter(autoApply = true) | |||||
| class ProductProcessStatusConverter : AttributeConverter<ProductProcessStatus, String> { | |||||
| override fun convertToDatabaseColumn(attribute: ProductProcessStatus?): String? { | |||||
| return attribute?.value | |||||
| } | |||||
| override fun convertToEntityAttribute(dbData: String?): ProductProcessStatus? { | |||||
| return dbData?.let { ProductProcessStatus.fromValue(it) } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,616 @@ | |||||
| package com.ffii.fpsms.modules.productProcess.service | |||||
| import com.ffii.fpsms.modules.productProcess.entity.* | |||||
| import com.ffii.fpsms.modules.productProcess.entity.projections.ProductProcessInfo | |||||
| import com.ffii.fpsms.modules.productProcess.entity.projections.ProductProcessLineInfo | |||||
| import com.ffii.fpsms.modules.productProcess.enums.ProductProcessStatus | |||||
| import com.ffii.fpsms.modules.productProcess.web.model.* | |||||
| import org.springframework.data.domain.Page | |||||
| import org.springframework.data.domain.Pageable | |||||
| import org.springframework.stereotype.Service | |||||
| import org.springframework.transaction.annotation.Transactional | |||||
| import java.time.LocalDate | |||||
| import java.time.LocalDateTime | |||||
| import java.time.temporal.ChronoUnit | |||||
| import com.ffii.fpsms.modules.user.entity.UserRepository | |||||
| import com.ffii.fpsms.modules.user.entity.User | |||||
| import java.time.format.DateTimeFormatter | |||||
| import com.ffii.fpsms.modules.master.entity.BomRepository | |||||
| import com.ffii.fpsms.modules.master.entity.BomProcessRepository | |||||
| import com.ffii.fpsms.modules.jobOrder.entity.JobOrderRepository | |||||
| import com.ffii.fpsms.modules.master.entity.ItemsRepository | |||||
| import com.ffii.fpsms.modules.master.entity.ProcessRepository | |||||
| import com.ffii.fpsms.modules.master.entity.EquipmentRepository | |||||
| import java.math.BigDecimal | |||||
| import com.ffii.fpsms.modules.master.entity.Process | |||||
| import com.ffii.fpsms.modules.master.entity.Equipment | |||||
| import com.ffii.fpsms.modules.master.entity.BomProcess | |||||
| import com.ffii.fpsms.modules.master.entity.Bom | |||||
| import com.ffii.fpsms.modules.master.web.models.MessageResponse | |||||
| @Service | |||||
| @Transactional | |||||
| open class ProductProcessService( | |||||
| private val productProcessRepository: ProductProcessRepository, | |||||
| private val productProcessLineRepository: ProductProcessLineRepository, | |||||
| private val productionProcessIssueRepository: ProductionProcessIssueRepository, | |||||
| private val bomRepository: BomRepository, | |||||
| private val bomProcessRepository: BomProcessRepository, | |||||
| private val jobOrderRepository: JobOrderRepository, | |||||
| private val itemsRepository: ItemsRepository, | |||||
| private val userRepository: UserRepository, | |||||
| private val processRepository: ProcessRepository, | |||||
| private val equipmentRepository: EquipmentRepository, | |||||
| ) { | |||||
| open fun findAll(pageable: Pageable): Page<ProductProcess> { | |||||
| println("📋 Service: Finding all ProductProcess with page: ${pageable.pageNumber}, size: ${pageable.pageSize}") | |||||
| val result = productProcessRepository.findAll(pageable) | |||||
| println("✅ Service: Found ${result.totalElements} records") | |||||
| return result | |||||
| } | |||||
| open fun findById(id: Long): ProductProcess { | |||||
| println("🔍 Service: Finding ProductProcess by ID: $id") | |||||
| return productProcessRepository.findById(id) | |||||
| .orElseThrow { IllegalArgumentException("ProductProcess not found with id: $id") } | |||||
| } | |||||
| open fun findByCode(code: String): ProductProcess { | |||||
| println("🔍 Service: Finding ProductProcess by code: $code") | |||||
| return productProcessRepository.findByProductProcessCode(code) | |||||
| .orElseThrow { IllegalArgumentException("ProductProcess not found with code: $code") } | |||||
| } | |||||
| open fun create(request: SaveProductProcessRequest): SaveProductProcessResponse { | |||||
| println("🔧 Service: Creating ProductProcess with bomId: ${request.bomId}") | |||||
| // 1. 查询 BOM | |||||
| val bom = bomRepository.findById(request.bomId) | |||||
| .orElseThrow { IllegalArgumentException("BOM not found with id: ${request.bomId}") } | |||||
| println("📦 Service: BOM found - name: ${bom.name}, item: ${bom.item?.name ?: "N/A"}") | |||||
| // 2. 生成 productProcessCode(格式:PP-20251026-001) | |||||
| //val datePrefix = (request.date ?: LocalDate.now()).format(DateTimeFormatter.ofPattern("yyyyMMdd")) | |||||
| val datePrefix = ( LocalDate.now()).format(DateTimeFormatter.ofPattern("yyyyMMdd")) | |||||
| val productProcessCode = generateProductProcessCode(datePrefix) | |||||
| println("🔢 Service: Generated code: $productProcessCode") | |||||
| // 3. 创建 ProductProcess | |||||
| val productProcess = ProductProcess().apply { | |||||
| this.productProcessCode = productProcessCode | |||||
| this.bom = bom | |||||
| this.item = bom.item | |||||
| this.jobOrder = request.jobOrderId?.let { jobOrderRepository.findById(it).orElse(null) } | |||||
| this.status = ProductProcessStatus.PENDING | |||||
| //this.date = request.date ?: LocalDate.now() | |||||
| this.date = LocalDate.now() | |||||
| } | |||||
| val savedProcess = productProcessRepository.save(productProcess) | |||||
| println("✅ Service: ProductProcess created with ID: ${savedProcess.id}") | |||||
| // 4. 查询 BOM 的所有工序步骤 | |||||
| val bomProcesses = bomProcessRepository.findByBomIdOrderBySeqNo(request.bomId) | |||||
| println("🔍 Service: Found ${bomProcesses.size} BOM processes") | |||||
| // 5. 为每个 BOM Process 创建 ProductProcessLine | |||||
| bomProcesses.forEachIndexed { index, bomProcess -> // ✅ 修复 forEach | |||||
| val line = ProductProcessLine().apply { | |||||
| this.productProcess = savedProcess | |||||
| this.bomProcess = bomProcess | |||||
| this.seqNo = bomProcess.seqNo | |||||
| this.name = bomProcess.process?.name | |||||
| this.description = bomProcess.description | |||||
| this.equipmentType = bomProcess.equipment?.name | |||||
| } | |||||
| productProcessLineRepository.save(line) | |||||
| println("➕ Service: Created line ${index + 1} - seq: ${line.seqNo}, name: ${line.name}") | |||||
| } | |||||
| println("✅ Service: All ${bomProcesses.size} lines created automatically") | |||||
| return SaveProductProcessResponse( | |||||
| id = savedProcess.id!!, | |||||
| productProcessCode = productProcessCode, | |||||
| linesCreated = bomProcesses.size | |||||
| ) | |||||
| } | |||||
| private fun generateProductProcessCode(datePrefix: String): String { | |||||
| val searchPattern = "PP-$datePrefix-" | |||||
| val existingCodes = productProcessRepository.findByProductProcessCodeStartingWith(searchPattern) | |||||
| val nextNumber = (existingCodes.size + 1).toString().padStart(3, '0') | |||||
| return "$searchPattern$nextNumber" | |||||
| } | |||||
| // ✅ 添加:查询工序的所有步骤 | |||||
| open fun getLines(productProcessId: Long): List<ProductProcessLine> { | |||||
| println("📋 Service: Getting lines for process ID: $productProcessId") | |||||
| val lines = productProcessLineRepository.findByProductProcess_Id(productProcessId) | |||||
| println("✅ Service: Found ${lines.size} lines") | |||||
| return lines | |||||
| } | |||||
| open fun startProcess(id: Long, operatorId: Long): ProductProcess { | |||||
| println("▶️ Service: Starting ProductProcess ID: $id with operatorId: $operatorId") | |||||
| val productProcess = findById(id) | |||||
| productProcess.status = ProductProcessStatus.IN_PROGRESS | |||||
| productProcess.startTime = LocalDateTime.now() | |||||
| val saved = productProcessRepository.save(productProcess) | |||||
| println("✅ Service: Process started, status: ${saved.status}") | |||||
| return saved | |||||
| } | |||||
| open fun stopProcess(id: Long, request: StopProcessRequest): ProductionProcessIssue { | |||||
| println("⏸️ Service: Stopping ProductProcess ID: $id") | |||||
| println("📦 Service: Stop reason: ${request.reason}") | |||||
| val productProcess = findById(id) | |||||
| productProcess.status = ProductProcessStatus.STOPPED | |||||
| val issue = ProductionProcessIssue().apply { | |||||
| this.productProcess = productProcess | |||||
| this.operatorName = request.operatorName | |||||
| this.reason = request.reason | |||||
| this.stopTime = LocalDateTime.now() | |||||
| } | |||||
| productProcessRepository.save(productProcess) | |||||
| val savedIssue = productionProcessIssueRepository.save(issue) | |||||
| println("✅ Service: Process stopped, issue ID: ${savedIssue.id}") | |||||
| return savedIssue | |||||
| } | |||||
| open fun resumeProcess(id: Long, issueId: Long): ProductionProcessIssue { | |||||
| println("▶️ Service: Resuming ProductProcess ID: $id, issueId: $issueId") | |||||
| val productProcess = findById(id) | |||||
| productProcess.status = ProductProcessStatus.IN_PROGRESS | |||||
| val issue = productionProcessIssueRepository.findById(issueId) | |||||
| .orElseThrow { IllegalArgumentException("Issue not found") } | |||||
| issue.resumeTime = LocalDateTime.now() | |||||
| issue.totalTime = ChronoUnit.MINUTES.between(issue.stopTime, issue.resumeTime).toInt() | |||||
| productProcessRepository.save(productProcess) | |||||
| val savedIssue = productionProcessIssueRepository.save(issue) | |||||
| println("✅ Service: Process resumed, total stop time: ${savedIssue.totalTime} minutes") | |||||
| return savedIssue | |||||
| } | |||||
| open fun completeProcess(id: Long): ProductProcess { | |||||
| println("✔️ Service: Completing ProductProcess ID: $id") | |||||
| val productProcess = findById(id) | |||||
| productProcess.status = ProductProcessStatus.COMPLETED | |||||
| productProcess.endTime = LocalDateTime.now() | |||||
| val saved = productProcessRepository.save(productProcess) | |||||
| println("✅ Service: Process completed") | |||||
| return saved | |||||
| } | |||||
| open fun addLine(productProcessId: Long, request: SaveProductProcessLineRequest): SaveProductProcessLineResponse { | |||||
| println("➕ Service: Adding line to ProductProcess ID: $productProcessId") | |||||
| println("📦 Service: Line data - name: ${request.name}, equipmentType: ${request.equipmentType}") | |||||
| val productProcess = findById(productProcessId) | |||||
| val line = ProductProcessLine().apply { | |||||
| this.productProcess = productProcess | |||||
| this.name = request.name | |||||
| this.description = request.description | |||||
| this.equipmentType = request.equipmentType | |||||
| } | |||||
| val saved = productProcessLineRepository.save(line) | |||||
| println("✅ Service: Line added with ID: ${saved.id}") | |||||
| return SaveProductProcessLineResponse(saved.id!!) | |||||
| } | |||||
| open fun updateLineOutput(lineId: Long, request: UpdateLineOutputRequest): ProductProcessLine { | |||||
| println("📊 Service: Updating line output for line ID: $lineId") | |||||
| val line = productProcessLineRepository.findById(lineId) | |||||
| .orElseThrow { IllegalArgumentException("Line not found") } | |||||
| line.apply { | |||||
| outputFromProcessQty = request.outputQty | |||||
| outputFromProcessUom = request.outputUom | |||||
| defectQty = request.defectQty | |||||
| defectUom = request.defectUom | |||||
| scrapQty = request.scrapQty | |||||
| scrapUom = request.scrapUom | |||||
| byproductName = request.byproductName | |||||
| byproductQty = request.byproductQty | |||||
| byproductUom = request.byproductUom | |||||
| endTime = LocalDateTime.now() | |||||
| } | |||||
| val saved = productProcessLineRepository.save(line) | |||||
| println("✅ Service: Line output updated") | |||||
| return saved | |||||
| } | |||||
| open fun getIssues(productProcessId: Long): List<ProductionProcessIssue> { | |||||
| println("📋 Service: Getting issues for ProductProcess ID: $productProcessId") | |||||
| val issues = productionProcessIssueRepository.findByProductProcess_Id(productProcessId) | |||||
| println("✅ Service: Found ${issues.size} issues") | |||||
| return issues | |||||
| } | |||||
| open fun findByJobOrderId(jobOrderId: Long): List<ProductProcess> { | |||||
| println("🔍 Service: Finding ProductProcess by jobOrderId: $jobOrderId") | |||||
| val result = productProcessRepository.findByJobOrder_Id(jobOrderId) | |||||
| println("✅ Service: Found ${result.size} processes") | |||||
| return result | |||||
| } | |||||
| open fun findByJobOrderIdWithLines(jobOrderId: Long): List<ProductProcessWithLinesResponse> { | |||||
| println("🔍 Service: Finding ProductProcess with lines by jobOrderId: $jobOrderId") | |||||
| val processes = productProcessRepository.findByJobOrder_Id(jobOrderId) | |||||
| val result = processes.map { process -> | |||||
| val lines = productProcessLineRepository.findByProductProcess_Id(process.id!!) | |||||
| ProductProcessWithLinesResponse( | |||||
| id = process.id!!, | |||||
| productProcessCode = process.productProcessCode, | |||||
| status = process.status.value, | |||||
| startTime = process.startTime, | |||||
| endTime = process.endTime, | |||||
| date = process.date, | |||||
| lines = lines.map { line -> | |||||
| ProductProcessLineResponse( | |||||
| id = line.id!!, | |||||
| seqNo = line.seqNo, | |||||
| name = line.name, | |||||
| description = line.description, | |||||
| equipmentType = line.equipmentType, | |||||
| startTime = line.startTime, | |||||
| endTime = line.endTime, | |||||
| outputFromProcessQty = line.outputFromProcessQty, | |||||
| outputFromProcessUom = line.outputFromProcessUom, | |||||
| defectQty = line.defectQty, | |||||
| scrapQty = line.scrapQty, | |||||
| byproductName = line.byproductName, | |||||
| byproductQty = line.byproductQty | |||||
| ) | |||||
| } | |||||
| ) | |||||
| } | |||||
| println("✅ Service: Returning ${result.size} processes with ${result.sumOf { it.lines.size }} total lines") | |||||
| return result | |||||
| } | |||||
| open fun findAllAsDto(pageable: Pageable): Page<ProductProcessSimpleResponse> { | |||||
| println("📋 Service: Finding all ProductProcess as DTO with page: ${pageable.pageNumber}, size: ${pageable.pageSize}") | |||||
| val entityPage = productProcessRepository.findAll(pageable) | |||||
| val dtoList = entityPage.content.map { entity -> | |||||
| ProductProcessSimpleResponse( | |||||
| id = entity.id!!, | |||||
| productProcessCode = entity.productProcessCode, | |||||
| status = entity.status.value, | |||||
| startTime = entity.startTime, | |||||
| endTime = entity.endTime, | |||||
| date = entity.date, | |||||
| bomId = entity.bom?.id, | |||||
| jobOrderId = entity.jobOrder?.id | |||||
| ) | |||||
| } | |||||
| println("✅ Service: Converted ${dtoList.size} entities to DTOs") | |||||
| return org.springframework.data.domain.PageImpl(dtoList, pageable, entityPage.totalElements) | |||||
| } | |||||
| open fun findByIdAsDto(id: Long): ProductProcessSimpleResponse { | |||||
| println("🔍 Service: Finding ProductProcess by ID: $id as DTO") | |||||
| val entity = productProcessRepository.findById(id) | |||||
| .orElseThrow { IllegalArgumentException("ProductProcess not found with id: $id") } | |||||
| return ProductProcessSimpleResponse( | |||||
| id = entity.id!!, | |||||
| productProcessCode = entity.productProcessCode, | |||||
| status = entity.status.value, | |||||
| startTime = entity.startTime, | |||||
| endTime = entity.endTime, | |||||
| date = entity.date, | |||||
| bomId = entity.bom?.id, | |||||
| jobOrderId = entity.jobOrder?.id | |||||
| ) | |||||
| } | |||||
| open fun stopProcessAsDto(id: Long, request: StopProcessRequest): ProductionProcessIssueResponse { | |||||
| val issue = stopProcess(id, request) | |||||
| return ProductionProcessIssueResponse( | |||||
| id = issue.id!!, | |||||
| productProcessId = issue.productProcess?.id, | |||||
| operatorId = issue.operator?.id, | |||||
| operatorName = issue.operatorName, | |||||
| reason = issue.reason!!, | |||||
| stopTime = issue.stopTime!!, | |||||
| resumeTime = issue.resumeTime, | |||||
| totalTime = issue.totalTime | |||||
| ) | |||||
| } | |||||
| open fun resumeProcessAsDto(id: Long, issueId: Long): ProductionProcessIssueResponse { | |||||
| val issue = resumeProcess(id, issueId) | |||||
| return ProductionProcessIssueResponse( | |||||
| id = issue.id!!, | |||||
| productProcessId = issue.productProcess?.id, | |||||
| operatorId = issue.operator?.id, | |||||
| operatorName = issue.operatorName, | |||||
| reason = issue.reason!!, | |||||
| stopTime = issue.stopTime!!, | |||||
| resumeTime = issue.resumeTime, | |||||
| totalTime = issue.totalTime | |||||
| ) | |||||
| } | |||||
| open fun getIssuesAsDto(productProcessId: Long): List<ProductionProcessIssueResponse> { | |||||
| val issues = getIssues(productProcessId) | |||||
| return issues.map { issue -> | |||||
| ProductionProcessIssueResponse( | |||||
| id = issue.id!!, | |||||
| productProcessId = issue.productProcess?.id, | |||||
| operatorId = issue.operator?.id, | |||||
| operatorName = issue.operatorName, | |||||
| reason = issue.reason!!, | |||||
| stopTime = issue.stopTime!!, | |||||
| resumeTime = issue.resumeTime, | |||||
| totalTime = issue.totalTime | |||||
| ) | |||||
| } | |||||
| } | |||||
| open fun startProcessAsDto(id: Long, operatorId: Long): ProductProcessSimpleResponse { | |||||
| val entity = startProcess(id, operatorId) | |||||
| return ProductProcessSimpleResponse( | |||||
| id = entity.id!!, | |||||
| productProcessCode = entity.productProcessCode, | |||||
| status = entity.status.value, | |||||
| startTime = entity.startTime, | |||||
| endTime = entity.endTime, | |||||
| date = entity.date, | |||||
| bomId = entity.bom?.id, | |||||
| jobOrderId = entity.jobOrder?.id | |||||
| ) | |||||
| } | |||||
| open fun completeProcessAsDto(id: Long): ProductProcessSimpleResponse { | |||||
| val entity = completeProcess(id) | |||||
| return ProductProcessSimpleResponse( | |||||
| id = entity.id!!, | |||||
| productProcessCode = entity.productProcessCode, | |||||
| status = entity.status.value, | |||||
| startTime = entity.startTime, | |||||
| endTime = entity.endTime, | |||||
| date = entity.date, | |||||
| bomId = entity.bom?.id, | |||||
| jobOrderId = entity.jobOrder?.id | |||||
| ) | |||||
| } | |||||
| open fun updateLineOutputAsDto(lineId: Long, request: UpdateLineOutputRequest): ProductProcessLineResponse { | |||||
| val entity = updateLineOutput(lineId, request) | |||||
| return ProductProcessLineResponse( | |||||
| id = entity.id!!, | |||||
| seqNo = entity.seqNo, | |||||
| name = entity.name, | |||||
| description = entity.description, | |||||
| equipmentType = entity.equipmentType, | |||||
| startTime = entity.startTime, | |||||
| endTime = entity.endTime, | |||||
| outputFromProcessQty = entity.outputFromProcessQty, | |||||
| outputFromProcessUom = entity.outputFromProcessUom, | |||||
| defectQty = entity.defectQty, | |||||
| scrapQty = entity.scrapQty, | |||||
| byproductName = entity.byproductName, | |||||
| byproductQty = entity.byproductQty | |||||
| ) | |||||
| } | |||||
| open fun getLinesAsDto(productProcessId: Long): List<ProductProcessLineResponse> { | |||||
| val lines = getLines(productProcessId) | |||||
| return lines.map { line -> | |||||
| ProductProcessLineResponse( | |||||
| id = line.id!!, | |||||
| seqNo = line.seqNo, | |||||
| name = line.name, | |||||
| description = line.description, | |||||
| equipmentType = line.equipmentType, | |||||
| startTime = line.startTime, | |||||
| endTime = line.endTime, | |||||
| outputFromProcessQty = line.outputFromProcessQty, | |||||
| outputFromProcessUom = line.outputFromProcessUom, | |||||
| defectQty = line.defectQty, | |||||
| scrapQty = line.scrapQty, | |||||
| byproductName = line.byproductName, | |||||
| byproductQty = line.byproductQty | |||||
| ) | |||||
| } | |||||
| } | |||||
| open fun startLine(lineId: Long, userId: Long): ProductProcessLine { | |||||
| println("▶️ Service: Starting ProductProcessLine ID: $lineId with userId: $userId") | |||||
| val line = productProcessLineRepository.findById(lineId) | |||||
| .orElseThrow { IllegalArgumentException("Line not found") } | |||||
| // ✅ 修复:使用 UserRepository 获取 User 对象 | |||||
| val user = userRepository.findById(userId) | |||||
| .orElseThrow { IllegalArgumentException("User not found with id: $userId") } | |||||
| line.handler = user | |||||
| line.startTime = LocalDateTime.now() | |||||
| val saved = productProcessLineRepository.save(line) | |||||
| println("✅ Service: Line started, handlerId: ${saved.handler?.id}") | |||||
| return saved | |||||
| } | |||||
| open fun findPendingLinesByHandlerId(handlerId: Long): List<ProductProcessLine> { | |||||
| println("🔍 Service: Finding pending lines for handlerId: $handlerId") | |||||
| val lines = productProcessLineRepository.findByHandler_IdAndStartTimeIsNotNullAndEndTimeIsNull(handlerId) | |||||
| println("✅ Service: Found ${lines.size} pending lines") | |||||
| return lines | |||||
| } | |||||
| open fun productProcessDetailfindbyjoid(joid: Long): List<ProductProcessInfo> { | |||||
| val productProcesses = productProcessRepository.findByJobOrder_Id(joid) | |||||
| //val processId = productProcess.id ?: 0 | |||||
| return productProcesses.map { process -> | |||||
| ProductProcessInfo( | |||||
| id = process.id?:0, | |||||
| bomId = process.bom?.id?:0, | |||||
| jobOrderId = process.jobOrder?.id?:0, | |||||
| productProcessCode = process.productProcessCode?:"", | |||||
| status = process.status?:ProductProcessStatus.PENDING, | |||||
| startTime = process.startTime?:LocalDateTime.now(), | |||||
| endTime = process.endTime?:LocalDateTime.now(), | |||||
| date = process.date?:LocalDate.now(), | |||||
| productProcessLines = productProcessLineRepository.findByProductProcess_Id(process.id?:0).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 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 { | |||||
| val jobOrder = jobOrderRepository.findById(jobOrderId).orElse(null) | |||||
| val bom = bomRepository.findById(jobOrder?.bom?.id ?: 0L).orElse(null) | |||||
| // val bom = jobOrder.bom.let { bomRepository.findById(it).orElse(null) } | |||||
| val bomProcess = bomProcessRepository.findByBomId(jobOrder?.bom?.id?:0L) | |||||
| val item = itemsRepository.findById(bom?.item?.id ?: 0L).orElse(null) | |||||
| val datePrefix = ( LocalDate.now()).format(DateTimeFormatter.ofPattern("yyyyMMdd")) | |||||
| val productProcessCode = generateProductProcessCode(datePrefix) | |||||
| val dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd") | |||||
| val productProcess = ProductProcess().apply { | |||||
| this.jobOrder = jobOrder | |||||
| this.productProcessCode =productProcessCode | |||||
| this.item = item | |||||
| this.status = ProductProcessStatus.PENDING | |||||
| this.date = jobOrder?.planEnd?.toLocalDate() | |||||
| this.bom = bom | |||||
| } | |||||
| productProcessRepository.save(productProcess) | |||||
| bomProcess.forEach { bomProcess -> | |||||
| val process = processRepository.findById(bomProcess?.process?.id?:0L).orElse(null) | |||||
| val equipment = equipmentRepository.findById(bomProcess?.equipment?.id?:0L).orElse(null) | |||||
| val productProcessLine = ProductProcessLine().apply { | |||||
| this.productProcess = productProcess | |||||
| this.bomProcess = bomProcess | |||||
| // this.equipment = equipment | |||||
| this.seqNo = bomProcess.seqNo?:0 | |||||
| this.name = process?.name?:"" | |||||
| this.description = bomProcess.description?:"" | |||||
| this.equipmentType = equipment?.name?:"" | |||||
| this.status = "Pending" | |||||
| } | |||||
| productProcessLineRepository.save(productProcessLine) | |||||
| } | |||||
| return MessageResponse( | |||||
| id = null, | |||||
| code = null, | |||||
| name = null, | |||||
| type = null, | |||||
| message = null, | |||||
| errorPosition = null, | |||||
| ) | |||||
| } | |||||
| open fun UpdateProductProcessLineOperatorIdOrEquipmentId(request: UpdateProductProcessLineOperatorIdOrEquipmentIdRequest): MessageResponse { | |||||
| val productProcessLine = productProcessLineRepository.findById(request.productProcessLineId).orElse(null) | |||||
| val equipmentId = request.equipmentId | |||||
| val user = userRepository.findById(request.operatorId).orElse(null) | |||||
| val bomProcess= bomProcessRepository.findById(productProcessLine?.bomProcess?.id?:0L).orElse(null) | |||||
| val bomProcessEquipment=bomProcess?.equipment | |||||
| if(equipmentId != null &&( equipmentId==bomProcessEquipment?.id)) { | |||||
| productProcessLine?.equipment = bomProcessEquipment | |||||
| productProcessLineRepository.save(productProcessLine) | |||||
| } | |||||
| else | |||||
| { | |||||
| println("not match") | |||||
| } | |||||
| if(user != null) { | |||||
| productProcessLine.operator = user | |||||
| productProcessLineRepository.save(productProcessLine) | |||||
| } | |||||
| return MessageResponse( | |||||
| id = null, | |||||
| code = null, | |||||
| name = null, | |||||
| type = null, | |||||
| message = null, | |||||
| errorPosition = null, | |||||
| ) | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,170 @@ | |||||
| package com.ffii.fpsms.modules.productProcess.web | |||||
| import com.ffii.fpsms.modules.productProcess.entity.ProductProcess | |||||
| import com.ffii.fpsms.modules.productProcess.entity.ProductProcessLine | |||||
| import com.ffii.fpsms.modules.productProcess.service.ProductProcessService | |||||
| import com.ffii.fpsms.modules.productProcess.web.model.* | |||||
| import org.springframework.data.domain.Page | |||||
| import org.springframework.data.domain.Pageable | |||||
| import org.springframework.web.bind.annotation.* | |||||
| import com.ffii.fpsms.modules.productProcess.entity.projections.ProductProcessInfo | |||||
| import com.ffii.fpsms.modules.master.web.models.MessageResponse | |||||
| @RestController | |||||
| @RequestMapping("/product-process") | |||||
| class ProductProcessController( | |||||
| private val productProcessService: ProductProcessService | |||||
| ) { | |||||
| @GetMapping | |||||
| fun findAll(pageable: Pageable): Page<ProductProcessSimpleResponse> { // ✅ 改为返回 DTO | |||||
| println("📋 Controller: GET /product-process - Finding all") | |||||
| val result = productProcessService.findAllAsDto(pageable) // ✅ 使用新方法 | |||||
| println("✅ Controller: Returning ${result.totalElements} records") | |||||
| return result | |||||
| } | |||||
| @GetMapping("/{id}") | |||||
| fun findById(@PathVariable id: Long): ProductProcessSimpleResponse { // ✅ 改为返回 DTO | |||||
| println("🔍 Controller: GET /product-process/$id") | |||||
| val result = productProcessService.findByIdAsDto(id) // ✅ 使用新方法 | |||||
| println("✅ Controller: Found: ${result.productProcessCode}") | |||||
| return result | |||||
| } | |||||
| @GetMapping("/code/{code}") | |||||
| fun findByCode(@PathVariable code: String): ProductProcess { | |||||
| println("🔍 Controller: GET /product-process/code/$code") | |||||
| val result = productProcessService.findByCode(code) | |||||
| println("✅ Controller: Found ID: ${result.id}") | |||||
| return result | |||||
| } | |||||
| @PostMapping | |||||
| fun create(@RequestBody request: SaveProductProcessRequest): SaveProductProcessResponse { | |||||
| println("💾 Controller: POST /product-process - Creating ProductProcess") | |||||
| //println("📦 Controller: Request - bomId: ${request.bomId}, jobOrderId: ${request.jobOrderId}, date: ${request.date}") // ✅ 修复 | |||||
| val result = productProcessService.create(request) | |||||
| println("✅ Controller: Created ProductProcess - ID: ${result.id}, Code: ${result.productProcessCode}, Lines: ${result.linesCreated}") // ✅ 改进日志 | |||||
| return result | |||||
| } | |||||
| @PostMapping("/{id}/start") | |||||
| fun startProcess(@PathVariable id: Long, @RequestParam operatorId: Long): ProductProcessSimpleResponse { | |||||
| println("▶️ Controller: POST /product-process/$id/start - operatorId: $operatorId") | |||||
| val result = productProcessService.startProcessAsDto(id, operatorId) // ✅ 改用 AsDto 方法 | |||||
| println("✅ Controller: Process started") | |||||
| return result | |||||
| } | |||||
| @PostMapping("/{id}/stop") | |||||
| fun stopProcess( | |||||
| @PathVariable id: Long, | |||||
| @RequestBody request: StopProcessRequest | |||||
| ): ProductionProcessIssueResponse { // ✅ 改为 Issue Response | |||||
| println("⏸️ Controller: POST /product-process/$id/stop") | |||||
| println("📦 Controller: Reason: ${request.reason}") | |||||
| val result = productProcessService.stopProcessAsDto(id, request) // ✅ 使用返回 DTO 的方法 | |||||
| println("✅ Controller: Process stopped, issue ID: ${result.id}") | |||||
| return result | |||||
| } | |||||
| @PostMapping("/{id}/resume/{issueId}") | |||||
| fun resumeProcess( | |||||
| @PathVariable id: Long, | |||||
| @PathVariable issueId: Long | |||||
| ): ProductionProcessIssueResponse { // ✅ 改为 Issue Response | |||||
| println("▶️ Controller: POST /product-process/$id/resume/$issueId") | |||||
| val result = productProcessService.resumeProcessAsDto(id, issueId) // ✅ 使用返回 DTO 的方法 | |||||
| println("✅ Controller: Process resumed, stop duration: ${result.totalTime} min") | |||||
| return result | |||||
| } | |||||
| @PostMapping("/{id}/complete") | |||||
| fun completeProcess(@PathVariable id: Long): ProductProcessSimpleResponse { | |||||
| println("✔️ Controller: POST /product-process/$id/complete") | |||||
| val result = productProcessService.completeProcessAsDto(id) // ✅ 改用 AsDto 方法 | |||||
| println("✅ Controller: Process completed") | |||||
| return result | |||||
| } | |||||
| @PostMapping("/{id}/lines") | |||||
| fun addLine( | |||||
| @PathVariable id: Long, | |||||
| @RequestBody request: SaveProductProcessLineRequest | |||||
| ): SaveProductProcessLineResponse { | |||||
| println("➕ Controller: POST /product-process/$id/lines") | |||||
| println("📦 Controller: Line - name: ${request.name}, equipment: ${request.equipmentType}") | |||||
| val result = productProcessService.addLine(id, request) | |||||
| println("✅ Controller: Line added with ID: ${result.id}") | |||||
| return result | |||||
| } | |||||
| @PutMapping("/lines/{lineId}/output") | |||||
| fun updateLineOutput( | |||||
| @PathVariable lineId: Long, | |||||
| @RequestBody request: UpdateLineOutputRequest | |||||
| ): ProductProcessLineResponse { // ✅ 改为 ProductProcessLineResponse | |||||
| println("📊 Controller: PUT /lines/$lineId/output") | |||||
| val result = productProcessService.updateLineOutputAsDto(lineId, request) | |||||
| println("✅ Controller: Line output updated") | |||||
| return result | |||||
| } | |||||
| @GetMapping("/{id}/lines") | |||||
| fun getLines(@PathVariable id: Long): List<ProductProcessLineResponse> { | |||||
| println("📋 Controller: GET /product-process/$id/lines") | |||||
| val result = productProcessService.getLinesAsDto(id) | |||||
| println("✅ Controller: Found ${result.size} lines") | |||||
| return result | |||||
| } | |||||
| @GetMapping("/{id}/issues") | |||||
| fun getIssues(@PathVariable id: Long): List<ProductionProcessIssueResponse> { // ✅ 改为 Issue Response List | |||||
| println("📋 Controller: GET /product-process/$id/issues") | |||||
| val result = productProcessService.getIssuesAsDto(id) // ✅ 使用返回 DTO 的方法 | |||||
| println("✅ Controller: Found ${result.size} issues") | |||||
| return result | |||||
| } | |||||
| @GetMapping("/by-job-order/{jobOrderId}") | |||||
| fun findByJobOrderId(@PathVariable jobOrderId: Long): List<ProductProcessWithLinesResponse> { // ✅ 改为返回 DTO | |||||
| println("🔍 Controller: GET /product-process/by-job-order/$jobOrderId") | |||||
| val result = productProcessService.findByJobOrderIdWithLines(jobOrderId) // ✅ 直接使用 with-lines 方法 | |||||
| println("✅ Controller: Found ${result.size} processes for Job Order $jobOrderId") | |||||
| return result | |||||
| } | |||||
| // ✅ 额外添加:获取带 lines 的完整数据 | |||||
| @GetMapping("/by-job-order/{jobOrderId}/with-lines") | |||||
| fun findByJobOrderIdWithLines(@PathVariable jobOrderId: Long): List<ProductProcessWithLinesResponse> { | |||||
| println("🔍 Controller: GET /product-process/by-job-order/$jobOrderId/with-lines") | |||||
| val result = productProcessService.findByJobOrderIdWithLines(jobOrderId) | |||||
| println("✅ Controller: Found ${result.size} processes with lines for Job Order $jobOrderId") | |||||
| return result | |||||
| } | |||||
| @PostMapping("/lines/{lineId}/start") | |||||
| fun startLine(@PathVariable lineId: Long, @RequestParam userId: Long): ProductProcessLineResponse { | |||||
| println("▶️ Controller: POST /product-process/lines/$lineId/start - userId: $userId") | |||||
| val entity = productProcessService.startLine(lineId, userId) | |||||
| // ✅ 修复:返回正确的 DTO | |||||
| return productProcessService.getLinesAsDto(entity.productProcess?.id!!).find { it.id == entity.id!! }!! | |||||
| } | |||||
| @GetMapping("/demo/{id}") | |||||
| fun demo(@PathVariable id: Long): ProductProcessInfo { | |||||
| return productProcessService.productProcessDetailfindbyidtest(id) | |||||
| } | |||||
| @GetMapping("/demo/joid/{joid}") | |||||
| fun demojoid(@PathVariable joid: Long): List<ProductProcessInfo> { | |||||
| return productProcessService.productProcessDetailfindbyjoid(joid) | |||||
| } | |||||
| @PostMapping("/demo/joid/{joid}") | |||||
| fun democreate(@PathVariable joid: Long): MessageResponse { | |||||
| return productProcessService.createProductProcessByJobOrderId(joid) | |||||
| } | |||||
| @PostMapping("/Demo/update") | |||||
| fun demoupdate(@RequestBody request: UpdateProductProcessLineOperatorIdOrEquipmentIdRequest): MessageResponse { | |||||
| return productProcessService.UpdateProductProcessLineOperatorIdOrEquipmentId(request) | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,92 @@ | |||||
| package com.ffii.fpsms.modules.productProcess.web.model | |||||
| import java.time.LocalDate | |||||
| import java.time.LocalDateTime | |||||
| data class SaveProductProcessRequest( | |||||
| val bomId: Long, | |||||
| val jobOrderId: Long?, | |||||
| ) | |||||
| data class UpdateProductProcessLineOperatorIdOrEquipmentIdRequest( | |||||
| val productProcessLineId: Long, | |||||
| val operatorId: Long?, | |||||
| val equipmentId: Long? | |||||
| ) | |||||
| data class ProductionProcessIssueResponse( | |||||
| val id: Long, | |||||
| val productProcessId: Long?, | |||||
| val operatorId: Long?, | |||||
| val operatorName: String?, | |||||
| val reason: String, | |||||
| val stopTime: LocalDateTime, | |||||
| val resumeTime: LocalDateTime?, | |||||
| val totalTime: Int? // 分钟 | |||||
| ) | |||||
| data class SaveProductProcessResponse( | |||||
| val id: Long, | |||||
| val productProcessCode: String? = null, // ✅ 添加 | |||||
| val linesCreated: Int = 0 // ✅ 添加 | |||||
| ) | |||||
| data class ProductProcessWithLinesResponse( | |||||
| val id: Long, | |||||
| val productProcessCode: String?, | |||||
| val status: String, | |||||
| val startTime: LocalDateTime?, | |||||
| val endTime: LocalDateTime?, | |||||
| val date: LocalDate?, | |||||
| val lines: List<ProductProcessLineResponse> | |||||
| ) | |||||
| data class ProductProcessSimpleResponse( | |||||
| val id: Long, | |||||
| val productProcessCode: String?, | |||||
| val status: String, | |||||
| val startTime: LocalDateTime?, | |||||
| val endTime: LocalDateTime?, | |||||
| val date: LocalDate?, | |||||
| val bomId: Long?, | |||||
| val jobOrderId: Long? | |||||
| ) | |||||
| data class ProductProcessLineResponse( | |||||
| val id: Long, | |||||
| val seqNo: Long?, | |||||
| val name: String?, | |||||
| val description: String?, | |||||
| val equipmentType: String?, | |||||
| val startTime: LocalDateTime?, | |||||
| val endTime: LocalDateTime?, | |||||
| val outputFromProcessQty: Int?, | |||||
| val outputFromProcessUom: String?, | |||||
| val defectQty: Int?, | |||||
| val scrapQty: Int?, | |||||
| val byproductName: String?, | |||||
| val byproductQty: Int? | |||||
| ) | |||||
| data class SaveProductProcessLineRequest( | |||||
| val name: String?, | |||||
| val description: String?, | |||||
| val equipmentType: String?, | |||||
| val operatorId: Long?, | |||||
| val equipmentId: Long? | |||||
| ) | |||||
| data class SaveProductProcessLineResponse( | |||||
| val id: Long | |||||
| ) | |||||
| data class StopProcessRequest( | |||||
| val operatorId: Long?, | |||||
| val operatorName: String?, | |||||
| val reason: String | |||||
| ) | |||||
| data class UpdateLineOutputRequest( | |||||
| val outputQty: Int?, | |||||
| val outputUom: String?, | |||||
| val defectQty: Int?, | |||||
| val defectUom: String?, | |||||
| val scrapQty: Int?, | |||||
| val scrapUom: String?, | |||||
| val byproductName: String?, | |||||
| val byproductQty: Int?, | |||||
| val byproductUom: String? | |||||
| ) | |||||
| @@ -368,12 +368,14 @@ private fun getStockOutIdFromPickOrderLine(pickOrderLineId: Long): Long { | |||||
| // 3) 全部完成 → 更新 do_pick_order 为 completed,并可复制到 record 表(可选) | // 3) 全部完成 → 更新 do_pick_order 为 completed,并可复制到 record 表(可选) | ||||
| val dpo = doPickOrderRepository.findById(dpoId).orElse(null) ?: return@forEach | val dpo = doPickOrderRepository.findById(dpoId).orElse(null) ?: return@forEach | ||||
| dpo.ticketStatus = DoPickOrderStatus.completed | dpo.ticketStatus = DoPickOrderStatus.completed | ||||
| dpo.ticketCompleteDateTime = LocalDateTime.now() | dpo.ticketCompleteDateTime = LocalDateTime.now() | ||||
| doPickOrderRepository.save(dpo) | doPickOrderRepository.save(dpo) | ||||
| // 4) 可选:复制 header 到 record 表,复制 lines 到 line_record,再删除原有行/头(与你在 PickOrderService.completeStockOut 的做法保持一致) | // 4) 可选:复制 header 到 record 表,复制 lines 到 line_record,再删除原有行/头(与你在 PickOrderService.completeStockOut 的做法保持一致) | ||||
| val dpoRecord = DoPickOrderRecord( | val dpoRecord = DoPickOrderRecord( | ||||
| recordId =dpoId, | |||||
| storeId = dpo.storeId ?: "", | storeId = dpo.storeId ?: "", | ||||
| ticketNo = dpo.ticketNo ?: "", | ticketNo = dpo.ticketNo ?: "", | ||||
| ticketStatus = DoPickOrderStatus.completed, | ticketStatus = DoPickOrderStatus.completed, | ||||
| @@ -398,6 +400,7 @@ private fun getStockOutIdFromPickOrderLine(pickOrderLineId: Long): Long { | |||||
| val lineRecords = allLines.map { l -> | val lineRecords = allLines.map { l -> | ||||
| DoPickOrderLineRecord().apply { | DoPickOrderLineRecord().apply { | ||||
| this.recordId = l.id | |||||
| this.doPickOrderId = savedHeader.id | this.doPickOrderId = savedHeader.id | ||||
| this.pickOrderId = l.pickOrderId | this.pickOrderId = l.pickOrderId | ||||
| this.doOrderId = l.doOrderId | this.doOrderId = l.doOrderId | ||||
| @@ -0,0 +1,106 @@ | |||||
| -- liquibase formatted sql | |||||
| -- changeset enson:alter_pick_execution_issue_category_20251023 | |||||
| CREATE TABLE productprocess ( | |||||
| id INT AUTO_INCREMENT PRIMARY KEY, | |||||
| productprocesscode VARCHAR(50) UNIQUE NOT NULL COMMENT '生产工序编号', | |||||
| jobOrderId INT COMMENT '工单ID', | |||||
| itemsId INT COMMENT '产品ID', | |||||
| -- 状态 | |||||
| status VARCHAR(20) DEFAULT 'pending' , | |||||
| -- 时间 | |||||
| startTime DATETIME , | |||||
| endTime DATETIME , | |||||
| date DATE , | |||||
| -- 审计字段 | |||||
| created DATETIME, | |||||
| createdBy VARCHAR(30), | |||||
| version INT DEFAULT 0, | |||||
| modified DATETIME, | |||||
| modifiedBy VARCHAR(30), | |||||
| deleted TINYINT(1) DEFAULT 0, | |||||
| FOREIGN KEY (jobOrderId) REFERENCES job_order(id), | |||||
| FOREIGN KEY (itemsId) REFERENCES items(id), | |||||
| INDEX idx_status (status), | |||||
| INDEX idx_date (date), | |||||
| INDEX idx_job_order (jobOrderId) | |||||
| ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; | |||||
| CREATE TABLE productprocessline ( | |||||
| id INT AUTO_INCREMENT PRIMARY KEY, | |||||
| productprocessid INT NOT NULL , | |||||
| -- 操作员和设备 | |||||
| operatorId INT , | |||||
| equipmentId INT, | |||||
| -- 步骤信息 | |||||
| name VARCHAR(100) , | |||||
| description varchar(255) , | |||||
| equipment VARCHAR(100) , | |||||
| -- 副产品信息 | |||||
| byproductId INT , | |||||
| byproductName VARCHAR(100) , | |||||
| byproductQty DECIMAL(16,2) , | |||||
| byproductUom VARCHAR(20) , | |||||
| -- 废品/次品/产出 | |||||
| scrapQty DECIMAL(16,2) , | |||||
| scrapUom VARCHAR(20) , | |||||
| defectQty DECIMAL(16,2) , | |||||
| defectUom VARCHAR(20) , | |||||
| outputFromProcessQty DECIMAL(16,2) , | |||||
| outputFromProcessUom VARCHAR(20) , | |||||
| -- 时间 | |||||
| startTime DATETIME , | |||||
| endTime DATETIME , | |||||
| -- 审计字段 | |||||
| created DATETIME, | |||||
| createdBy VARCHAR(30), | |||||
| version INT DEFAULT 0, | |||||
| modified DATETIME, | |||||
| modifiedBy VARCHAR(30), | |||||
| deleted TINYINT(1) DEFAULT 0, | |||||
| FOREIGN KEY (productprocessid) REFERENCES productprocess(id), | |||||
| FOREIGN KEY (operatorId) REFERENCES user(id), | |||||
| FOREIGN KEY (equipmentId) REFERENCES equipment(id), | |||||
| FOREIGN KEY (byproductId) REFERENCES items(id), | |||||
| INDEX idx_productprocess (productprocessid) | |||||
| ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; | |||||
| CREATE TABLE productionprocessissue ( | |||||
| id INT AUTO_INCREMENT PRIMARY KEY, | |||||
| productprocessid INT NOT NULL , | |||||
| operatorId INT , | |||||
| operatorName VARCHAR(100) , | |||||
| -- 暂停信息 | |||||
| reason varchar(255) NOT NULL , | |||||
| stopTime DATETIME NOT NULL , | |||||
| resumeTime DATETIME , | |||||
| totalTime INT , | |||||
| -- 审计字段 | |||||
| created DATETIME, | |||||
| createdBy VARCHAR(30), | |||||
| version INT DEFAULT 0, | |||||
| modified DATETIME, | |||||
| modifiedBy VARCHAR(30), | |||||
| deleted TINYINT(1) DEFAULT 0, | |||||
| FOREIGN KEY (productprocessid) REFERENCES productprocess(id), | |||||
| FOREIGN KEY (operatorId) REFERENCES user(id), | |||||
| INDEX idx_productprocess (productprocessid), | |||||
| INDEX idx_stop_time (stopTime) | |||||
| ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; | |||||
| @@ -0,0 +1,12 @@ | |||||
| -- liquibase formatted sql | |||||
| -- changeset enson:alter_pick_execution_issue_category_20251023 | |||||
| ALTER TABLE productprocess | |||||
| ADD COLUMN bomId INT COMMENT 'BOM ID'; | |||||
| ALTER TABLE productprocess | |||||
| ADD CONSTRAINT fk_productprocess_bom | |||||
| FOREIGN KEY (bomId) REFERENCES bom(id); | |||||
| -- 添加索引 | |||||
| CREATE INDEX idx_productprocess_bom ON productprocess(bomId); | |||||
| @@ -0,0 +1,15 @@ | |||||
| -- liquibase formatted sql | |||||
| -- changeset enson:alter_pick_execution_issue_category_20251023 | |||||
| ALTER TABLE productprocessline | |||||
| ADD COLUMN bomProcessId INT , | |||||
| ADD COLUMN seqNo INT; | |||||
| ALTER TABLE productprocessline | |||||
| ADD CONSTRAINT fk_productprocessline_bomprocess | |||||
| FOREIGN KEY (bomProcessId) REFERENCES bom_process(id); | |||||
| -- 添加索引 | |||||
| CREATE INDEX idx_productprocessline_bomprocess ON productprocessline(bomProcessId); | |||||
| CREATE INDEX idx_productprocessline_seqno ON productprocessline(seqNo); | |||||
| @@ -0,0 +1,5 @@ | |||||
| -- liquibase formatted sql | |||||
| -- changeset Enson:alter qc category table | |||||
| ALTER TABLE `productprocessline` | |||||
| ADD COLUMN `handlerId` INT NULL AFTER `equipmentId`; | |||||
| @@ -0,0 +1,12 @@ | |||||
| -- liquibase formatted sql | |||||
| -- changeset Enson:alter qc category table | |||||
| ALTER TABLE `productprocessline` | |||||
| CHANGE COLUMN `equipment` `equipment_name` VARCHAR(255); | |||||
| ALTER TABLE `productprocessline` | |||||
| ADD COLUMN `status` VARCHAR(255) DEFAULT 'pending' AFTER `equipment_name`; | |||||
| ALTER TABLE `productprocessline` | |||||
| MODIFY COLUMN `bomprocessId` INT AFTER `productprocessId`, | |||||
| MODIFY COLUMN `seqNo` INT AFTER `handlerId`; | |||||
| @@ -0,0 +1,17 @@ | |||||
| -- liquibase formatted sql | |||||
| -- changeset enson:altertable_enson | |||||
| ALTER TABLE `fpsmsdb`.`pick_execution_issue` | |||||
| DROP FOREIGN KEY `FK_PICK_EXECUTION_ISSUE_ON_PICK_ORDER`, | |||||
| DROP FOREIGN KEY `FK_PICK_EXECUTION_ISSUE_ON_PICK_ORDER_LINE`; | |||||
| ALTER TABLE `fpsmsdb`.`pick_execution_issue` | |||||
| CHANGE COLUMN `pick_order_id` `pick_order_id` INT NULL , | |||||
| CHANGE COLUMN `pick_order_code` `pick_order_code` VARCHAR(50) NULL , | |||||
| CHANGE COLUMN `pick_order_line_id` `pick_order_line_id` INT NULL ; | |||||
| ALTER TABLE `fpsmsdb`.`pick_execution_issue` | |||||
| ADD CONSTRAINT `FK_PICK_EXECUTION_ISSUE_ON_PICK_ORDER` | |||||
| FOREIGN KEY (`pick_order_id`) | |||||
| REFERENCES `fpsmsdb`.`pick_order` (`id`), | |||||
| ADD CONSTRAINT `FK_PICK_EXECUTION_ISSUE_ON_PICK_ORDER_LINE` | |||||
| FOREIGN KEY (`pick_order_line_id`) | |||||
| REFERENCES `fpsmsdb`.`pick_order_line` (`id`); | |||||
| @@ -0,0 +1,7 @@ | |||||
| -- liquibase formatted sql | |||||
| -- changeset enson:altertable_enson | |||||
| ALTER TABLE `fpsmsdb`.`do_pick_order_record` | |||||
| ADD COLUMN `record_id` INT NOT NULL After `id`; | |||||
| ALTER TABLE `fpsmsdb`.`do_pick_order_line_record` | |||||
| ADD COLUMN `record_id` INT NOT NULL After `id`; | |||||