From 307d3e06e32b4665be3fb579d195a36a07cd83a7 Mon Sep 17 00:00:00 2001 From: "MSI\\derek" Date: Thu, 15 May 2025 17:21:34 +0800 Subject: [PATCH] Update po stock in flow related --- .../fpsms/modules/master/entity/ItemUom.kt | 4 +- .../purchaseOrder/entity/PurchaseOrderLine.kt | 10 +- .../projections/PurchaseOrderLineInfo.kt | 1 + .../service/PurchaseOrderLineService.kt | 1 - .../service/PurchaseOrderService.kt | 1 + .../fpsms/modules/stock/entity/Inventory.kt | 48 ++++--- .../modules/stock/entity/InventoryLot.kt | 42 ++++++ .../modules/stock/entity/InventoryLotLine.kt | 35 +++++ .../entity/InventoryLotLineRepository.kt | 8 ++ .../modules/stock/entity/InventoryLotNo.kt | 25 ---- ...epository.kt => InventoryLotRepository.kt} | 2 +- .../stock/entity/InventoryRepository.kt | 2 +- .../fpsms/modules/stock/entity/StockInLine.kt | 22 ++- .../entity/projection/StockInLineInfo.kt | 8 +- .../stock/service/InventoryLotService.kt | 46 ++++++ .../modules/stock/service/InventoryService.kt | 136 ++++++++---------- .../stock/service/StockInLineService.kt | 79 ++++++++-- .../ffii/fpsms/modules/stock/sql/StockSql.kt | 13 ++ .../stock/web/model/SaveInventoryRequest.kt | 15 +- .../stock/web/model/SaveStockInRequest.kt | 6 + .../20250515_01_derek/01_inventory.sql | 68 +++++++++ .../20250515_01_derek/02_update_inventory.sql | 5 + .../20250515_01_derek/03_update_lot_line.sql | 7 + .../04_update_add_lotNo_to_stock_in_line.sql | 5 + ...05_update_stockinline_add_receipt_date.sql | 5 + .../06_update_shelfLifeDate_name.sql | 5 + .../07_update_add_product_lotno.sql | 5 + .../08_update_change_to_productionDate.sql | 5 + 28 files changed, 449 insertions(+), 160 deletions(-) create mode 100644 src/main/java/com/ffii/fpsms/modules/stock/entity/InventoryLot.kt create mode 100644 src/main/java/com/ffii/fpsms/modules/stock/entity/InventoryLotLine.kt create mode 100644 src/main/java/com/ffii/fpsms/modules/stock/entity/InventoryLotLineRepository.kt delete mode 100644 src/main/java/com/ffii/fpsms/modules/stock/entity/InventoryLotNo.kt rename src/main/java/com/ffii/fpsms/modules/stock/entity/{InventoryLotNoRepository.kt => InventoryLotRepository.kt} (65%) create mode 100644 src/main/java/com/ffii/fpsms/modules/stock/service/InventoryLotService.kt create mode 100644 src/main/java/com/ffii/fpsms/modules/stock/sql/StockSql.kt create mode 100644 src/main/resources/db/changelog/changes/20250515_01_derek/01_inventory.sql create mode 100644 src/main/resources/db/changelog/changes/20250515_01_derek/02_update_inventory.sql create mode 100644 src/main/resources/db/changelog/changes/20250515_01_derek/03_update_lot_line.sql create mode 100644 src/main/resources/db/changelog/changes/20250515_01_derek/04_update_add_lotNo_to_stock_in_line.sql create mode 100644 src/main/resources/db/changelog/changes/20250515_01_derek/05_update_stockinline_add_receipt_date.sql create mode 100644 src/main/resources/db/changelog/changes/20250515_01_derek/06_update_shelfLifeDate_name.sql create mode 100644 src/main/resources/db/changelog/changes/20250515_01_derek/07_update_add_product_lotno.sql create mode 100644 src/main/resources/db/changelog/changes/20250515_01_derek/08_update_change_to_productionDate.sql diff --git a/src/main/java/com/ffii/fpsms/modules/master/entity/ItemUom.kt b/src/main/java/com/ffii/fpsms/modules/master/entity/ItemUom.kt index 0e3d801..ef3ae99 100644 --- a/src/main/java/com/ffii/fpsms/modules/master/entity/ItemUom.kt +++ b/src/main/java/com/ffii/fpsms/modules/master/entity/ItemUom.kt @@ -10,12 +10,12 @@ import java.time.LocalDateTime @Table(name = "item_uom") open class ItemUom : BaseEntity() { @NotNull - @ManyToOne(fetch = FetchType.LAZY, optional = false) + @ManyToOne @JoinColumn(name = "uomId", nullable = false) open var uom: UomConversion? = null @NotNull - @ManyToOne(fetch = FetchType.LAZY, optional = false) + @ManyToOne @JoinColumn(name = "itemId", nullable = false) open var item: Items? = null diff --git a/src/main/java/com/ffii/fpsms/modules/purchaseOrder/entity/PurchaseOrderLine.kt b/src/main/java/com/ffii/fpsms/modules/purchaseOrder/entity/PurchaseOrderLine.kt index f113f7a..d5166c4 100644 --- a/src/main/java/com/ffii/fpsms/modules/purchaseOrder/entity/PurchaseOrderLine.kt +++ b/src/main/java/com/ffii/fpsms/modules/purchaseOrder/entity/PurchaseOrderLine.kt @@ -4,6 +4,7 @@ import com.ffii.core.entity.BaseEntity import com.ffii.fpsms.modules.master.entity.Items import com.ffii.fpsms.m18.entity.M18DataLog import com.ffii.fpsms.modules.master.entity.Currency +import com.ffii.fpsms.modules.master.entity.UomConversion import com.ffii.fpsms.modules.purchaseOrder.enums.PurchaseOrderLineStatus import com.ffii.fpsms.modules.purchaseOrder.enums.PurchaseOrderLineStatusConverter import jakarta.persistence.* @@ -50,10 +51,9 @@ open class PurchaseOrderLine : BaseEntity(){ @JoinColumn(name = "m18DataLogId", nullable = false) open var m18DataLog: M18DataLog? = null - @Column(name = "uomId") - open var uomId: Long? = null + @ManyToOne + @JoinColumn(name = "uomId") +// @Column(name = "uomId") + open var uom: UomConversion? = null - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "currencyId") - open var currency: Currency? = null } \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/modules/purchaseOrder/entity/projections/PurchaseOrderLineInfo.kt b/src/main/java/com/ffii/fpsms/modules/purchaseOrder/entity/projections/PurchaseOrderLineInfo.kt index 33faafa..958bebe 100644 --- a/src/main/java/com/ffii/fpsms/modules/purchaseOrder/entity/projections/PurchaseOrderLineInfo.kt +++ b/src/main/java/com/ffii/fpsms/modules/purchaseOrder/entity/projections/PurchaseOrderLineInfo.kt @@ -24,6 +24,7 @@ data class PoLineWithStockInLine ( val itemNo: String, val itemName: String?, val qty: BigDecimal, + val uom: String? = null, val price: BigDecimal, val status: String, diff --git a/src/main/java/com/ffii/fpsms/modules/purchaseOrder/service/PurchaseOrderLineService.kt b/src/main/java/com/ffii/fpsms/modules/purchaseOrder/service/PurchaseOrderLineService.kt index f385e60..d3a96e1 100644 --- a/src/main/java/com/ffii/fpsms/modules/purchaseOrder/service/PurchaseOrderLineService.kt +++ b/src/main/java/com/ffii/fpsms/modules/purchaseOrder/service/PurchaseOrderLineService.kt @@ -53,7 +53,6 @@ open class PurchaseOrderLineService( this.purchaseOrder = purchaseOrder qty = request.qty price = request.price - this.currency = currency this.status = status this.m18DataLog = m18DataLog ?: this.m18DataLog } diff --git a/src/main/java/com/ffii/fpsms/modules/purchaseOrder/service/PurchaseOrderService.kt b/src/main/java/com/ffii/fpsms/modules/purchaseOrder/service/PurchaseOrderService.kt index 783cac0..b58d5bd 100644 --- a/src/main/java/com/ffii/fpsms/modules/purchaseOrder/service/PurchaseOrderService.kt +++ b/src/main/java/com/ffii/fpsms/modules/purchaseOrder/service/PurchaseOrderService.kt @@ -56,6 +56,7 @@ open class PurchaseOrderService( thisPol.itemNo!!, thisPol.item!!.name, thisPol.qty!!, + thisPol.uom!!.code, thisPol.price!!, thisPol.status!!.toString(), inLine diff --git a/src/main/java/com/ffii/fpsms/modules/stock/entity/Inventory.kt b/src/main/java/com/ffii/fpsms/modules/stock/entity/Inventory.kt index c8f1fd9..49496ed 100644 --- a/src/main/java/com/ffii/fpsms/modules/stock/entity/Inventory.kt +++ b/src/main/java/com/ffii/fpsms/modules/stock/entity/Inventory.kt @@ -1,7 +1,9 @@ package com.ffii.fpsms.modules.stock.entity import com.ffii.core.entity.BaseEntity +import com.ffii.fpsms.modules.master.entity.Currency import com.ffii.fpsms.modules.master.entity.Items +import com.ffii.fpsms.modules.master.entity.UomConversion import com.ffii.fpsms.modules.master.entity.Warehouse import jakarta.persistence.* import jakarta.validation.constraints.NotNull @@ -13,42 +15,42 @@ import java.time.LocalDate @Table(name = "inventory") open class Inventory: BaseEntity(){ @NotNull - @OneToOne - @JoinColumn(name = "itemId") - open var item: Items? = null + @Column(name = "qty") + open var qty: BigDecimal? = null + + @NotNull + @Column(name = "price") + open var price: BigDecimal? = null @Column(name = "stockInLineId") open var stockInLine: Long? = null // change this later + @ManyToOne + @JoinColumn(name = "currencyId") + open var currency: Currency? = null + @NotNull - @Column(name = "qty") - open var qty: Double? = null + @Column(name = "cpu") // cost per unit + open var cpu: BigDecimal? = null @NotNull - @Column(name = "lotNo") - open var lotNo: String? = null + @Column(name = "cpuUnit") + open var cpuUnit: String? = null @NotNull - @Column(name = "expiryDate") - open var expiryDate: LocalDate? = null + @Column(name = "cpm") // cost per unit + open var cpm: BigDecimal? = null @NotNull - @Column(name = "uomId") - open var uomId: Long? = null + @Column(name = "cpmUnit") + open var cpmUnit: String? = null + + @NotNull + @ManyToOne + @JoinColumn(name = "uomId") + open var uomId: UomConversion? = null // @NotNull @Column(name = "status") open var status: String? = null - - @NotNull - @ManyToOne(fetch = FetchType.LAZY, optional = false) - @JoinColumn(name = "warehouseId", nullable = false) - open var warehouse: Warehouse? = null - - @Column(name = "price", precision = 14, scale = 2) - open var price: BigDecimal? = null - - @Size(max = 5) - @Column(name = "priceUnit", length = 5) - open var priceUnit: String? = null } \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/modules/stock/entity/InventoryLot.kt b/src/main/java/com/ffii/fpsms/modules/stock/entity/InventoryLot.kt new file mode 100644 index 0000000..5c16b1e --- /dev/null +++ b/src/main/java/com/ffii/fpsms/modules/stock/entity/InventoryLot.kt @@ -0,0 +1,42 @@ +package com.ffii.fpsms.modules.stock.entity + +import com.ffii.core.entity.BaseEntity +import com.ffii.fpsms.modules.master.entity.Items +import jakarta.persistence.* +import jakarta.validation.constraints.NotNull +import jakarta.validation.constraints.Size +import org.hibernate.annotations.JdbcTypeCode +import org.hibernate.type.SqlTypes +import java.time.LocalDate +import java.time.LocalDateTime + +@Entity +@Table(name = "inventory_lot") +open class InventoryLot : BaseEntity() { + @NotNull + @OneToOne + @JoinColumn(name = "itemId", nullable = false) + open var item: Items? = null + + @NotNull + @ManyToOne + @JoinColumn(name = "stockInLineId", nullable = false) + open var stockInLine: StockInLine? = null + + @Column(name = "productionDate") + open var productionDate: LocalDateTime? = null + + @Column(name = "stockInDate") + open var stockInDate: LocalDateTime? = null + + @NotNull + @Column(name = "expiryDate") + open var expiryDate: LocalDate? = null + + @Column(name = "lotNo") + open var lotNo: String? = null + +// @JdbcTypeCode(SqlTypes.JSON) +// @Column(name = "qrCodeJson") +// open var qrCodeJson: MutableMap? = null +} \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/modules/stock/entity/InventoryLotLine.kt b/src/main/java/com/ffii/fpsms/modules/stock/entity/InventoryLotLine.kt new file mode 100644 index 0000000..eaf7b9b --- /dev/null +++ b/src/main/java/com/ffii/fpsms/modules/stock/entity/InventoryLotLine.kt @@ -0,0 +1,35 @@ +package com.ffii.fpsms.modules.stock.entity + +import com.ffii.core.entity.BaseEntity +import jakarta.persistence.Column +import jakarta.persistence.Entity +import jakarta.persistence.Table +import jakarta.validation.constraints.NotNull +import org.hibernate.annotations.JdbcTypeCode +import org.hibernate.type.SqlTypes +import java.math.BigDecimal + +@Entity +@Table(name = "inventory_lot_line") +open class InventoryLotLine : BaseEntity() { + + @NotNull + @Column(name = "inQty") + open var inQty: BigDecimal? = null + + @NotNull + @Column(name = "outQty") + open var outQty: BigDecimal? = null + + @NotNull + @Column(name = "holdQty") + open var holdQty: BigDecimal? = null + + @NotNull + @Column(name = "status") + open var status: String? = null + + @JdbcTypeCode(SqlTypes.JSON) + @Column(name = "qrCode") + open var qrCode: MutableMap? = null +} \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/modules/stock/entity/InventoryLotLineRepository.kt b/src/main/java/com/ffii/fpsms/modules/stock/entity/InventoryLotLineRepository.kt new file mode 100644 index 0000000..6ea1e52 --- /dev/null +++ b/src/main/java/com/ffii/fpsms/modules/stock/entity/InventoryLotLineRepository.kt @@ -0,0 +1,8 @@ +package com.ffii.fpsms.modules.stock.entity + +import com.ffii.core.support.AbstractRepository +import org.springframework.stereotype.Repository + +@Repository +interface InventoryLotLineRepository : AbstractRepository { +} \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/modules/stock/entity/InventoryLotNo.kt b/src/main/java/com/ffii/fpsms/modules/stock/entity/InventoryLotNo.kt deleted file mode 100644 index 2b225c9..0000000 --- a/src/main/java/com/ffii/fpsms/modules/stock/entity/InventoryLotNo.kt +++ /dev/null @@ -1,25 +0,0 @@ -package com.ffii.fpsms.modules.stock.entity - -import com.ffii.core.entity.BaseEntity -import jakarta.persistence.* -import jakarta.validation.constraints.NotNull -import jakarta.validation.constraints.Size -import org.hibernate.annotations.JdbcTypeCode -import org.hibernate.type.SqlTypes - -@Entity -@Table(name = "inventory_lot_no") -open class InventoryLotNo : BaseEntity() { - @NotNull - @ManyToOne(fetch = FetchType.LAZY, optional = false) - @JoinColumn(name = "inventoryId", nullable = false) - open var inventory: Inventory? = null - - @Size(max = 30) - @Column(name = "lotNo", length = 30) - open var lotNo: String? = null - - @JdbcTypeCode(SqlTypes.JSON) - @Column(name = "qrCodeJson") - open var qrCodeJson: MutableMap? = null -} \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/modules/stock/entity/InventoryLotNoRepository.kt b/src/main/java/com/ffii/fpsms/modules/stock/entity/InventoryLotRepository.kt similarity index 65% rename from src/main/java/com/ffii/fpsms/modules/stock/entity/InventoryLotNoRepository.kt rename to src/main/java/com/ffii/fpsms/modules/stock/entity/InventoryLotRepository.kt index 208f277..f61518b 100644 --- a/src/main/java/com/ffii/fpsms/modules/stock/entity/InventoryLotNoRepository.kt +++ b/src/main/java/com/ffii/fpsms/modules/stock/entity/InventoryLotRepository.kt @@ -4,5 +4,5 @@ import com.ffii.core.support.AbstractRepository import org.springframework.stereotype.Repository @Repository -interface InventoryLotNoRepository : AbstractRepository { +interface InventoryLotRepository: AbstractRepository { } \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/modules/stock/entity/InventoryRepository.kt b/src/main/java/com/ffii/fpsms/modules/stock/entity/InventoryRepository.kt index b9c0571..354ed59 100644 --- a/src/main/java/com/ffii/fpsms/modules/stock/entity/InventoryRepository.kt +++ b/src/main/java/com/ffii/fpsms/modules/stock/entity/InventoryRepository.kt @@ -4,5 +4,5 @@ import com.ffii.core.support.AbstractRepository import org.springframework.stereotype.Repository @Repository -interface InventoryRepository : AbstractRepository { +interface InventoryRepository: AbstractRepository { } \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/modules/stock/entity/StockInLine.kt b/src/main/java/com/ffii/fpsms/modules/stock/entity/StockInLine.kt index 4a276fa..6e9bc88 100644 --- a/src/main/java/com/ffii/fpsms/modules/stock/entity/StockInLine.kt +++ b/src/main/java/com/ffii/fpsms/modules/stock/entity/StockInLine.kt @@ -9,6 +9,7 @@ import jakarta.validation.constraints.NotNull import jakarta.validation.constraints.Size import java.math.BigDecimal import java.time.Instant +import java.time.LocalDate import java.time.LocalDateTime @Entity @@ -46,20 +47,27 @@ open class StockInLine : BaseEntity() { @Column(name = "priceUnit", length = 5) open var priceUnit: String? = null - @Column(name = "productDate") - open var productDate: LocalDateTime? = null + @Column(name = "receiptDate") + open var receiptDate: LocalDateTime? = null - @Column(name = "shelfLifeDate") - open var shelfLifeDate: LocalDateTime? = null + @Column(name = "productionDate") + open var productionDate: LocalDateTime? = null + + @Column(name = "expiryDate") + open var expiryDate: LocalDate? = null -// @Size(max = 10) @NotNull - @Column(name = "status", nullable = false, length = 10) -// @Enumerated(EnumType.STRING) + @Column(name = "status") open var status: String? = null @ManyToOne @JoinColumn(name = "userId") open var user: User? = null + @Column(name = "lotNo") + open var lotNo: String? = null + + @Column(name = "productLotNo") + open var productLotNo: String? = null + } \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/modules/stock/entity/projection/StockInLineInfo.kt b/src/main/java/com/ffii/fpsms/modules/stock/entity/projection/StockInLineInfo.kt index c2283ee..6516548 100644 --- a/src/main/java/com/ffii/fpsms/modules/stock/entity/projection/StockInLineInfo.kt +++ b/src/main/java/com/ffii/fpsms/modules/stock/entity/projection/StockInLineInfo.kt @@ -4,6 +4,7 @@ import com.ffii.fpsms.modules.master.entity.Items import com.ffii.fpsms.modules.master.entity.ItemsRepository import org.springframework.beans.factory.annotation.Value import java.math.BigDecimal +import java.time.LocalDate import java.time.LocalDateTime interface StockInLineInfo { @@ -21,7 +22,10 @@ interface StockInLineInfo { val acceptedQty: BigDecimal val price: BigDecimal? val priceUnit: BigDecimal? - val productDate: LocalDateTime? - val shelfLifeDate: LocalDateTime? + val receiptDate: LocalDateTime? + val productionDate: LocalDateTime? + val expiryDate: LocalDate? val status: String + var lotNo: String? + var productLotNo: String? } \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/modules/stock/service/InventoryLotService.kt b/src/main/java/com/ffii/fpsms/modules/stock/service/InventoryLotService.kt new file mode 100644 index 0000000..80ffda4 --- /dev/null +++ b/src/main/java/com/ffii/fpsms/modules/stock/service/InventoryLotService.kt @@ -0,0 +1,46 @@ +package com.ffii.fpsms.modules.stock.service + +import com.ffii.core.support.AbstractBaseEntityService +import com.ffii.core.support.JdbcDao +import com.ffii.fpsms.modules.master.entity.ItemsRepository +import com.ffii.fpsms.modules.master.web.models.MessageResponse +import com.ffii.fpsms.modules.purchaseOrder.entity.PurchaseOrder +import com.ffii.fpsms.modules.purchaseOrder.entity.PurchaseOrderRepository +import com.ffii.fpsms.modules.stock.entity.InventoryLot +import com.ffii.fpsms.modules.stock.entity.InventoryLotRepository +import com.ffii.fpsms.modules.stock.web.model.SaveInventoryRequest +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional +import java.io.IOException + +@Service +open class InventoryLotService( + private val jdbcDao: JdbcDao, + private val itemsRepository: ItemsRepository, + private val inventoryLotRepository: InventoryLotRepository, +): AbstractBaseEntityService(jdbcDao, inventoryLotRepository) { + + @Throws(IOException::class) + @Transactional + open fun createOrUpdate(request: SaveInventoryRequest): MessageResponse { + val inventoryLot = if (request.id !== null) inventoryLotRepository.findById(request.id).orElseThrow() else InventoryLot() + val thisExpiryDate = if (request.id !== null) inventoryLot.expiryDate else request.expiryDate + val item = itemsRepository.findById(request.itemId).orElseThrow() + inventoryLot.apply { + this.item = item + stockInDate = request.stockInDate + expiryDate = thisExpiryDate + lotNo = request.lotNo + } + val savedInventoryLot = saveAndFlush(inventoryLot) + return MessageResponse( + id = savedInventoryLot.id, + code = savedInventoryLot.lotNo, + name = item.name, + type = item.type, + message = "Inventory Lot Save Success", + errorPosition = null, + entity = savedInventoryLot, + ) + } +} \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/modules/stock/service/InventoryService.kt b/src/main/java/com/ffii/fpsms/modules/stock/service/InventoryService.kt index ca42715..653267d 100644 --- a/src/main/java/com/ffii/fpsms/modules/stock/service/InventoryService.kt +++ b/src/main/java/com/ffii/fpsms/modules/stock/service/InventoryService.kt @@ -8,7 +8,6 @@ import com.ffii.fpsms.modules.master.entity.ItemsRepository import com.ffii.fpsms.modules.master.web.models.MessageResponse import com.ffii.fpsms.modules.stock.entity.Inventory import com.ffii.fpsms.modules.stock.entity.InventoryRepository -import com.ffii.fpsms.modules.stock.service.InventoryService.SQL.INVENTORY_COUNT import com.ffii.fpsms.modules.stock.web.model.SaveInventoryRequest import org.springframework.stereotype.Service import java.io.IOException @@ -26,76 +25,67 @@ open class InventoryService( val inventory = inventoryRepository.findAll() return inventory } - object SQL { - val INVENTORY_COUNT = StringBuilder("select" - + " count(id) " - + " from inventory i " - + " where i.created >= :from " - + " and i.created = :to " - + " and i.itemId = :itemId" - ) - } - @Throws(IOException::class) - open fun updateInventory(request: SaveInventoryRequest): MessageResponse { - // out need id - // in not necessary - var reqQty = request.qty - if (request.type === "out") reqQty *= -1 - if (request.id !== null) { // old record - val inventory = inventoryRepository.findById(request.id).orElseThrow() - val newStatus = request.status ?: inventory.status - val newExpiry = request.expiryDate ?: inventory.expiryDate - // uom should not be changing - // stock in line should not be changing - // item id should not be changing - inventory.apply { - qty = inventory.qty!! + reqQty - expiryDate = newExpiry - status = newStatus - } - val savedInventory = inventoryRepository.saveAndFlush(inventory) - return MessageResponse( - id = savedInventory.id, - code = savedInventory.lotNo, - name = savedInventory.item!!.name, - type = savedInventory.status, - message = "update success", - errorPosition = null - ) - } else { // new record - val inventory = Inventory() - val item = itemsRepository.findById(request.itemId).orElseThrow() - val from = LocalDate.now().format(DateTimeFormatter.ISO_LOCAL_DATE) - val to = LocalDate.now().plusDays(1).format(DateTimeFormatter.ISO_LOCAL_DATE) -// val stockInLine = .... - val args = mapOf( - "from" to from, - "to" to to, - "itemId" to item.id - ) - val prefix = "LOT" - val count = jdbcDao.queryForInt(INVENTORY_COUNT.toString(), args) - val newLotNo = CodeGenerator.generateCode(prefix, item.id!!, count) - val newExpiry = request.expiryDate - inventory.apply { -// this.stockInLine = stockInline - this.item = item - stockInLine = 0 - qty = reqQty - lotNo = newLotNo - expiryDate = newExpiry - uomId = 0 - // status default "pending" in db - } - val savedInventory = inventoryRepository.saveAndFlush(inventory) - return MessageResponse( - id = savedInventory.id, - code = savedInventory.lotNo, - name = savedInventory.item!!.name, - type = savedInventory.status, - message = "save success", - errorPosition = null - ) - } - } +// @Throws(IOException::class) +// open fun updateInventory(request: SaveInventoryRequest): MessageResponse { +// // out need id +// // in not necessary +// var reqQty = request.qty +// if (request.type === "out") reqQty *= -1 +// if (request.id !== null) { // old record +// val inventory = inventoryRepository.findById(request.id).orElseThrow() +// val newStatus = request.status ?: inventory.status +// val newExpiry = request.expiryDate ?: inventory.expiryDate +// // uom should not be changing +// // stock in line should not be changing +// // item id should not be changing +// inventory.apply { +// qty = inventory.qty!! + reqQty +// expiryDate = newExpiry +// status = newStatus +// } +// val savedInventory = inventoryRepository.saveAndFlush(inventory) +// return MessageResponse( +// id = savedInventory.id, +// code = savedInventory.lotNo, +// name = "savedInventory.item!!.name", +// type = savedInventory.status, +// message = "update success", +// errorPosition = null +// ) +// } else { // new record +// val inventory = Inventory() +// val item = itemsRepository.findById(request.itemId).orElseThrow() +// val from = LocalDate.now().format(DateTimeFormatter.ISO_LOCAL_DATE) +// val to = LocalDate.now().plusDays(1).format(DateTimeFormatter.ISO_LOCAL_DATE) +//// val stockInLine = .... +// val args = mapOf( +// "from" to from, +// "to" to to, +// "itemId" to item.id +// ) +// val prefix = "LOT" +// val count = jdbcDao.queryForInt(INVENTORY_COUNT.toString(), args) +// val newLotNo = CodeGenerator.generateCode(prefix, item.id!!, count) +// val newExpiry = request.expiryDate +// inventory.apply { +//// this.stockInLine = stockInline +//// this.item = item +// stockInLine = 0 +// qty = reqQty +// lotNo = newLotNo +// expiryDate = newExpiry +// uomId = 0 +// // status default "pending" in db +// } +// val savedInventory = inventoryRepository.saveAndFlush(inventory) +// return MessageResponse( +// id = savedInventory.id, +// code = savedInventory.lotNo, +// name = "savedInventory.item!!.name", +// type = savedInventory.status, +// message = "save success", +// errorPosition = null +// ) +// } +// } } \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/modules/stock/service/StockInLineService.kt b/src/main/java/com/ffii/fpsms/modules/stock/service/StockInLineService.kt index 551dd1c..1cdb91f 100644 --- a/src/main/java/com/ffii/fpsms/modules/stock/service/StockInLineService.kt +++ b/src/main/java/com/ffii/fpsms/modules/stock/service/StockInLineService.kt @@ -2,6 +2,7 @@ package com.ffii.fpsms.modules.stock.service import com.ffii.core.support.AbstractBaseEntityService import com.ffii.core.support.JdbcDao +import com.ffii.fpsms.modules.common.CodeGenerator import com.ffii.fpsms.modules.master.entity.ItemsRepository import com.ffii.fpsms.modules.master.web.models.MessageResponse import com.ffii.fpsms.modules.purchaseOrder.entity.PurchaseOrderLineRepository @@ -9,10 +10,14 @@ import com.ffii.fpsms.modules.stock.entity.* import com.ffii.fpsms.modules.stock.web.model.SaveStockInLineRequest import com.ffii.fpsms.modules.stock.web.model.SaveStockInRequest import com.ffii.fpsms.modules.stock.web.model.StockInLineStatus +import com.ffii.fpsms.modules.stock.sql.StockSql.SQL.INVENTORY_COUNT +import com.ffii.fpsms.modules.stock.web.model.SaveInventoryRequest import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional import java.io.IOException import java.math.BigDecimal +import java.time.LocalDate +import java.time.LocalDateTime @Service open class StockInLineService( @@ -21,7 +26,9 @@ open class StockInLineService( private val stockInService: StockInService, private val stockInRepository: StockInRepository, private val stockInLineRepository: StockInLineRepository, + private val inventoryLotRepository: InventoryLotRepository, private val itemRepository: ItemsRepository, + private val inventoryLotService: InventoryLotService, ): AbstractBaseEntityService(jdbcDao, stockInLineRepository) { @Throws(IOException::class) @@ -53,6 +60,25 @@ open class StockInLineService( ) } + @Transactional + fun saveInventoryLotWhenStockIn(request: SaveStockInLineRequest, stockInLine: StockInLine): InventoryLot { + val inventoryLot = InventoryLot() + val args = mapOf( + "from" to LocalDate.now().atStartOfDay(), + "to" to LocalDateTime.now(), + "itemId" to stockInLine.item!!.id + ) + val inventoryCount = jdbcDao.queryForInt(INVENTORY_COUNT.toString(), args) + val newLotNo = CodeGenerator.generateCode(prefix = "POLOT", itemId = stockInLine.item!!.id!!, count = inventoryCount) + inventoryLot.apply { + this.item = stockInLine.item + this.stockInLine = stockInLine + stockInDate = LocalDateTime.now() + expiryDate = request.expiryDate// frontend form input + lotNo = newLotNo + } + return inventoryLotRepository.saveAndFlush(inventoryLot) + } @Throws(IOException::class) @Transactional open fun update(request: SaveStockInLineRequest): MessageResponse { @@ -66,15 +92,29 @@ open class StockInLineService( errorPosition = null, ) // return list of stock in line, update data grid with the list - println(request.acceptedQty) - println(stockInLine.acceptedQty) - println(request.acceptedQty == stockInLine.acceptedQty) - println(request.acceptedQty.equals(stockInLine.acceptedQty)) - println(request.acceptedQty.compareTo(stockInLine.acceptedQty) == 0) if (request.acceptedQty.compareTo(stockInLine.acceptedQty) == 0) { + var savedInventoryLot: InventoryLot? = null + if (request.status == StockInLineStatus.RECEIVED.status) { + if (request.expiryDate == null) { + return MessageResponse( + id = null, + code = null, + name = null, + type = "Found Null", + message = "missing expiry", + errorPosition = "expiryDate", + ) + } + savedInventoryLot = saveInventoryLotWhenStockIn(request = request, stockInLine = stockInLine) + } stockInLine.apply { // user = null + productionDate = request.productionDate?.atStartOfDay() // maybe need to change the request to LocalDateTime + productLotNo = request.productLotNo + receiptDate = request.receiptDate?.atStartOfDay() status = request.status + expiryDate = request.expiryDate + lotNo = savedInventoryLot?.lotNo } val savedStockInLine = saveAndFlush(stockInLine) val lineInfo = stockInLineRepository.findStockInLineInfoByIdAndDeletedFalse(savedStockInLine.id!!) @@ -108,19 +148,40 @@ open class StockInLineService( acceptedQty = stockInLine.acceptedQty!!.minus(request.acceptedQty) price = stockInLine.price priceUnit = stockInLine.priceUnit - productDate = stockInLine.productDate - shelfLifeDate = stockInLine.shelfLifeDate + productionDate = stockInLine.productionDate + expiryDate = stockInLine.expiryDate status = stockInLine.status // this does update status user = stockInLine.user } + var savedInventoryLot: InventoryLot? = null + if (request.status == StockInLineStatus.RECEIVED.status) { + if (request.expiryDate == null) { + return MessageResponse( + id = null, + code = null, + name = null, + type = "Found Null", + message = "missing expiry", + errorPosition = "expiryDate", + ) + } + savedInventoryLot = saveInventoryLotWhenStockIn(request = request, stockInLine = stockInLine) + } stockInLine.apply { + receiptDate = request.receiptDate?.atStartOfDay() + productionDate = request.productionDate?.atStartOfDay() acceptedQty = request.acceptedQty status = request.status + lotNo = savedInventoryLot?.lotNo + expiryDate = request.expiryDate + productLotNo = request.productLotNo } + val stockInLineEntries = listOf(stockInLine, newStockInLine) val savedEntries = stockInLineRepository.saveAllAndFlush(stockInLineEntries) val ids = savedEntries.map { it.id!! } - val lineInfos = stockInLineRepository.findStockInLineInfoByIdInAndDeletedFalse(ids) + val lineInfoList = stockInLineRepository.findStockInLineInfoByIdInAndDeletedFalse(ids) + return MessageResponse( id = stockInLine.id, code = null, @@ -128,7 +189,7 @@ open class StockInLineService( type = "Save success", message = "created 2 stock in line", errorPosition = null, - entity = lineInfos + entity = lineInfoList ) } } diff --git a/src/main/java/com/ffii/fpsms/modules/stock/sql/StockSql.kt b/src/main/java/com/ffii/fpsms/modules/stock/sql/StockSql.kt new file mode 100644 index 0000000..9ae949d --- /dev/null +++ b/src/main/java/com/ffii/fpsms/modules/stock/sql/StockSql.kt @@ -0,0 +1,13 @@ +package com.ffii.fpsms.modules.stock.sql + +open class StockSql { + object SQL { + val INVENTORY_COUNT = StringBuilder("select" + + " count(id) " + + " from inventory_lot i " + + " where i.stockInDate <= :from " + + " and i.stockInDate < :to " + + " and i.itemId = :itemId" + ) + } +} \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/modules/stock/web/model/SaveInventoryRequest.kt b/src/main/java/com/ffii/fpsms/modules/stock/web/model/SaveInventoryRequest.kt index 3e8809e..9dd7139 100644 --- a/src/main/java/com/ffii/fpsms/modules/stock/web/model/SaveInventoryRequest.kt +++ b/src/main/java/com/ffii/fpsms/modules/stock/web/model/SaveInventoryRequest.kt @@ -3,19 +3,12 @@ package com.ffii.fpsms.modules.stock.web.model import jakarta.validation.constraints.NotBlank import jakarta.validation.constraints.NotNull import java.time.LocalDate +import java.time.LocalDateTime data class SaveInventoryRequest( val id: Long?, - val stockInLineId: Long?, - val status: String?, - val uomId: Long?, - val expiryDate: LocalDate?, - - @field:NotNull(message = "itemId cannot be null") val itemId: Long, - @field:NotNull(message = "qty cannot be null") - val qty: Double, -// FOR POSTING STOCK IN AND STOCK OUT - @field:NotBlank(message = "type cannot be empty") - val type: String, // E.G. "in", "out", "disable": for disable lot + val stockInDate: LocalDateTime?, + val expiryDate: LocalDate?, + val lotNo: String?, ) \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/modules/stock/web/model/SaveStockInRequest.kt b/src/main/java/com/ffii/fpsms/modules/stock/web/model/SaveStockInRequest.kt index b56bd53..7b86d25 100644 --- a/src/main/java/com/ffii/fpsms/modules/stock/web/model/SaveStockInRequest.kt +++ b/src/main/java/com/ffii/fpsms/modules/stock/web/model/SaveStockInRequest.kt @@ -17,6 +17,7 @@ enum class StockInLineStatus(val status: String) { SecondDetermine("determine2"), ThirdDetermine("determine3"), RECEIVING("receiving"), + RECEIVED("received"), COMPLETE("completed"); } data class SaveStockInRequest( @@ -38,5 +39,10 @@ data class SaveStockInLineRequest( val purchaseOrderLineId: Long, val itemId: Long, val acceptedQty: BigDecimal, + val acceptedWeight: BigDecimal?, val status: String?, + val expiryDate: LocalDate?, + val productLotNo: String?, + val receiptDate: LocalDate?, + val productionDate: LocalDate?, ) diff --git a/src/main/resources/db/changelog/changes/20250515_01_derek/01_inventory.sql b/src/main/resources/db/changelog/changes/20250515_01_derek/01_inventory.sql new file mode 100644 index 0000000..c68021d --- /dev/null +++ b/src/main/resources/db/changelog/changes/20250515_01_derek/01_inventory.sql @@ -0,0 +1,68 @@ +--liquibase formatted sql + +--changeset derek:create inventory related +ALTER TABLE `stock_ledger` +DROP CONSTRAINT `fk_ledger_inventory_id`; + +DROP TABLE `inventory_lot_no`; +DROP TABLE `inventory`; +CREATE TABLE `inventory` +( + `id` INT NOT NULL AUTO_INCREMENT, + `created` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + `createdBy` VARCHAR(30) NULL DEFAULT NULL, + `version` INT NOT NULL DEFAULT '0', + `modified` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + `modifiedBy` VARCHAR(30) NULL DEFAULT NULL, + `deleted` TINYINT(1) NOT NULL DEFAULT '0', + `qty` DECIMAL(14, 2) NOT NULL, + `price` VARCHAR(30) NOT NULL, + `currencyId` INT(11) NOT NULL, + `cpu` DECIMAL(14, 2) NOT NULL, + `cpuUnit` VARCHAR(255) NOT NULL, + `cpm` DECIMAL(14, 2) NOT NULL, + `cpmUnit` VARCHAR(255) NOT NULL, + `uomId` INT(11) NOT NULL, + `status` VARCHAR(255) NOT NULL, + CONSTRAINT pk_inventory PRIMARY KEY (id), + CONSTRAINT FK_INVENTORY_TO_CURRENCY_ON_CURRENCY_ID FOREIGN KEY (`currencyId`) REFERENCES `currency` (`id`), + CONSTRAINT FK_INVENTORY_TO_UOM_ON_UOM_ID FOREIGN KEY (`uomId`) REFERENCES `uom_conversion` (`id`) +); +CREATE TABLE `inventory_lot` +( + `id` INT NOT NULL AUTO_INCREMENT, + `created` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + `createdBy` VARCHAR(30) NULL DEFAULT NULL, + `version` INT NOT NULL DEFAULT '0', + `modified` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + `modifiedBy` VARCHAR(30) NULL DEFAULT NULL, + `deleted` TINYINT(1) NOT NULL DEFAULT '0', + `itemId` INT(11) NOT NULL, + `stockInLineId` INT(30) NOT NULL, + `productionDate` DATETIME NULL, + `stockInDate` DATETIME NULL, + `expiryDate` DATE NOT NULL, + `lotNo` VARCHAR(512) NOT NULL, + CONSTRAINT pk_inventory_lot PRIMARY KEY (id), + CONSTRAINT FK_INVENTORY_LOT_TO_ITEMS_ON_ITEM_ID FOREIGN KEY (`itemId`) REFERENCES `items` (`id`), + CONSTRAINT FK_INVENTORY_LOT_TO_STOCK_IN_LINE_ON_STOCKINLINE_ID FOREIGN KEY (`stockInLineId`) REFERENCES `stock_in_line` (`id`) +); +CREATE TABLE `inventory_lot_line` +( + `id` INT NOT NULL AUTO_INCREMENT, + `created` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + `createdBy` VARCHAR(30) NULL DEFAULT NULL, + `version` INT NOT NULL DEFAULT '0', + `modified` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + `modifiedBy` VARCHAR(30) NULL DEFAULT NULL, + `deleted` TINYINT(1) NOT NULL DEFAULT '0', + `inQty` DECIMAL(14, 2) NOT NULL, + `outQty` DECIMAL(14, 2) NOT NULL, + `holdQty` DECIMAL(14, 2) NOT NULL, + `status` VARCHAR(255) NOT NULL DEFAULT 'AVAILABLE', + `remarks` VARCHAR(1024) NULL, + `qrCode` JSON NOT NULL, + CONSTRAINT pk_inventory_lot PRIMARY KEY (id) +); +ALTER TABLE `stock_ledger` +ADD CONSTRAINT `fk_ledger_inventory_id` FOREIGN KEY (inventoryId) REFERENCES `inventory` (`id`); \ No newline at end of file diff --git a/src/main/resources/db/changelog/changes/20250515_01_derek/02_update_inventory.sql b/src/main/resources/db/changelog/changes/20250515_01_derek/02_update_inventory.sql new file mode 100644 index 0000000..bc2ceae --- /dev/null +++ b/src/main/resources/db/changelog/changes/20250515_01_derek/02_update_inventory.sql @@ -0,0 +1,5 @@ +--liquibase formatted sql + +--changeset derek:update inventory data type +ALTER TABLE `inventory` +MODIFY COLUMN `price` INT NOT NULL; diff --git a/src/main/resources/db/changelog/changes/20250515_01_derek/03_update_lot_line.sql b/src/main/resources/db/changelog/changes/20250515_01_derek/03_update_lot_line.sql new file mode 100644 index 0000000..0a9f14d --- /dev/null +++ b/src/main/resources/db/changelog/changes/20250515_01_derek/03_update_lot_line.sql @@ -0,0 +1,7 @@ +--liquibase formatted sql + +--changeset derek:update inventory lot line data type +ALTER TABLE `inventory_lot_line` +MODIFY COLUMN `inQty` DECIMAL(14, 2) NOT NULL DEFAULT 0, +MODIFY COLUMN `outQty` DECIMAL(14, 2) NOT NULL DEFAULT 0, +MODIFY COLUMN `holdQty` DECIMAL(14, 2) NOT NULL DEFAULT 0; \ No newline at end of file diff --git a/src/main/resources/db/changelog/changes/20250515_01_derek/04_update_add_lotNo_to_stock_in_line.sql b/src/main/resources/db/changelog/changes/20250515_01_derek/04_update_add_lotNo_to_stock_in_line.sql new file mode 100644 index 0000000..98e3dde --- /dev/null +++ b/src/main/resources/db/changelog/changes/20250515_01_derek/04_update_add_lotNo_to_stock_in_line.sql @@ -0,0 +1,5 @@ +--liquibase formatted sql + +--changeset derek:add lotNo in stock in line +ALTER TABLE `stock_in_line` +ADD COLUMN `lotNo` VARCHAR(512) NULL AFTER `userId`; \ No newline at end of file diff --git a/src/main/resources/db/changelog/changes/20250515_01_derek/05_update_stockinline_add_receipt_date.sql b/src/main/resources/db/changelog/changes/20250515_01_derek/05_update_stockinline_add_receipt_date.sql new file mode 100644 index 0000000..c3f9c6f --- /dev/null +++ b/src/main/resources/db/changelog/changes/20250515_01_derek/05_update_stockinline_add_receipt_date.sql @@ -0,0 +1,5 @@ +--liquibase formatted sql + +--changeset derek:add receipt date in stock in line +ALTER TABLE `stock_in_line` +ADD COLUMN `receiptDate` DATETIME NULL AFTER `priceUnit`; \ No newline at end of file diff --git a/src/main/resources/db/changelog/changes/20250515_01_derek/06_update_shelfLifeDate_name.sql b/src/main/resources/db/changelog/changes/20250515_01_derek/06_update_shelfLifeDate_name.sql new file mode 100644 index 0000000..33e46d7 --- /dev/null +++ b/src/main/resources/db/changelog/changes/20250515_01_derek/06_update_shelfLifeDate_name.sql @@ -0,0 +1,5 @@ +--liquibase formatted sql + +--changeset derek:add receipt date in stock in line +ALTER TABLE `stock_in_line` +CHANGE COLUMN `shelfLifeDate` `expiryDate` DATE NULL; \ No newline at end of file diff --git a/src/main/resources/db/changelog/changes/20250515_01_derek/07_update_add_product_lotno.sql b/src/main/resources/db/changelog/changes/20250515_01_derek/07_update_add_product_lotno.sql new file mode 100644 index 0000000..3f3d7a0 --- /dev/null +++ b/src/main/resources/db/changelog/changes/20250515_01_derek/07_update_add_product_lotno.sql @@ -0,0 +1,5 @@ +--liquibase formatted sql + +--changeset derek:add product lotno in stock in line +ALTER TABLE `stock_in_line` +ADD COLUMN `productLotNo` VARCHAR(255) NULL; diff --git a/src/main/resources/db/changelog/changes/20250515_01_derek/08_update_change_to_productionDate.sql b/src/main/resources/db/changelog/changes/20250515_01_derek/08_update_change_to_productionDate.sql new file mode 100644 index 0000000..b8b18e4 --- /dev/null +++ b/src/main/resources/db/changelog/changes/20250515_01_derek/08_update_change_to_productionDate.sql @@ -0,0 +1,5 @@ +--liquibase formatted sql + +--changeset derek:RENAME PRODUCT DATE in stock in line +ALTER TABLE `stock_in_line` +CHANGE COLUMN `productDate` `productionDate` DATETIME NULL; \ No newline at end of file