| @@ -246,7 +246,7 @@ open class JoPickOrderService( | |||
| } | |||
| val pickOrderIds = filteredPickOrders.map { it.id!! } | |||
| println("🎯 Job Order Pick order IDs to fetch: $pickOrderIds") | |||
| println(" Job Order Pick order IDs to fetch: $pickOrderIds") | |||
| if (pickOrderIds.isEmpty()) { | |||
| return mapOf( | |||
| @@ -467,6 +467,53 @@ open class JobOrderService( | |||
| } | |||
| } | |||
| //New Print Pick Record | |||
| //Print Pick Record | |||
| @Transactional | |||
| open fun NewPrintPickRecord(request: PrintPickRecordRequest){ | |||
| val printer = printerService.findById(request.printerId) ?: throw java.util.NoSuchElementException("No such printer") | |||
| println("New DEBUG: Printer found: ${printer.name}") | |||
| println("New DEBUG: Exporting pick record for pick order ID: ${request.pickOrderId}") | |||
| val pdf = exportPickRecord( | |||
| ExportPickRecordRequest( | |||
| pickOrderIds = request.pickOrderId | |||
| ) | |||
| ) | |||
| println("New DEBUG: PDF exported: ${pdf}") | |||
| val jasperPrint = pdf["report"] as JasperPrint | |||
| println("New DEBUG: JasperPrint: ${jasperPrint}") | |||
| val tempPdfFile = File.createTempFile("print_job_",".pdf") | |||
| println("New DEBUG: Temporary PDF file created: ${tempPdfFile.absolutePath}") | |||
| try{ | |||
| JasperExportManager.exportReportToPdfFile(jasperPrint,tempPdfFile.absolutePath) | |||
| println("New DEBUG: JasperPrint exported to PDF file: ${tempPdfFile.absolutePath}") | |||
| val printQty = if (request.printQty == null || request.printQty <= 0) 1 else request.printQty | |||
| println("New DEBUG: Print quantity: $printQty") | |||
| // Auto-detect orientation and set duplex mode accordingly | |||
| val duplexMode = if (CanonPrinterUtil.isLandscape(tempPdfFile)) { | |||
| CanonPrinterUtil.DuplexMode.DUPLEX_SHORT_EDGE // Landscape: flip on short edge | |||
| } else { | |||
| CanonPrinterUtil.DuplexMode.DUPLEX_LONG_EDGE // Portrait: flip on long edge | |||
| } | |||
| println("New DEBUG: PDF orientation detected - Landscape: ${CanonPrinterUtil.isLandscape(tempPdfFile)}, Duplex mode: $duplexMode") | |||
| printer.ip?.let { ip -> | |||
| printer.port?.let { port -> | |||
| CanonPrinterUtil.printPdfToCanon( | |||
| tempPdfFile, | |||
| ip, | |||
| port, | |||
| printQty, | |||
| duplexMode | |||
| ) | |||
| } | |||
| } | |||
| } finally { | |||
| //tempPdfFile.delete() | |||
| } | |||
| } | |||
| //FG Pick Record Label | |||
| @Throws(IOException::class) | |||
| @Transactional | |||
| @@ -191,7 +191,10 @@ fun recordSecondScanIssue( | |||
| fun printPickRecord(@ModelAttribute request: PrintPickRecordRequest){ | |||
| jobOrderService.printPickRecord(request) | |||
| } | |||
| @GetMapping("/newPrint-PickRecord") | |||
| fun NewprintPickRecord(@ModelAttribute request: PrintPickRecordRequest){ | |||
| jobOrderService.NewPrintPickRecord(request) | |||
| } | |||
| @PostMapping("/FGPickRecordLabel") | |||
| @Throws(UnsupportedEncodingException::class, NoSuchMessageException::class, ParseException::class, Exception::class) | |||
| fun exportFGPickRecordLabel(@Valid @RequestBody request: ExportPickRecordRequest, response: HttpServletResponse){ | |||
| @@ -25,5 +25,5 @@ open class Equipment : BaseEntity<Long>() { | |||
| @ManyToOne | |||
| @JoinColumn(name = "equipmentTypeId") | |||
| open var equipmentType: EquipmentType? = null | |||
| open var EquipmentDetail: EquipmentDetail? = null | |||
| } | |||
| @@ -7,9 +7,9 @@ import jakarta.persistence.Table | |||
| import jakarta.validation.constraints.NotNull | |||
| import jakarta.validation.constraints.Size | |||
| @Table(name = "equipment_type") | |||
| @Table(name = "equipment_detail") | |||
| @Entity | |||
| open class EquipmentType : BaseEntity<Long>() { | |||
| open class EquipmentDetail : BaseEntity<Long>() { | |||
| @Size(max = 30) | |||
| @NotNull | |||
| @Column(name = "code", nullable = false, length = 30) | |||
| @@ -0,0 +1,17 @@ | |||
| package com.ffii.fpsms.modules.master.entity | |||
| import com.ffii.core.support.AbstractRepository | |||
| import org.springframework.stereotype.Repository | |||
| @Repository | |||
| interface EquipmentDetailRepository : AbstractRepository<EquipmentDetail, Long> { | |||
| fun findAllByDeletedFalse(): List<EquipmentDetail>; | |||
| fun findByCodeAndDeletedFalse(code: String): EquipmentDetail? | |||
| fun findByIdAndDeletedFalse(id: Long): EquipmentDetail?; | |||
| fun findByCodeAndDeletedIsFalse(code: String): EquipmentDetail?; | |||
| fun findByNameAndDeletedIsFalse(name: String): EquipmentDetail?; | |||
| fun findByDescriptionAndDeletedIsFalse(description: String): EquipmentDetail?; | |||
| } | |||
| @@ -1,17 +0,0 @@ | |||
| package com.ffii.fpsms.modules.master.entity | |||
| import com.ffii.core.support.AbstractRepository | |||
| import org.springframework.stereotype.Repository | |||
| @Repository | |||
| interface EquipmentTypeRepository : AbstractRepository<EquipmentType, Long> { | |||
| fun findAllByDeletedFalse(): List<EquipmentType>; | |||
| fun findByCodeAndDeletedFalse(code: String): EquipmentType? | |||
| fun findByIdAndDeletedFalse(id: Long): EquipmentType?; | |||
| fun findByCodeAndDeletedIsFalse(code: String): EquipmentType?; | |||
| fun findByNameAndDeletedIsFalse(name: String): EquipmentType?; | |||
| fun findByDescriptionAndDeletedIsFalse(description: String): EquipmentType?; | |||
| } | |||
| @@ -0,0 +1,90 @@ | |||
| package com.ffii.fpsms.modules.master.service | |||
| import com.ffii.core.support.AbstractBaseEntityService | |||
| import com.ffii.core.support.JdbcDao | |||
| import com.ffii.fpsms.modules.master.entity.EquipmentDetail | |||
| import com.ffii.fpsms.modules.master.entity.EquipmentDetailRepository | |||
| import org.springframework.stereotype.Service | |||
| import org.springframework.transaction.annotation.Transactional | |||
| import com.ffii.fpsms.modules.master.web.models.NewEquipmentDetailRequest | |||
| @Service | |||
| open class EquipmentDetailService( | |||
| private val jdbcDao: JdbcDao, | |||
| private val equipmentDetailRepository: EquipmentDetailRepository, | |||
| ) : AbstractBaseEntityService<EquipmentDetail, Long, EquipmentDetailRepository>(jdbcDao, equipmentDetailRepository) { | |||
| open fun allEquipmentDetails(): List<EquipmentDetail> { | |||
| return equipmentDetailRepository.findAll() | |||
| } | |||
| open fun getEquipmentDetailsByPage(args: Map<String, Any>): List<Map<String, Any>> { | |||
| val sql = StringBuilder( | |||
| "SELECT e.id, e.code, e.name, e.description FROM equipment_detail e WHERE e.deleted = FALSE" | |||
| ) | |||
| if (args.containsKey("code")) { | |||
| sql.append(" AND e.code like :code ") | |||
| } | |||
| if (args.containsKey("id")) { | |||
| sql.append(" AND e.id like :id ") | |||
| } | |||
| if (args.containsKey("name")) { | |||
| sql.append(" AND e.name like :name ") | |||
| } | |||
| if (args.containsKey("description")) { | |||
| sql.append(" AND e.description like :description ") | |||
| } | |||
| return jdbcDao.queryForList(sql.toString(), args) | |||
| } | |||
| open fun findById(id: Long): EquipmentDetail? { | |||
| return equipmentDetailRepository.findByIdAndDeletedFalse(id) | |||
| } | |||
| open fun findByCode(code: String): EquipmentDetail? { | |||
| return equipmentDetailRepository.findByCodeAndDeletedIsFalse(code) | |||
| } | |||
| open fun findByName(name: String): EquipmentDetail? { | |||
| return equipmentDetailRepository.findByNameAndDeletedIsFalse(name) | |||
| } | |||
| open fun findByDescription(description: String): EquipmentDetail? { | |||
| return equipmentDetailRepository.findByDescriptionAndDeletedIsFalse(description) | |||
| } | |||
| @Transactional | |||
| open fun saveEquipmentDetail(request: NewEquipmentDetailRequest): EquipmentDetail { | |||
| if (request.code.isNullOrBlank()) { | |||
| throw IllegalArgumentException("Equipment detail code cannot be null or blank") | |||
| } | |||
| val duplicated = equipmentDetailRepository.findByCodeAndDeletedIsFalse(request.code!!) | |||
| if (duplicated != null && duplicated.id != request.id) { | |||
| throw IllegalArgumentException("Equipment detail code already exists") | |||
| } | |||
| val entity = if (request.id != null && request.id > 0) { | |||
| equipmentDetailRepository.findByIdAndDeletedFalse(request.id) ?: EquipmentDetail() | |||
| } else { | |||
| EquipmentDetail() | |||
| } | |||
| entity.code = request.code | |||
| entity.name = request.name | |||
| entity.description = request.description | |||
| return equipmentDetailRepository.saveAndFlush(entity) | |||
| } | |||
| @Transactional | |||
| open fun deleteEquipmentDetail(id: Long) { | |||
| val equipmentDetail = equipmentDetailRepository.findByIdAndDeletedFalse(id) | |||
| equipmentDetail?.let { et -> | |||
| et.deleted = true | |||
| equipmentDetailRepository.saveAndFlush(et) | |||
| } | |||
| } | |||
| } | |||
| @@ -79,7 +79,7 @@ open class EquipmentService( | |||
| entity.code = request.code | |||
| entity.name = request.name | |||
| entity.description = request.description | |||
| entity.equipmentType= request.equipmentType | |||
| entity.EquipmentDetail= request.equipmentType | |||
| return equipmentRepository.saveAndFlush(entity) | |||
| } | |||
| @@ -1,90 +0,0 @@ | |||
| package com.ffii.fpsms.modules.master.service | |||
| import com.ffii.core.support.AbstractBaseEntityService | |||
| import com.ffii.core.support.JdbcDao | |||
| import com.ffii.fpsms.modules.master.entity.EquipmentType | |||
| import com.ffii.fpsms.modules.master.entity.EquipmentTypeRepository | |||
| import org.springframework.stereotype.Service | |||
| import org.springframework.transaction.annotation.Transactional | |||
| import com.ffii.fpsms.modules.master.web.models.NewEquipmentTypeRequest | |||
| @Service | |||
| open class EquipmentTypeService( | |||
| private val jdbcDao: JdbcDao, | |||
| private val equipmentTypeRepository: EquipmentTypeRepository, | |||
| ) : AbstractBaseEntityService<EquipmentType, Long, EquipmentTypeRepository>(jdbcDao, equipmentTypeRepository) { | |||
| open fun allEquipmentTypes(): List<EquipmentType> { | |||
| return equipmentTypeRepository.findAll() | |||
| } | |||
| open fun getEquipmentTypesByPage(args: Map<String, Any>): List<Map<String, Any>> { | |||
| val sql = StringBuilder( | |||
| "SELECT e.id, e.code, e.name, e.description FROM equipment_type e WHERE e.deleted = FALSE" | |||
| ) | |||
| if (args.containsKey("code")) { | |||
| sql.append(" AND e.code like :code ") | |||
| } | |||
| if (args.containsKey("id")) { | |||
| sql.append(" AND e.id like :id ") | |||
| } | |||
| if (args.containsKey("name")) { | |||
| sql.append(" AND e.name like :name ") | |||
| } | |||
| if (args.containsKey("description")) { | |||
| sql.append(" AND e.description like :description ") | |||
| } | |||
| return jdbcDao.queryForList(sql.toString(), args) | |||
| } | |||
| open fun findById(id: Long): EquipmentType? { | |||
| return equipmentTypeRepository.findByIdAndDeletedFalse(id) | |||
| } | |||
| open fun findByCode(code: String): EquipmentType? { | |||
| return equipmentTypeRepository.findByCodeAndDeletedIsFalse(code) | |||
| } | |||
| open fun findByName(name: String): EquipmentType? { | |||
| return equipmentTypeRepository.findByNameAndDeletedIsFalse(name) | |||
| } | |||
| open fun findByDescription(description: String): EquipmentType? { | |||
| return equipmentTypeRepository.findByDescriptionAndDeletedIsFalse(description) | |||
| } | |||
| @Transactional | |||
| open fun saveEquipmentType(request: NewEquipmentTypeRequest): EquipmentType { | |||
| if (request.code.isNullOrBlank()) { | |||
| throw IllegalArgumentException("Equipment type code cannot be null or blank") | |||
| } | |||
| val duplicated = equipmentTypeRepository.findByCodeAndDeletedFalse(request.code!!) | |||
| if (duplicated != null && duplicated.id != request.id) { | |||
| throw IllegalArgumentException("Equipment type code already exists") | |||
| } | |||
| val entity = if (request.id != null && request.id > 0) { | |||
| equipmentTypeRepository.findByIdAndDeletedFalse(request.id) ?: EquipmentType() | |||
| } else { | |||
| EquipmentType() | |||
| } | |||
| entity.code = request.code | |||
| entity.name = request.name | |||
| entity.description = request.description | |||
| return equipmentTypeRepository.saveAndFlush(entity) | |||
| } | |||
| @Transactional | |||
| open fun deleteEquipmentType(id: Long) { | |||
| val equipmentType = equipmentTypeRepository.findByIdAndDeletedFalse(id) | |||
| equipmentType?.let { et -> | |||
| et.deleted = true | |||
| equipmentTypeRepository.saveAndFlush(et) | |||
| } | |||
| } | |||
| } | |||
| @@ -93,7 +93,7 @@ open class WarehouseService( | |||
| val warehouseCode = "$code-$zone-$slot" | |||
| val warehouseName = "$floor-$place" | |||
| val existingWarehouse = findByCode(warehouseCode) | |||
| //check id | |||
| if (existingWarehouse == null) { | |||
| val warehouseRequest = SaveWarehouseRequest( | |||
| code = warehouseCode, | |||
| @@ -3,21 +3,21 @@ package com.ffii.fpsms.modules.master.web | |||
| import com.ffii.core.response.RecordsRes | |||
| import com.ffii.core.utils.CriteriaArgsBuilder | |||
| import com.ffii.core.utils.PagingUtils | |||
| import com.ffii.fpsms.modules.master.entity.EquipmentType | |||
| import com.ffii.fpsms.modules.master.service.EquipmentTypeService | |||
| import com.ffii.fpsms.modules.master.entity.EquipmentDetail | |||
| import com.ffii.fpsms.modules.master.service.EquipmentDetailService | |||
| import jakarta.servlet.http.HttpServletRequest | |||
| import jakarta.validation.Valid | |||
| import org.springframework.web.bind.annotation.* | |||
| import java.util.Collections.emptyList | |||
| import com.ffii.fpsms.modules.master.web.models.NewEquipmentTypeRequest | |||
| import com.ffii.fpsms.modules.master.web.models.NewEquipmentDetailRequest | |||
| @RestController | |||
| @RequestMapping("/EquipmentType") | |||
| class EquipmentTypeController( | |||
| private val equipmentTypeService: EquipmentTypeService | |||
| @RequestMapping("/EquipmentDetail") | |||
| class EquipmentDetailController( | |||
| private val equipmentDetailService: EquipmentDetailService | |||
| ) { | |||
| @GetMapping | |||
| fun allEquipmentType(): List<EquipmentType> { | |||
| return equipmentTypeService.allEquipmentTypes() | |||
| fun allEquipmentDetail(): List<EquipmentDetail> { | |||
| return equipmentDetailService.allEquipmentDetails() | |||
| } | |||
| // @GetMapping("/getRecordByPage") | |||
| @@ -35,7 +35,7 @@ class EquipmentTypeController( | |||
| // } | |||
| @GetMapping("/getRecordByPage") | |||
| fun getAllEquipmentTypeByPage( | |||
| fun getAllEquipmentDetailByPage( | |||
| request: HttpServletRequest | |||
| ): RecordsRes<Map<String, Any>> { | |||
| val criteriaArgs = CriteriaArgsBuilder.withRequest(request) | |||
| @@ -49,7 +49,7 @@ fun getAllEquipmentTypeByPage( | |||
| val pageNum = request.getParameter("pageNum")?.toIntOrNull() ?: 1 | |||
| // 方法名和变量名都要和 Service 保持一致 | |||
| val fullList = equipmentTypeService.getEquipmentTypesByPage(criteriaArgs) ?: emptyList() | |||
| val fullList = equipmentDetailService.getEquipmentDetailsByPage(criteriaArgs) ?: emptyList() | |||
| val paginatedList = PagingUtils.getPaginatedList(fullList, pageSize, pageNum) | |||
| return RecordsRes(paginatedList as List<Map<String, Any>>, fullList.size) | |||
| @@ -57,20 +57,20 @@ fun getAllEquipmentTypeByPage( | |||
| // 详情 | |||
| @GetMapping("/details/{id}") | |||
| fun getEquipmentType(@PathVariable id: Long): EquipmentType? { | |||
| return equipmentTypeService.findById(id) | |||
| fun getEquipmentDetail(@PathVariable id: Long): EquipmentDetail? { | |||
| return equipmentDetailService.findById(id) | |||
| } | |||
| // 新增/编辑 | |||
| @PostMapping("/save") | |||
| fun saveEquipmentType(@Valid @RequestBody equipmentType: NewEquipmentTypeRequest): EquipmentType { | |||
| return equipmentTypeService.saveEquipmentType(equipmentType) | |||
| fun saveEquipmentDetail(@Valid @RequestBody equipmentDetail: NewEquipmentDetailRequest): EquipmentDetail { | |||
| return equipmentDetailService.saveEquipmentDetail(equipmentDetail) | |||
| } | |||
| // 逻辑删除 | |||
| @DeleteMapping("/delete/{id}") | |||
| fun deleteEquipmentType(@PathVariable id: Long) { | |||
| equipmentTypeService.deleteEquipmentType(id) | |||
| fun deleteEquipmentDetail(@PathVariable id: Long) { | |||
| equipmentDetailService.deleteEquipmentDetail(id) | |||
| } | |||
| } | |||
| @@ -11,7 +11,7 @@ enum class EquipmentType(val type: String) { | |||
| CONSUMABLE("consumables"), | |||
| } | |||
| */ | |||
| data class NewEquipmentTypeRequest( | |||
| data class NewEquipmentDetailRequest( | |||
| @field:NotBlank(message = "material code cannot be empty") | |||
| val code: String, | |||
| @field:NotBlank(message = "material name cannot be empty") | |||
| @@ -1,6 +1,6 @@ | |||
| package com.ffii.fpsms.modules.master.web.models | |||
| import com.ffii.fpsms.modules.master.entity.EquipmentType | |||
| import com.ffii.fpsms.modules.master.entity.EquipmentDetail | |||
| import jakarta.validation.constraints.NotBlank | |||
| import jakarta.validation.constraints.NotNull | |||
| import java.time.LocalDateTime | |||
| @@ -20,7 +20,7 @@ data class NewEquipmentRequest( | |||
| val id: Long?, | |||
| val description: String?, | |||
| val equipmentType: EquipmentType?, | |||
| val equipmentType: EquipmentDetail?, | |||
| // val type: List<NewTypeRequest>?, | |||
| // val uom: List<NewUomRequest>?, | |||
| // val weightUnit: List<NewWeightUnitRequest>?, | |||
| @@ -2208,7 +2208,7 @@ open class PickOrderService( | |||
| } | |||
| } | |||
| println("🎯 Active pick orders: ${activePickOrders.size}") | |||
| println(" Active pick orders: ${activePickOrders.size}") | |||
| if (activePickOrders.isNotEmpty()) { | |||
| // User already has active pick orders, return existing ones | |||
| @@ -2686,7 +2686,7 @@ open class PickOrderService( | |||
| println("userId filter: $userId") | |||
| // First attempt auto-assignment for the user | |||
| println("🎯 Attempting auto-assignment for user $userId") | |||
| println(" Attempting auto-assignment for user $userId") | |||
| val assignedPickOrderResponse = autoAssignAndReleasePickOrder(userId) | |||
| // Get all pick order IDs assigned to the user (both RELEASED and PENDING with doId) | |||
| @@ -4379,7 +4379,7 @@ println("DEBUG sol polIds in linesResults: " + linesResults.mapNotNull { it["sto | |||
| // Get the incomplete date + next 2 days (total 3 days) | |||
| val targetDates = (0..2).map { days -> startDate.plusDays(days.toLong()) } | |||
| println("🎯 Target dates to return: $targetDates") | |||
| println(" Target dates to return: $targetDates") | |||
| // Only return dates that actually exist in the database | |||
| ordersToReturn.addAll( | |||
| @@ -4389,7 +4389,7 @@ println("DEBUG sol polIds in linesResults: " + linesResults.mapNotNull { it["sto | |||
| }.map { it["rawData"] as Map<String, Any?> } | |||
| ) | |||
| } else { | |||
| println("🎯 All orders are completed, returning empty list") | |||
| println(" All orders are completed, returning empty list") | |||
| } | |||
| // Transform results into the required structure | |||
| @@ -0,0 +1,15 @@ | |||
| -- liquibase formatted sql | |||
| -- changeset enson:altertable_enson | |||
| ALTER TABLE `fpsmsdb`.`productprocessline` | |||
| ADD COLUMN `defectDescription` VARCHAR(255) After `defectUom`, | |||
| ADD COLUMN `defectQty2` INT After `defectDescription`, | |||
| ADD COLUMN `defectRemark2` VARCHAR(255) After `defectQty2`, | |||
| ADD COLUMN `defectUom2` VARCHAR(255) After `defectRemark2`, | |||
| ADD COLUMN `defectQty3` INT After `defectUom2`, | |||
| ADD COLUMN `defectUom3` VARCHAR(255) After `defectQty3`, | |||
| ADD COLUMN `defectDescription3` VARCHAR(255) After `defectUom3`, | |||
| ADD COLUMN `equipmentDetailId` INT After `equipmentId`; | |||
| ALTER TABLE `fpsmsdb`.`equipment_type` | |||
| RENAME TO `fpsmsdb`.`equipment_detail`; | |||
| @@ -0,0 +1,6 @@ | |||
| -- liquibase formatted sql | |||
| -- changeset enson:altertable_enson | |||
| ALTER TABLE `fpsmsdb`.`bom` | |||
| ADD COLUMN `ScrapRate` INT AFTER `isDense`, | |||
| ADD COLUMN `AllergicSubstance` INT AFTER `ScrapRate`; | |||