diff --git a/src/main/java/com/ffii/fpsms/config/security/SecurityConfig.java b/src/main/java/com/ffii/fpsms/config/security/SecurityConfig.java index 44c34b5..b18b847 100644 --- a/src/main/java/com/ffii/fpsms/config/security/SecurityConfig.java +++ b/src/main/java/com/ffii/fpsms/config/security/SecurityConfig.java @@ -77,8 +77,8 @@ public class SecurityConfig { /** * FP-MTMS Version Checklist | Functions Ref. No. 67 | v1.0.0 | 2026-08-13 * FP-MTMS Version Checklist | Functions Ref. No. 51 | v1.0.1 | 2026-08-06 - * FP-MTMS Version Checklist | Functions Ref. No. 3 | v1.0.6 | 2026-09-07 - * (stockAdjustment/submit → INVENTORY_ADJUST only) + * FP-MTMS Version Checklist | Functions Ref. No. 3 | v1.0.7 | 2026-09-08 + * (stockAdjustment/submit and GET /latestRemarks → INVENTORY_ADJUST) */ @Bean @Order(1) @@ -119,6 +119,8 @@ public class SecurityConfig { .hasAnyAuthority("TESTING", "ADMIN") .requestMatchers(HttpMethod.POST, "/stockAdjustment/submit") .hasAuthority("INVENTORY_ADJUST") + .requestMatchers(HttpMethod.GET, "/stockAdjustment/latestRemarks") + .hasAuthority("INVENTORY_ADJUST") .requestMatchers(HttpMethod.GET, "/inventoryLotLine/trace") .hasAuthority("ITEM_TRACING") .requestMatchers(HttpMethod.GET, "/inventoryLotLine/trace/location/**") diff --git a/src/main/java/com/ffii/fpsms/modules/report/web/StockLotOnhandReportController.kt b/src/main/java/com/ffii/fpsms/modules/report/web/StockLotOnhandReportController.kt index 01efc8f..041b6ca 100644 --- a/src/main/java/com/ffii/fpsms/modules/report/web/StockLotOnhandReportController.kt +++ b/src/main/java/com/ffii/fpsms/modules/report/web/StockLotOnhandReportController.kt @@ -216,7 +216,6 @@ class StockLotOnhandReportController( "樓層", "倉庫", "區域", "儲位", "最後異動日", "最後異動(入庫/出庫)", "批號結餘", "單位均價", "庫存總價值", - "備註", ) val totalColumns = headers.size var rowIndex = 0 @@ -301,7 +300,6 @@ class StockLotOnhandReportController( setNumberCell(r, 12, m["lotQtyRaw"], styles.number) setNumberCell(r, 13, m["avgUnitPriceRaw"], styles.number) setNumberCell(r, 14, m["stockValueRaw"], styles.number) - setTextCell(r, 15, m["remarks"], styles.text) } } @@ -310,7 +308,7 @@ class StockLotOnhandReportController( sheet.setAutoFilter(CellRangeAddress(headerRowIndex, lastRowIndex, 0, totalColumns - 1)) } sheet.createFreezePane(0, headerRowIndex + 1) - intArrayOf(14, 28, 14, 8, 20, 12, 10, 12, 10, 10, 12, 20, 12, 12, 14, 28) + intArrayOf(14, 28, 14, 8, 20, 12, 10, 12, 10, 10, 12, 20, 12, 12, 14) .forEachIndexed { i, w -> sheet.setColumnWidth(i, w * 256) } val out = ByteArrayOutputStream() diff --git a/src/main/java/com/ffii/fpsms/modules/stock/entity/StockAdjustmentRecord.kt b/src/main/java/com/ffii/fpsms/modules/stock/entity/StockAdjustmentRecord.kt index dc711d4..2166583 100644 --- a/src/main/java/com/ffii/fpsms/modules/stock/entity/StockAdjustmentRecord.kt +++ b/src/main/java/com/ffii/fpsms/modules/stock/entity/StockAdjustmentRecord.kt @@ -31,6 +31,9 @@ open class StockAdjustmentRecord : BaseEntity() { @Column(name = "outQty", precision = 14, scale = 2) open var outQty: BigDecimal? = null + @Column(name = "remarks", length = 500) + open var remarks: String? = null + @JsonBackReference @ManyToOne @JoinColumn(name = "stockInLineId") diff --git a/src/main/java/com/ffii/fpsms/modules/stock/entity/StockAdjustmentRecordRepository.kt b/src/main/java/com/ffii/fpsms/modules/stock/entity/StockAdjustmentRecordRepository.kt index 4a087bd..e14ba7e 100644 --- a/src/main/java/com/ffii/fpsms/modules/stock/entity/StockAdjustmentRecordRepository.kt +++ b/src/main/java/com/ffii/fpsms/modules/stock/entity/StockAdjustmentRecordRepository.kt @@ -1,7 +1,20 @@ package com.ffii.fpsms.modules.stock.entity import com.ffii.core.support.AbstractRepository +import org.springframework.data.jpa.repository.Query +import org.springframework.data.repository.query.Param import org.springframework.stereotype.Repository @Repository -interface StockAdjustmentRecordRepository : AbstractRepository \ No newline at end of file +interface StockAdjustmentRecordRepository : AbstractRepository { + @Query( + """ + SELECT r FROM StockAdjustmentRecord r + WHERE r.item.id = :itemId + AND r.deleted = false + AND r.remarks IS NOT NULL + ORDER BY r.id DESC + """ + ) + fun findRemarkRecordsByItemId(@Param("itemId") itemId: Long): List +} diff --git a/src/main/java/com/ffii/fpsms/modules/stock/service/StockAdjustmentService.kt b/src/main/java/com/ffii/fpsms/modules/stock/service/StockAdjustmentService.kt index f997f28..6b192dc 100644 --- a/src/main/java/com/ffii/fpsms/modules/stock/service/StockAdjustmentService.kt +++ b/src/main/java/com/ffii/fpsms/modules/stock/service/StockAdjustmentService.kt @@ -4,6 +4,7 @@ import com.ffii.fpsms.modules.master.web.models.MessageResponse import com.ffii.fpsms.modules.stock.entity.InventoryLotLine import com.ffii.fpsms.modules.stock.entity.InventoryLotLineRepository import com.ffii.fpsms.modules.stock.web.model.StockAdjustmentRequest +import com.ffii.fpsms.modules.stock.web.model.StockAdjustmentRemarksResponse import com.ffii.fpsms.modules.stock.web.model.StockInRequest import com.ffii.fpsms.modules.stock.web.model.StockOutRequest import org.springframework.stereotype.Service @@ -24,6 +25,7 @@ open class StockAdjustmentService( private val stockAdjustmentRecordRepository: StockAdjustmentRecordRepository ) { + /** FP-MTMS Version Checklist | Functions Ref. No. 3 | v1.0.7 | 2026-09-08 */ @Transactional open fun submit(request: StockAdjustmentRequest): MessageResponse { val originalById = request.originalLines.filter { it.id > 0 }.associateBy { it.id } @@ -36,7 +38,7 @@ open class StockAdjustmentService( inventoryLotLineId = line.id, type = "ADJ" ) - saveAdjustmentRecordForStockOut(stockOutLine) + saveAdjustmentRecordForStockOut(stockOutLine, line.remarks) } for (current in request.currentLines) { // Branch 2: New entry — createStockIn (OPEN or ADJ) @@ -56,7 +58,7 @@ open class StockAdjustmentService( warehouseId = current.warehouseId ) ) - saveAdjustmentRecordForStockIn(stockInLine) + saveAdjustmentRecordForStockIn(stockInLine, current.remarks) continue } @@ -74,7 +76,7 @@ open class StockAdjustmentService( stockInRequest, inventoryLotLine ) - saveAdjustmentRecordForStockIn(stockInLine) + saveAdjustmentRecordForStockIn(stockInLine, current.remarks) } else { // Branch 3 (qty down): adjustment outbound only (not pick createStockOut) val stockOutLine = stockOutLineService.createStockOutForAdjustment( @@ -84,7 +86,7 @@ open class StockAdjustmentService( type = "ADJ" ) ) - saveAdjustmentRecordForStockOut(stockOutLine) + saveAdjustmentRecordForStockOut(stockOutLine, current.remarks) } } @@ -98,6 +100,19 @@ open class StockAdjustmentService( ) } + /** FP-MTMS Version Checklist | Functions Ref. No. 3 | v1.0.7 | 2026-09-08 */ + open fun findLatestRemarksByItemId(itemId: Long): List { + val seenLotNos = HashSet() + val result = mutableListOf() + for (row in stockAdjustmentRecordRepository.findRemarkRecordsByItemId(itemId)) { + val remarks = normalizeRemarks(row.remarks) ?: continue + val lotNo = row.lotNo?.trim().orEmpty() + if (lotNo.isEmpty() || !seenLotNos.add(lotNo)) continue + result.add(StockAdjustmentRemarksResponse(lotNo = lotNo, remarks = remarks)) + } + return result + } + private fun buildStockInRequestFromExistingLotLine( inventoryLotLine: InventoryLotLine, acceptedQty: BigDecimal @@ -131,7 +146,7 @@ open class StockAdjustmentService( warehouseId = warehouseId ) } - private fun saveAdjustmentRecordForStockIn(stockInLine: StockInLine) { + private fun saveAdjustmentRecordForStockIn(stockInLine: StockInLine, remarks: String?) { val item = stockInLine.item ?: return val record = StockAdjustmentRecord().apply { this.item = item @@ -140,13 +155,14 @@ open class StockAdjustmentService( this.lotNo = stockInLine.lotNo this.inQty = stockInLine.acceptedQty this.outQty = null + this.remarks = normalizeRemarks(remarks) this.stockInLine = stockInLine this.stockOutLine = null } stockAdjustmentRecordRepository.save(record) } - private fun saveAdjustmentRecordForStockOut(stockOutLine: StockOutLine) { + private fun saveAdjustmentRecordForStockOut(stockOutLine: StockOutLine, remarks: String?) { val item = stockOutLine.item ?: return val lotNo = stockOutLine.inventoryLotLine?.inventoryLot?.lotNo val record = StockAdjustmentRecord().apply { @@ -156,9 +172,13 @@ open class StockAdjustmentService( this.lotNo = lotNo this.inQty = null this.outQty = BigDecimal.valueOf(stockOutLine.qty ?: 0.0) + this.remarks = normalizeRemarks(remarks) this.stockInLine = null this.stockOutLine = stockOutLine } stockAdjustmentRecordRepository.save(record) } + + private fun normalizeRemarks(remarks: String?): String? = + remarks?.trim()?.takeIf { it.isNotEmpty() } } \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/modules/stock/web/StockAdjustmentController.kt b/src/main/java/com/ffii/fpsms/modules/stock/web/StockAdjustmentController.kt index c76f6ec..71551cf 100644 --- a/src/main/java/com/ffii/fpsms/modules/stock/web/StockAdjustmentController.kt +++ b/src/main/java/com/ffii/fpsms/modules/stock/web/StockAdjustmentController.kt @@ -3,6 +3,7 @@ package com.ffii.fpsms.modules.stock.web import com.ffii.fpsms.modules.master.web.models.MessageResponse import com.ffii.fpsms.modules.stock.service.StockAdjustmentService import com.ffii.fpsms.modules.stock.web.model.StockAdjustmentRequest +import com.ffii.fpsms.modules.stock.web.model.StockAdjustmentRemarksResponse import jakarta.validation.Valid import org.springframework.web.bind.annotation.* @@ -11,8 +12,15 @@ import org.springframework.web.bind.annotation.* class StockAdjustmentController( private val stockAdjustmentService: StockAdjustmentService ) { + /** FP-MTMS Version Checklist | Functions Ref. No. 3 | v1.0.7 | 2026-09-08 */ @PostMapping("/submit") fun submit(@Valid @RequestBody request: StockAdjustmentRequest): MessageResponse { return stockAdjustmentService.submit(request) } + + /** FP-MTMS Version Checklist | Functions Ref. No. 3 | v1.0.7 | 2026-09-08 */ + @GetMapping("/latestRemarks") + fun latestRemarks(@RequestParam itemId: Long): List { + return stockAdjustmentService.findLatestRemarksByItemId(itemId) + } } \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/modules/stock/web/model/StockAdjustmentRequest.kt b/src/main/java/com/ffii/fpsms/modules/stock/web/model/StockAdjustmentRequest.kt index fc60c4b..570985c 100644 --- a/src/main/java/com/ffii/fpsms/modules/stock/web/model/StockAdjustmentRequest.kt +++ b/src/main/java/com/ffii/fpsms/modules/stock/web/model/StockAdjustmentRequest.kt @@ -14,11 +14,17 @@ data class StockAdjustmentLineRequest( val itemNo: String, val expiryDate: String, val warehouseId: Long, - val uom: String? = null + val uom: String? = null, + val remarks: String? = null ) data class StockAdjustmentRequest( val itemId: Long, val originalLines: List, val currentLines: List +) + +data class StockAdjustmentRemarksResponse( + val lotNo: String?, + val remarks: String ) \ No newline at end of file diff --git a/src/main/resources/db/changelog/changes/20260908_stock_adjustment_record_remarks/01_add_remarks.sql b/src/main/resources/db/changelog/changes/20260908_stock_adjustment_record_remarks/01_add_remarks.sql new file mode 100644 index 0000000..fd2673d --- /dev/null +++ b/src/main/resources/db/changelog/changes/20260908_stock_adjustment_record_remarks/01_add_remarks.sql @@ -0,0 +1,6 @@ +--liquibase formatted sql +--changeset fpsms:stock_adjustment_record_remarks +--comment: Store stock adjustment reason/remarks + +ALTER TABLE `stock_adjustment_record` + ADD COLUMN `remarks` VARCHAR(500) NULL AFTER `outQty`;