From 9dd08d6a7030211f558795b4c1b676ec0f7938f7 Mon Sep 17 00:00:00 2001 From: "CANCERYS\\kw093" Date: Wed, 13 May 2026 23:00:12 +0800 Subject: [PATCH] update Report and stock ledger search --- .../FGStockOutTraceabilityReportService.kt | 70 +++++++++++-------- .../modules/report/service/ReportService.kt | 65 +++++++++-------- .../stock/entity/StockLedgerRepository.kt | 25 +++---- .../stock/service/StockTakeRecordService.kt | 53 +++++--------- .../stock/web/StockTakeRecordController.kt | 15 +++- 5 files changed, 123 insertions(+), 105 deletions(-) diff --git a/src/main/java/com/ffii/fpsms/modules/report/service/FGStockOutTraceabilityReportService.kt b/src/main/java/com/ffii/fpsms/modules/report/service/FGStockOutTraceabilityReportService.kt index 7c0857e..10e625e 100644 --- a/src/main/java/com/ffii/fpsms/modules/report/service/FGStockOutTraceabilityReportService.kt +++ b/src/main/java/com/ffii/fpsms/modules/report/service/FGStockOutTraceabilityReportService.kt @@ -9,13 +9,23 @@ class FGStockOutTraceabilityReportService( ) { fun getDistinctHandlersForFGStockOutTraceability(): List { val sql = """ - SELECT DISTINCT COALESCE(picker_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 = 'do' - LEFT JOIN user picker_user ON sol.handled_by = picker_user.id AND picker_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 + SELECT DISTINCT h.handler + FROM ( + SELECT TRIM(COALESCE(picker_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 = 'do' + LEFT JOIN user picker_user ON sol.handled_by = picker_user.id AND picker_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 + UNION + SELECT TRIM(IFNULL(handlerName, '')) AS handler + FROM delivery_order_pick_order + WHERE deleted = 0 + AND ticketStatus = 'completed' + AND IFNULL(handlerName, '') <> '' + ) h + WHERE TRIM(IFNULL(h.handler, '')) <> '' + ORDER BY h.handler """.trimIndent() return jdbcDao @@ -54,7 +64,7 @@ class FGStockOutTraceabilityReportService( val yearSql = if (!year.isNullOrBlank()) { args["year"] = year - "AND YEAR(IFNULL(dpor.RequiredDeliveryDate, do.estimatedArrivalDate)) = :year" + "AND YEAR(IFNULL(dopo.requiredDeliveryDate, do.estimatedArrivalDate)) = :year" } else { "" } @@ -62,7 +72,7 @@ class FGStockOutTraceabilityReportService( val lastOutDateStartSql = if (!lastOutDateStart.isNullOrBlank()) { val formattedDate = lastOutDateStart.replace("/", "-") args["lastOutDateStart"] = formattedDate - "AND DATE(IFNULL(dpor.RequiredDeliveryDate, do.estimatedArrivalDate)) >= DATE(:lastOutDateStart)" + "AND DATE(IFNULL(dopo.requiredDeliveryDate, do.estimatedArrivalDate)) >= DATE(:lastOutDateStart)" } else { "" } @@ -70,14 +80,14 @@ class FGStockOutTraceabilityReportService( val lastOutDateEndSql = if (!lastOutDateEnd.isNullOrBlank()) { val formattedDate = lastOutDateEnd.replace("/", "-") args["lastOutDateEnd"] = formattedDate - "AND DATE(IFNULL(dpor.RequiredDeliveryDate, do.estimatedArrivalDate)) <= DATE(:lastOutDateEnd)" + "AND DATE(IFNULL(dopo.requiredDeliveryDate, do.estimatedArrivalDate)) <= DATE(:lastOutDateEnd)" } else { "" } val handlerSql = buildMultiValueExactClause( handler, - "COALESCE(picker_user.name, modified_user.name, '')", + "COALESCE(picker_user.name, modified_user.name, IFNULL(dopo.handlerName, ''))", "handler", args, ) @@ -85,13 +95,13 @@ class FGStockOutTraceabilityReportService( val sql = """ SELECT IFNULL(DATE_FORMAT( - IFNULL(dpor.RequiredDeliveryDate, do.estimatedArrivalDate), + IFNULL(dopo.requiredDeliveryDate, do.estimatedArrivalDate), '%Y-%m-%d' ), '') AS deliveryDate, IFNULL(it.code, '') AS itemNo, IFNULL(it.name, '') AS itemName, IFNULL(uc.udfudesc, '') AS unitOfMeasure, - IFNULL(dpor.deliveryNoteCode, '') AS dnNo, + IFNULL(dopo.deliveryNoteCode, '') AS dnNo, CAST(IFNULL(sp.id, 0) AS CHAR) AS customerId, IFNULL(sp.name, '') AS customerName, FORMAT( @@ -109,11 +119,13 @@ class FGStockOutTraceabilityReportService( COALESCE( picker_user.name, modified_user.name, + dopo.handlerName, '' ) AS handler, COALESCE( picker_user.name, modified_user.name, + dopo.handlerName, '' ) AS pickedBy, GROUP_CONCAT(DISTINCT wh.code ORDER BY wh.code SEPARATOR ', ') AS storeLocation, @@ -122,19 +134,22 @@ class FGStockOutTraceabilityReportService( ROUND(SUM(IFNULL(sol.qty, 0)) OVER (PARTITION BY it.code), 0), 0 ) AS totalStockOutQty, 0 AS stockSubCategory - FROM do_pick_order_line_record dpolr - LEFT JOIN do_pick_order_record dpor - ON dpolr.record_id = dpor.id - AND dpor.deleted = 0 - AND dpor.ticket_status = 'completed' + FROM delivery_order_pick_order dopo + INNER JOIN pick_order po + ON po.deliveryOrderPickOrderId = dopo.id + AND po.deleted = 0 INNER JOIN delivery_order do - ON dpolr.do_order_id = do.id + ON po.doId = do.id AND do.deleted = 0 LEFT JOIN shop sp ON do.shopId = sp.id AND sp.deleted = 0 + LEFT JOIN pick_order_line pol + ON pol.poId = po.id + AND pol.deleted = 0 LEFT JOIN delivery_order_line dol - ON do.id = dol.deliveryOrderId + ON dol.deliveryOrderId = do.id + AND dol.itemId = pol.itemId AND dol.deleted = 0 LEFT JOIN items it ON dol.itemId = it.id @@ -144,13 +159,6 @@ class FGStockOutTraceabilityReportService( 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 pick_order po - ON pol.poId = po.id - AND po.deleted = 0 LEFT JOIN stock_out_line sol ON pol.id = sol.pickOrderLineId AND sol.itemId = it.id @@ -176,7 +184,8 @@ class FGStockOutTraceabilityReportService( AND modified_user.deleted = 0 AND sol.handled_by IS NULL WHERE - dpolr.deleted = 0 + dopo.deleted = 0 + AND dopo.ticketStatus = 'completed' $stockCategorySql $stockSubCategorySql $itemCodeSql @@ -186,12 +195,13 @@ class FGStockOutTraceabilityReportService( $handlerSql GROUP BY sol.id, - dpor.RequiredDeliveryDate, + dopo.requiredDeliveryDate, + dopo.handlerName, do.estimatedArrivalDate, it.code, it.name, uc.udfudesc, - dpor.deliveryNoteCode, + dopo.deliveryNoteCode, sp.id, sp.name, sol.qty, 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 ffac33c..67fec79 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 @@ -101,7 +101,7 @@ open class ReportService( val yearSql = if (!year.isNullOrBlank()) { args["year"] = year - "AND YEAR(IFNULL(dpor.RequiredDeliveryDate, do.estimatedArrivalDate)) = :year" + "AND YEAR(IFNULL(dopo.requiredDeliveryDate, do.estimatedArrivalDate)) = :year" } else { "" } @@ -109,25 +109,25 @@ open class ReportService( val lastOutDateStartSql = if (!lastOutDateStart.isNullOrBlank()) { val formattedDate = lastOutDateStart.replace("/", "-") args["lastOutDateStart"] = formattedDate - "AND DATE(IFNULL(dpor.RequiredDeliveryDate, do.estimatedArrivalDate)) >= DATE(:lastOutDateStart)" + "AND DATE(IFNULL(dopo.requiredDeliveryDate, do.estimatedArrivalDate)) >= DATE(:lastOutDateStart)" } else "" val lastOutDateEndSql = if (!lastOutDateEnd.isNullOrBlank()) { val formattedDate = lastOutDateEnd.replace("/", "-") args["lastOutDateEnd"] = formattedDate - "AND DATE(IFNULL(dpor.RequiredDeliveryDate, do.estimatedArrivalDate)) <= DATE(:lastOutDateEnd)" + "AND DATE(IFNULL(dopo.requiredDeliveryDate, do.estimatedArrivalDate)) <= DATE(:lastOutDateEnd)" } else "" val sql = """ SELECT IFNULL(DATE_FORMAT( - IFNULL(dpor.RequiredDeliveryDate, do.estimatedArrivalDate), + IFNULL(dopo.requiredDeliveryDate, do.estimatedArrivalDate), '%Y-%m-%d' ), '') AS deliveryDate, IFNULL(it.code, '') AS itemNo, IFNULL(it.name, '') AS itemName, IFNULL(uc.udfudesc, '') AS unitOfMeasure, - IFNULL(dpor.deliveryNoteCode, '') AS dnNo, + IFNULL(dopo.deliveryNoteCode, '') AS dnNo, CAST(IFNULL(sp.id, 0) AS CHAR) AS customerId, IFNULL(sp.name, '') AS customerName, CAST( @@ -138,7 +138,7 @@ open class ReportService( FORMAT(ROUND(IFNULL(IFNULL(sol.qty, dol.qty), 0), 0), 0) AS qty, COALESCE( - dpor.TruckLanceCode, + dopo.truckLanceCode, (SELECT t2.TruckLanceCode FROM truck t2 WHERE t2.shopId = do.shopId @@ -157,9 +157,9 @@ FORMAT(ROUND(IFNULL(IFNULL(sol.qty, dol.qty), 0), 0), 0) AS qty, 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 IFNULL(dopo.requiredDeliveryDate, do.estimatedArrivalDate) IS NOT NULL AND t2.TruckLanceCode LIKE CONCAT('%', - CASE DAYNAME(IFNULL(dpor.RequiredDeliveryDate, do.estimatedArrivalDate)) + CASE DAYNAME(IFNULL(dopo.requiredDeliveryDate, do.estimatedArrivalDate)) WHEN 'Monday' THEN 'Mon' WHEN 'Tuesday' THEN 'Tue' WHEN 'Wednesday' THEN 'Wed' @@ -183,13 +183,12 @@ FORMAT(ROUND(IFNULL(IFNULL(sol.qty, dol.qty), 0), 0), 0) AS qty, '' 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.record_id - AND dpor.deleted = 0 - AND dpor.ticket_status = 'completed' + FROM delivery_order_pick_order dopo + INNER JOIN pick_order po + ON po.deliveryOrderPickOrderId = dopo.id + AND po.deleted = 0 INNER JOIN delivery_order do - ON dpolr.do_order_id = do.id + ON po.doId = do.id AND do.deleted = 0 LEFT JOIN shop supplier ON do.supplierId = supplier.id @@ -197,8 +196,12 @@ FORMAT(ROUND(IFNULL(IFNULL(sol.qty, dol.qty), 0), 0), 0) AS qty, LEFT JOIN shop sp ON do.shopId = sp.id AND sp.deleted = 0 + LEFT JOIN pick_order_line pol + ON pol.poId = po.id + AND pol.deleted = 0 LEFT JOIN delivery_order_line dol - ON do.id = dol.deliveryOrderId + ON dol.deliveryOrderId = do.id + AND dol.itemId = pol.itemId AND dol.deleted = 0 LEFT JOIN items it ON dol.itemId = it.id @@ -215,10 +218,6 @@ FORMAT(ROUND(IFNULL(IFNULL(sol.qty, dol.qty), 0), 0), 0) AS qty, 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 @@ -234,8 +233,8 @@ FORMAT(ROUND(IFNULL(IFNULL(sol.qty, dol.qty), 0), 0), 0) AS qty, ON il.stockInLineId = sil.id AND sil.deleted = 0 WHERE - dpolr.deleted = 0 - AND (dpor.id IS NULL OR dpor.ticket_status = 'completed') + dopo.deleted = 0 + AND dopo.ticketStatus = 'completed' AND COALESCE(sol.qty, dol.qty, 0) <> 0 $stockCategorySql $stockSubCategorySql @@ -258,13 +257,23 @@ return result fun getDistinctHandlersForFGStockOutTraceability(): List { val sql = """ - SELECT DISTINCT COALESCE(picker_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 = 'do' - LEFT JOIN user picker_user ON sol.handled_by = picker_user.id AND picker_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 + SELECT DISTINCT h.handler + FROM ( + SELECT TRIM(COALESCE(picker_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 = 'do' + LEFT JOIN user picker_user ON sol.handled_by = picker_user.id AND picker_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 + UNION + SELECT TRIM(IFNULL(handlerName, '')) AS handler + FROM delivery_order_pick_order + WHERE deleted = 0 + AND ticketStatus = 'completed' + AND IFNULL(handlerName, '') <> '' + ) h + WHERE TRIM(IFNULL(h.handler, '')) <> '' + ORDER BY h.handler """.trimIndent() return jdbcDao.queryForList(sql, emptyMap()).map { row -> (row["handler"]?.toString() ?: "").trim() }.filter { it.isNotBlank() } } diff --git a/src/main/java/com/ffii/fpsms/modules/stock/entity/StockLedgerRepository.kt b/src/main/java/com/ffii/fpsms/modules/stock/entity/StockLedgerRepository.kt index 9ac5eac..1a9858a 100644 --- a/src/main/java/com/ffii/fpsms/modules/stock/entity/StockLedgerRepository.kt +++ b/src/main/java/com/ffii/fpsms/modules/stock/entity/StockLedgerRepository.kt @@ -1,11 +1,12 @@ package com.ffii.fpsms.modules.stock.entity import com.ffii.core.support.AbstractRepository +import org.springframework.data.domain.Page +import org.springframework.data.domain.Pageable import org.springframework.data.jpa.repository.Query import org.springframework.data.repository.query.Param import org.springframework.stereotype.Repository -import java.time.LocalDate -import java.util.Optional +import java.time.LocalDateTime @Repository interface StockLedgerRepository: AbstractRepository { @@ -19,17 +20,17 @@ interface StockLedgerRepository: AbstractRepository { AND (:itemCode IS NULL OR sl.itemCode LIKE CONCAT('%', :itemCode, '%')) AND (:itemName IS NULL OR i.name LIKE CONCAT('%', :itemName, '%')) AND (:type IS NULL OR sl.type = :type) - AND (:startDate IS NULL OR DATE(sl.created) >= :startDate) - AND (:endDate IS NULL OR DATE(sl.created) <= :endDate) - ORDER BY sl.created ASC, sl.itemId + AND (:startDateTime IS NULL OR sl.created >= :startDateTime) + AND (:endDateExclusive IS NULL OR sl.created < :endDateExclusive) """) fun findStockTransactions( @Param("itemCode") itemCode: String?, @Param("itemName") itemName: String?, @Param("type") type: String?, - @Param("startDate") startDate: LocalDate?, - @Param("endDate") endDate: LocalDate? - ): List + @Param("startDateTime") startDateTime: LocalDateTime?, + @Param("endDateExclusive") endDateExclusive: LocalDateTime?, + pageable: Pageable + ): Page @Query(""" SELECT COUNT(sl) FROM StockLedger sl @@ -39,15 +40,15 @@ interface StockLedgerRepository: AbstractRepository { AND (:itemCode IS NULL OR sl.itemCode LIKE CONCAT('%', :itemCode, '%')) AND (:itemName IS NULL OR i.name LIKE CONCAT('%', :itemName, '%')) AND (:type IS NULL OR sl.type = :type) - AND (:startDate IS NULL OR DATE(sl.created) >= :startDate) - AND (:endDate IS NULL OR DATE(sl.created) <= :endDate) + AND (:startDateTime IS NULL OR sl.created >= :startDateTime) + AND (:endDateExclusive IS NULL OR sl.created < :endDateExclusive) """) fun countStockTransactions( @Param("itemCode") itemCode: String?, @Param("itemName") itemName: String?, @Param("type") type: String?, - @Param("startDate") startDate: LocalDate?, - @Param("endDate") endDate: LocalDate? + @Param("startDateTime") startDateTime: LocalDateTime?, + @Param("endDateExclusive") endDateExclusive: LocalDateTime? ): Long diff --git a/src/main/java/com/ffii/fpsms/modules/stock/service/StockTakeRecordService.kt b/src/main/java/com/ffii/fpsms/modules/stock/service/StockTakeRecordService.kt index b15337b..812c325 100644 --- a/src/main/java/com/ffii/fpsms/modules/stock/service/StockTakeRecordService.kt +++ b/src/main/java/com/ffii/fpsms/modules/stock/service/StockTakeRecordService.kt @@ -16,6 +16,7 @@ import java.time.LocalDateTime import java.math.BigDecimal import com.ffii.fpsms.modules.user.entity.UserRepository import org.springframework.data.domain.PageRequest +import org.springframework.data.domain.Sort import com.ffii.core.response.RecordsRes import com.ffii.fpsms.modules.stock.service.InventoryLotLineService import com.ffii.fpsms.modules.stock.entity.StockTakeLine @@ -2741,40 +2742,32 @@ open fun searchStockTransactions(request: SearchStockTransactionRequest): Record return RecordsRes(emptyList(), 0) } - val startDate = request.startDate - val endDate = request.endDate + val startDateTime = request.startDate?.atStartOfDay() + val endDateExclusive = request.endDate?.plusDays(1)?.atStartOfDay() - println("Processed params: itemCode=$itemCode, itemName=$itemName, startDate=$startDate, endDate=$endDate") - - val total = stockLedgerRepository.countStockTransactions( - itemCode = itemCode, - itemName = itemName, - type = request.type, - startDate = startDate, - endDate = endDate + println( + "Processed params: itemCode=$itemCode, itemName=$itemName, " + + "startDateTime=$startDateTime, endDateExclusive=$endDateExclusive" ) - println("Total count: $total") - - val actualPageSize = if (request.pageSize == 100) { - total.toInt().coerceAtLeast(1) - } else { - request.pageSize - } - - val offset = request.pageNum * actualPageSize + val pageable = PageRequest.of( + request.pageNum.coerceAtLeast(0), + request.pageSize.coerceAtLeast(1), + Sort.by(Sort.Order.asc("created"), Sort.Order.asc("itemId")) + ) - val ledgers = stockLedgerRepository.findStockTransactions( + val ledgerPage = stockLedgerRepository.findStockTransactions( itemCode = itemCode, itemName = itemName, type = request.type, - startDate = startDate, - endDate = endDate + startDateTime = startDateTime, + endDateExclusive = endDateExclusive, + pageable = pageable ) - println("Found ${ledgers.size} ledgers") + println("Found ${ledgerPage.numberOfElements} ledgers in current page, total=${ledgerPage.totalElements}") - val transactions = ledgers.map { ledger -> + val transactions = ledgerPage.content.map { ledger -> val stockInLine = ledger.stockInLine val stockOutLine = ledger.stockOutLine @@ -2805,17 +2798,9 @@ open fun searchStockTransactions(request: SearchStockTransactionRequest): Record ) } - val sortedTransactions = transactions.sortedWith( - compareBy( - { it.date ?: it.transactionDate?.toLocalDate() }, - { it.transactionDate } - ) - ) - - val paginatedTransactions = sortedTransactions.drop(offset).take(actualPageSize) val totalTime = System.currentTimeMillis() - startTime - println("Total time (Repository query): ${totalTime}ms, count: ${paginatedTransactions.size}, total: $total") + println("Total time (Repository query): ${totalTime}ms, count: ${transactions.size}, total: ${ledgerPage.totalElements}") - return RecordsRes(paginatedTransactions, total.toInt()) + return RecordsRes(transactions, ledgerPage.totalElements.toInt()) } } diff --git a/src/main/java/com/ffii/fpsms/modules/stock/web/StockTakeRecordController.kt b/src/main/java/com/ffii/fpsms/modules/stock/web/StockTakeRecordController.kt index 806d3e4..6931ea9 100644 --- a/src/main/java/com/ffii/fpsms/modules/stock/web/StockTakeRecordController.kt +++ b/src/main/java/com/ffii/fpsms/modules/stock/web/StockTakeRecordController.kt @@ -32,7 +32,8 @@ class StockTakeRecordController( @RequestParam(required = false) stockTakeSections: String?, @RequestParam(required = false) status: String?, @RequestParam(required = false) area: String?, - @RequestParam(required = false) storeId: String? + @RequestParam(required = false) storeId: String?, + @RequestParam(required = false, defaultValue = "false") onlyLatestRound: Boolean ): RecordsRes { var all = stockOutRecordService.AllPickedStockTakeList() if (sectionDescription != null && sectionDescription != "All") { @@ -71,6 +72,18 @@ class StockTakeRecordController( it.storeId?.contains(storeIdKeyword, ignoreCase = true) == true } } + if (onlyLatestRound) { + val latestRoundKey = all + .mapNotNull { item -> + item.stockTakeRoundId ?: item.stockTakeId.takeIf { it > 0 } + } + .maxOrNull() + all = if (latestRoundKey == null) { + emptyList() + } else { + all.filter { (it.stockTakeRoundId ?: it.stockTakeId) == latestRoundKey } + } + } val total = all.size val fromIndex = pageNum * pageSize val toIndex = minOf(fromIndex + pageSize, total)