diff --git a/src/main/java/com/ffii/fpsms/modules/report/service/SemiFGProductionAnalysisReportService.kt b/src/main/java/com/ffii/fpsms/modules/report/service/SemiFGProductionAnalysisReportService.kt index fa459f7..bdcd360 100644 --- a/src/main/java/com/ffii/fpsms/modules/report/service/SemiFGProductionAnalysisReportService.kt +++ b/src/main/java/com/ffii/fpsms/modules/report/service/SemiFGProductionAnalysisReportService.kt @@ -62,7 +62,10 @@ class SemiFGProductionAnalysisReportService( * - Include only stock_in_line rows with non-null jobOrderId * - Exclude stock_in_line rows with status = 'Pending' * - stockCategory → items.type (exact, comma-separated); itemCode → items.code (LIKE, comma-separated) - * - Date range / year on productionDate (with IS NOT NULL when range bound is set) + * - Date path: + * stock_in_line.productLotNo (must be present) -> + * stock_in_line.inventoryLotId -> inventory_lot.id -> + * inventory_lot.stockInDate (used for month/year/date filters) * - Quantity source: stock_in_line.acceptedQty * - QC any fail → line qty 0 (same as traceability stockInQty) * - One row per stockInLineId per month before pivot; all lines counted (not only job orders) @@ -89,7 +92,7 @@ class SemiFGProductionAnalysisReportService( val yearSql = if (!year.isNullOrBlank() && year != "All") { args["year"] = year - "AND YEAR(si.productionDate) = :year" + "AND YEAR(CASE WHEN si.productLotNo IS NOT NULL AND TRIM(si.productLotNo) <> '' THEN il.stockInDate ELSE si.productionDate END) = :year" } else { "" } @@ -97,13 +100,13 @@ class SemiFGProductionAnalysisReportService( val lastOutDateStartSql = if (!lastOutDateStart.isNullOrBlank()) { val formattedDate = lastOutDateStart.replace("/", "-") args["lastOutDateStart"] = formattedDate - "AND si.productionDate IS NOT NULL AND DATE(si.productionDate) >= DATE(:lastOutDateStart)" + "AND DATE(CASE WHEN si.productLotNo IS NOT NULL AND TRIM(si.productLotNo) <> '' THEN il.stockInDate ELSE si.productionDate END) >= DATE(:lastOutDateStart)" } else "" val lastOutDateEndSql = if (!lastOutDateEnd.isNullOrBlank()) { val formattedDate = lastOutDateEnd.replace("/", "-") args["lastOutDateEnd"] = formattedDate - "AND si.productionDate IS NOT NULL AND DATE(si.productionDate) <= DATE(:lastOutDateEnd)" + "AND DATE(CASE WHEN si.productLotNo IS NOT NULL AND TRIM(si.productLotNo) <> '' THEN il.stockInDate ELSE si.productionDate END) <= DATE(:lastOutDateEnd)" } else "" val sql = """ @@ -121,7 +124,12 @@ class SemiFGProductionAnalysisReportService( COALESCE(it.name, '') AS itemName, COALESCE(ic.sub, '') AS stockSubCategory, COALESCE(uc.udfudesc, '') AS unitOfMeasure, - MONTH(si.productionDate) AS mon, + MONTH( + CASE + WHEN si.productLotNo IS NOT NULL AND TRIM(si.productLotNo) <> '' THEN il.stockInDate + ELSE si.productionDate + END + ) AS mon, si.id AS stockInLineId, CASE WHEN COALESCE(qr_agg.qcFailed, 0) = 1 THEN 0 ELSE COALESCE(si.acceptedQty, 0) @@ -129,12 +137,20 @@ class SemiFGProductionAnalysisReportService( FROM stock_in_line si INNER JOIN items it ON si.itemId = it.id INNER JOIN bom b ON b.code = it.code AND b.deleted = false + LEFT JOIN inventory_lot il ON il.id = si.inventoryLotId AND il.deleted = false LEFT JOIN qr_agg ON qr_agg.stockInLineId = si.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 WHERE si.deleted = false - AND si.productionDate IS NOT NULL + AND si.productLotNo IS NOT NULL + AND TRIM(si.productLotNo) <> '' + AND ( + CASE + WHEN si.productLotNo IS NOT NULL AND TRIM(si.productLotNo) <> '' THEN il.stockInDate + ELSE si.productionDate + END + ) IS NOT NULL AND si.jobOrderId IS NOT NULL AND (si.status IS NULL OR si.status <> 'Pending') $stockCategorySql