From 7d517e05118db661b3a212a32816c67ebbd8d335 Mon Sep 17 00:00:00 2001 From: "kelvin.yau" Date: Mon, 9 Feb 2026 06:08:54 +0800 Subject: [PATCH 1/7] stock TRF update --- .../service/StockTransferRecordService.kt | 28 +------------------ 1 file changed, 1 insertion(+), 27 deletions(-) diff --git a/src/main/java/com/ffii/fpsms/modules/stock/service/StockTransferRecordService.kt b/src/main/java/com/ffii/fpsms/modules/stock/service/StockTransferRecordService.kt index 7ebf943..3e164fd 100644 --- a/src/main/java/com/ffii/fpsms/modules/stock/service/StockTransferRecordService.kt +++ b/src/main/java/com/ffii/fpsms/modules/stock/service/StockTransferRecordService.kt @@ -94,14 +94,6 @@ open class StockTransferRecordService( throw IllegalArgumentException("warehouseId is required for stock in") } - // Step 4: Check if existing InventoryLotLine with same lot and warehouse exists - val existingInventoryLotLine = inventoryLotLineRepository.findByLotNoAndItemIdAndWarehouseId( - lotNo = lotNo, - itemId = itemId, - warehouseId = request.warehouseId - ) - - // Step 5: Map to StockInRequest val stockInRequest = StockInRequest( itemId = itemId, itemNo = itemCode, @@ -115,25 +107,7 @@ open class StockTransferRecordService( warehouseId = request.warehouseId ) - return if (existingInventoryLotLine != null) { - // Update existing InventoryLotLine's inQty - existingInventoryLotLine.apply { - val currentInQty = this.inQty ?: BigDecimal.ZERO - this.inQty = currentInQty + request.transferredQty - - // Update status if it was UNAVAILABLE and now has stock - if (this.status == InventoryLotLineStatus.UNAVAILABLE) { - this.status = InventoryLotLineStatus.AVAILABLE - } - } - inventoryLotLineRepository.saveAndFlush(existingInventoryLotLine) - - // Create StockIn and StockInLine for record keeping, linking to existing InventoryLotLine - stockInLineService.createStockInForExistingInventoryLotLine(stockInRequest, existingInventoryLotLine) - } else { - // Normal flow: create new InventoryLotLine - stockInLineService.createStockIn(stockInRequest) - } + return stockInLineService.createStockIn(stockInRequest) } private fun createStockTransferRecord( From 7c6eefd1558d2a0e0a53ae9fdd3e03265b716e92 Mon Sep 17 00:00:00 2001 From: "kelvin.yau" Date: Mon, 9 Feb 2026 14:04:59 +0800 Subject: [PATCH 2/7] stock transfer update, with qr code adoption --- .../stock/entity/projection/QrCodeInfo.kt | 3 +- .../stock/service/InventoryLotLineService.kt | 72 ++++++++++++++----- .../stock/service/StockInLineService.kt | 3 +- .../stock/web/InventoryLotLineController.kt | 2 +- .../resources/qrCodeLabel/poItemPDF.jrxml | 15 ++++ 5 files changed, 76 insertions(+), 19 deletions(-) diff --git a/src/main/java/com/ffii/fpsms/modules/stock/entity/projection/QrCodeInfo.kt b/src/main/java/com/ffii/fpsms/modules/stock/entity/projection/QrCodeInfo.kt index 9efb7ad..2614893 100644 --- a/src/main/java/com/ffii/fpsms/modules/stock/entity/projection/QrCodeInfo.kt +++ b/src/main/java/com/ffii/fpsms/modules/stock/entity/projection/QrCodeInfo.kt @@ -29,5 +29,6 @@ interface QrCodeInfo { // stockInLine } data class LotLineToQrcode ( - val inventoryLotLineId: Long + val inventoryLotLineId: Long, + val isTransfer: String? = null ) diff --git a/src/main/java/com/ffii/fpsms/modules/stock/service/InventoryLotLineService.kt b/src/main/java/com/ffii/fpsms/modules/stock/service/InventoryLotLineService.kt index 0413eea..818d051 100644 --- a/src/main/java/com/ffii/fpsms/modules/stock/service/InventoryLotLineService.kt +++ b/src/main/java/com/ffii/fpsms/modules/stock/service/InventoryLotLineService.kt @@ -14,7 +14,7 @@ import com.ffii.fpsms.modules.stock.entity.projection.InventoryLotLineInfo import com.ffii.fpsms.modules.stock.entity.projection.LotLineToQrcode import com.ffii.fpsms.modules.stock.web.InventoryLotLineController import com.ffii.fpsms.modules.stock.web.model.UpdateInventoryLotLineStatusRequest - +import org.springframework.context.annotation.Lazy import com.ffii.fpsms.modules.stock.web.model.ExportQrCodeRequest import com.ffii.fpsms.modules.stock.web.model.SaveInventoryLotLineRequest import com.ffii.fpsms.modules.stock.web.model.SearchInventoryLotLineInfoRequest @@ -38,6 +38,8 @@ import com.ffii.fpsms.modules.stock.web.model.QrCodeAnalysisRequest import com.ffii.fpsms.modules.stock.web.model.QrCodeAnalysisResponse import com.ffii.fpsms.modules.stock.web.model.ScannedLotInfo import com.ffii.fpsms.modules.stock.web.model.SameItemLotInfo +import com.ffii.fpsms.modules.jobOrder.service.JobOrderService +import com.ffii.fpsms.modules.jobOrder.web.model.ExportFGStockInLabelRequest @Service open class InventoryLotLineService( @@ -46,7 +48,9 @@ open class InventoryLotLineService( private val warehouseRepository: WarehouseRepository, private val itemUomRespository: ItemUomRespository, private val stockInLineRepository: StockInLineRepository, - private val inventoryRepository: InventoryRepository + private val inventoryRepository: InventoryRepository, + @Lazy + private val jobOrderService: JobOrderService ) { open fun findById(id: Long): Optional { return inventoryLotLineRepository.findById(id) @@ -184,32 +188,41 @@ open class InventoryLotLineService( } val inputStream = resource.inputStream val poLabel = JasperCompileManager.compileReport(inputStream) -// val stockInLineInfo = stockInLineRepository.findStockInLineInfoByInventoryLotLineId(request.inventoryLotLineId).orElseThrow() + + // 1. 从 inventoryLotLineId 获取 inventory_lot_line val inventoryLotLine = inventoryLotLineRepository.findById(request.inventoryLotLineId).orElseThrow() - val stockInLineInfo = inventoryLotLine.inventoryLot?.stockInLine?.id?.let { stockInLineRepository.findStockInLineInfoById(it).orElseThrow() } ?: throw NoSuchElementException() + + // 2. 通过 inventory_lot_line.inventoryLot.stockInLine 获取 stock_in_line 信息(用于其他字段) + val stockInLineInfo = inventoryLotLine.inventoryLot?.stockInLine?.id?.let { + stockInLineRepository.findStockInLineInfoById(it).orElseThrow() + } ?: throw NoSuchElementException("StockInLine not found for inventoryLotLineId=${request.inventoryLotLineId}") val qrCodeInfo = listOf(stockInLineInfo) -// val qrCodeInfo = stockInLineRepository.findStockInLineInfoByIdInAndDeletedFalse(request.stockInLineIds).toMutableList() val fields = mutableListOf>() for (info in qrCodeInfo) { val field = mutableMapOf() val qrContent = QrContent(itemId = info.itemId, stockInLineId = info.id) val qrCodeContent = (Json.encodeToString(qrContent)) -// field["itemId"] = info.itemId + + // 使用 stockInLineInfo 的其他字段 field["itemName"] = info.itemName ?: "N/A" field["itemNo"] = info.itemNo field["poCode"] = info.poCode ?: "N/A" field["itemType"] = info.itemType ?: "N/A" - val stockItemUom = itemUomRespository.findBaseUnitByItemIdAndStockUnitIsTrueAndDeletedIsFalse(info.itemId) - val purchaseItemUom = itemUomRespository.findByItemIdAndPurchaseUnitIsTrueAndDeletedIsFalse(info.itemId) - val stockQty = if (stockItemUom != null && purchaseItemUom != null) { - (info.acceptedQty) * (purchaseItemUom.ratioN!! / purchaseItemUom.ratioD!!) / (stockItemUom.ratioN!! / stockItemUom.ratioD!!) - } else { - info.acceptedQty - } - field["acceptedQty"] = "%.2f".format(stockQty) - field["uom"] = inventoryLotLine.stockUom?.uom?.udfudesc ?: stockItemUom?.uom?.udfudesc ?: info.uom?.udfudesc?.toString() ?: "N/A" + + // 3. 计算 inventory_lot_line 的剩余数量(onHandQty) + val zero = BigDecimal.ZERO + val onHandQty = (inventoryLotLine.inQty ?: zero) + // .minus(inventoryLotLine.outQty ?: zero) + // .minus(inventoryLotLine.holdQty ?: zero) + + // 4. 使用 inventory_lot_line 的剩余数量(已经是库存单位,无需转换) + field["acceptedQty"] = "%.2f".format(onHandQty) + + // 5. 使用 inventory_lot_line.stockUom 获取 UOM(通过 stockItemUomId) + field["uom"] = inventoryLotLine.stockUom?.uom?.udfudesc ?: "N/A" + field["productionDate"] = info.productionDate?.format(DateTimeFormatter.ISO_LOCAL_DATE) ?: "" field["expiryDate"] = info.expiryDate?.format(DateTimeFormatter.ISO_LOCAL_DATE) ?: "" field["lotNo"] = info.lotNo!! @@ -219,7 +232,8 @@ open class InventoryLotLineService( fields.add(field) } val params: MutableMap = mutableMapOf( - "poCode" to (qrCodeInfo[0].poCode ?: "N/A") + "poCode" to (qrCodeInfo[0].poCode ?: "N/A"), + "isTransfer" to (request.isTransfer ?: "") ) return mapOf( "report" to PdfUtils.fillReport(poLabel,fields, params), @@ -227,6 +241,32 @@ open class InventoryLotLineService( ); } + @Throws(IOException::class) + @Transactional + open fun exportLabelForInventoryLotLine(inventoryLotLineId: Long): Map { + val inventoryLotLine = inventoryLotLineRepository.findById(inventoryLotLineId).orElseThrow() + val stockInLine = inventoryLotLine.inventoryLot?.stockInLine + + return when { + stockInLine?.jobOrder != null -> { + val result = jobOrderService.exportFGStockInLabel( + ExportFGStockInLabelRequest(stockInLineId = stockInLine.id!!) + ) + mapOf( + "report" to (result["report"]!!), + "fileName" to (result["filename"] ?: "label") + ) + } + stockInLine?.stockTransferRecord != null -> { + val targetLocation = stockInLine.stockTransferRecord?.targetLocation ?: "" + exportStockInLineQrcode( + LotLineToQrcode(inventoryLotLineId = inventoryLotLineId, isTransfer = "轉倉至 $targetLocation") + ) + } + else -> exportStockInLineQrcode(LotLineToQrcode(inventoryLotLineId = inventoryLotLineId)) + } + } + @Transactional open fun updateInventoryLotLineQuantities(request: UpdateInventoryLotLineQuantitiesRequest): MessageResponse { try { diff --git a/src/main/java/com/ffii/fpsms/modules/stock/service/StockInLineService.kt b/src/main/java/com/ffii/fpsms/modules/stock/service/StockInLineService.kt index 0a67655..74dbc93 100644 --- a/src/main/java/com/ffii/fpsms/modules/stock/service/StockInLineService.kt +++ b/src/main/java/com/ffii/fpsms/modules/stock/service/StockInLineService.kt @@ -618,7 +618,8 @@ open class StockInLineService( fields.add(field) } val params: MutableMap = mutableMapOf( - "poCode" to (qrCodeInfo[0].poCode ?: "N/A") //TODO change to JO code for JO + "poCode" to (qrCodeInfo[0].poCode ?: "N/A"), //TODO change to JO code for JO + "isTransfer" to "" ) return mapOf( "report" to PdfUtils.fillReport(poLabel,fields, params), diff --git a/src/main/java/com/ffii/fpsms/modules/stock/web/InventoryLotLineController.kt b/src/main/java/com/ffii/fpsms/modules/stock/web/InventoryLotLineController.kt index d7580a1..c86d521 100644 --- a/src/main/java/com/ffii/fpsms/modules/stock/web/InventoryLotLineController.kt +++ b/src/main/java/com/ffii/fpsms/modules/stock/web/InventoryLotLineController.kt @@ -79,7 +79,7 @@ class InventoryLotLineController ( response.characterEncoding = "utf-8"; response.contentType = "application/pdf"; val out: OutputStream = response.outputStream - val pdf = inventoryLotLineService.exportStockInLineQrcode(request) + val pdf = inventoryLotLineService.exportLabelForInventoryLotLine(request.inventoryLotLineId) val jasperPrint = pdf["report"] as JasperPrint response.addHeader("filename", "${pdf["fileName"]}.pdf") out.write(JasperExportManager.exportReportToPdf(jasperPrint)); diff --git a/src/main/resources/qrCodeLabel/poItemPDF.jrxml b/src/main/resources/qrCodeLabel/poItemPDF.jrxml index 3a99743..44606a4 100644 --- a/src/main/resources/qrCodeLabel/poItemPDF.jrxml +++ b/src/main/resources/qrCodeLabel/poItemPDF.jrxml @@ -9,6 +9,7 @@ + @@ -172,6 +173,20 @@ + + + + + + + + + + + + + + From 62dd4557ea2b6b7ff423d8c8962211cf88872e37 Mon Sep 17 00:00:00 2001 From: "kelvin.yau" Date: Mon, 9 Feb 2026 14:49:06 +0800 Subject: [PATCH 3/7] QR code adaptation update --- .../modules/stock/service/InventoryLotLineService.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/ffii/fpsms/modules/stock/service/InventoryLotLineService.kt b/src/main/java/com/ffii/fpsms/modules/stock/service/InventoryLotLineService.kt index 818d051..2e7d8a1 100644 --- a/src/main/java/com/ffii/fpsms/modules/stock/service/InventoryLotLineService.kt +++ b/src/main/java/com/ffii/fpsms/modules/stock/service/InventoryLotLineService.kt @@ -217,11 +217,11 @@ open class InventoryLotLineService( // .minus(inventoryLotLine.outQty ?: zero) // .minus(inventoryLotLine.holdQty ?: zero) - // 4. 使用 inventory_lot_line 的剩余数量(已经是库存单位,无需转换) - field["acceptedQty"] = "%.2f".format(onHandQty) + // Accepted qty at stock-in, no conversion (stays e.g. 50000 even after stock out) + field["acceptedQty"] = "%.2f".format(info.acceptedQty) - // 5. 使用 inventory_lot_line.stockUom 获取 UOM(通过 stockItemUomId) - field["uom"] = inventoryLotLine.stockUom?.uom?.udfudesc ?: "N/A" + val stockItemUom = itemUomRespository.findBaseUnitByItemIdAndStockUnitIsTrueAndDeletedIsFalse(info.itemId) + field["uom"] = stockItemUom?.uom?.udfudesc ?: info.uom?.udfudesc?.toString() ?: "N/A" field["productionDate"] = info.productionDate?.format(DateTimeFormatter.ISO_LOCAL_DATE) ?: "" field["expiryDate"] = info.expiryDate?.format(DateTimeFormatter.ISO_LOCAL_DATE) ?: "" From 44a4938f255a4cef58876746199c8912860997b8 Mon Sep 17 00:00:00 2001 From: "B.E.N.S.O.N" Date: Mon, 9 Feb 2026 15:05:07 +0800 Subject: [PATCH 4/7] Report Update --- .../SemiFGProductionAnalysisReport.jrxml | 116 +- .../StockItemConsumptionTrendReport.jrxml | 1294 ++++++++--------- 2 files changed, 705 insertions(+), 705 deletions(-) diff --git a/src/main/resources/jasper/SemiFGProductionAnalysisReport.jrxml b/src/main/resources/jasper/SemiFGProductionAnalysisReport.jrxml index 7ce2d33..26c6bdc 100644 --- a/src/main/resources/jasper/SemiFGProductionAnalysisReport.jrxml +++ b/src/main/resources/jasper/SemiFGProductionAnalysisReport.jrxml @@ -227,18 +227,18 @@ - + - + - + @@ -247,17 +247,17 @@ - + - + - + @@ -272,248 +272,248 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + diff --git a/src/main/resources/jasper/StockItemConsumptionTrendReport.jrxml b/src/main/resources/jasper/StockItemConsumptionTrendReport.jrxml index 92b7c6e..3ca9080 100644 --- a/src/main/resources/jasper/StockItemConsumptionTrendReport.jrxml +++ b/src/main/resources/jasper/StockItemConsumptionTrendReport.jrxml @@ -1,650 +1,650 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From b573c92b7752d6e74db747c64d0603a478470d8a Mon Sep 17 00:00:00 2001 From: "Tommy\\2Fi-Staff" Date: Mon, 9 Feb 2026 16:19:23 +0800 Subject: [PATCH 5/7] TruckScheduleDashboard & StockInTraceability report update --- .../modules/report/service/ReportService.kt | 48 ++- .../modules/report/web/ReportController.kt | 7 - .../jasper/StockInTraceabilityReport.jrxml | 282 ++++++------------ 3 files changed, 114 insertions(+), 223 deletions(-) diff --git a/src/main/java/com/ffii/fpsms/modules/report/service/ReportService.kt b/src/main/java/com/ffii/fpsms/modules/report/service/ReportService.kt index c2138f1..0bce8f6 100644 --- a/src/main/java/com/ffii/fpsms/modules/report/service/ReportService.kt +++ b/src/main/java/com/ffii/fpsms/modules/report/service/ReportService.kt @@ -327,30 +327,20 @@ return result /** * Queries the database for Stock In Traceability Report data. - * Joins stock_in_line, stock_in, items, item_category, qc_result, inventory_lot, inventory_lot_line, warehouse, and shop tables. - * Supports comma-separated values for stockCategory, stockSubCategory, and itemCode. + * Joins stock_in_line, stock_in, items, qc_result, inventory_lot, inventory_lot_line, warehouse, and shop tables. + * Supports comma-separated values for stockCategory (items.type) and itemCode. */ fun searchStockInTraceabilityReport( stockCategory: String?, - stockSubCategory: String?, itemCode: String?, - year: String?, lastInDateStart: String?, lastInDateEnd: String? ): List> { val args = mutableMapOf() - val stockCategorySql = buildMultiValueLikeClause(stockCategory, "ic.parent", "stockCategory", args) - val stockSubCategorySql = buildMultiValueLikeClause(stockSubCategory, "ic.sub", "stockSubCategory", args) + val stockCategorySql = buildMultiValueExactClause(stockCategory, "it.type", "stockCategory", args) val itemCodeSql = buildMultiValueLikeClause(itemCode, "it.code", "itemCode", args) - val yearSql = if (!year.isNullOrBlank()) { - args["year"] = year - "AND YEAR(sil.receiptDate) = :year" - } else { - "" - } - val lastInDateStartSql = if (!lastInDateStart.isNullOrBlank()) { args["lastInDateStart"] = lastInDateStart "AND sil.receiptDate >= :lastInDateStart" @@ -363,51 +353,49 @@ return result val sql = """ SELECT - COALESCE(ic.sub, '') as stockSubCategory, COALESCE(it.code, '') as itemNo, - COALESCE(CONCAT(COALESCE(it.name, ''), ' ', COALESCE(it.description, '')), '') as itemName, + COALESCE(it.name, '') as itemName, COALESCE(uc.code, '') as unitOfMeasure, COALESCE(sil.dnNo, '') as dnNo, COALESCE(sil.lotNo, il.lotNo, '') as lotNo, COALESCE(DATE_FORMAT(COALESCE(sil.expiryDate, il.expiryDate), '%Y-%m-%d'), '') as expiryDate, - CAST(COALESCE(sil.acceptedQty, 0) AS CHAR) as stockInQty, - CAST(COALESCE(sil.acceptedQty, 0) AS CHAR) as iqcSampleQty, - CAST(COALESCE(qr.failQty, 0) AS CHAR) as iqcDefectQty, - CAST(CASE + FORMAT(COALESCE(sil.acceptedQty, 0), 2) as stockInQty, + FORMAT(COALESCE(sil.acceptedQty, 0), 2) as iqcSampleQty, + FORMAT(COALESCE(qr.failQty, 0), 2) as iqcDefectQty, + FORMAT(CASE WHEN COALESCE(sil.acceptedQty, 0) > 0 THEN ROUND((COALESCE(qr.failQty, 0) / sil.acceptedQty) * 100, 2) ELSE 0 - END AS CHAR) as iqcDefectPercentage, + END, 2) as iqcDefectPercentage, CASE WHEN qr.qcPassed = true OR qr.qcPassed IS NULL THEN 'Accept' ELSE 'Reject' END as iqcResult, COALESCE(qr.remarks, '') as iqcRemarks, COALESCE(wh.code, '') as storeLocation, - COALESCE(sp.code, '') as supplierID, - COALESCE(sp.name, '') as supplierName, - CAST(SUM(COALESCE(sil.acceptedQty, 0)) OVER (PARTITION BY it.id) AS CHAR) as totalStockInQty, - CAST(SUM(COALESCE(sil.acceptedQty, 0)) OVER (PARTITION BY it.id) AS CHAR) as totalIqcSampleQty, - CAST(SUM(COALESCE(qr.failQty, 0)) OVER (PARTITION BY it.id) AS CHAR) as totalIqcDefectQty + COALESCE(sp_si.code, sp_po.code, '') as supplierID, + COALESCE(sp_si.name, sp_po.name, '') as supplierName, + FORMAT(SUM(COALESCE(sil.acceptedQty, 0)) OVER (PARTITION BY it.id), 2) as totalStockInQty, + FORMAT(SUM(COALESCE(sil.acceptedQty, 0)) OVER (PARTITION BY it.id), 2) as totalIqcSampleQty, + FORMAT(SUM(COALESCE(qr.failQty, 0)) OVER (PARTITION BY it.id), 2) as totalIqcDefectQty FROM stock_in_line sil LEFT JOIN stock_in si ON sil.stockInId = si.id + LEFT JOIN purchase_order po ON sil.purchaseOrderId = po.id LEFT JOIN items it ON sil.itemId = it.id - LEFT JOIN item_category ic ON it.categoryId = ic.id LEFT JOIN item_uom iu ON it.id = iu.itemId AND iu.stockUnit = true LEFT JOIN uom_conversion uc ON iu.uomId = uc.id LEFT JOIN qc_result qr ON sil.id = qr.stockInLineId LEFT JOIN inventory_lot il ON sil.inventoryLotId = il.id LEFT JOIN inventory_lot_line ill ON il.id = ill.inventoryLotId LEFT JOIN warehouse wh ON ill.warehouseId = wh.id - LEFT JOIN shop sp ON si.supplierId = sp.id + LEFT JOIN shop sp_si ON si.supplierId = sp_si.id + LEFT JOIN shop sp_po ON po.supplierId = sp_po.id WHERE sil.deleted = false $stockCategorySql - $stockSubCategorySql $itemCodeSql - $yearSql $lastInDateStartSql $lastInDateEndSql - ORDER BY ic.sub, it.code, sil.lotNo + ORDER BY it.code, sil.lotNo """.trimIndent() return jdbcDao.queryForList(sql, args) diff --git a/src/main/java/com/ffii/fpsms/modules/report/web/ReportController.kt b/src/main/java/com/ffii/fpsms/modules/report/web/ReportController.kt index 341bb97..997087d 100644 --- a/src/main/java/com/ffii/fpsms/modules/report/web/ReportController.kt +++ b/src/main/java/com/ffii/fpsms/modules/report/web/ReportController.kt @@ -83,19 +83,14 @@ class ReportController( @GetMapping("/print-stock-in-traceability") fun generateStockInTraceabilityReport( @RequestParam(required = false) stockCategory: String?, - @RequestParam(required = false) stockSubCategory: String?, @RequestParam(required = false) itemCode: String?, - @RequestParam(required = false) year: String?, @RequestParam(required = false) lastInDateStart: String?, @RequestParam(required = false) lastInDateEnd: String? ): ResponseEntity { val parameters = mutableMapOf() // Set report header parameters - parameters["stockCategory"] = stockCategory ?: "All" - parameters["stockSubCategory"] = stockSubCategory ?: "All" parameters["itemNo"] = itemCode ?: "All" - parameters["year"] = year ?: LocalDate.now().year.toString() parameters["reportDate"] = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")) parameters["reportTime"] = LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")) parameters["lastInDateStart"] = lastInDateStart ?: "" @@ -104,9 +99,7 @@ class ReportController( // Query the DB to get a list of data val dbData = reportService.searchStockInTraceabilityReport( stockCategory, - stockSubCategory, itemCode, - year, lastInDateStart, lastInDateEnd ) diff --git a/src/main/resources/jasper/StockInTraceabilityReport.jrxml b/src/main/resources/jasper/StockInTraceabilityReport.jrxml index c0171a7..b1dfa09 100644 --- a/src/main/resources/jasper/StockInTraceabilityReport.jrxml +++ b/src/main/resources/jasper/StockInTraceabilityReport.jrxml @@ -28,21 +28,21 @@ - - + + - - + + - - - + + + @@ -64,38 +64,29 @@ - + - - - - - - - - - - + - + - + - + - + @@ -103,31 +94,20 @@ - + - + - + - - - - - - - - - - - - + @@ -135,10 +115,10 @@ - + - + @@ -146,10 +126,10 @@ - + - + @@ -161,7 +141,7 @@ 缺陷數量]]> - + @@ -172,7 +152,7 @@ - + @@ -184,7 +164,7 @@ 編號]]> - + @@ -196,7 +176,7 @@ 樣品數量]]> - + @@ -207,7 +187,7 @@ - + @@ -218,7 +198,7 @@ - + @@ -226,10 +206,10 @@ - + - + @@ -240,7 +220,7 @@ - + @@ -252,7 +232,7 @@ 檢查結果]]> - + @@ -263,7 +243,7 @@ - + @@ -275,7 +255,7 @@ 檢查備註]]> - + @@ -287,7 +267,7 @@ 缺陷百分比]]> - + @@ -296,12 +276,12 @@ - + - + @@ -310,7 +290,7 @@ - + @@ -319,7 +299,7 @@ - + @@ -328,7 +308,7 @@ - + @@ -351,72 +331,35 @@ - - <band height="85" splitType="Stretch"> - <staticText> - <reportElement x="288" y="0" width="226" height="23" uuid="15ab756b-0e92-466c-be47-112c2ee1aad1"> - <property name="com.jaspersoft.studio.unit.y" value="px"/> - <property name="com.jaspersoft.studio.unit.height" value="px"/> - </reportElement> - <textElement textAlignment="Left" verticalAlignment="Middle"> - <font fontName="微軟正黑體" size="16" isBold="true"/> - </textElement> - <text><![CDATA[Stock In Traceability Report -]]></text> - </staticText> - <staticText> - <reportElement x="0" y="35" width="90" height="23" uuid="7338c712-b4ee-4194-9c37-07af197eee92"> - <property name="com.jaspersoft.studio.unit.y" value="px"/> + <pageHeader> + <band height="71" splitType="Stretch"> + <line> + <reportElement x="0" y="70" width="799" height="1" uuid="8628d83e-856d-44d2-9454-b6d048e6ecae"> <property name="com.jaspersoft.studio.unit.height" value="px"/> </reportElement> - <textElement textAlignment="Left" verticalAlignment="Middle"> - <font fontName="微軟正黑體" size="16" isBold="true"/> - </textElement> - <text><![CDATA[報告日期:]]></text> - </staticText> + </line> <staticText> - <reportElement x="0" y="58" width="90" height="23" uuid="84d51895-1f38-40bc-a2f8-ad5979628d51"> + <reportElement x="760" y="0" width="20" height="18" uuid="c612993d-f309-41f0-bda2-abc0a7d5a3b5"> <property name="com.jaspersoft.studio.unit.y" value="px"/> <property name="com.jaspersoft.studio.unit.height" value="px"/> </reportElement> - <textElement textAlignment="Left" verticalAlignment="Middle"> - <font fontName="微軟正黑體" size="16" isBold="true"/> + <textElement textAlignment="Center" verticalAlignment="Middle"> + <font fontName="微軟正黑體" size="12"/> </textElement> - <text><![CDATA[貨物分類:]]></text> + <text><![CDATA[/]]></text> </staticText> - <textField> - <reportElement x="90" y="35" width="390" height="23" uuid="ff7dd53c-f505-4615-bed4-107d0f053ffe"/> - <textElement verticalAlignment="Middle"> - <font fontName="微軟正黑體" size="16" isBold="true"/> - </textElement> - <textFieldExpression><![CDATA[$P{reportDate}]]></textFieldExpression> - </textField> - <textField> - <reportElement x="90" y="58" width="708" height="23" uuid="451b69eb-de5f-49e6-b8ba-d579f51e9658"/> - <textElement> - <font fontName="微軟正黑體" size="16" isBold="true"/> - </textElement> - <textFieldExpression><![CDATA[$P{stockCategory}]]></textFieldExpression> - </textField> <staticText> - <reportElement x="480" y="35" width="90" height="23" uuid="465d0d50-d1f6-49e2-966a-86c87294e1c3"> + <reportElement x="335" y="0" width="100" height="23" uuid="15ab756b-0e92-466c-be47-112c2ee1aad1"> <property name="com.jaspersoft.studio.unit.y" value="px"/> <property name="com.jaspersoft.studio.unit.height" value="px"/> </reportElement> <textElement textAlignment="Left" verticalAlignment="Middle"> <font fontName="微軟正黑體" size="16" isBold="true"/> </textElement> - <text><![CDATA[報告時間:]]></text> + <text><![CDATA[入倉記錄報告]]></text> </staticText> - <textField> - <reportElement x="570" y="35" width="228" height="23" uuid="bf131b2e-1da1-411a-b247-97280b89de21"/> - <textElement verticalAlignment="Middle"> - <font fontName="微軟正黑體" size="16" isBold="true"/> - </textElement> - <textFieldExpression><![CDATA[$P{reportTime}]]></textFieldExpression> - </textField> <textField evaluationTime="Report"> - <reportElement x="780" y="12" width="20" height="18" uuid="ad15e154-51b2-4775-8b7e-3cf2d3bc8da9"> + <reportElement x="780" y="0" width="20" height="18" uuid="ad15e154-51b2-4775-8b7e-3cf2d3bc8da9"> <property name="com.jaspersoft.studio.unit.width" value="px"/> <property name="com.jaspersoft.studio.unit.height" value="px"/> </reportElement> @@ -425,28 +368,25 @@ </textElement> <textFieldExpression><![CDATA[$V{PAGE_NUMBER}]]></textFieldExpression> </textField> - <staticText> - <reportElement x="760" y="12" width="20" height="18" uuid="c612993d-f309-41f0-bda2-abc0a7d5a3b5"> - <property name="com.jaspersoft.studio.unit.y" value="px"/> - <property name="com.jaspersoft.studio.unit.height" value="px"/> - </reportElement> - <textElement textAlignment="Center" verticalAlignment="Middle"> - <font fontName="微軟正黑體" size="12"/> + <textField> + <reportElement x="570" y="23" width="230" height="22" uuid="bf131b2e-1da1-411a-b247-97280b89de21"/> + <textElement verticalAlignment="Middle"> + <font fontName="微軟正黑體" size="14" isBold="true"/> </textElement> - <text><![CDATA[/]]></text> - </staticText> + <textFieldExpression><![CDATA[$P{reportTime}]]></textFieldExpression> + </textField> <staticText> - <reportElement x="700" y="12" width="40" height="18" uuid="375abc61-d5a7-4b06-8f95-b2ce305302c6"> + <reportElement x="0" y="23" width="100" height="22" uuid="7338c712-b4ee-4194-9c37-07af197eee92"> <property name="com.jaspersoft.studio.unit.y" value="px"/> <property name="com.jaspersoft.studio.unit.height" value="px"/> </reportElement> - <textElement textAlignment="Center" verticalAlignment="Middle"> - <font fontName="微軟正黑體" size="12"/> + <textElement textAlignment="Left" verticalAlignment="Middle"> + <font fontName="微軟正黑體" size="14" isBold="true"/> </textElement> - <text><![CDATA[頁數]]></text> + <text><![CDATA[報告日期:]]></text> </staticText> <textField> - <reportElement x="740" y="12" width="20" height="18" uuid="c58d1f01-d047-414b-8436-b173dcb58d48"> + <reportElement x="740" y="0" width="20" height="18" uuid="c58d1f01-d047-414b-8436-b173dcb58d48"> <property name="com.jaspersoft.studio.unit.height" value="px"/> </reportElement> <textElement textAlignment="Center" verticalAlignment="Middle"> @@ -454,89 +394,59 @@ </textElement> <textFieldExpression><![CDATA[$V{PAGE_NUMBER}]]></textFieldExpression> </textField> - <line> - <reportElement x="0" y="84" width="800" height="1" uuid="51721ea2-ec7b-4532-9e60-4903d8400cc8"> - <property name="com.jaspersoft.studio.unit.height" value="px"/> - </reportElement> - </line> - </band> - - - + + + + + + + - + - - + + - + - - + + - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - + - - + + - - - - - - - - - - + - + @@ -545,7 +455,7 @@ - + @@ -554,14 +464,14 @@ - + - + @@ -570,7 +480,7 @@ - + @@ -579,7 +489,7 @@ - + @@ -588,7 +498,7 @@ - + @@ -597,7 +507,7 @@ - + @@ -606,7 +516,7 @@ - + @@ -615,7 +525,7 @@ - + @@ -624,7 +534,7 @@ - + @@ -633,7 +543,7 @@ - + From 7e512e810ed547225c4cd0a3904caa7bd7ebfc52 Mon Sep 17 00:00:00 2001 From: "Tommy\\2Fi-Staff" Date: Mon, 9 Feb 2026 16:50:15 +0800 Subject: [PATCH 6/7] report update --- .../modules/report/service/ReportService.kt | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/ffii/fpsms/modules/report/service/ReportService.kt b/src/main/java/com/ffii/fpsms/modules/report/service/ReportService.kt index 0bce8f6..09edeb5 100644 --- a/src/main/java/com/ffii/fpsms/modules/report/service/ReportService.kt +++ b/src/main/java/com/ffii/fpsms/modules/report/service/ReportService.kt @@ -329,6 +329,7 @@ return result * Queries the database for Stock In Traceability Report data. * Joins stock_in_line, stock_in, items, qc_result, inventory_lot, inventory_lot_line, warehouse, and shop tables. * Supports comma-separated values for stockCategory (items.type) and itemCode. + * When "All" is selected, it expands to all categories: MAT, FG, WIP, NM, CMB. */ fun searchStockInTraceabilityReport( stockCategory: String?, @@ -338,7 +339,22 @@ return result ): List> { val args = mutableMapOf() - val stockCategorySql = buildMultiValueExactClause(stockCategory, "it.type", "stockCategory", args) + // Handle "All" option by expanding to all categories + val processedStockCategory = if (!stockCategory.isNullOrBlank()) { + val categories = stockCategory.split(",").map { it.trim() }.filter { it.isNotBlank() } + if (categories.contains("All")) { + // Replace "All" with all categories: MAT, FG, WIP, NM, CMB + val allCategories = listOf("MAT", "FG", "WIP", "NM", "CMB") + val otherCategories = categories.filter { it != "All" } + (allCategories + otherCategories).distinct().joinToString(",") + } else { + stockCategory + } + } else { + stockCategory + } + + val stockCategorySql = buildMultiValueExactClause(processedStockCategory, "it.type", "stockCategory", args) val itemCodeSql = buildMultiValueLikeClause(itemCode, "it.code", "itemCode", args) val lastInDateStartSql = if (!lastInDateStart.isNullOrBlank()) { From a9c2091fceee11132ed400f5586bd5d0fb746be6 Mon Sep 17 00:00:00 2001 From: "B.E.N.S.O.N" Date: Mon, 9 Feb 2026 19:33:03 +0800 Subject: [PATCH 7/7] FG Delivery Report Update for Enson --- .../resources/jasper/FGDeliveryReport.jrxml | 976 ++++++++---------- 1 file changed, 419 insertions(+), 557 deletions(-) diff --git a/src/main/resources/jasper/FGDeliveryReport.jrxml b/src/main/resources/jasper/FGDeliveryReport.jrxml index 60d49bd..45312ed 100644 --- a/src/main/resources/jasper/FGDeliveryReport.jrxml +++ b/src/main/resources/jasper/FGDeliveryReport.jrxml @@ -1,560 +1,422 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +