From 7606c052e301d5429875bd12900215515b8a4388 Mon Sep 17 00:00:00 2001 From: "CANCERYS\\kw093" Date: Sat, 7 Feb 2026 17:55:35 +0800 Subject: [PATCH] update FG report --- .../modules/report/service/ReportService.kt | 204 ++++++++++++++++++ .../modules/report/web/ReportController.kt | 46 ++-- .../resources/jasper/FGDeliveryReport.jrxml | 45 ++-- 3 files changed, 253 insertions(+), 42 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 55ef7d3..1cf68f6 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 @@ -72,7 +72,211 @@ open class ReportService( return jdbcDao.queryForList(sql, args) } + fun searchFGDeliveryReport( + stockCategory: String?, + stockSubCategory: String?, + itemCode: String?, + year: String?, + lastOutDateStart: String?, + lastOutDateEnd: String? + ): List> { + val args = mutableMapOf() + + // Stock Category 过滤:通过 qc_category.code 或 qc_category.name + val stockCategorySql = if (!stockCategory.isNullOrBlank()) { + val categories = stockCategory.split(",").map { it.trim() }.filter { it.isNotBlank() } + if (categories.isNotEmpty()) { + val conditions = categories.mapIndexed { index, cat -> + val paramName = "stockCategory_$index" + args[paramName] = "%$cat%" + "(qc.code LIKE :$paramName OR qc.name LIKE :$paramName)" + } + "AND (${conditions.joinToString(" OR ")})" + } else { + "" + } + } else { + "" + } + + // 修正:stockSubCategory 也过滤 qc_category.name(而不是 item_category.sub) + val stockSubCategorySql = if (!stockSubCategory.isNullOrBlank()) { + val values = stockSubCategory.split(",").map { it.trim() }.filter { it.isNotBlank() } + if (values.isNotEmpty()) { + val conditions = values.mapIndexed { index, value -> + val paramName = "stockSubCategory_$index" + args[paramName] = "%$value%" + "qc.name LIKE :$paramName" + } + "AND (${conditions.joinToString(" OR ")})" + } else { + "" + } + } else { + "" + } + + val itemCodeSql = buildMultiValueLikeClause(itemCode, "it.code", "itemCode", args) + + val yearSql = if (!year.isNullOrBlank()) { + args["year"] = year + "AND YEAR(IFNULL(dpor.RequiredDeliveryDate, do.estimatedArrivalDate)) = :year" + } else { + "" + } + + val lastOutDateStartSql = if (!lastOutDateStart.isNullOrBlank()) { + args["lastOutDateStart"] = lastOutDateStart + "AND DATE(IFNULL(dpor.RequiredDeliveryDate, do.estimatedArrivalDate)) >= :lastOutDateStart" + } else "" + + val lastOutDateEndSql = if (!lastOutDateEnd.isNullOrBlank()) { + args["lastOutDateEnd"] = lastOutDateEnd + "AND DATE(IFNULL(dpor.RequiredDeliveryDate, do.estimatedArrivalDate)) < :lastOutDateEnd" + } else "" + + val sql = """ + SELECT + IFNULL(DATE_FORMAT( + IFNULL(dpor.RequiredDeliveryDate, do.estimatedArrivalDate), + '%Y-%m-%d' + ), '') AS deliveryDate, + IFNULL(it.code, '') AS itemNo, + IFNULL(it.name, '') AS itemName, + IFNULL(uc.udfudesc, '') AS unitOfMeasure, + IFNULL(sil.dnNo, '') AS dnNo, + CAST(IFNULL(sp.id, 0) AS CHAR) AS customerId, + IFNULL(sp.name, '') AS customerName, + CAST( + SUM(IFNULL(IFNULL(sol.qty, dol.qty), 0)) OVER ( + PARTITION BY it.code + ) AS DECIMAL(14,2) +) AS qtyNumeric, +CAST(ROUND(IFNULL(IFNULL(sol.qty, dol.qty), 0), 2) AS CHAR) AS qty, + COALESCE( + dpor.TruckLanceCode, + (SELECT t2.TruckLanceCode + FROM truck t2 + WHERE t2.shopId = do.shopId + AND t2.deleted = 0 + AND t2.Store_id = CASE + WHEN supplier.code = 'P06B' THEN '4F' + ELSE '2F' + END + AND ( + (CASE WHEN supplier.code = 'P06B' THEN '4F' ELSE '2F' END = '4F' + AND (SELECT COUNT(*) FROM truck t3 + WHERE t3.shopId = do.shopId AND t3.deleted = 0 + AND t3.Store_id = '4F') > 1 + AND IFNULL(dpor.RequiredDeliveryDate, do.estimatedArrivalDate) IS NOT NULL + AND t2.TruckLanceCode LIKE CONCAT('%', + CASE DAYNAME(IFNULL(dpor.RequiredDeliveryDate, do.estimatedArrivalDate)) + WHEN 'Monday' THEN 'Mon' + WHEN 'Tuesday' THEN 'Tue' + WHEN 'Wednesday' THEN 'Wed' + WHEN 'Thursday' THEN 'Thu' + WHEN 'Friday' THEN 'Fri' + WHEN 'Saturday' THEN 'Sat' + WHEN 'Sunday' THEN 'Sun' + ELSE '' + END, '%')) + OR + t2.Store_id = CASE WHEN supplier.code = 'P06B' THEN '4F' ELSE '2F' END + ) + ORDER BY t2.DepartureTime ASC + LIMIT 1), + '' + ) AS truckNo, + '' AS driver, + IFNULL(do.code, '') AS deliveryOrderNo, + IFNULL(qc.name, '') AS stockSubCategory + FROM do_pick_order_line_record dpolr + LEFT JOIN do_pick_order_record dpor + ON dpolr.do_pick_order_id = dpor.id + AND dpor.deleted = 0 + AND dpor.ticket_status = 'completed' + INNER JOIN delivery_order do + ON dpolr.do_order_id = do.id + AND do.deleted = 0 + LEFT JOIN shop supplier + ON do.supplierId = supplier.id + AND supplier.deleted = 0 + LEFT JOIN shop sp + ON do.shopId = sp.id + AND sp.deleted = 0 + LEFT JOIN delivery_order_line dol + ON do.id = dol.deliveryOrderId + AND dol.deleted = 0 + LEFT JOIN items it + ON dol.itemId = it.id + AND it.deleted = 0 + LEFT JOIN items_qc_category_mapping iqcm + ON it.id = iqcm.itemId + LEFT JOIN qc_category qc + ON iqcm.qcCategoryId = qc.id + AND qc.deleted = 0 + LEFT JOIN item_category ic + ON it.categoryId = ic.id + LEFT JOIN item_uom iu + ON it.id = iu.itemId + AND iu.stockUnit = 1 + LEFT JOIN uom_conversion uc + ON iu.uomId = uc.id + LEFT JOIN pick_order_line pol + ON dpolr.pick_order_id = pol.poId + AND pol.itemId = it.id + AND pol.deleted = 0 + LEFT JOIN stock_out_line sol + ON pol.id = sol.pickOrderLineId + AND sol.itemId = it.id + AND sol.deleted = 0 + LEFT JOIN inventory_lot_line ill + ON sol.inventoryLotLineId = ill.id + AND ill.deleted = 0 + LEFT JOIN inventory_lot il + ON ill.inventoryLotId = il.id + AND il.deleted = 0 + LEFT JOIN stock_in_line sil + ON il.stockInLineId = sil.id + AND sil.deleted = 0 + WHERE + dpolr.deleted = 0 + AND (dpor.id IS NULL OR dpor.ticket_status = 'completed') + $stockCategorySql + $stockSubCategorySql + $itemCodeSql + $yearSql + $lastOutDateStartSql + $lastOutDateEndSql + ORDER BY + qc.name, + it.code, + IFNULL(sil.lotNo, '') +""".trimIndent() + +val result = jdbcDao.queryForList(sql, args) + +// 打印查询结果(前 10 行) +println("=== Query Result (Total: ${result.size} rows) ===") +result.take(50).forEachIndexed { index, row -> + println("Row $index:") + println(" deliveryDate: ${row["deliveryDate"]}") + println(" itemNo: ${row["itemNo"]}") + println(" itemName: ${row["itemName"]}") + println(" qty: ${row["qty"]}") + println(" qtyNumeric: ${row["qtyNumeric"]}") + println(" deliveryOrderNo: ${row["deliveryOrderNo"]}") + println(" stockSubCategory: ${row["stockSubCategory"]}") + println(" ---") +} +if (result.size > 50) { + println("... (showing first 10 rows, total ${result.size} rows)") +} + +return result + + } /** * Helper function to build SQL clause for comma-separated values. * Supports multiple values like "val1, val2, val3" and generates OR conditions with LIKE. 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 ceaf074..b2c8ccb 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 @@ -79,50 +79,50 @@ class ReportController( return ResponseEntity(pdfBytes, headers, HttpStatus.OK) } - - @GetMapping("/print-stock-in-traceability") - fun generateStockInTraceabilityReport( + @GetMapping("/print-fg-delivery-report") + fun generateFGDeliveryReport( @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? + @RequestParam(required = false) lastOutDateStart: String?, + @RequestParam(required = false) lastOutDateEnd: 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 ?: "" - parameters["lastInDateEnd"] = lastInDateEnd ?: "" - - // Query the DB to get a list of data - val dbData = reportService.searchStockInTraceabilityReport( - stockCategory, - stockSubCategory, - itemCode, - year, - lastInDateStart, - lastInDateEnd + parameters["lastOutDateStart"] = lastOutDateStart ?: "" + parameters["lastOutDateEnd"] = lastOutDateEnd ?: "" + parameters["deliveryPeriodStart"] = "" + parameters["deliveryPeriodEnd"] = "" + + val dbData = reportService.searchFGDeliveryReport( + stockCategory, + stockSubCategory, + itemCode, + year, + lastOutDateStart, + lastOutDateEnd ) - + val pdfBytes = reportService.createPdfResponse( - "/jasper/StockInTraceabilityReport.jrxml", + "/jasper/FGDeliveryReport.jrxml", parameters, dbData ) - + val headers = HttpHeaders().apply { contentType = MediaType.APPLICATION_PDF - setContentDispositionFormData("attachment", "StockInTraceabilityReport.pdf") - set("filename", "StockInTraceabilityReport.pdf") + setContentDispositionFormData("attachment", "FGDeliveryReport.pdf") + set("filename", "FGDeliveryReport.pdf") } - + return ResponseEntity(pdfBytes, headers, HttpStatus.OK) } diff --git a/src/main/resources/jasper/FGDeliveryReport.jrxml b/src/main/resources/jasper/FGDeliveryReport.jrxml index aba30ec..60d49bd 100644 --- a/src/main/resources/jasper/FGDeliveryReport.jrxml +++ b/src/main/resources/jasper/FGDeliveryReport.jrxml @@ -1,6 +1,6 @@ - - + + @@ -10,33 +10,32 @@ - - + - + - + - - - - - - + + + + + + - + - + @@ -60,13 +59,21 @@ + - - - + + + + + @@ -260,7 +267,7 @@ - + @@ -310,7 +317,7 @@ - +