| @@ -16,6 +16,8 @@ import java.nio.file.Path | |||||
| import java.nio.file.Paths | import java.nio.file.Paths | ||||
| import java.nio.file.Files; | import java.nio.file.Files; | ||||
| import java.nio.file.StandardCopyOption | import java.nio.file.StandardCopyOption | ||||
| import com.ffii.fpsms.modules.master.entity.EquipmentDetailRepository | |||||
| @Service | @Service | ||||
| open class BomService( | open class BomService( | ||||
| @@ -29,6 +31,7 @@ open class BomService( | |||||
| private val uomConversionRepository: UomConversionRepository, | private val uomConversionRepository: UomConversionRepository, | ||||
| private val equipmentRepository: EquipmentRepository, | private val equipmentRepository: EquipmentRepository, | ||||
| private val processRepository: ProcessRepository, | private val processRepository: ProcessRepository, | ||||
| private val equipmentDetailRepository: EquipmentDetailRepository, | |||||
| ) { | ) { | ||||
| open fun findAll(): List<Bom> { | open fun findAll(): List<Bom> { | ||||
| return bomRepository.findAll() | return bomRepository.findAll() | ||||
| @@ -97,6 +100,8 @@ open class BomService( | |||||
| this.isDense = req.isDense | this.isDense = req.isDense | ||||
| this.code = req.code | this.code = req.code | ||||
| this.scrapRate = req.scrapRate | this.scrapRate = req.scrapRate | ||||
| this.timeSequence = req.timeSequence | |||||
| this.complexity = req.complexity | |||||
| this.allergicSubstances = req.allergicSubstances | this.allergicSubstances = req.allergicSubstances | ||||
| this.name = req.name | this.name = req.name | ||||
| this.description = req.description | this.description = req.description | ||||
| @@ -263,7 +268,7 @@ open class BomService( | |||||
| description = "", | description = "", | ||||
| ) | ) | ||||
| var startRowIndex = 0 | var startRowIndex = 0 | ||||
| val endRowIndex = 8 | |||||
| val endRowIndex = 10 | |||||
| var startColumnIndex = 0 | var startColumnIndex = 0 | ||||
| val endColumnIndex = 9 | val endColumnIndex = 9 | ||||
| while (startRowIndex != endRowIndex || startColumnIndex != endColumnIndex) { | while (startRowIndex != endRowIndex || startColumnIndex != endColumnIndex) { | ||||
| @@ -328,6 +333,7 @@ open class BomService( | |||||
| } | } | ||||
| when { | when { | ||||
| //use fix row column by index not by search value contain later | |||||
| tempCellVal.contains("深淺") -> request.isDark = calculateColourScore(getCellValueAsString(leftTargetValueCell)) | tempCellVal.contains("深淺") -> request.isDark = calculateColourScore(getCellValueAsString(leftTargetValueCell)) | ||||
| tempCellVal.contains("浮沉") -> request.isFloat = calculateFloatScore(getCellValueAsString(leftTargetValueCell)) | tempCellVal.contains("浮沉") -> request.isFloat = calculateFloatScore(getCellValueAsString(leftTargetValueCell)) | ||||
| tempCellVal.contains("過敏原 (如有)") -> request.allergicSubstances = calculateAllergicSubstancesScore(getCellValueAsString(leftTargetValueCell)) | tempCellVal.contains("過敏原 (如有)") -> request.allergicSubstances = calculateAllergicSubstancesScore(getCellValueAsString(leftTargetValueCell)) | ||||
| @@ -337,8 +343,15 @@ open class BomService( | |||||
| tempCellVal.contains("損耗率") -> request.scrapRate = if (leftTargetValueCell?.cellType == CellType.NUMERIC) | tempCellVal.contains("損耗率") -> request.scrapRate = if (leftTargetValueCell?.cellType == CellType.NUMERIC) | ||||
| leftTargetValueCell.numericCellValue.toInt() | leftTargetValueCell.numericCellValue.toInt() | ||||
| else 0 | else 0 | ||||
| tempCellVal.contains("生產先後次序") -> request.timeSequence = if (leftTargetValueCell?.cellType == CellType.NUMERIC) | |||||
| leftTargetValueCell.numericCellValue.toInt() | |||||
| else 0 | |||||
| tempCellVal.contains("複雜度") -> request.complexity = if (leftTargetValueCell?.cellType == CellType.NUMERIC) | |||||
| leftTargetValueCell.numericCellValue.toInt() | |||||
| else 0 | |||||
| } | } | ||||
| } | } | ||||
| if (startRowIndex < endRowIndex) { | if (startRowIndex < endRowIndex) { | ||||
| startRowIndex++ | startRowIndex++ | ||||
| } else if (startColumnIndex < endColumnIndex) { | } else if (startColumnIndex < endColumnIndex) { | ||||
| @@ -349,19 +362,61 @@ open class BomService( | |||||
| return saveBomEntity(request) | return saveBomEntity(request) | ||||
| } | } | ||||
| private fun bomGetOrCreateEquipment(name: String): Equipment { | |||||
| var equipment = equipmentRepository.findByNameAndDeletedIsFalse(name) | |||||
| ?: equipmentRepository.findByCodeAndDeletedIsFalse(name) | |||||
| private fun generateNextTMPEquipmentCode(): String { | |||||
| // 查询所有未删除的 EquipmentDetail | |||||
| val allEquipmentDetails = equipmentDetailRepository.findAllByDeletedFalse() | |||||
| // 过滤出以 "TMP" 开头的 equipmentCode,并提取数字部分 | |||||
| val tmpNumbers = allEquipmentDetails | |||||
| .mapNotNull { it.equipmentCode } | |||||
| .filter { it.startsWith("TMP") } | |||||
| .mapNotNull { code -> | |||||
| // 提取 TMP 后面的数字部分(例如:TMP01 -> 1, TMP02 -> 2) | |||||
| val numberPart = code.substring(3).trim() | |||||
| numberPart.toIntOrNull() | |||||
| } | |||||
| // 找到最大编号,如果没有则从 0 开始 | |||||
| val maxNumber = tmpNumbers.maxOrNull() ?: 0 | |||||
| // 递增并格式化为两位数(TMP01, TMP02, ...) | |||||
| val nextNumber = maxNumber + 1 | |||||
| return "TMP${nextNumber.toString().padStart(2, '0')}" | |||||
| } | |||||
| private fun bomGetOrCreateEquipment(equipmentName: String): Equipment { | |||||
| var equipment = equipmentRepository.findByNameAndDeletedIsFalse(equipmentName) | |||||
| ?: equipmentRepository.findByCodeAndDeletedIsFalse(equipmentName) | |||||
| var equipment_detail = equipmentDetailRepository.findByNameAndDeletedIsFalse(equipmentName) | |||||
| if (equipment == null) { | if (equipment == null) { | ||||
| // 解析 XXX-YYY 格式 | |||||
| val parts = equipmentName.split("-") | |||||
| val firstPart = if (parts.size > 0) parts[0] else equipmentName // XXX | |||||
| val secondPart = if (parts.size > 1) parts[1] else "" // YYY | |||||
| // 创建 equipment | |||||
| equipment = Equipment().apply { | equipment = Equipment().apply { | ||||
| this.name = name | |||||
| this.code = name | |||||
| this.description = name | |||||
| this.name = equipmentName // 完整值 XXX-YYY | |||||
| this.code = secondPart | |||||
| this.description = firstPart // XXX 写入 description | |||||
| } | } | ||||
| equipment = equipmentRepository.saveAndFlush(equipment) | equipment = equipmentRepository.saveAndFlush(equipment) | ||||
| // 创建 equipment_detail | |||||
| if (equipment_detail == null) { | |||||
| val nextEquipmentCode = generateNextTMPEquipmentCode() | |||||
| equipment_detail = EquipmentDetail().apply { | |||||
| this.name = "1號" // 默认值 | |||||
| this.description = equipmentName // equipmentName (完整值 XXX-YYY) | |||||
| this.code = "${this.description}-$name" | |||||
| this.equipmentCode=nextEquipmentCode | |||||
| } | |||||
| equipment_detail = equipmentDetailRepository.saveAndFlush(equipment_detail) | |||||
| } | |||||
| } | } | ||||
| return equipment!! | return equipment!! | ||||
| } | } | ||||
| private fun bomGetOrCreateProcess(name: String): Process { | private fun bomGetOrCreateProcess(name: String): Process { | ||||
| var process = processRepository.findByNameAndDeletedIsFalse(name) | var process = processRepository.findByNameAndDeletedIsFalse(name) | ||||
| ?: processRepository.findByCodeAndDeletedIsFalse(name) | ?: processRepository.findByCodeAndDeletedIsFalse(name) | ||||
| @@ -403,7 +458,7 @@ open class BomService( | |||||
| } | } | ||||
| private fun importExcelBomProcess(bom: Bom, sheet: Sheet) { | private fun importExcelBomProcess(bom: Bom, sheet: Sheet) { | ||||
| var startRowIndex = 30 | var startRowIndex = 30 | ||||
| val endRowIndex = 70 | |||||
| var endRowIndex = 70 | |||||
| var startColumnIndex = 0 | var startColumnIndex = 0 | ||||
| val endColumnIndex = 11 | val endColumnIndex = 11 | ||||
| while (startRowIndex < endRowIndex) { | while (startRowIndex < endRowIndex) { | ||||
| @@ -416,6 +471,17 @@ open class BomService( | |||||
| } | } | ||||
| startRowIndex++ | startRowIndex++ | ||||
| } | } | ||||
| var searchRowIndex = startRowIndex | |||||
| val maxSearchRow = 50 | |||||
| while (searchRowIndex < maxSearchRow) { | |||||
| val tempRow = sheet.getRow(searchRowIndex) | |||||
| val tempCell = tempRow?.getCell(0) | |||||
| if (tempCell == null || tempCell.cellType == CellType.BLANK) { | |||||
| endRowIndex = searchRowIndex | |||||
| break | |||||
| } | |||||
| searchRowIndex++ | |||||
| } | |||||
| var bomProcessRequest = ImportBomProcessRequest( | var bomProcessRequest = ImportBomProcessRequest( | ||||
| bom = bom | bom = bom | ||||
| ) | ) | ||||
| @@ -439,25 +505,26 @@ open class BomService( | |||||
| // println("seqNo: ${tempCell.numericCellValue.toLong()}") | // println("seqNo: ${tempCell.numericCellValue.toLong()}") | ||||
| // println("bomProcessRequest: $bomProcessRequest") | // println("bomProcessRequest: $bomProcessRequest") | ||||
| } | } | ||||
| 1 -> { | 1 -> { | ||||
| val equipmentName = tempCell.stringCellValue.trim() | |||||
| if (equipmentName != "不適用") { | |||||
| val equipment = bomGetOrCreateEquipment(equipmentName) | |||||
| // println("equipment created") | |||||
| bomProcessRequest.equipment = equipment | |||||
| } | |||||
| } | |||||
| 2 -> { | |||||
| val processName = tempCell.stringCellValue.trim() | val processName = tempCell.stringCellValue.trim() | ||||
| val process = bomGetOrCreateProcess(processName) | val process = bomGetOrCreateProcess(processName) | ||||
| bomProcessRequest.process = process | bomProcessRequest.process = process | ||||
| // println("process created") | // println("process created") | ||||
| } | } | ||||
| 3 -> { | |||||
| 2 -> { | |||||
| val description = tempCell.stringCellValue.trim() | val description = tempCell.stringCellValue.trim() | ||||
| bomProcessRequest.description = description | bomProcessRequest.description = description | ||||
| } | } | ||||
| 6 -> { //duration | |||||
| 3 -> { | |||||
| val equipmentName = tempCell.stringCellValue.trim() | |||||
| if (equipmentName != "不適用") { | |||||
| val equipment = bomGetOrCreateEquipment(equipmentName) | |||||
| // println("equipment created") | |||||
| bomProcessRequest.equipment = equipment | |||||
| } | |||||
| } | |||||
| 5 -> { //duration | |||||
| when (tempCell.cellType) { | when (tempCell.cellType) { | ||||
| CellType.NUMERIC -> { | CellType.NUMERIC -> { | ||||
| bomProcessRequest.durationInMinute = tempCell.numericCellValue.toInt() | bomProcessRequest.durationInMinute = tempCell.numericCellValue.toInt() | ||||
| @@ -471,6 +538,35 @@ open class BomService( | |||||
| } | } | ||||
| } | } | ||||
| /* | |||||
| 5 -> { //processOutputQty | |||||
| val processOutputQty = tempCell.stringCellValue.trim() | |||||
| bomProcessRequest.processOutputQty = processOutputQty | |||||
| } | |||||
| 6 -> { //processOutputUnit | |||||
| val processOutputUnit = tempCell.stringCellValue.trim() | |||||
| bomProcessRequest.processOutputUnit = processOutputUnit | |||||
| } | |||||
| 7 -> { //byProductName | |||||
| val byProductQty = tempCell.stringCellValue.trim() | |||||
| bomProcessRequest.byProductQty = byProductQty | |||||
| } | |||||
| 8 -> { //byProductQty | |||||
| val byProductUnit = tempCell.stringCellValue.trim() | |||||
| bomProcessRequest.byProductUnit = byProductUnit | |||||
| } | |||||
| 9 -> { //byProductUnit | |||||
| val byProductUnit = tempCell.stringCellValue.trim() | |||||
| bomProcessRequest.byProductUnit = byProductUnit | |||||
| } | |||||
| */ | |||||
| 9 -> { //scrapRate | |||||
| // val scrapRate = tempCell.stringCellValue.trim() | |||||
| // bomProcessRequest.scrapRate = scrapRate | |||||
| } | |||||
| 10 -> { //prepTimeInMinute | 10 -> { //prepTimeInMinute | ||||
| when (tempCell.cellType) { | when (tempCell.cellType) { | ||||
| CellType.NUMERIC -> { | CellType.NUMERIC -> { | ||||
| @@ -537,8 +633,8 @@ open class BomService( | |||||
| val resolver = PathMatchingResourcePatternResolver() | val resolver = PathMatchingResourcePatternResolver() | ||||
| // val excels = resolver.getResources("bomImport/*.xlsx") | // val excels = resolver.getResources("bomImport/*.xlsx") | ||||
| //val excels = resolver.getResources("file:C:/Users/Kelvin YAU/Downloads/bom/*.xlsx") | //val excels = resolver.getResources("file:C:/Users/Kelvin YAU/Downloads/bom/*.xlsx") | ||||
| val excels = resolver.getResources("file:C:/Users/Kelvin YAU/Downloads/bom/*.xlsx") | |||||
| //val excels = resolver.getResources("file:C:/Users/kw093/Downloads/bom/bom/*.xlsx") | |||||
| //val excels = resolver.getResources("file:C:/Users/Kelvin YAU/Downloads/bom/*.xlsx") | |||||
| val excels = resolver.getResources("file:C:/Users/kw093/Downloads/bom/bom/*.xlsx") | |||||
| // val excels = resolver.getResources("file:C:/Users/2Fi/Desktop/Third Wave of BOM Excel/*.xlsx") | // val excels = resolver.getResources("file:C:/Users/2Fi/Desktop/Third Wave of BOM Excel/*.xlsx") | ||||
| println("size: ${excels.size}") | println("size: ${excels.size}") | ||||
| val logExcel = ClassPathResource("excelTemplate/bom_excel_issue_log.xlsx") | val logExcel = ClassPathResource("excelTemplate/bom_excel_issue_log.xlsx") | ||||