@@ -2,18 +2,16 @@ package com.ffii.fpsms.modules.pickOrder.service | |||||
import com.ffii.core.response.RecordsRes | import com.ffii.core.response.RecordsRes | ||||
import com.ffii.fpsms.modules.common.SecurityUtils | import com.ffii.fpsms.modules.common.SecurityUtils | ||||
import com.ffii.fpsms.modules.master.web.models.MessageResponse | |||||
import com.ffii.fpsms.modules.pickOrder.entity.PickOrder | |||||
import com.ffii.fpsms.modules.pickOrder.entity.PickOrderRepository | import com.ffii.fpsms.modules.pickOrder.entity.PickOrderRepository | ||||
import com.ffii.fpsms.modules.pickOrder.entity.projection.PickOrderInfo | import com.ffii.fpsms.modules.pickOrder.entity.projection.PickOrderInfo | ||||
import com.ffii.fpsms.modules.pickOrder.entity.projection.PickOrderLineInfo | |||||
import com.ffii.fpsms.modules.pickOrder.enums.PickOrderStatus | import com.ffii.fpsms.modules.pickOrder.enums.PickOrderStatus | ||||
import com.ffii.fpsms.modules.pickOrder.web.models.* | import com.ffii.fpsms.modules.pickOrder.web.models.* | ||||
import com.ffii.fpsms.modules.stock.entity.InventoryLotLineRepository | |||||
import com.ffii.fpsms.modules.stock.entity.projection.CurrentInventoryItemInfo | |||||
import com.ffii.fpsms.modules.stock.service.StockOutLineService | import com.ffii.fpsms.modules.stock.service.StockOutLineService | ||||
import com.ffii.fpsms.modules.stock.service.SuggestedPickLotService | import com.ffii.fpsms.modules.stock.service.SuggestedPickLotService | ||||
import com.ffii.fpsms.modules.stock.web.model.SuggestedPickLotForPoRequest | import com.ffii.fpsms.modules.stock.web.model.SuggestedPickLotForPoRequest | ||||
import com.ffii.fpsms.modules.user.service.UserService | import com.ffii.fpsms.modules.user.service.UserService | ||||
import org.springframework.context.annotation.Lazy | |||||
import org.springframework.data.domain.PageRequest | import org.springframework.data.domain.PageRequest | ||||
import org.springframework.stereotype.Service | import org.springframework.stereotype.Service | ||||
import java.io.Serializable | import java.io.Serializable | ||||
@@ -28,7 +26,7 @@ open class PickOrderService( | |||||
val pickOrderRepository: PickOrderRepository, | val pickOrderRepository: PickOrderRepository, | ||||
val stockOutLineService: StockOutLineService, | val stockOutLineService: StockOutLineService, | ||||
val suggestedPickLotService: SuggestedPickLotService, | val suggestedPickLotService: SuggestedPickLotService, | ||||
val userService: UserService, | |||||
val userService: UserService, private val inventoryLotLineRepository: InventoryLotLineRepository, | |||||
) { | ) { | ||||
open fun localDateTimeParse(dateTime: String?, pattern: String? = "YYYY-MM-DD hh:mm:ss"): LocalDateTime? { | open fun localDateTimeParse(dateTime: String?, pattern: String? = "YYYY-MM-DD hh:mm:ss"): LocalDateTime? { | ||||
try { | try { | ||||
@@ -69,7 +67,6 @@ open class PickOrderService( | |||||
val prefix = "PICK" | val prefix = "PICK" | ||||
val midfix = LocalDate.now().format(formatter) | val midfix = LocalDate.now().format(formatter) | ||||
println(midfix) | |||||
val suffix = String.format(suffixFormat, 1) | val suffix = String.format(suffixFormat, 1) | ||||
val latestConsoCode = pickOrderRepository.findLatestConsoCodeByPrefix("${prefix}-${midfix}") | val latestConsoCode = pickOrderRepository.findLatestConsoCodeByPrefix("${prefix}-${midfix}") | ||||
@@ -240,16 +237,43 @@ open class PickOrderService( | |||||
return response | return response | ||||
} | } | ||||
open fun releaseConsoPickOrderInfo() { | |||||
open fun releaseConsoPickOrderInfo(request: ReleaseConsoPickOrderRequest): ReleasePickOrderInfoResponse { | |||||
val zero = BigDecimal.ZERO | |||||
val pos = pickOrderRepository.findAllByConsoCode(request.consoCode) | |||||
val requiredItems = pos | |||||
.flatMap { it.pickOrderLines } | |||||
.groupBy { it.item?.id } | |||||
.map { (key, value) -> key to object : CurrentInventoryItemInfo { | |||||
override val id: Long? = value[0].item?.id | |||||
override val code: String? = value[0].item?.code | |||||
override val name: String? = value[0].item?.name | |||||
override var availableQty: BigDecimal? = zero | |||||
override val requiredQty: BigDecimal = value.sumOf { it.qty ?: zero } | |||||
}} // itemId - requiredQty | |||||
val itemIds = requiredItems.mapNotNull { it.first } | |||||
val inventories = inventoryLotLineRepository.findCurrentInventoryByItems(itemIds) | |||||
val currentInventoryInfos = requiredItems.map { item -> | |||||
val inventory = inventories.find { it.id == item.first } | |||||
item.second.let { | |||||
it.availableQty = inventory?.availableQty | |||||
// return | |||||
it | |||||
} | |||||
} | |||||
return ReleasePickOrderInfoResponse( | |||||
consoCode = request.consoCode, | |||||
items = currentInventoryInfos, | |||||
) | |||||
} | } | ||||
open fun releaseConsoPickOrderAction(request: ReleaseConsoPickOrderRequest) { | open fun releaseConsoPickOrderAction(request: ReleaseConsoPickOrderRequest) { | ||||
val releasedBy = SecurityUtils.getUser().getOrNull() | val releasedBy = SecurityUtils.getUser().getOrNull() | ||||
val assignTo = request.assignTo?.let { userService.find(it) }?.getOrNull() | val assignTo = request.assignTo?.let { userService.find(it) }?.getOrNull() | ||||
println("123") | |||||
val pos = pickOrderRepository.findAllByConsoCode(request.consoCode) | val pos = pickOrderRepository.findAllByConsoCode(request.consoCode) | ||||
println("456") | |||||
pos.forEach { | pos.forEach { | ||||
it.apply { | it.apply { | ||||
this.releasedBy = releasedBy | this.releasedBy = releasedBy | ||||
@@ -257,10 +281,6 @@ open class PickOrderService( | |||||
status = PickOrderStatus.RELEASED | status = PickOrderStatus.RELEASED | ||||
} | } | ||||
} | } | ||||
println(pos[0].releasedBy?.id) | |||||
pickOrderRepository.saveAll(pos) | pickOrderRepository.saveAll(pos) | ||||
// val suggestedPickLots = suggestedPickLotService.convertRequestsToEntities(request.suggestedPickLots) | |||||
// | |||||
// suggestedPickLotService.saveAll(suggestedPickLots) | |||||
} | } | ||||
} | } |
@@ -4,10 +4,7 @@ import com.ffii.core.response.RecordsRes | |||||
import com.ffii.fpsms.modules.pickOrder.entity.PickOrderRepository | import com.ffii.fpsms.modules.pickOrder.entity.PickOrderRepository | ||||
import com.ffii.fpsms.modules.pickOrder.entity.projection.PickOrderInfo | import com.ffii.fpsms.modules.pickOrder.entity.projection.PickOrderInfo | ||||
import com.ffii.fpsms.modules.pickOrder.service.PickOrderService | import com.ffii.fpsms.modules.pickOrder.service.PickOrderService | ||||
import com.ffii.fpsms.modules.pickOrder.web.models.ConsoPickOrderRequest | |||||
import com.ffii.fpsms.modules.pickOrder.web.models.ConsoPickOrderResponse | |||||
import com.ffii.fpsms.modules.pickOrder.web.models.ReleaseConsoPickOrderRequest | |||||
import com.ffii.fpsms.modules.pickOrder.web.models.SearchPickOrderRequest | |||||
import com.ffii.fpsms.modules.pickOrder.web.models.* | |||||
import jakarta.validation.Valid | import jakarta.validation.Valid | ||||
import org.springframework.data.domain.Page | import org.springframework.data.domain.Page | ||||
import org.springframework.data.domain.PageRequest | import org.springframework.data.domain.PageRequest | ||||
@@ -56,8 +53,13 @@ class PickOrderController( | |||||
return pickOrderService.consoPickOrderDetail(consoCode); | return pickOrderService.consoPickOrderDetail(consoCode); | ||||
} | } | ||||
@GetMapping("/releaseConso") | |||||
fun releaseConsoPickOrderInfo(@Valid @RequestBody request: ReleaseConsoPickOrderRequest): ReleasePickOrderInfoResponse { | |||||
return pickOrderService.releaseConsoPickOrderInfo(request); | |||||
} | |||||
@PostMapping("/releaseConso") | @PostMapping("/releaseConso") | ||||
fun releaseConsoPickOrders(@Valid @RequestBody request: ReleaseConsoPickOrderRequest) { | |||||
fun releaseConsoPickOrderAction(@Valid @RequestBody request: ReleaseConsoPickOrderRequest) { | |||||
pickOrderService.releaseConsoPickOrderAction(request) | pickOrderService.releaseConsoPickOrderAction(request) | ||||
} | } | ||||
} | } |
@@ -1,20 +1,13 @@ | |||||
package com.ffii.fpsms.modules.pickOrder.web.models | package com.ffii.fpsms.modules.pickOrder.web.models | ||||
import com.ffii.fpsms.modules.stock.entity.projection.CurrentInventoryItemInfo | |||||
import java.math.BigDecimal | import java.math.BigDecimal | ||||
import java.time.LocalDateTime | import java.time.LocalDateTime | ||||
// Final Response - Release Conso Pick Order Page | // Final Response - Release Conso Pick Order Page | ||||
data class ReleasePickOrderInfoResponse( | data class ReleasePickOrderInfoResponse( | ||||
val consoCode: String, | val consoCode: String, | ||||
val inventory: List<ReleasePickOrderInfoInventory> | |||||
) | |||||
data class ReleasePickOrderInfoInventory( | |||||
val id: Long?, | |||||
val itemCode: String?, | |||||
val itemName: String?, | |||||
val availableQty: BigDecimal?, | |||||
val requiredQty: BigDecimal?, | |||||
val items: List<CurrentInventoryItemInfo> | |||||
) | ) | ||||
// Final Response - Conso Pick Order Detail | // Final Response - Conso Pick Order Detail | ||||
@@ -1,11 +1,27 @@ | |||||
package com.ffii.fpsms.modules.stock.entity | package com.ffii.fpsms.modules.stock.entity | ||||
import com.ffii.core.support.AbstractRepository | import com.ffii.core.support.AbstractRepository | ||||
import com.ffii.fpsms.modules.stock.entity.projection.CurrentInventoryItemInfo | |||||
import com.ffii.fpsms.modules.stock.entity.projection.InventoryLotLineInfo | import com.ffii.fpsms.modules.stock.entity.projection.InventoryLotLineInfo | ||||
import org.springframework.data.jpa.repository.Query | |||||
import org.springframework.stereotype.Repository | import org.springframework.stereotype.Repository | ||||
import java.io.Serializable | import java.io.Serializable | ||||
@Repository | @Repository | ||||
interface InventoryLotLineRepository : AbstractRepository<InventoryLotLine, Long> { | interface InventoryLotLineRepository : AbstractRepository<InventoryLotLine, Long> { | ||||
fun findInventoryLotLineInfoByInventoryLotItemIdIn(ids: List<Serializable>): List<InventoryLotLineInfo> | fun findInventoryLotLineInfoByInventoryLotItemIdIn(ids: List<Serializable>): List<InventoryLotLineInfo> | ||||
@Query(""" | |||||
select | |||||
i.id as id, | |||||
i.code as itemCode, | |||||
i.name as itemName, | |||||
sum(coalesce(ill.inQty, 0) - coalesce(ill.outQty, 0) - coalesce(ill.holdQty, 0)) as availableQty | |||||
from InventoryLotLine ill | |||||
left join InventoryLot il on ill.inventoryLot = il | |||||
left join Items i on il.item = i | |||||
where i.id in :items | |||||
group by i.id | |||||
""") | |||||
fun findCurrentInventoryByItems(items: List<Serializable>): List<CurrentInventoryItemInfo> | |||||
} | } |
@@ -20,17 +20,29 @@ interface InventoryLotLineWarehouseInfo { | |||||
interface InventoryLotLineInfo { | interface InventoryLotLineInfo { | ||||
val id: Long? | val id: Long? | ||||
@get:Value("#{target.inventoryLot.item}") | @get:Value("#{target.inventoryLot.item}") | ||||
val item: InventoryLotLineItemInfo? | val item: InventoryLotLineItemInfo? | ||||
val warehouse: InventoryLotLineWarehouseInfo? | val warehouse: InventoryLotLineWarehouseInfo? | ||||
var inQty: BigDecimal? | var inQty: BigDecimal? | ||||
var outQty: BigDecimal? | var outQty: BigDecimal? | ||||
var holdQty: BigDecimal? | var holdQty: BigDecimal? | ||||
@get:Value("#{target.status.value}") | @get:Value("#{target.status.value}") | ||||
val status: String? | val status: String? | ||||
val remarks: String? | val remarks: String? | ||||
@get:Value("#{target.stockUom.uom.udfudesc}") | @get:Value("#{target.stockUom.uom.udfudesc}") | ||||
val uom: String? | val uom: String? | ||||
@get:Value("#{target.inventoryLot.expiryDate}") | @get:Value("#{target.inventoryLot.expiryDate}") | ||||
val expiryDate: LocalDate | val expiryDate: LocalDate | ||||
} | |||||
interface CurrentInventoryItemInfo { | |||||
val id: Long? // item id | |||||
val code: String? | |||||
val name: String? | |||||
val availableQty: BigDecimal? | |||||
val requiredQty: BigDecimal? | |||||
} | } |
@@ -3,10 +3,7 @@ package com.ffii.fpsms.modules.stock.service | |||||
import com.ffii.fpsms.modules.pickOrder.entity.PickOrder | import com.ffii.fpsms.modules.pickOrder.entity.PickOrder | ||||
import com.ffii.fpsms.modules.pickOrder.entity.PickOrderLine | import com.ffii.fpsms.modules.pickOrder.entity.PickOrderLine | ||||
import com.ffii.fpsms.modules.pickOrder.entity.PickOrderLineRepository | import com.ffii.fpsms.modules.pickOrder.entity.PickOrderLineRepository | ||||
import com.ffii.fpsms.modules.stock.entity.InventoryLotLineRepository | |||||
import com.ffii.fpsms.modules.stock.entity.StockOutLIneRepository | |||||
import com.ffii.fpsms.modules.stock.entity.SuggestPickLotRepository | |||||
import com.ffii.fpsms.modules.stock.entity.SuggestedPickLot | |||||
import com.ffii.fpsms.modules.stock.entity.* | |||||
import com.ffii.fpsms.modules.stock.entity.enum.InventoryLotLineStatus | import com.ffii.fpsms.modules.stock.entity.enum.InventoryLotLineStatus | ||||
import com.ffii.fpsms.modules.stock.entity.projection.InventoryLotLineInfo | import com.ffii.fpsms.modules.stock.entity.projection.InventoryLotLineInfo | ||||
import com.ffii.fpsms.modules.stock.enums.SuggestedPickLotType | import com.ffii.fpsms.modules.stock.enums.SuggestedPickLotType | ||||
@@ -27,6 +24,22 @@ open class SuggestedPickLotService( | |||||
val pickOrderLineRepository: PickOrderLineRepository, | val pickOrderLineRepository: PickOrderLineRepository, | ||||
val inventoryLotLineService: InventoryLotLineService, | val inventoryLotLineService: InventoryLotLineService, | ||||
) { | ) { | ||||
// Calculation Available Qty / Remaining Qty | |||||
open fun calculateRemainingQtyForInfo(inventoryLotLine: InventoryLotLineInfo?): BigDecimal { | |||||
val zero = BigDecimal.ZERO | |||||
return (inventoryLotLine?.inQty ?: zero) | |||||
.minus(inventoryLotLine?.outQty ?: zero) | |||||
.minus((inventoryLotLine?.holdQty ?: zero)) | |||||
} | |||||
open fun calculateRemainingQty(inventoryLotLine: InventoryLotLine?): BigDecimal { | |||||
val zero = BigDecimal.ZERO | |||||
return (inventoryLotLine?.inQty ?: zero) | |||||
.minus(inventoryLotLine?.outQty ?: zero) | |||||
.minus((inventoryLotLine?.holdQty ?: zero)) | |||||
} | |||||
// Suggestion | |||||
open fun suggestionForPickOrders(request: SuggestedPickLotForPoRequest): SuggestedPickLotResponse { | open fun suggestionForPickOrders(request: SuggestedPickLotForPoRequest): SuggestedPickLotResponse { | ||||
val pos = request.pickOrders | val pos = request.pickOrders | ||||
val suggestedList = mutableListOf<SuggestedPickLot>() | val suggestedList = mutableListOf<SuggestedPickLot>() | ||||
@@ -70,11 +83,9 @@ open class SuggestedPickLotService( | |||||
lotLines.forEachIndexed { index, lotLine -> | lotLines.forEachIndexed { index, lotLine -> | ||||
if (remainingQty <= zero) return@forEachIndexed | if (remainingQty <= zero) return@forEachIndexed | ||||
val availableQty = (lotLine.inQty ?: zero) | |||||
.minus(lotLine.outQty ?: zero) | |||||
.minus((lotLine.holdQty ?: zero) | |||||
.plus(holdQtyMap[lotLine.id] ?: zero) | |||||
) | |||||
val availableQty = calculateRemainingQtyForInfo(lotLine) | |||||
.minus(holdQtyMap[lotLine.id] ?: zero) | |||||
if (availableQty <= zero) { | if (availableQty <= zero) { | ||||
updatedLotLines += lotLine | updatedLotLines += lotLine | ||||
@@ -109,6 +120,25 @@ open class SuggestedPickLotService( | |||||
return SuggestedPickLotResponse(holdQtyMap = holdQtyMap, suggestedList = suggestedList) | return SuggestedPickLotResponse(holdQtyMap = holdQtyMap, suggestedList = suggestedList) | ||||
} | } | ||||
// Convertion | |||||
open fun convertRequestsToEntities(request: List<SaveSuggestedPickLotRequest>): List<SuggestedPickLot> { | |||||
// val zero = BigDecimal.ZERO | |||||
// val entities = mutableListOf<SuggestedPickLot>() | |||||
// val holdQtyCount = mutableMapOf<Long?, BigDecimal?>() | |||||
// request.forEach { | |||||
// val entity = convertRequestToEntity(it) | |||||
// val suggestedLotLine = entity.suggestedLotLine | |||||
// val remainQty = calculateRemainingQty(suggestedLotLine) | |||||
// holdQtyCount[suggestedLotLine?.id] = (holdQtyCount[suggestedLotLine?.id] ?: zero).plus(suggestedLotLine?.holdQty ?: zero) | |||||
// if (remainQty.minus(holdQtyCount[suggestedLotLine?.id] ?: zero) < zero) { | |||||
// throw RuntimeException("The suggested pick qty is over. Please re-suggest the pick qty."); | |||||
// } | |||||
// entities += entity | |||||
// } | |||||
// return entities | |||||
return request.map { convertRequestToEntity(it) } | |||||
} | |||||
open fun convertRequestToEntity(request: SaveSuggestedPickLotRequest): SuggestedPickLot{ | open fun convertRequestToEntity(request: SaveSuggestedPickLotRequest): SuggestedPickLot{ | ||||
val suggestedPickLot = | val suggestedPickLot = | ||||
request.id?.let { id -> suggestedPickLotRepository.findById(id).getOrDefault(SuggestedPickLot()) } | request.id?.let { id -> suggestedPickLotRepository.findById(id).getOrDefault(SuggestedPickLot()) } | ||||
@@ -130,6 +160,7 @@ open class SuggestedPickLotService( | |||||
return suggestedPickLot | return suggestedPickLot | ||||
} | } | ||||
// Save | |||||
open fun saveSuggestedPickLot(request: SaveSuggestedPickLotRequest): SuggestedPickLot { | open fun saveSuggestedPickLot(request: SaveSuggestedPickLotRequest): SuggestedPickLot { | ||||
val suggestedPickLot = convertRequestToEntity(request) | val suggestedPickLot = convertRequestToEntity(request) | ||||