Selaa lähdekoodia

update stockout + ledger

create_edit_user
MSI\derek 4 kuukautta sitten
vanhempi
commit
9d65dd4e93
13 muutettua tiedostoa jossa 450 lisäystä ja 22 poistoa
  1. +0
    -6
      src/main/java/com/ffii/fpsms/enums/Enums.kt
  2. +1
    -1
      src/main/java/com/ffii/fpsms/m18/service/M18TokenService.kt
  3. +35
    -0
      src/main/java/com/ffii/fpsms/modules/stock/entity/StockLedger.kt
  4. +8
    -0
      src/main/java/com/ffii/fpsms/modules/stock/entity/StockLedgerRepository.kt
  5. +41
    -0
      src/main/java/com/ffii/fpsms/modules/stock/entity/StockOut.kt
  6. +11
    -0
      src/main/java/com/ffii/fpsms/modules/stock/entity/StockOutLIneRepository.kt
  7. +39
    -0
      src/main/java/com/ffii/fpsms/modules/stock/entity/StockOutLine.kt
  8. +8
    -0
      src/main/java/com/ffii/fpsms/modules/stock/entity/StockOutRepository.kt
  9. +17
    -15
      src/main/java/com/ffii/fpsms/modules/stock/service/InventoryService.kt
  10. +119
    -0
      src/main/java/com/ffii/fpsms/modules/stock/service/StockOutLineService.kt
  11. +125
    -0
      src/main/java/com/ffii/fpsms/modules/stock/service/StockOutService.kt
  12. +40
    -0
      src/main/java/com/ffii/fpsms/modules/stock/web/model/SaveStockOutRequest.kt
  13. +6
    -0
      src/main/resources/db/changelog/changes/20250327_01_derek/01_update_stockoutline.sql

+ 0
- 6
src/main/java/com/ffii/fpsms/enums/Enums.kt Näytä tiedosto

@@ -1,6 +0,0 @@
package com.ffii.fpsms.enums

enum class Status(val value: Int) {
PENDING(1),
COMPLETE(2)
}

+ 1
- 1
src/main/java/com/ffii/fpsms/m18/service/M18TokenService.kt Näytä tiedosto

