@@ -15,7 +15,7 @@ open class M18TokenService( | |||
private val m18Config: M18Config | |||
) { | |||
@Bean | |||
// @Bean | |||
fun run() { | |||
// val params: MutableMap<String, String> = mutableMapOf( | |||
// "grant_type" to m18Config.GRANT_TYPE, | |||
@@ -153,6 +153,7 @@ open class PickOrderService( | |||
+ " i.name as itemName, " | |||
+ " pol.qty as qty, " | |||
+ " max(uc.code) as uom, " | |||
+ " group_concat(JSON_ARRAY(ill.id)) as lotLineId, " | |||
+ " group_concat(JSON_ARRAY(w.name)) as warehouse, " | |||
+ " group_concat(JSON_ARRAY(il.lotNo)) as suggestedLotNo " | |||
+ " from pick_order po " | |||
@@ -8,4 +8,5 @@ import org.springframework.stereotype.Repository | |||
@Repository | |||
interface QcResultRepository: AbstractRepository<QcResult, Long> { | |||
fun findQcResultInfoByStockInLineIdAndDeletedFalse(stockInLineId: Long): List<QcResultInfo> | |||
fun findQcResultInfoByStockOutLineIdAndDeletedFalse(stockOutLineId: Long): List<QcResultInfo> | |||
} |
@@ -10,7 +10,9 @@ interface QcResultInfo { | |||
val name: String | |||
@get:Value("#{target.qcItem.code}") | |||
val code: String | |||
@get:Value("#{target.stockInLine.id}") | |||
val stockInLineId: Long | |||
@get:Value("#{target.stockInLine?.id}") | |||
val stockInLineId: Long? | |||
@get:Value("#{target.stockOutLine?.id}") | |||
val stockOutLineId: Long? | |||
val failQty: Double | |||
} |
@@ -57,4 +57,7 @@ open class QcResultService( | |||
open fun getAllQcResultInfoByStockInLineId(stockInLineId: Long): List<QcResultInfo> { | |||
return qcResultRepository.findQcResultInfoByStockInLineIdAndDeletedFalse(stockInLineId) | |||
} | |||
open fun getAllQcResultInfoByStockOutLineId(stockOutLineId: Long): List<QcResultInfo> { | |||
return qcResultRepository.findQcResultInfoByStockOutLineIdAndDeletedFalse(stockOutLineId) | |||
} | |||
} |
@@ -23,4 +23,9 @@ class QcResultController( | |||
fun getAllQcResultInfoByStockInLineId(@PathVariable stockInLineId: Long): List<QcResultInfo> { | |||
return qcResultService.getAllQcResultInfoByStockInLineId(stockInLineId) | |||
} | |||
@GetMapping("/pick-order/{stockOutLineId}") | |||
fun getAllQcResultInfoByStockOutLineId(@PathVariable stockOutLineId: Long): List<QcResultInfo> { | |||
return qcResultService.getAllQcResultInfoByStockOutLineId(stockOutLineId) | |||
} | |||
} |
@@ -10,4 +10,8 @@ interface StockOutLIneRepository: AbstractRepository<StockOutLine, Long> { | |||
fun findAllByStockOutIdAndDeletedFalse(stockOutId: Long): List<StockOutLine> | |||
// fun findAllByStockOutIdAndDeletedFalse(stockOutId: Long, status: StockOutStatus): List<StockOutLine> | |||
fun findAllByPickOrderLineIdAndDeletedFalse(pickOrderLineId: Long): List<StockOutLineInfo> | |||
fun findAllByIdIn(id: List<Long>): List<StockOutLineInfo> | |||
fun findStockOutLineInfoById(id: Long): StockOutLineInfo | |||
} |
@@ -20,11 +20,13 @@ open class StockOutLine: BaseEntity<Long>() { | |||
@Column(name = "qty") | |||
open var qty: Double? = null | |||
@JsonBackReference | |||
@NotNull | |||
@ManyToOne | |||
@JoinColumn(name = "stockOutId") | |||
open var stockOut: StockOut? = null | |||
@JsonBackReference | |||
@ManyToOne | |||
@JoinColumn(name = "inventoryLotLineId") | |||
open var inventoryLotLine: InventoryLotLine? = null | |||
@@ -10,17 +10,21 @@ interface StockOutLineInfo { | |||
val itemId: Long | |||
@get:Value("#{target.item?.name}") | |||
val itemName: String? | |||
@get:Value("#{target.item?.code}") | |||
val itemNo: String | |||
val qty: BigDecimal | |||
@get:Value("#{target.stockOut?.id}") | |||
val stockOutId: Long | |||
@get:Value("#{target.pickOrderLine?.id}") | |||
val pickOrderLineId: Long | |||
val pickOrderLineId: Long? | |||
@get:Value("#{target.inventoryLotLine?.id}") | |||
val inventoryLotLineId: Long? | |||
@get:Value("#{target.inventoryLotLine?.inventoryLot?.lotNo}") | |||
val lotNo: String? | |||
val status: String | |||
val pickTime: LocalDateTime? | |||
} |
@@ -193,6 +193,26 @@ open class StockInLineService( | |||
@Transactional | |||
fun updatePurchaseOrderLineStatus(request: SaveStockInLineRequest) { | |||
println(request.status) | |||
if (request.status == StockInLineStatus.RECEIVING.status) { | |||
val unQcedLines = stockInLineRepository.findStockInLineInfoByPurchaseOrderLineIdAndDeletedFalse(purchaseOrderLineId = request.purchaseOrderLineId) | |||
.filter { | |||
it.status != StockInLineStatus.RECEIVING.status | |||
&& it.status != StockInLineStatus.RECEIVED.status | |||
&& it.status != StockInLineStatus.COMPLETE.status | |||
&& it.status != StockInLineStatus.REJECT.status | |||
} | |||
if (unQcedLines.isEmpty()) { | |||
// all stock in lines finished | |||
// change status of purchase order line | |||
val purchaseOrderLine = polRepository.findById(request.purchaseOrderLineId).orElseThrow() | |||
purchaseOrderLine.apply { | |||
status = PurchaseOrderLineStatus.RECEIVING | |||
} | |||
polRepository.saveAndFlush(purchaseOrderLine) | |||
} else { | |||
// still have unQcedLines lines | |||
} | |||
} | |||
if (request.status == StockInLineStatus.COMPLETE.status || request.status == StockInLineStatus.REJECT.status) { | |||
// val unfinishedLines = stockInLineRepository.findStockInLineInfoByPurchaseOrderLineIdAndStatusNotAndDeletedFalse(purchaseOrderLineId = request.purchaseOrderLineId, status = request.status!!) | |||
val unfinishedLines = stockInLineRepository.findStockInLineInfoByPurchaseOrderLineIdAndDeletedFalse(purchaseOrderLineId = request.purchaseOrderLineId) | |||
@@ -5,12 +5,11 @@ 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.pickOrder.entity.PickOrderLineRepository | |||
import com.ffii.fpsms.modules.pickOrder.enums.PickOrderLineStatus | |||
import com.ffii.fpsms.modules.stock.entity.* | |||
import com.ffii.fpsms.modules.stock.entity.projection.StockOutLineInfo | |||
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 com.ffii.fpsms.modules.stock.web.model.* | |||
import org.springframework.data.repository.query.Param | |||
import org.springframework.stereotype.Service | |||
import org.springframework.transaction.annotation.Transactional | |||
import java.io.IOException | |||
@@ -61,21 +60,30 @@ open class StockOutLineService( | |||
} | |||
@Transactional | |||
open fun create(request: SaveStockOutLineRequest): MessageResponse { | |||
open fun create(request: CreateStockOutLineRequest): MessageResponse { | |||
// pick flow step 1 | |||
// println(request.pickOrderLineId) | |||
val stockOut = stockOutRepository.findByConsoPickOrderCode(request.consoCode).orElseThrow() | |||
val pickOrderLine = pickOrderLineRepository.findById(request.pickOrderLineId).orElseThrow() | |||
val item = itemRepository.findById(request.itemId).orElseThrow() | |||
val pickOrderLine = pickOrderLineRepository.saveAndFlush( | |||
pickOrderLineRepository.findById(request.pickOrderLineId).orElseThrow() | |||
.apply { | |||
this.status = PickOrderLineStatus.PICKING | |||
} | |||
) | |||
val item = itemRepository.findById(pickOrderLine.item!!.id!!).orElseThrow() | |||
val inventoryLotLine = inventoryLotLineRepository.findById(request.inventoryLotLineId).orElseThrow() | |||
val stockOutLine = StockOutLine() | |||
.apply { | |||
this.item = item | |||
this.qty = request.qty | |||
this.stockOut = stockOut | |||
this.inventoryLotLine | |||
this.inventoryLotLine = inventoryLotLine | |||
this.pickOrderLine = pickOrderLine | |||
this.status = StockOutLineStatus.PENDING.status | |||
} | |||
val savedStockOutLine = saveAndFlush(stockOutLine) | |||
val mappedSavedStockOutLine = stockOutLineRepository.findStockOutLineInfoById(savedStockOutLine.id!!) | |||
// println("triggering") | |||
return MessageResponse( | |||
id = savedStockOutLine.id, | |||
name = savedStockOutLine.inventoryLotLine!!.inventoryLot!!.lotNo, | |||
@@ -83,13 +91,126 @@ open class StockOutLineService( | |||
type = savedStockOutLine.status, | |||
message = "success", | |||
errorPosition = null, | |||
entity = savedStockOutLine, | |||
entity = mappedSavedStockOutLine, | |||
) | |||
} | |||
@Transactional | |||
open fun update(request: SaveStockOutLineRequest) { | |||
val stockOutLine = stockOutLineRepository.findById(request.id!!).orElseThrow() | |||
fun handleQc(stockOutLine: StockOutLine, request: UpdateStockOutLineRequest): List<StockOutLine?> { | |||
var newStockOutLine: StockOutLine? = null | |||
if (request.qty < stockOutLine.qty!!) { | |||
newStockOutLine = StockOutLine().apply { | |||
this.pickOrderLine = stockOutLine.pickOrderLine | |||
this.stockOut = stockOutLine.stockOut | |||
this.item = stockOutLine.item | |||
this.qty = stockOutLine.qty!! - request.qty | |||
this.status = StockOutLineStatus.DETERMINE1.status // escalated | |||
} | |||
} | |||
val inventoryLotLine = if (request.inventoryLotLineId != null) | |||
inventoryLotLineRepository.findById(request.inventoryLotLineId).orElseThrow() | |||
else null | |||
stockOutLine.apply { | |||
this.inventoryLotLine = inventoryLotLine ?: stockOutLine.inventoryLotLine | |||
this.qty = request.qty | |||
this.status = StockOutLineStatus.COMPLETE.status // complete | |||
} | |||
return listOf(stockOutLine, newStockOutLine) | |||
} | |||
@Transactional | |||
fun handleLotChangeApprovalOrReject(stockOutLine: StockOutLine, request: UpdateStockOutLineRequest): List<StockOutLine?> { | |||
/** | |||
* @param request.qty | |||
* qty that requires lot change | |||
*/ | |||
var newStockOutLine: StockOutLine? = null | |||
if (request.qty < stockOutLine.qty!!) { | |||
newStockOutLine = StockOutLine().apply { | |||
this.pickOrderLine = stockOutLine.pickOrderLine | |||
this.stockOut = stockOutLine.stockOut | |||
this.item = stockOutLine.item | |||
this.qty = stockOutLine.qty!! - request.qty | |||
this.status = StockOutLineStatus.REJECTED.status // original status | |||
} | |||
} | |||
stockOutLine.apply { | |||
this.qty = request.qty | |||
this.status = StockOutLineStatus.LOT_CHANGE_APPROVAL.status // require new lot no | |||
} | |||
return listOf(stockOutLine, newStockOutLine) | |||
} | |||
// @Transactional | |||
// fun assignNewLotLine(stockOutLine: StockOutLine, request: UpdateStockOutLineRequest): List<StockOutLine?> { | |||
// val newInventoryLotLine = inventoryLotLineRepository.findById(request.inventoryLotLineId).orElseThrow() | |||
// return listOf(stockOutLine.apply { | |||
// this.inventoryLotLine = newInventoryLotLine | |||
// }) | |||
// } | |||
private fun checkIsStockOutLineCompleted(pickOrderLineId: Long) { | |||
val unfinishedLine = stockOutLineRepository | |||
.findAllByPickOrderLineIdAndDeletedFalse(pickOrderLineId) | |||
.filter { | |||
it.status != StockOutLineStatus.COMPLETE.status | |||
|| it.status != StockOutLineStatus.REJECTED.status | |||
} | |||
if (unfinishedLine.isEmpty()) { | |||
// set pick order line status to complete | |||
val pol = pickOrderLineRepository.findById(pickOrderLineId).orElseThrow() | |||
pickOrderLineRepository.save( | |||
pol.apply { | |||
this.status = PickOrderLineStatus.COMPLETED | |||
} | |||
) | |||
} else { | |||
// return unfinished ids to frontend | |||
} | |||
} | |||
@Transactional | |||
open fun update(request: UpdateStockOutLineRequest): MessageResponse { | |||
val stockOutLine = stockOutLineRepository.findById(request.id).orElseThrow() | |||
var stockOutLineEntries: List<StockOutLine?> = listOf() | |||
// pick flow step 2 | |||
if (request.status == StockOutLineStatus.COMPLETE.status) { // doing qc | |||
println("doing sth") | |||
if (request.qty <= 0) { | |||
return MessageResponse( | |||
id = null, | |||
code = null, | |||
name = null, | |||
type = "qty == 0", | |||
message = "qty cannot be 0", | |||
errorPosition = "request.qty", | |||
) | |||
} | |||
stockOutLineEntries = handleQc(stockOutLine, request) | |||
} | |||
if (request.status == StockOutLineStatus.LOT_CHANGE_APPROVAL.status) { | |||
if (request.qty < 0) { | |||
return MessageResponse( | |||
id = null, | |||
code = null, | |||
name = null, | |||
type = "qty < 0", | |||
message = "qty cannot be smaller than 0", | |||
errorPosition = "request.qty", | |||
) | |||
} | |||
stockOutLineEntries = handleLotChangeApprovalOrReject(stockOutLine, request) | |||
} | |||
checkIsStockOutLineCompleted(pickOrderLineId = stockOutLine.pickOrderLine!!.id!!) | |||
val savedEntries = stockOutLineRepository.saveAllAndFlush(stockOutLineEntries.filterNotNull()) | |||
val lineInfoList = stockOutLineRepository.findAllByIdIn(savedEntries.map { it.id!! }) | |||
return MessageResponse( | |||
id = 0, | |||
name = "id: ${lineInfoList.map { it.id }.joinToString(separator = ",")}", | |||
code = stockOutLine.stockOut!!.consoPickOrderCode, | |||
type = lineInfoList.joinToString(separator = ",") { it.status }, | |||
message = "success", | |||
errorPosition = null, | |||
entity = lineInfoList, | |||
) | |||
} | |||
} |
@@ -44,7 +44,7 @@ open class StockOutService( | |||
var sum = 0.0 | |||
when (status) { | |||
StockOutLineStatus.PENDING.status -> sum += it.qty ?: 0.0; | |||
StockOutLineStatus.PICKED.status -> sum -= it.qty ?: 0.0; | |||
// StockOutLineStatus.PICKED.status -> sum -= it.qty ?: 0.0; | |||
} | |||
sum == 0.0 | |||
} | |||
@@ -62,7 +62,7 @@ open class StockOutService( | |||
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} | |||
// .filter { stockOutLine -> stockOutLine.status === StockOutLineStatus.PICKED.status} | |||
.map { stockOutLine -> | |||
stockOutLine.apply { | |||
status = StockOutLineStatus.COMPLETE.status | |||
@@ -1,16 +1,15 @@ | |||
package com.ffii.fpsms.modules.stock.web | |||
import com.ffii.fpsms.modules.master.web.models.MessageResponse | |||
import com.ffii.fpsms.modules.purchaseOrder.entity.PurchaseOrderLine | |||
import com.ffii.fpsms.modules.stock.entity.StockOutLine | |||
import com.ffii.fpsms.modules.stock.entity.projection.StockOutLineInfo | |||
import com.ffii.fpsms.modules.stock.service.StockInLineService | |||
import com.ffii.fpsms.modules.stock.service.StockOutLineService | |||
import com.ffii.fpsms.modules.stock.web.model.CreateStockOutLineRequest | |||
import com.ffii.fpsms.modules.stock.web.model.UpdateStockOutLineRequest | |||
import jakarta.validation.Valid | |||
import org.springframework.web.bind.annotation.GetMapping | |||
import org.springframework.web.bind.annotation.PathVariable | |||
import org.springframework.web.bind.annotation.PostMapping | |||
import org.springframework.web.bind.annotation.RequestMapping | |||
import org.springframework.web.bind.annotation.RestController | |||
import org.springframework.web.bind.annotation.* | |||
@RestController | |||
@RequestMapping("/stockOutLine") | |||
@@ -22,4 +21,13 @@ class StockOutLineController( | |||
return stockOutLineService.getAllStockOutLineByPickOrderLineId(pickOrderLineId) | |||
} | |||
@PostMapping("/create") | |||
fun create(@Valid @RequestBody request: CreateStockOutLineRequest): MessageResponse { | |||
return stockOutLineService.create(request) | |||
} | |||
@PostMapping("/update") | |||
fun update(@Valid @RequestBody request: UpdateStockOutLineRequest): MessageResponse { | |||
println("triggering") | |||
return stockOutLineService.update(request) | |||
} | |||
} |
@@ -10,7 +10,6 @@ enum class StockInStatus(val status: String) { | |||
COMPLETE("completed"), | |||
// CANCELLED("cancelled") | |||
} | |||
class GameScore(val grade: String) | |||
enum class StockInLineStatus(val status: String) { | |||
PENDING("pending"), | |||
QC("qc"), | |||
@@ -1,8 +1,9 @@ | |||
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 | |||
enum class StockOutStatus(val status: String) { | |||
PENDING("pending"), | |||
COMPLETE("completed"), | |||
@@ -10,11 +11,12 @@ enum class StockOutStatus(val status: String) { | |||
} | |||
enum class StockOutLineStatus(val status: String) { | |||
PENDING("pending"), | |||
PICKED("picked"), | |||
COMPLETE("completed"), | |||
// CANCELLED("cancelled") | |||
DETERMINE1("determine1"), // qc failed qty? | |||
LOT_CHANGE_APPROVAL("lot-change"), // just a flag for frontend | |||
REJECTED("rejected"), | |||
COMPLETE("completed"), // == picked | |||
} | |||
data class SaveStockOutRequest( | |||
data class SaveStockOutRequest( // not usable | |||
val id: Long?, | |||
val type: String, // delivery || pick || etc | |||
val deliveryOrderCode: String?, | |||
@@ -25,17 +27,22 @@ data class SaveStockOutRequest( | |||
val handler: Long?, | |||
val targetOutletId: Long?, | |||
val remarks: String?, | |||
val stockOutLine: List<SaveStockOutLineRequest> | |||
val stockOutLine: List<UpdateStockOutLineRequest> | |||
) | |||
data class SaveStockOutLineRequest( | |||
val id: Long?, | |||
data class CreateStockOutLineRequest( | |||
val consoCode: String, | |||
val pickOrderLineId: Long, | |||
val inventoryLotLineId: Long, | |||
val qty: Double, | |||
) | |||
data class UpdateStockOutLineRequest( | |||
val id: Long, | |||
val itemId: Long, | |||
val qty: Double, | |||
val pickOrderLineId: Long, | |||
val inventoryLotLineId: Long, | |||
val status: StockOutLineStatus?, | |||
val status: String, | |||
val inventoryLotLineId: Long?, | |||
val pickTime: LocalDateTime?, | |||
val pickerId: Long? | |||
// val pickerId: Long? | |||
) |