@@ -10,12 +10,12 @@ import java.time.LocalDateTime | |||
@Table(name = "item_uom") | |||
open class ItemUom : BaseEntity<Long>() { | |||
@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 | |||
@@ -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<Long>(){ | |||
@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 | |||
} |
@@ -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, | |||
@@ -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 | |||
} | |||
@@ -56,6 +56,7 @@ open class PurchaseOrderService( | |||
thisPol.itemNo!!, | |||
thisPol.item!!.name, | |||
thisPol.qty!!, | |||
thisPol.uom!!.code, | |||
thisPol.price!!, | |||
thisPol.status!!.toString(), | |||
inLine | |||
@@ -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<Long>(){ | |||
@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 | |||
} |
@@ -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<Long>() { | |||
@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<String, Any>? = null | |||
} |
@@ -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<Long>() { | |||
@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<String, Any?>? = null | |||
} |
@@ -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<InventoryLotLine, Long> { | |||
} |
@@ -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<Long>() { | |||
@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<String, Any>? = null | |||
} |
@@ -4,5 +4,5 @@ import com.ffii.core.support.AbstractRepository | |||
import org.springframework.stereotype.Repository | |||
@Repository | |||
interface InventoryLotNoRepository : AbstractRepository<InventoryLotNo, Long> { | |||
interface InventoryLotRepository: AbstractRepository<InventoryLot, Long> { | |||
} |
@@ -4,5 +4,5 @@ import com.ffii.core.support.AbstractRepository | |||
import org.springframework.stereotype.Repository | |||
@Repository | |||
interface InventoryRepository : AbstractRepository<Inventory, Long> { | |||
interface InventoryRepository: AbstractRepository<Inventory, Long> { | |||
} |
@@ -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<Long>() { | |||
@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 | |||
} |
@@ -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? | |||
} |
@@ -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<InventoryLot, Long, InventoryLotRepository>(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, | |||
) | |||
} | |||
} |
@@ -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 | |||
// ) | |||
// } | |||
// } | |||
} |
@@ -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<StockInLine, Long, StockInLineRepository>(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 | |||
) | |||
} | |||
} | |||
@@ -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" | |||
) | |||
} | |||
} |
@@ -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?, | |||
) |
@@ -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?, | |||
) |
@@ -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`); |
@@ -0,0 +1,5 @@ | |||
--liquibase formatted sql | |||
--changeset derek:update inventory data type | |||
ALTER TABLE `inventory` | |||
MODIFY COLUMN `price` INT NOT NULL; |
@@ -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; |
@@ -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`; |
@@ -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`; |
@@ -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; |
@@ -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; |
@@ -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; |