@@ -16,7 +16,7 @@ open class M18TokenService(
private val m18Config: M18Config
) {

@PostConstruct
// @Bean
fun run() {
// val params: MutableMap<String, String> = mutableMapOf(
// "grant_type" to m18Config.GRANT_TYPE,


+ 35
- 0
src/main/java/com/ffii/fpsms/modules/stock/entity/StockLedger.kt Näytä tiedosto

@@ -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.JoinColumn
import jakarta.persistence.OneToOne
import jakarta.persistence.Table
import jakarta.validation.constraints.NotNull

@Entity
@Table(name = "stock_ledger")
open class StockLedger: BaseEntity<Long>() {
// @OneToOne
// @JoinColumn(name = "stockInLineId")
// open var stockInLine: StockInLine? = null

@OneToOne
@JoinColumn(name = "stockOutLineId")
open var stockOutLine: StockOutLine? = null

@NotNull
@OneToOne
@JoinColumn(name = "inventoryId")
open var inventory: Inventory? = null

@Column(name = "inQty")
open var inQty: Double? = null

@Column(name = "outQty")
open var outQty: Double? = null

@Column(name = "balance")
open var balance: Double? = null
}

+ 8
- 0
src/main/java/com/ffii/fpsms/modules/stock/entity/StockLedgerRepository.kt Näytä tiedosto

@@ -0,0 +1,8 @@
package com.ffii.fpsms.modules.stock.entity

import com.ffii.core.support.AbstractRepository
import org.springframework.stereotype.Repository

@Repository
interface StockLedgerRepository: AbstractRepository<StockLedger, Long> {
}

+ 41
- 0
src/main/java/com/ffii/fpsms/modules/stock/entity/StockOut.kt Näytä tiedosto

@@ -0,0 +1,41 @@
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 java.time.LocalDateTime

@Entity
@Table(name = "stock_out")
open class StockOut : BaseEntity<Long>(){
@NotNull
@Column(name = "type")
open var type: String? = null

@Column(name = "deliveryOrderCode")
open var deliveryOrderCode: String? = null

@Column(name = "pickOrderCode")
open var pickOrderCode: String? = null

@Column(name = "consoCode")
open var consoCode: String? = null

@Column(name = "completeDate")
open var completeDate: LocalDateTime? = null

@Column(name = "status")
open var status: String? = null

@Column(name = "handlerId")
open var handler: Long? = null

@Column(name = "targetOutletId")
open var targetOutletId: Long? = null

@Column(name = "remarks")
open var remarks: String? = null

}

+ 11
- 0
src/main/java/com/ffii/fpsms/modules/stock/entity/StockOutLIneRepository.kt Näytä tiedosto

@@ -0,0 +1,11 @@
package com.ffii.fpsms.modules.stock.entity

import com.ffii.core.support.AbstractRepository
import com.ffii.fpsms.modules.stock.web.model.StockOutStatus
import org.springframework.stereotype.Repository

@Repository
interface StockOutLIneRepository: AbstractRepository<StockOutLine, Long> {
fun findAllByStockOutIdAndDeletedFalse(stockOutId: Long): List<StockOutLine>
// fun findAllByStockOutIdAndDeletedFalse(stockOutId: Long, status: StockOutStatus): List<StockOutLine>
}

+ 39
- 0
src/main/java/com/ffii/fpsms/modules/stock/entity/StockOutLine.kt Näytä tiedosto

@@ -0,0 +1,39 @@
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 java.time.LocalDateTime

@Entity
@Table(name = "stock_out_line")
open class StockOutLine: BaseEntity<Long>() {
@NotNull
@OneToOne
@JoinColumn(name = "itemId")
open var item: Items? = null

@NotNull
@Column(name = "qty")
open var qty: Double? = null

@NotNull
@JoinColumn(name = "stockOutId")
open var stockOut: StockOut? = null

@NotNull
@OneToOne
@JoinColumn(name = "inventoryId")
open var inventory: Inventory? = null

@NotNull
@Column(name = "status")
open var status: String? = null

@Column(name = "pickTime")
open var pickTime: LocalDateTime? = null

@Column(name = "pickerId")
open var pickerId: Long? = null
}

+ 8
- 0
src/main/java/com/ffii/fpsms/modules/stock/entity/StockOutRepository.kt Näytä tiedosto

@@ -0,0 +1,8 @@
package com.ffii.fpsms.modules.stock.entity

import com.ffii.core.support.AbstractRepository
import org.springframework.stereotype.Repository

@Repository
interface StockOutRepository: AbstractRepository<StockOut, Long> {
}

+ 17
- 15
src/main/java/com/ffii/fpsms/modules/stock/service/InventoryService.kt Näytä tiedosto

@@ -8,6 +8,7 @@ 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
@@ -25,22 +26,28 @@ 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
val reqQty = if (request.type === "out") {
request.qty * -1
} else {
request.qty
}
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 be changing
// stock in line should be changing
// item id should be changing
// 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
@@ -64,15 +71,10 @@ open class InventoryService(
val args = mapOf(
"from" to from,
"to" to to,
)
val sql = StringBuilder("select"
+ " count(id) "
+ " from inventory i "
+ " where i.created >= :from "
+ " and i.created = :to "
"itemId" to item.id
)
val prefix = "LOT"
val count = jdbcDao.queryForInt(sql.toString(), args)
val count = jdbcDao.queryForInt(INVENTORY_COUNT.toString(), args)
val newLotNo = CodeGenerator.generateCode(prefix, item.id!!, count)
val newExpiry = request.expiryDate
inventory.apply {


+ 119
- 0
src/main/java/com/ffii/fpsms/modules/stock/service/StockOutLineService.kt Näytä tiedosto

@@ -0,0 +1,119 @@
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.stock.entity.*
import com.ffii.fpsms.modules.stock.web.model.SaveStockOutLineRequest
import com.ffii.fpsms.modules.stock.web.model.SaveStockOutRequest
import com.ffii.fpsms.modules.stock.web.model.StockOutLineStatus
import com.ffii.fpsms.modules.stock.web.model.StockOutStatus
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import java.io.IOException
import java.time.LocalDate
import java.time.LocalDateTime

@Service
open class StockOutLineService(
private val jdbcDao: JdbcDao,
private val stockOutRepository: StockOutRepository,
private val stockOutLIneRepository: StockOutLIneRepository,
private val itemRepository: ItemsRepository,
private val inventoryRepository: InventoryRepository,
): AbstractBaseEntityService<StockOutLine, Long, StockOutLIneRepository>(jdbcDao, stockOutLIneRepository) {
@Throws(IOException::class)
@Transactional
open fun findAllByStockOutId(stockOutId: Long): List<StockOutLine> {
return stockOutLIneRepository.findAllByStockOutIdAndDeletedFalse(stockOutId)
}
@Throws(IOException::class)
@Transactional
open fun deleteById(id: Long): String {
val deleteStockOutline = stockOutLIneRepository.findById(id).orElseThrow().apply {
deleted = true
}
val updateItem = stockOutLIneRepository.save(deleteStockOutline)
val response = "mark deleted item: ${updateItem.id}"
return response
}
@Throws(IOException::class)
@Transactional
open fun deleteByStockOutId(id: Long): String {
val deleteStockOutline = stockOutLIneRepository.findAllByStockOutIdAndDeletedFalse(id).map {sol ->
sol.apply {
deleted = true
}
}
val updateItemIds = stockOutLIneRepository.saveAllAndFlush(deleteStockOutline).map { it.id }
val response = "mark deleted items: $updateItemIds"
return response
}

@Throws(IOException::class)
@Transactional
/// only create??????
open fun create(request: SaveStockOutLineRequest): MessageResponse {
val stockOutLine = StockOutLine()
val item = itemRepository.findById(request.itemId).orElseThrow()
stockOutLine.apply {
this.item = item
qty = request.qty
status = StockOutLineStatus.PENDING.status //create the base record = the original total sum of one item
}
val savedStockOutLine = stockOutLIneRepository.saveAndFlush(stockOutLine)
return MessageResponse(
id = savedStockOutLine.id,
code = item.code,
name = item.name,
type = savedStockOutLine.status,
message = "save success",
errorPosition = null
)
}
// stock out -> stock out line record : {qty = 100}
// each pick create new stock out line {...sol, status = picked}
// when confirm all picked and complete in web
// update:
// 1.stock out status
// remove:
// 1.stock out line : {qty = 100}
@Throws(IOException::class)
@Transactional
open fun pick(request: SaveStockOutLineRequest): MessageResponse {
val item = itemRepository.findById(request.itemId).orElseThrow()
if (request.inventoryId === null) {
return MessageResponse(
id = request.id,
code = null,
name = item.name,
type = null,
message = "inventory is null or not exist",
errorPosition = "inventoryId"
)
}
val stockOutLine = StockOutLine()
val _stockOut = stockOutRepository.findById(request.stockOutId).orElseThrow()
val _inventory = inventoryRepository.findById(request.inventoryId).orElseThrow()
val picker = request.pickerId
stockOutLine.apply {
this.item = item
qty = request.qty
stockOut = _stockOut
inventory = _inventory
status = "picked"
pickTime = LocalDateTime.now()
pickerId = picker
}
val savedOutLine = stockOutLIneRepository.saveAndFlush(stockOutLine)
return MessageResponse(
id = savedOutLine.id,
code = null,
name = null,
type = savedOutLine.status,
message = "item picked",
errorPosition = null
)
}
}

+ 125
- 0
src/main/java/com/ffii/fpsms/modules/stock/service/StockOutService.kt Näytä tiedosto

@@ -0,0 +1,125 @@
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.Items
import com.ffii.fpsms.modules.master.entity.ItemsRepository
import com.ffii.fpsms.modules.master.web.models.MessageResponse
import com.ffii.fpsms.modules.stock.entity.*
import com.ffii.fpsms.modules.stock.web.model.SaveStockOutRequest
import com.ffii.fpsms.modules.stock.web.model.StockOutLineStatus
import com.ffii.fpsms.modules.stock.web.model.StockOutStatus
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import java.io.IOException
import java.time.LocalDate
import java.time.LocalDateTime

@Service
open class StockOutService(
private val jdbcDao: JdbcDao,
private val stockOutRepository: StockOutRepository,
private val stockOutLIneRepository: StockOutLIneRepository,
private val stockOutLineService: StockOutLineService,
private val stockLedgerRepository: StockLedgerRepository,
): AbstractBaseEntityService<StockOut, Long, StockOutRepository>(jdbcDao, stockOutRepository) {
@Throws(IOException::class)
@Transactional
// update record data
open fun saveStockOut(request: SaveStockOutRequest): MessageResponse {
val stockOut = if (request.id !== null) stockOutRepository.findById(request.id).orElseThrow() else StockOut()
stockOut.apply {
type = request.type
deliveryOrderCode = request.deliveryOrderCode
pickOrderCode = request.pickOrderCode
consoCode = request.consoCode
completeDate = request.completeDate
handler = request.handler
targetOutletId = request.targetOutletId
remarks = request.remarks
}
val savedStockOut = stockOutRepository.saveAndFlush(stockOut)
// only create stock out line, no update
for (outLine in request.stockOutLine) {
stockOutLineService.create(outLine)
}
return MessageResponse(
id = savedStockOut.id,
code = savedStockOut.pickOrderCode ?: savedStockOut.deliveryOrderCode ,
name = savedStockOut.consoCode,
type = savedStockOut.type,
message = "save success",
errorPosition = null
)
}
@Throws(IOException::class)
@Transactional
open fun complete(request: SaveStockOutRequest): MessageResponse {
if (request.id === null) {
return MessageResponse(
id = null,
code = null,
name = null,
type = null,
message = "id cannot be null",
errorPosition = "id"
)
}
/// checking pick quantity
val stockOut = stockOutRepository.findById(request.id).orElseThrow()
val allLines = stockOutLineService.findAllByStockOutId(request.id)
val isBalanced = allLines.all{
val status = it.status
var sum = 0.0
when (status) {
StockOutLineStatus.PENDING.status -> sum += it.qty ?: 0.0;
StockOutLineStatus.PICKED.status -> sum -= it.qty ?: 0.0;
}
sum == 0.0
}
if (!isBalanced) {
return MessageResponse(
id = request.id,
code = stockOut.consoCode,
name = stockOut.pickOrderCode ?: stockOut.deliveryOrderCode,
type = stockOut.type,
message = "there are items not picked",
errorPosition = null
)
}
// remove base record
val baseLines = allLines.filter { stockOutLine -> stockOutLine.status === StockOutLineStatus.PENDING.status}
// update pick record to complete
val pickLines = allLines
.filter { stockOutLine -> stockOutLine.status === StockOutLineStatus.PICKED.status}
.map { stockOutLine ->
stockOutLine.apply {
status = StockOutLineStatus.COMPLETE.status
}
}
// write ledger
val ledgers = pickLines.map {stockOutLine ->
StockLedger().apply {
this.stockOutLine = stockOutLine
this.inventory = stockOutLine.inventory
outQty = stockOutLine.qty
}
}
stockLedgerRepository.saveAll(ledgers)
stockOutLIneRepository.deleteAll(baseLines)
stockOutLIneRepository.saveAll(pickLines)
stockOut.apply {
completeDate = LocalDateTime.now()
status = StockOutStatus.COMPLETE.status
}
val savedStockOut = stockOutRepository.saveAndFlush(stockOut)
return MessageResponse(
id = savedStockOut.id,
code = savedStockOut.consoCode,
name = savedStockOut.pickOrderCode ?: savedStockOut.deliveryOrderCode,
type = savedStockOut.type,
message = "stock out completed",
errorPosition = null
)
}
}

+ 40
- 0
src/main/java/com/ffii/fpsms/modules/stock/web/model/SaveStockOutRequest.kt Näytä tiedosto

@@ -0,0 +1,40 @@
package com.ffii.fpsms.modules.stock.web.model

import java.time.LocalDate
import java.time.LocalDateTime

enum class StockOutStatus(val status: String) {
PENDING("pending"),
COMPLETE("completed"),
// CANCELLED("cancelled")
}
enum class StockOutLineStatus(val status: String) {
PENDING("pending"),
PICKED("picked"),
COMPLETE("completed"),
// CANCELLED("cancelled")
}
data class SaveStockOutRequest(
val id: Long?,
val type: String, // delivery || pick || etc
val deliveryOrderCode: String?,
val pickOrderCode: String?,
val consoCode: String?,
val completeDate: LocalDateTime?,
val status: StockOutStatus?,
val handler: Long?,
val targetOutletId: Long?,
val remarks: String?,
val stockOutLine: List<SaveStockOutLineRequest>
)

data class SaveStockOutLineRequest(
val id: Long?,
val itemId: Long,
val qty: Double,
val stockOutId: Long,
val inventoryId: Long?,
val status: StockOutLineStatus?,
val pickTime: LocalDateTime?,
val pickerId: Long?
)

+ 6
- 0
src/main/resources/db/changelog/changes/20250327_01_derek/01_update_stockoutline.sql Näytä tiedosto

@@ -0,0 +1,6 @@
--liquibase formatted sql

--changeset derek:m18_raw_data
ALTER TABLE `stock_out_line`
ADD COLUMN `stockOutId` INT NOT NULL AFTER `qty`,
ADD CONSTRAINT FK_STOCKOUT_LINE_STOCKOUT_ID FOREIGN KEY (stockOutId) REFERENCES stock_out (id);

Ladataan…
Peruuta
Tallenna