| @@ -2,18 +2,16 @@ package com.ffii.fpsms.modules.pickOrder.service | |||
| import com.ffii.core.response.RecordsRes | |||
| 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.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.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.SuggestedPickLotService | |||
| import com.ffii.fpsms.modules.stock.web.model.SuggestedPickLotForPoRequest | |||
| import com.ffii.fpsms.modules.user.service.UserService | |||
| import org.springframework.context.annotation.Lazy | |||
| import org.springframework.data.domain.PageRequest | |||
| import org.springframework.stereotype.Service | |||
| import java.io.Serializable | |||
| @@ -28,7 +26,7 @@ open class PickOrderService( | |||
| val pickOrderRepository: PickOrderRepository, | |||
| val stockOutLineService: StockOutLineService, | |||
| 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? { | |||
| try { | |||
| @@ -69,7 +67,6 @@ open class PickOrderService( | |||
| val prefix = "PICK" | |||
| val midfix = LocalDate.now().format(formatter) | |||
| println(midfix) | |||
| val suffix = String.format(suffixFormat, 1) | |||
| val latestConsoCode = pickOrderRepository.findLatestConsoCodeByPrefix("${prefix}-${midfix}") | |||
| @@ -240,16 +237,43 @@ open class PickOrderService( | |||
| 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) { | |||
| val releasedBy = SecurityUtils.getUser().getOrNull() | |||
| val assignTo = request.assignTo?.let { userService.find(it) }?.getOrNull() | |||
| println("123") | |||
| val pos = pickOrderRepository.findAllByConsoCode(request.consoCode) | |||
| println("456") | |||
| pos.forEach { | |||
| it.apply { | |||
| this.releasedBy = releasedBy | |||
| @@ -257,10 +281,6 @@ open class PickOrderService( | |||
| status = PickOrderStatus.RELEASED | |||
| } | |||
| } | |||
| println(pos[0].releasedBy?.id) | |||
| 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.projection.PickOrderInfo | |||
| 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 org.springframework.data.domain.Page | |||
| import org.springframework.data.domain.PageRequest | |||
| @@ -56,8 +53,13 @@ class PickOrderController( | |||
| return pickOrderService.consoPickOrderDetail(consoCode); | |||
| } | |||
| @GetMapping("/releaseConso") | |||
| fun releaseConsoPickOrderInfo(@Valid @RequestBody request: ReleaseConsoPickOrderRequest): ReleasePickOrderInfoResponse { | |||
| return pickOrderService.releaseConsoPickOrderInfo(request); | |||
| } | |||
| @PostMapping("/releaseConso") | |||
| fun releaseConsoPickOrders(@Valid @RequestBody request: ReleaseConsoPickOrderRequest) { | |||
| fun releaseConsoPickOrderAction(@Valid @RequestBody request: ReleaseConsoPickOrderRequest) { | |||
| pickOrderService.releaseConsoPickOrderAction(request) | |||
| } | |||
| } | |||
| @@ -1,20 +1,13 @@ | |||
| package com.ffii.fpsms.modules.pickOrder.web.models | |||
| import com.ffii.fpsms.modules.stock.entity.projection.CurrentInventoryItemInfo | |||
| import java.math.BigDecimal | |||
| import java.time.LocalDateTime | |||
| // Final Response - Release Conso Pick Order Page | |||
| data class ReleasePickOrderInfoResponse( | |||
| 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 | |||
| @@ -1,11 +1,27 @@ | |||
| package com.ffii.fpsms.modules.stock.entity | |||
| 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 org.springframework.data.jpa.repository.Query | |||
| import org.springframework.stereotype.Repository | |||
| import java.io.Serializable | |||
| @Repository | |||
| interface InventoryLotLineRepository : AbstractRepository<InventoryLotLine, Long> { | |||
| 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 { | |||
| val id: Long? | |||
| @get:Value("#{target.inventoryLot.item}") | |||
| val item: InventoryLotLineItemInfo? | |||
| val warehouse: InventoryLotLineWarehouseInfo? | |||
| var inQty: BigDecimal? | |||
| var outQty: BigDecimal? | |||
| var holdQty: BigDecimal? | |||
| @get:Value("#{target.status.value}") | |||
| val status: String? | |||
| val remarks: String? | |||
| @get:Value("#{target.stockUom.uom.udfudesc}") | |||
| val uom: String? | |||
| @get:Value("#{target.inventoryLot.expiryDate}") | |||
| 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.PickOrderLine | |||
| 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.projection.InventoryLotLineInfo | |||
| import com.ffii.fpsms.modules.stock.enums.SuggestedPickLotType | |||
| @@ -27,6 +24,22 @@ open class SuggestedPickLotService( | |||
| val pickOrderLineRepository: PickOrderLineRepository, | |||
| 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 { | |||
| val pos = request.pickOrders | |||
| val suggestedList = mutableListOf<SuggestedPickLot>() | |||
| @@ -70,11 +83,9 @@ open class SuggestedPickLotService( | |||
| lotLines.forEachIndexed { index, lotLine -> | |||
| 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) { | |||
| updatedLotLines += lotLine | |||
| @@ -109,6 +120,25 @@ open class SuggestedPickLotService( | |||
| 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{ | |||
| val suggestedPickLot = | |||
| request.id?.let { id -> suggestedPickLotRepository.findById(id).getOrDefault(SuggestedPickLot()) } | |||
| @@ -130,6 +160,7 @@ open class SuggestedPickLotService( | |||
| return suggestedPickLot | |||
| } | |||
| // Save | |||
| open fun saveSuggestedPickLot(request: SaveSuggestedPickLotRequest): SuggestedPickLot { | |||
| val suggestedPickLot = convertRequestToEntity(request) | |||