From a58bea58e7054040ea442e921c1ed24a06268c82 Mon Sep 17 00:00:00 2001 From: "Tommy\\2Fi-Staff" Date: Sun, 18 Jan 2026 17:45:40 +0800 Subject: [PATCH] add mapping to itemqccategorymapping, update FG pick status dashboard --- .../fpsms/m18/service/M18MasterDataService.kt | 6 ++-- .../fpsms/modules/bag/service/bagService.kt | 28 +++++++++++++++++ .../fpsms/modules/bag/web/bagController.kt | 4 +++ .../service/DoPickOrderService.kt | 16 +++++----- .../web/DoPickOrderController.kt | 6 ++-- .../ItemsQcCategoryMappingRepository.kt | 4 +++ .../modules/master/service/ItemsService.kt | 15 ++++++++++ .../master/service/QcCategoryService.kt | 7 +++++ .../master/web/QcCategoryController.kt | 6 ++++ .../master/web/models/NewItemRequest.kt | 1 + .../qc/entity/projection/QcCategoryInfo.kt | 2 +- .../modules/report/service/ReportService.kt | 30 +++++++++++++++++++ .../modules/report/web/ReportController.kt | 16 +++++----- 13 files changed, 119 insertions(+), 22 deletions(-) diff --git a/src/main/java/com/ffii/fpsms/m18/service/M18MasterDataService.kt b/src/main/java/com/ffii/fpsms/m18/service/M18MasterDataService.kt index b1a5798..e7c3144 100644 --- a/src/main/java/com/ffii/fpsms/m18/service/M18MasterDataService.kt +++ b/src/main/java/com/ffii/fpsms/m18/service/M18MasterDataService.kt @@ -173,7 +173,8 @@ open class M18MasterDataService( LocationCode = null, isEgg = null, isFee = null, - isBag = null + isBag = null, + qcType = null ) val savedItem = itemsService.saveItem(saveItemRequest) @@ -276,7 +277,8 @@ open class M18MasterDataService( LocationCode = null, isEgg = null, isFee = null, - isBag = null + isBag = null, + qcType = null ) val savedItem = itemsService.saveItem(saveItemRequest) diff --git a/src/main/java/com/ffii/fpsms/modules/bag/service/bagService.kt b/src/main/java/com/ffii/fpsms/modules/bag/service/bagService.kt index d467a01..4ae1cc6 100644 --- a/src/main/java/com/ffii/fpsms/modules/bag/service/bagService.kt +++ b/src/main/java/com/ffii/fpsms/modules/bag/service/bagService.kt @@ -240,4 +240,32 @@ open fun getBagConsumptions(bagLotLineId: Long): List { ) } } + +open fun softDeleteBagByItemId(itemId: Long): MessageResponse { + val bag = bagRepository.findByItemIdAndDeletedIsFalse(itemId) + if (bag == null) { + return MessageResponse( + id = null, + code = null, + name = null, + type = null, + message = "No bag found for itemId: $itemId", + errorPosition = null, + entity = null, + ) + } + + bag.deleted = true + bagRepository.save(bag) + + return MessageResponse( + id = bag.id, + code = null, + name = null, + type = null, + message = "Bag soft-deleted successfully", + errorPosition = null, + entity = null, + ) +} } \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/modules/bag/web/bagController.kt b/src/main/java/com/ffii/fpsms/modules/bag/web/bagController.kt index 13b2698..a992be7 100644 --- a/src/main/java/com/ffii/fpsms/modules/bag/web/bagController.kt +++ b/src/main/java/com/ffii/fpsms/modules/bag/web/bagController.kt @@ -62,4 +62,8 @@ class BagController( @GetMapping("/lot-lines/{bagLotLineId}/consumptions") fun getBagConsumptions(@PathVariable bagLotLineId: Long): List = bagService.getBagConsumptions(bagLotLineId) + + @PutMapping("/by-item/{itemId}/soft-delete") + fun softDeleteBagByItemId(@PathVariable itemId: Long): MessageResponse = + bagService.softDeleteBagByItemId(itemId) } \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoPickOrderService.kt b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoPickOrderService.kt index be23065..4e016df 100644 --- a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoPickOrderService.kt +++ b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoPickOrderService.kt @@ -754,21 +754,19 @@ open class DoPickOrderService( * Get truck schedule dashboard data aggregated by store, truck lane, and departure time. * Groups DoPickOrder and DoPickOrderRecord data to provide summary statistics. */ - open fun getTruckScheduleDashboard(): List { - val today = LocalDate.now() - - // Fetch all active DoPickOrders for today + open fun getTruckScheduleDashboard(targetDate: LocalDate): List { + // Fetch all active DoPickOrders for the target date val doPickOrders = doPickOrderRepository.findByStoreIdAndRequiredDeliveryDateAndTicketStatusIn( - "2/F", today, listOf(DoPickOrderStatus.pending, DoPickOrderStatus.released, DoPickOrderStatus.completed) + "2/F", targetDate, listOf(DoPickOrderStatus.pending, DoPickOrderStatus.released, DoPickOrderStatus.completed) ) + doPickOrderRepository.findByStoreIdAndRequiredDeliveryDateAndTicketStatusIn( - "4/F", today, listOf(DoPickOrderStatus.pending, DoPickOrderStatus.released, DoPickOrderStatus.completed) + "4/F", targetDate, listOf(DoPickOrderStatus.pending, DoPickOrderStatus.released, DoPickOrderStatus.completed) ) - // Fetch all DoPickOrderRecords for today (completed records) + // Fetch all DoPickOrderRecords for the target date (completed records) val doPickOrderRecords = doPickOrderRecordRepository.findByStoreIdAndRequiredDeliveryDateAndTicketStatusIn( - "2/F", today, listOf(DoPickOrderStatus.completed) + "2/F", targetDate, listOf(DoPickOrderStatus.completed) ) + doPickOrderRecordRepository.findByStoreIdAndRequiredDeliveryDateAndTicketStatusIn( - "4/F", today, listOf(DoPickOrderStatus.completed) + "4/F", targetDate, listOf(DoPickOrderStatus.completed) ) // Combine both types into a unified data structure for aggregation diff --git a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/web/DoPickOrderController.kt b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/web/DoPickOrderController.kt index 710b09b..9d58b48 100644 --- a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/web/DoPickOrderController.kt +++ b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/web/DoPickOrderController.kt @@ -105,8 +105,10 @@ class DoPickOrderController( } @GetMapping("/truck-schedule-dashboard") - fun getTruckScheduleDashboard(): List { - return doPickOrderService.getTruckScheduleDashboard() + fun getTruckScheduleDashboard( + @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) date: LocalDate? + ): List { + return doPickOrderService.getTruckScheduleDashboard(date ?: LocalDate.now()) } } \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/modules/master/entity/ItemsQcCategoryMappingRepository.kt b/src/main/java/com/ffii/fpsms/modules/master/entity/ItemsQcCategoryMappingRepository.kt index 5b8fc02..7b9193a 100644 --- a/src/main/java/com/ffii/fpsms/modules/master/entity/ItemsQcCategoryMappingRepository.kt +++ b/src/main/java/com/ffii/fpsms/modules/master/entity/ItemsQcCategoryMappingRepository.kt @@ -22,6 +22,10 @@ interface ItemsQcCategoryMappingRepository : AbstractRepository + + fun findByItemIdAndType(itemId: Long, type: String): ItemsQcCategoryMapping? + fun findByItemId(itemId: Long): List + fun findFirstByItemId(itemId: Long): ItemsQcCategoryMapping? } diff --git a/src/main/java/com/ffii/fpsms/modules/master/service/ItemsService.kt b/src/main/java/com/ffii/fpsms/modules/master/service/ItemsService.kt index 337c6c9..1de1c80 100644 --- a/src/main/java/com/ffii/fpsms/modules/master/service/ItemsService.kt +++ b/src/main/java/com/ffii/fpsms/modules/master/service/ItemsService.kt @@ -66,6 +66,7 @@ open class ItemsService( private val inventoryLotLineRepository: InventoryLotLineRepository, private val inventoryLotRepository: InventoryLotRepository, private val bagRepository: BagRepository, + private val itemsQcCategoryMappingRepository: ItemsQcCategoryMappingRepository, ): AbstractBaseEntityService(jdbcDao, itemsRepository) { private val excelImportPath: String = System.getProperty("user.home") + "/Downloads/StockTakeImport/" @@ -555,6 +556,20 @@ open class ItemsService( } } + // Save QC category mapping if qcType and qcCategoryId are provided + if (request.qcType != null && request.qcCategoryId != null && savedItem.id != null) { + // Find existing mapping by itemId only (update existing record for this item) + val existingMapping = itemsQcCategoryMappingRepository.findFirstByItemId(savedItem.id!!) + val mapping = existingMapping ?: ItemsQcCategoryMapping() + mapping.apply { + itemId = savedItem.id + qcCategoryId = request.qcCategoryId + type = request.qcType + } + itemsQcCategoryMappingRepository.save(mapping) + logger.info("Saved QC category mapping for item: ${savedItem.code} (ID: ${savedItem.id}), type: ${request.qcType}") + } + return MessageResponse( id = savedItem.id, name = savedItem.name, diff --git a/src/main/java/com/ffii/fpsms/modules/master/service/QcCategoryService.kt b/src/main/java/com/ffii/fpsms/modules/master/service/QcCategoryService.kt index 2fc4197..5c5ce8f 100644 --- a/src/main/java/com/ffii/fpsms/modules/master/service/QcCategoryService.kt +++ b/src/main/java/com/ffii/fpsms/modules/master/service/QcCategoryService.kt @@ -4,10 +4,12 @@ import com.ffii.core.support.AbstractBaseEntityService import com.ffii.fpsms.modules.master.entity.QcCategory import com.ffii.fpsms.modules.master.entity.QcCategoryRepository import com.ffii.fpsms.modules.master.entity.QcItem +import com.ffii.fpsms.modules.master.entity.QcItemCategoryRepository import com.ffii.fpsms.modules.master.entity.projections.QcCategoryCombo import com.ffii.fpsms.modules.master.web.models.SaveQcCategoryRequest import com.ffii.fpsms.modules.master.web.models.SaveQcCategoryResponse import com.ffii.fpsms.modules.qc.entity.projection.QcCategoryInfo +import com.ffii.fpsms.modules.qc.entity.projection.QcItemInfo import jakarta.validation.Valid import org.springframework.stereotype.Service import org.springframework.web.bind.annotation.RequestBody @@ -15,6 +17,7 @@ import org.springframework.web.bind.annotation.RequestBody @Service open class QcCategoryService( private val qcCategoryRepository: QcCategoryRepository, + private val qcItemCategoryRepository: QcItemCategoryRepository, private val itemsService: ItemsService ) { open fun allQcCategories(): List { @@ -29,6 +32,10 @@ open class QcCategoryService( return qcCategoryRepository.findQcCategoryComboByDeletedIsFalse(); } + open fun getQcItemsByCategoryId(categoryId: Long): List { + return qcItemCategoryRepository.findAllByQcCategoryId(categoryId) + } + open fun getQcCategoryInfoByMapping(itemId : Long, type: String): QcCategoryInfo? { var result = qcCategoryRepository.findQcCategoryInfoByItemIdAndType(itemId, type) if (result == null) { // Temporarily fix for missing QC template (Auto find template from similar items) diff --git a/src/main/java/com/ffii/fpsms/modules/master/web/QcCategoryController.kt b/src/main/java/com/ffii/fpsms/modules/master/web/QcCategoryController.kt index 9cc43f1..8367770 100644 --- a/src/main/java/com/ffii/fpsms/modules/master/web/QcCategoryController.kt +++ b/src/main/java/com/ffii/fpsms/modules/master/web/QcCategoryController.kt @@ -8,6 +8,7 @@ import com.ffii.fpsms.modules.master.service.QcCategoryService import com.ffii.fpsms.modules.master.web.models.SaveQcCategoryRequest import com.ffii.fpsms.modules.master.web.models.SaveQcCategoryResponse import com.ffii.fpsms.modules.qc.entity.projection.QcCategoryInfo +import com.ffii.fpsms.modules.qc.entity.projection.QcItemInfo import jakarta.validation.Valid import org.springframework.web.bind.annotation.* @@ -41,6 +42,11 @@ class QcCategoryController( return qcCategoryService.getQcCategoryCombo(); } + @GetMapping("/{id}/items") + fun getQcItemsByCategoryId(@PathVariable id: Long): List { + return qcCategoryService.getQcItemsByCategoryId(id) + } + @GetMapping("/items") fun getQcCategoryByTemplate(@RequestParam itemId: Long, @RequestParam(defaultValue = "IQC") type: String): QcCategoryInfo { return qcCategoryService.getQcCategoryInfoByMapping(itemId, type) ?: throw NotFoundException() diff --git a/src/main/java/com/ffii/fpsms/modules/master/web/models/NewItemRequest.kt b/src/main/java/com/ffii/fpsms/modules/master/web/models/NewItemRequest.kt index bef2536..59aec0e 100644 --- a/src/main/java/com/ffii/fpsms/modules/master/web/models/NewItemRequest.kt +++ b/src/main/java/com/ffii/fpsms/modules/master/web/models/NewItemRequest.kt @@ -53,6 +53,7 @@ data class NewItemRequest( val isEgg: Boolean?, val isFee: Boolean?, val isBag: Boolean?, + val qcType: String?, // val type: List?, // val uom: List?, // val weightUnit: List?, diff --git a/src/main/java/com/ffii/fpsms/modules/qc/entity/projection/QcCategoryInfo.kt b/src/main/java/com/ffii/fpsms/modules/qc/entity/projection/QcCategoryInfo.kt index 8b6513d..f0abd3a 100644 --- a/src/main/java/com/ffii/fpsms/modules/qc/entity/projection/QcCategoryInfo.kt +++ b/src/main/java/com/ffii/fpsms/modules/qc/entity/projection/QcCategoryInfo.kt @@ -21,6 +21,6 @@ interface QcItemInfo { val code: String @get:Value("#{target.qcItem.name}") val name: String? - @get:Value("#{target.qcItem.description}") + // Use description from qc_item_category table (category-specific description) val description: String? } \ No newline at end of file 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 01387b7..74b8ca6 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 @@ -43,6 +43,36 @@ open class ReportService( return jdbcDao.queryForList(sql, args) } + + fun searchReport3( itemType: String?): List> { + val args = mutableMapOf( + + ) + + val itemTypeSql = if (!itemType.isNullOrBlank()) { + args["itemType"] = "%$itemType%" + "AND it.type LIKE :itemType" + } else "" + + val sql = """ + SELECT + -- fake value for demo + 8.8 * iv.onHandQty as stockValue, + iv.onHandQty, + it.code as itemCode, + it.name as itemName, + uc.code as uom, + it.type, iv.status + FROM inventory iv + LEFT JOIN items it ON iv.itemId = it.id + LEFT JOIN uom_conversion uc ON iv.uomId = uc.id + WHERE iv.created >= :fromDate AND iv.created < :toDate + $itemTypeSql + """.trimIndent() + + return jdbcDao.queryForList(sql, args) + } + /** * Compiles and fills a Jasper Report, returning the PDF as a ByteArray. */ 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 832a274..82ed31f 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 @@ -47,23 +47,23 @@ class ReportController( @GetMapping("/print-report3") fun generateReport3( - @RequestParam fromDate: String, - @RequestParam toDate: String, + //@RequestParam fromDate: String, + // @RequestParam toDate: String, //this is an exampe of optional param @RequestParam(required = false) itemType: String? ): ResponseEntity { val parameters = mutableMapOf() - parameters["fromDate"] = fromDate - parameters["toDate"] = toDate + //parameters["lastInDateStart"] = fromDate + //parameters["lastInDateEnd"] = toDate // you may put more params to show - parameters["reportDate"] = "param1Value" - parameters["param2"] = "param2Value" + parameters["lastOutDateStart"] = "param1Value" + parameters["lastOutDateEnd"] = "param2Value" // Query the DB to get a list of data - val dbData = reportService.searchReport1(fromDate, toDate, itemType) + val dbData = reportService.searchReport3(itemType) val pdfBytes = reportService.createPdfResponse( - "/jasper/FGDeliveryReport.jrxml", + "/jasper/StockBalanceReport.jrxml", parameters, dbData )