| @@ -0,0 +1,235 @@ | |||
| package com.ffii.fpsms.modules.report.service | |||
| import com.ffii.core.support.JdbcDao | |||
| import org.springframework.stereotype.Service | |||
| @Service | |||
| class MaterialStockOutTraceabilityReportService( | |||
| private val jdbcDao: JdbcDao, | |||
| ) { | |||
| fun getDistinctHandlersForMaterialStockOutTraceability(): List<String> { | |||
| val sql = """ | |||
| SELECT DISTINCT COALESCE(picker_user.name, jpo_handler_user.name, created_user.name, modified_user.name, '') AS handler | |||
| FROM stock_out_line sol | |||
| INNER JOIN stock_out so ON sol.stockOutId = so.id AND so.deleted = 0 AND so.type = 'job' | |||
| INNER JOIN pick_order_line pol ON sol.pickOrderLineId = pol.id AND pol.deleted = 0 | |||
| INNER JOIN pick_order po ON pol.poId = po.id AND po.deleted = 0 AND po.type IN ('jo', 'JOB_ORDER') AND po.joId IS NOT NULL | |||
| LEFT JOIN user picker_user ON sol.handled_by = picker_user.id AND picker_user.deleted = 0 | |||
| LEFT JOIN jo_pick_order jpo ON po.id = jpo.pick_order_id AND pol.itemId = jpo.item_id AND jpo.deleted = 0 | |||
| LEFT JOIN user jpo_handler_user ON jpo.handled_by = jpo_handler_user.id AND jpo_handler_user.deleted = 0 | |||
| LEFT JOIN user created_user ON sol.createdBy = created_user.username AND created_user.deleted = 0 | |||
| LEFT JOIN user modified_user ON sol.modifiedBy = modified_user.staffNo AND modified_user.deleted = 0 AND sol.handled_by IS NULL | |||
| WHERE sol.deleted = 0 | |||
| ORDER BY handler | |||
| """.trimIndent() | |||
| return jdbcDao | |||
| .queryForList(sql, emptyMap<String, Any>()) | |||
| .map { row -> (row["handler"]?.toString() ?: "").trim() } | |||
| .filter { it.isNotBlank() } | |||
| } | |||
| fun searchMaterialStockOutTraceabilityReport( | |||
| stockCategory: String?, | |||
| stockSubCategory: String?, | |||
| itemCode: String?, | |||
| year: String?, | |||
| lastOutDateStart: String?, | |||
| lastOutDateEnd: String?, | |||
| handler: String?, | |||
| ): List<Map<String, Any>> { | |||
| val args = mutableMapOf<String, Any>() | |||
| // Stock Category filtering (items.type) | |||
| val stockCategorySql = buildMultiValueExactClause( | |||
| stockCategory, | |||
| "it.type", | |||
| "stockCategory", | |||
| args, | |||
| ) | |||
| // Keep as-is (no filter yet) | |||
| val stockSubCategorySql = "" | |||
| val itemCodeSql = buildMultiValueLikeClause( | |||
| itemCode, | |||
| "it.code", | |||
| "itemCode", | |||
| args, | |||
| ) | |||
| // Filter by sol.endTime year | |||
| val yearSql = if (!year.isNullOrBlank()) { | |||
| args["year"] = year | |||
| "AND YEAR(sol.endTime) = :year" | |||
| } else "" | |||
| val lastOutDateStartSql = if (!lastOutDateStart.isNullOrBlank()) { | |||
| val formattedDate = lastOutDateStart.replace("/", "-") | |||
| args["lastOutDateStart"] = formattedDate | |||
| "AND DATE(sol.endTime) >= DATE(:lastOutDateStart)" | |||
| } else "" | |||
| val lastOutDateEndSql = if (!lastOutDateEnd.isNullOrBlank()) { | |||
| val formattedDate = lastOutDateEnd.replace("/", "-") | |||
| args["lastOutDateEnd"] = formattedDate | |||
| "AND DATE(sol.endTime) <= DATE(:lastOutDateEnd)" | |||
| } else "" | |||
| val handlerSql = buildMultiValueExactClause( | |||
| handler, | |||
| "COALESCE(picker_user.name, jpo_handler_user.name, created_user.name, modified_user.name, '')", | |||
| "handler", | |||
| args, | |||
| ) | |||
| val sql = """ | |||
| SELECT | |||
| IFNULL(it.code, '') AS itemNo, | |||
| IFNULL(it.name, '') AS itemName, | |||
| IFNULL(it.categoryId, 0) AS stockSubCategory, | |||
| IFNULL(uc.udfudesc, '') AS unitOfMeasure, | |||
| IFNULL(jo.code, '') AS jobOrderNo, | |||
| IFNULL(po.consoCode, '') AS stockReqNo, | |||
| IFNULL(il.lotNo, '') AS lotNo, | |||
| IFNULL(DATE_FORMAT(il.expiryDate, '%Y-%m-%d'), '') AS expiryDate, | |||
| FORMAT(ROUND(IFNULL(sol.qty, 0), 0), 0) AS stockOutQty, | |||
| IFNULL(po.code, '') AS materialPickOrderNo, | |||
| COALESCE( | |||
| picker_user.name, | |||
| jpo_handler_user.name, | |||
| created_user.name, | |||
| modified_user.name, | |||
| '' | |||
| ) AS handler, | |||
| COALESCE(wh.code, '') AS storeLocation, | |||
| '' AS pickRemark, | |||
| FORMAT( | |||
| ROUND(SUM(IFNULL(sol.qty, 0)) OVER (PARTITION BY it.code), 0), 0 | |||
| ) AS totalStockOutQty | |||
| FROM stock_out_line sol | |||
| INNER JOIN stock_out so | |||
| ON sol.stockOutId = so.id | |||
| AND so.deleted = 0 | |||
| AND so.type = 'job' | |||
| INNER JOIN pick_order_line pol | |||
| ON sol.pickOrderLineId = pol.id | |||
| AND pol.deleted = 0 | |||
| INNER JOIN pick_order po | |||
| ON pol.poId = po.id | |||
| AND po.deleted = 0 | |||
| AND po.type IN ('jo', 'JOB_ORDER') | |||
| AND po.joId IS NOT NULL | |||
| LEFT JOIN job_order jo | |||
| ON po.joId = jo.id | |||
| AND jo.deleted = 0 | |||
| INNER JOIN items it | |||
| ON sol.itemId = it.id | |||
| AND it.deleted = 0 | |||
| 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 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 warehouse wh | |||
| ON ill.warehouseId = wh.id | |||
| AND wh.deleted = 0 | |||
| LEFT JOIN user picker_user | |||
| ON sol.handled_by = picker_user.id | |||
| AND picker_user.deleted = 0 | |||
| LEFT JOIN jo_pick_order jpo | |||
| ON po.id = jpo.pick_order_id | |||
| AND pol.itemId = jpo.item_id | |||
| AND jpo.deleted = 0 | |||
| LEFT JOIN user jpo_handler_user | |||
| ON jpo.handled_by = jpo_handler_user.id | |||
| AND jpo_handler_user.deleted = 0 | |||
| LEFT JOIN user created_user | |||
| ON sol.createdBy = created_user.username | |||
| AND created_user.deleted = 0 | |||
| LEFT JOIN user modified_user | |||
| ON sol.modifiedBy = modified_user.staffNo | |||
| AND modified_user.deleted = 0 | |||
| AND sol.handled_by IS NULL | |||
| WHERE | |||
| sol.deleted = 0 | |||
| AND (sol.inventoryLotLineId IS NULL OR ill.id IS NOT NULL) | |||
| $stockCategorySql | |||
| $stockSubCategorySql | |||
| $itemCodeSql | |||
| $yearSql | |||
| $lastOutDateStartSql | |||
| $lastOutDateEndSql | |||
| $handlerSql | |||
| ORDER BY | |||
| it.code, | |||
| il.lotNo, | |||
| sol.endTime | |||
| """.trimIndent() | |||
| val result = jdbcDao.queryForList(sql, args) | |||
| println("=== Material Stock Out Traceability (Total: ${result.size} rows) ===") | |||
| result.take(50).forEachIndexed { index, row -> | |||
| println("Row $index:") | |||
| println(" itemNo: ${row["itemNo"]}") | |||
| println(" itemName: ${row["itemName"]}") | |||
| println(" jobOrderNo: ${row["jobOrderNo"]}") | |||
| println(" stockOutQty: ${row["stockOutQty"]}") | |||
| println(" totalStockOutQty: ${row["totalStockOutQty"]}") | |||
| println(" materialPickOrderNo: ${row["materialPickOrderNo"]}") | |||
| println(" handler: ${row["handler"]}") | |||
| println(" storeLocation: ${row["storeLocation"]}") | |||
| println(" ---") | |||
| } | |||
| return result | |||
| } | |||
| private fun buildMultiValueLikeClause( | |||
| paramValue: String?, | |||
| columnName: String, | |||
| paramPrefix: String, | |||
| args: MutableMap<String, Any>, | |||
| ): String { | |||
| if (paramValue.isNullOrBlank()) return "" | |||
| val values = paramValue.split(",").map { it.trim() }.filter { it.isNotBlank() } | |||
| if (values.isEmpty()) return "" | |||
| val conditions = values.mapIndexed { index, value -> | |||
| val paramName = "${paramPrefix}_$index" | |||
| args[paramName] = "%$value%" | |||
| "$columnName LIKE :$paramName" | |||
| } | |||
| return "AND (${conditions.joinToString(" OR ")})" | |||
| } | |||
| private fun buildMultiValueExactClause( | |||
| paramValue: String?, | |||
| columnName: String, | |||
| paramPrefix: String, | |||
| args: MutableMap<String, Any>, | |||
| ): String { | |||
| if (paramValue.isNullOrBlank()) return "" | |||
| val values = paramValue.split(",").map { it.trim() }.filter { it.isNotBlank() } | |||
| if (values.isEmpty()) return "" | |||
| val conditions = values.mapIndexed { index, value -> | |||
| val paramName = "${paramPrefix}_$index" | |||
| args[paramName] = value | |||
| "$columnName = :$paramName" | |||
| } | |||
| return "AND (${conditions.joinToString(" OR ")})" | |||
| } | |||
| } | |||
| @@ -282,24 +282,6 @@ return result | |||
| return jdbcDao.queryForList(sql, emptyMap<String, Any>()).map { row -> (row["handler"]?.toString() ?: "").trim() }.filter { it.isNotBlank() } | |||
| } | |||
| fun getDistinctHandlersForMaterialStockOutTraceability(): List<String> { | |||
| val sql = """ | |||
| SELECT DISTINCT COALESCE(picker_user.name, jpo_handler_user.name, created_user.name, modified_user.name, '') AS handler | |||
| FROM stock_out_line sol | |||
| INNER JOIN stock_out so ON sol.stockOutId = so.id AND so.deleted = 0 AND so.type = 'job' | |||
| INNER JOIN pick_order_line pol ON sol.pickOrderLineId = pol.id AND pol.deleted = 0 | |||
| INNER JOIN pick_order po ON pol.poId = po.id AND po.deleted = 0 AND po.type IN ('jo', 'JOB_ORDER') AND po.joId IS NOT NULL | |||
| LEFT JOIN user picker_user ON sol.handled_by = picker_user.id AND picker_user.deleted = 0 | |||
| LEFT JOIN jo_pick_order jpo ON po.id = jpo.pick_order_id AND pol.itemId = jpo.item_id AND jpo.deleted = 0 | |||
| LEFT JOIN user jpo_handler_user ON jpo.handled_by = jpo_handler_user.id AND jpo_handler_user.deleted = 0 | |||
| LEFT JOIN user created_user ON sol.createdBy = created_user.username AND created_user.deleted = 0 | |||
| LEFT JOIN user modified_user ON sol.modifiedBy = modified_user.staffNo AND modified_user.deleted = 0 AND sol.handled_by IS NULL | |||
| WHERE sol.deleted = 0 | |||
| ORDER BY handler | |||
| """.trimIndent() | |||
| return jdbcDao.queryForList(sql, emptyMap<String, Any>()).map { row -> (row["handler"]?.toString() ?: "").trim() }.filter { it.isNotBlank() } | |||
| } | |||
| fun searchFGStockOutTraceabilityReport( | |||
| stockCategory: String?, | |||
| stockSubCategory: String?, | |||
| @@ -506,175 +488,6 @@ return result | |||
| return result | |||
| } | |||
| fun searchMaterialStockOutTraceabilityReport( | |||
| stockCategory: String?, | |||
| stockSubCategory: String?, | |||
| itemCode: String?, | |||
| year: String?, | |||
| lastOutDateStart: String?, | |||
| lastOutDateEnd: String?, | |||
| handler: String? | |||
| ): List<Map<String, Any>> { | |||
| val args = mutableMapOf<String, Any>() | |||
| // Stock Category 过滤:通过 items.type | |||
| val stockCategorySql = buildMultiValueExactClause( | |||
| stockCategory, | |||
| "it.type", | |||
| "stockCategory", | |||
| args | |||
| ) | |||
| val stockSubCategorySql = "" | |||
| val itemCodeSql = buildMultiValueLikeClause( | |||
| itemCode, | |||
| "it.code", | |||
| "itemCode", | |||
| args | |||
| ) | |||
| // 年份过滤:使用 sol.endTime 的年份 | |||
| val yearSql = if (!year.isNullOrBlank()) { | |||
| args["year"] = year | |||
| "AND YEAR(sol.endTime) = :year" | |||
| } else { | |||
| "" | |||
| } | |||
| val lastOutDateStartSql = if (!lastOutDateStart.isNullOrBlank()) { | |||
| val formattedDate = lastOutDateStart.replace("/", "-") | |||
| args["lastOutDateStart"] = formattedDate | |||
| "AND DATE(sol.endTime) >= DATE(:lastOutDateStart)" | |||
| } else { | |||
| "" | |||
| } | |||
| val lastOutDateEndSql = if (!lastOutDateEnd.isNullOrBlank()) { | |||
| val formattedDate = lastOutDateEnd.replace("/", "-") | |||
| args["lastOutDateEnd"] = formattedDate | |||
| "AND DATE(sol.endTime) <= DATE(:lastOutDateEnd)" | |||
| } else { | |||
| "" | |||
| } | |||
| val handlerSql = buildMultiValueExactClause( | |||
| handler, | |||
| "COALESCE(picker_user.name, jpo_handler_user.name, created_user.name, modified_user.name, '')", | |||
| "handler", | |||
| args | |||
| ) | |||
| val sql = """ | |||
| SELECT | |||
| IFNULL(it.code, '') AS itemNo, | |||
| IFNULL(it.name, '') AS itemName, | |||
| IFNULL(it.categoryId, 0) AS stockSubCategory, | |||
| IFNULL(uc.udfudesc, '') AS unitOfMeasure, | |||
| IFNULL(jo.code, '') AS jobOrderNo, | |||
| IFNULL(po.consoCode, '') AS stockReqNo, | |||
| IFNULL(il.lotNo, '') AS lotNo, | |||
| IFNULL(DATE_FORMAT(il.expiryDate, '%Y-%m-%d'), '') AS expiryDate, | |||
| FORMAT(ROUND(IFNULL(sol.qty, 0), 0), 0) AS stockOutQty, | |||
| IFNULL(po.code, '') AS materialPickOrderNo, | |||
| COALESCE( | |||
| picker_user.name, | |||
| jpo_handler_user.name, | |||
| created_user.name, | |||
| modified_user.name, | |||
| '' | |||
| ) AS handler, | |||
| COALESCE(wh.code, '') AS storeLocation, | |||
| '' AS pickRemark, | |||
| FORMAT( | |||
| ROUND(SUM(IFNULL(sol.qty, 0)) OVER (PARTITION BY it.code), 0), 0 | |||
| ) AS totalStockOutQty | |||
| FROM stock_out_line sol | |||
| INNER JOIN stock_out so | |||
| ON sol.stockOutId = so.id | |||
| AND so.deleted = 0 | |||
| AND so.type = 'job' | |||
| INNER JOIN pick_order_line pol | |||
| ON sol.pickOrderLineId = pol.id | |||
| AND pol.deleted = 0 | |||
| INNER JOIN pick_order po | |||
| ON pol.poId = po.id | |||
| AND po.deleted = 0 | |||
| AND po.type IN ('jo', 'JOB_ORDER') | |||
| AND po.joId IS NOT NULL | |||
| LEFT JOIN job_order jo | |||
| ON po.joId = jo.id | |||
| AND jo.deleted = 0 | |||
| INNER JOIN items it | |||
| ON sol.itemId = it.id | |||
| AND it.deleted = 0 | |||
| 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 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 warehouse wh | |||
| ON ill.warehouseId = wh.id | |||
| AND wh.deleted = 0 | |||
| LEFT JOIN user picker_user | |||
| ON sol.handled_by = picker_user.id | |||
| AND picker_user.deleted = 0 | |||
| LEFT JOIN jo_pick_order jpo | |||
| ON po.id = jpo.pick_order_id | |||
| AND pol.itemId = jpo.item_id | |||
| AND jpo.deleted = 0 | |||
| LEFT JOIN user jpo_handler_user | |||
| ON jpo.handled_by = jpo_handler_user.id | |||
| AND jpo_handler_user.deleted = 0 | |||
| LEFT JOIN user created_user | |||
| ON sol.createdBy = created_user.username | |||
| AND created_user.deleted = 0 | |||
| LEFT JOIN user modified_user | |||
| ON sol.modifiedBy = modified_user.staffNo | |||
| AND modified_user.deleted = 0 | |||
| AND sol.handled_by IS NULL | |||
| WHERE | |||
| sol.deleted = 0 | |||
| AND (sol.inventoryLotLineId IS NULL OR ill.id IS NOT NULL) | |||
| $stockCategorySql | |||
| $stockSubCategorySql | |||
| $itemCodeSql | |||
| $yearSql | |||
| $lastOutDateStartSql | |||
| $lastOutDateEndSql | |||
| $handlerSql | |||
| ORDER BY | |||
| it.code, | |||
| il.lotNo, | |||
| sol.endTime | |||
| """.trimIndent() | |||
| val result = jdbcDao.queryForList(sql, args) | |||
| println("=== Material Stock Out Traceability (Total: ${result.size} rows) ===") | |||
| result.take(50).forEachIndexed { index, row -> | |||
| println("Row $index:") | |||
| println(" itemNo: ${row["itemNo"]}") | |||
| println(" itemName: ${row["itemName"]}") | |||
| println(" jobOrderNo: ${row["jobOrderNo"]}") | |||
| println(" stockOutQty: ${row["stockOutQty"]}") | |||
| println(" totalStockOutQty: ${row["totalStockOutQty"]}") | |||
| println(" materialPickOrderNo: ${row["materialPickOrderNo"]}") | |||
| println(" handler: ${row["handler"]}") | |||
| println(" storeLocation: ${row["storeLocation"]}") | |||
| println(" ---") | |||
| } | |||
| if (result.size > 50) { | |||
| println("... (showing first 50 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. | |||
| @@ -0,0 +1,76 @@ | |||
| package com.ffii.fpsms.modules.report.web | |||
| import com.ffii.fpsms.modules.report.service.MaterialStockOutTraceabilityReportService | |||
| import com.ffii.fpsms.modules.report.service.ReportService | |||
| import org.springframework.http.HttpHeaders | |||
| import org.springframework.http.HttpStatus | |||
| import org.springframework.http.MediaType | |||
| import org.springframework.http.ResponseEntity | |||
| import org.springframework.web.bind.annotation.GetMapping | |||
| import org.springframework.web.bind.annotation.RequestMapping | |||
| import org.springframework.web.bind.annotation.RequestParam | |||
| import org.springframework.web.bind.annotation.RestController | |||
| import java.time.LocalDate | |||
| import java.time.LocalTime | |||
| import java.time.format.DateTimeFormatter | |||
| @RestController | |||
| @RequestMapping("/report") | |||
| class MaterialStockOutTraceabilityReportController( | |||
| private val reportService: ReportService, | |||
| private val materialStockOutTraceabilityReportService: MaterialStockOutTraceabilityReportService, | |||
| ) { | |||
| @GetMapping("/material-stock-out-traceability-handlers") | |||
| fun getMaterialStockOutTraceabilityHandlers(): List<String> = | |||
| materialStockOutTraceabilityReportService.getDistinctHandlersForMaterialStockOutTraceability() | |||
| @GetMapping("/print-material-stock-out-traceability") | |||
| fun generateMaterialStockOutTraceabilityReport( | |||
| @RequestParam(required = false) stockCategory: String?, | |||
| @RequestParam(required = false) stockSubCategory: String?, | |||
| @RequestParam(required = false) itemCode: String?, | |||
| @RequestParam(required = false) year: String?, | |||
| @RequestParam(required = false) lastOutDateStart: String?, | |||
| @RequestParam(required = false) lastOutDateEnd: String?, | |||
| @RequestParam(required = false) handler: String?, | |||
| ): ResponseEntity<ByteArray> { | |||
| val parameters = mutableMapOf<String, Any>() | |||
| // 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["lastOutDateStart"] = lastOutDateStart ?: "" | |||
| parameters["lastOutDateEnd"] = lastOutDateEnd ?: "" | |||
| parameters["deliveryPeriodStart"] = "" | |||
| parameters["deliveryPeriodEnd"] = "" | |||
| val dbData = materialStockOutTraceabilityReportService.searchMaterialStockOutTraceabilityReport( | |||
| stockCategory, | |||
| stockSubCategory, | |||
| itemCode, | |||
| year, | |||
| lastOutDateStart, | |||
| lastOutDateEnd, | |||
| handler, | |||
| ) | |||
| val pdfBytes = reportService.createPdfResponse( | |||
| "/jasper/MaterialStockOutTraceability.jrxml", | |||
| parameters, | |||
| dbData, | |||
| ) | |||
| val headers = HttpHeaders().apply { | |||
| contentType = MediaType.APPLICATION_PDF | |||
| setContentDispositionFormData("attachment", "MaterialStockOutTraceabilityReport.pdf") | |||
| set("filename", "MaterialStockOutTraceabilityReport.pdf") | |||
| } | |||
| return ResponseEntity(pdfBytes, headers, HttpStatus.OK) | |||
| } | |||
| } | |||
| @@ -168,10 +168,6 @@ class ReportController( | |||
| fun getFGStockOutTraceabilityHandlers(): List<String> = | |||
| reportService.getDistinctHandlersForFGStockOutTraceability() | |||
| @GetMapping("/material-stock-out-traceability-handlers") | |||
| fun getMaterialStockOutTraceabilityHandlers(): List<String> = | |||
| reportService.getDistinctHandlersForMaterialStockOutTraceability() | |||
| @GetMapping("/print-fg-stock-out-traceability") | |||
| fun generateFGStockOutTraceabilityReport( | |||
| @RequestParam(required = false) stockCategory: String?, | |||
| @@ -220,54 +216,6 @@ class ReportController( | |||
| return ResponseEntity(pdfBytes, headers, HttpStatus.OK) | |||
| } | |||
| @GetMapping("/print-material-stock-out-traceability") | |||
| fun generateMaterialStockOutTraceabilityReport( | |||
| @RequestParam(required = false) stockCategory: String?, | |||
| @RequestParam(required = false) stockSubCategory: String?, | |||
| @RequestParam(required = false) itemCode: String?, | |||
| @RequestParam(required = false) year: String?, | |||
| @RequestParam(required = false) lastOutDateStart: String?, | |||
| @RequestParam(required = false) lastOutDateEnd: String?, | |||
| @RequestParam(required = false) handler: String? | |||
| ): ResponseEntity<ByteArray> { | |||
| val parameters = mutableMapOf<String, Any>() | |||
| // 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["lastOutDateStart"] = lastOutDateStart ?: "" | |||
| parameters["lastOutDateEnd"] = lastOutDateEnd ?: "" | |||
| parameters["deliveryPeriodStart"] = "" | |||
| parameters["deliveryPeriodEnd"] = "" | |||
| val dbData = reportService.searchMaterialStockOutTraceabilityReport( | |||
| stockCategory, | |||
| stockSubCategory, | |||
| itemCode, | |||
| year, | |||
| lastOutDateStart, | |||
| lastOutDateEnd, | |||
| handler | |||
| ) | |||
| val pdfBytes = reportService.createPdfResponse( | |||
| "/jasper/MaterialStockOutTraceability.jrxml", | |||
| parameters, | |||
| dbData | |||
| ) | |||
| val headers = HttpHeaders().apply { | |||
| contentType = MediaType.APPLICATION_PDF | |||
| setContentDispositionFormData("attachment", "MaterialStockOutTraceabilityReport.pdf") | |||
| set("filename", "MaterialStockOutTraceabilityReport.pdf") | |||
| } | |||
| return ResponseEntity(pdfBytes, headers, HttpStatus.OK) | |||
| } | |||
| @GetMapping("/print-stock-balance") | |||
| fun generateStockBalanceReport( | |||
| @RequestParam(required = false) stockCategory: String?, | |||