@@ -25,7 +25,8 @@ interface JobOrderRepository : AbstractRepository<JobOrder, Long> { | |||
jo.code, | |||
b.name, | |||
jo.reqQty, | |||
b.outputQtyUom, | |||
-- b.outputQtyUom, | |||
uc2.udfudesc as uom, | |||
json_arrayagg( | |||
json_object( | |||
'id', jobm.id, | |||
@@ -40,6 +41,8 @@ interface JobOrderRepository : AbstractRepository<JobOrder, Long> { | |||
jo.status | |||
from job_order jo | |||
left join bom b on b.id = jo.bomId | |||
left join item_uom iu on b.itemId = iu.itemId and iu.salesUnit = true | |||
left join uom_conversion uc2 on uc2.id = iu.uomId | |||
left join job_order_bom_material jobm on jo.id = jobm.jobOrderId | |||
left join items i on i.id = jobm.itemId | |||
left join uom_conversion uc on uc.id = jobm.uomId | |||
@@ -47,7 +50,7 @@ interface JobOrderRepository : AbstractRepository<JobOrder, Long> { | |||
left join inventory_lot_line ill on ill.id = sol.inventoryLotLineId | |||
left join inventory_lot il on il.id = ill.inventoryLotId | |||
where jo.id = :id | |||
group by jo.id | |||
group by jo.id, uc2.udfudesc | |||
limit 1 | |||
""" | |||
) | |||
@@ -12,7 +12,7 @@ interface JobOrderInfo { | |||
val name: String; | |||
val reqQty: BigDecimal; | |||
@get:Value("#{target.bom.outputQtyUom}") | |||
@get:Value("#{target.bom.item.itemUoms.^[salesUnit == true && deleted == false]?.uom.udfudesc}") | |||
val uom: String; | |||
val status: String; | |||
} | |||
@@ -23,7 +23,7 @@ interface JobOrderDetailWithJsonString { | |||
val code: String?; | |||
val name: String?; | |||
val reqQty: BigDecimal?; | |||
val outputQtyUom: String?; | |||
val uom: String?; | |||
val pickLines: String?; | |||
val status: String?; | |||
} | |||
@@ -33,7 +33,7 @@ data class JobOrderDetail( | |||
val code: String?, | |||
val name: String?, | |||
val reqQty: BigDecimal?, | |||
val outputQtyUom: String?, | |||
val uom: String?, | |||
val pickLines: List<JobOrderDetailPickLine>?, | |||
val status: String? | |||
) | |||
@@ -6,16 +6,40 @@ import com.ffii.fpsms.modules.jobOrder.entity.JobOrderRepository | |||
import com.ffii.fpsms.modules.jobOrder.web.model.CreateJobOrderBomMaterialRequest | |||
import com.ffii.fpsms.modules.master.entity.ItemsRepository | |||
import com.ffii.fpsms.modules.master.entity.UomConversionRepository | |||
import com.ffii.fpsms.modules.master.service.ItemUomService | |||
import com.ffii.fpsms.modules.master.web.models.MessageResponse | |||
import org.springframework.stereotype.Service | |||
import java.math.BigDecimal | |||
import java.math.RoundingMode | |||
import kotlin.jvm.optionals.getOrNull | |||
@Service | |||
open class JobOrderBomMaterialService( | |||
val jobOrderBomMaterialRepository: JobOrderBomMaterialRepository, private val jobOrderRepository: JobOrderRepository, | |||
val jobOrderBomMaterialRepository: JobOrderBomMaterialRepository, | |||
private val jobOrderRepository: JobOrderRepository, | |||
private val itemsRepository: ItemsRepository, | |||
val itemUomService: ItemUomService, | |||
private val uomConversionRepository: UomConversionRepository | |||
) { | |||
open fun createJobOrderBomMaterialRequests(joId: Long): List<CreateJobOrderBomMaterialRequest> { | |||
val zero = BigDecimal.ZERO | |||
val jo = jobOrderRepository.findById(joId).getOrNull() ?: throw NoSuchElementException() | |||
val proportion = (jo.reqQty ?: zero).divide(jo.bom?.outputQty ?: BigDecimal.ONE, 5, RoundingMode.HALF_UP) | |||
val jobmRequests = jo.bom?.bomMaterials?.map { bm -> | |||
val salesUnit = bm.item?.id?.let { itemUomService.findSalesUnitByItemId(it) } | |||
CreateJobOrderBomMaterialRequest( | |||
joId = joId, | |||
itemId = bm.item?.id, | |||
reqQty = bm.qty?.times(proportion) ?: zero, | |||
uomId = salesUnit?.uom?.id | |||
) | |||
} ?: listOf() | |||
return jobmRequests | |||
} | |||
fun createJobOrderBomMaterials(request: List<CreateJobOrderBomMaterialRequest>): MessageResponse { | |||
val joBomMaterials = request.map { req -> | |||
val jo = req.joId?.let { jobOrderRepository.findById(it).getOrNull() } | |||
@@ -42,4 +66,8 @@ open class JobOrderBomMaterialService( | |||
errorPosition = null | |||
) | |||
} | |||
fun createJobOrderBomMaterialsByJoId(joId: Long): MessageResponse { | |||
return createJobOrderBomMaterials(createJobOrderBomMaterialRequests(joId)) | |||
} | |||
} |
@@ -2,6 +2,7 @@ package com.ffii.fpsms.modules.jobOrder.service | |||
import com.ffii.core.response.RecordsRes | |||
import com.ffii.core.utils.GsonUtils | |||
import com.ffii.fpsms.modules.common.SecurityUtils | |||
import com.ffii.fpsms.modules.jobOrder.entity.JobOrder | |||
import com.ffii.fpsms.modules.jobOrder.entity.JobOrderRepository | |||
import com.ffii.fpsms.modules.jobOrder.entity.projections.JobOrderDetail | |||
@@ -61,7 +62,7 @@ open class JobOrderService( | |||
code = sqlResult.code, | |||
name = sqlResult.name, | |||
reqQty = sqlResult.reqQty, | |||
outputQtyUom = sqlResult.outputQtyUom, | |||
uom = sqlResult.uom, | |||
pickLines = jsonResult, | |||
status = sqlResult.status | |||
) | |||
@@ -90,7 +91,7 @@ open class JobOrderService( | |||
open fun createJobOrder(request: CreateJobOrderRequest): MessageResponse { | |||
val jo = JobOrder() | |||
val bom = request.bomId?.let { bomService.findById(it) } | |||
val approver = request.approverId?.let { userService.find(it).getOrNull() } | |||
val approver = request.approverId?.let { userService.find(it).getOrNull() } ?: SecurityUtils.getUser().getOrNull() | |||
val prodScheduleLine = request.prodScheduleLineId?.let { productionScheduleLineRepository.findById(it).getOrNull() } | |||
val code = assignJobNo() | |||
@@ -98,8 +99,8 @@ open class JobOrderService( | |||
this.code = code | |||
this.bom = bom | |||
//TODO: planStart & planEnd | |||
planStart = LocalDateTime.now() | |||
planEnd = LocalDateTime.now() | |||
planStart = request.planStart ?: LocalDateTime.now() | |||
planEnd = request.planEnd ?: LocalDateTime.now() | |||
reqQty = request.reqQty | |||
status = request.status | |||
type = request.type | |||
@@ -3,7 +3,9 @@ package com.ffii.fpsms.modules.jobOrder.web | |||
import com.ffii.core.response.RecordsRes | |||
import com.ffii.fpsms.modules.jobOrder.entity.projections.JobOrderDetail | |||
import com.ffii.fpsms.modules.jobOrder.entity.projections.JobOrderInfo | |||
import com.ffii.fpsms.modules.jobOrder.service.JobOrderBomMaterialService | |||
import com.ffii.fpsms.modules.jobOrder.service.JobOrderService | |||
import com.ffii.fpsms.modules.jobOrder.web.model.CreateJobOrderRequest | |||
import com.ffii.fpsms.modules.jobOrder.web.model.JobOrderReleaseRequest | |||
import com.ffii.fpsms.modules.jobOrder.web.model.SearchJobOrderInfoRequest | |||
import com.ffii.fpsms.modules.master.web.models.MessageResponse | |||
@@ -20,6 +22,7 @@ import org.springframework.web.bind.annotation.RestController | |||
@RequestMapping("/jo") | |||
class JobOrderController( | |||
private val jobOrderService: JobOrderService, | |||
private val jobOrderBomMaterialService: JobOrderBomMaterialService, | |||
) { | |||
@GetMapping("/getRecordByPage") | |||
@@ -36,4 +39,15 @@ class JobOrderController( | |||
fun releaseJobOrder(@Valid @RequestBody request: JobOrderReleaseRequest): MessageResponse { | |||
return jobOrderService.releaseJobOrder(request) | |||
} | |||
@PostMapping("/manualCreate") | |||
fun manualCreateJobOrder(@Valid @RequestBody request: CreateJobOrderRequest): MessageResponse { | |||
val jo = jobOrderService.createJobOrder(request) | |||
if (jo.id == null) { | |||
throw NoSuchElementException() | |||
} | |||
jobOrderBomMaterialService.createJobOrderBomMaterialsByJoId(jo.id) | |||
return jo | |||
} | |||
} |
@@ -9,8 +9,8 @@ data class CreateJobOrderRequest ( | |||
val planEnd: LocalDateTime? = null, | |||
val reqQty: BigDecimal?, | |||
val type: String? = "detailed", | |||
val approverId: Long?, | |||
val prodScheduleLineId: Long?, | |||
val approverId: Long? = null, | |||
val prodScheduleLineId: Long? = null, | |||
val status: String = "planning", | |||
) | |||
@@ -11,4 +11,6 @@ interface BomMaterialRepository : AbstractRepository<BomMaterial, Long> { | |||
fun findByM18IdAndDeletedIsFalse(m18Id: Long): BomMaterial? | |||
fun findAllByBomItemIdAndDeletedIsFalse(itemId: Long): List<BomMaterial> | |||
fun findAllByBomIdAndDeletedIsFalse(bomId: Long): List<BomMaterial> | |||
} |
@@ -1,6 +1,7 @@ | |||
package com.ffii.fpsms.modules.master.entity | |||
import com.ffii.core.support.AbstractRepository | |||
import com.ffii.fpsms.modules.master.entity.projections.BomCombo | |||
import org.springframework.stereotype.Repository | |||
import java.io.Serializable | |||
@@ -13,4 +14,6 @@ interface BomRepository : AbstractRepository<Bom, Long> { | |||
fun findByM18IdAndDeletedIsFalse(m18Id: Long): Bom? | |||
fun findByItemIdAndDeletedIsFalse(itemId: Serializable): Bom? | |||
fun findBomComboByDeletedIsFalse(): List<BomCombo> | |||
} |
@@ -0,0 +1,11 @@ | |||
package com.ffii.fpsms.modules.master.entity.projections | |||
import org.springframework.beans.factory.annotation.Value | |||
interface BomCombo { | |||
val id: Long; | |||
@get:Value("#{target.id}") | |||
val value: Long; | |||
@get:Value("#{target.code} - #{target.name} - #{target.item.itemUoms.^[salesUnit == true && deleted == false]?.uom.udfudesc}") | |||
val label: String; | |||
} |
@@ -1,5 +1,6 @@ | |||
package com.ffii.fpsms.modules.master.service | |||
import com.ffii.fpsms.modules.jobOrder.web.model.CreateJobOrderBomMaterialRequest | |||
import com.ffii.fpsms.modules.master.entity.* | |||
import com.ffii.fpsms.modules.master.web.models.SaveBomMaterialRequest | |||
import com.ffii.fpsms.modules.master.web.models.SaveBomMaterialResponse | |||
@@ -20,6 +21,10 @@ open class BomMaterialService( | |||
return bomMaterialRepository.findByM18IdAndDeletedIsFalse(m18Id); | |||
} | |||
open fun findAllByBomId(bomId: Long): List<BomMaterial> { | |||
return bomMaterialRepository.findAllByBomIdAndDeletedIsFalse(bomId); | |||
} | |||
open fun saveBomMaterial(request: SaveBomMaterialRequest): SaveBomMaterialResponse { | |||
val bomMaterial = request.m18Id?.let { findByM18Id(it) } | |||
?: request.id?.let { findById(it) } | |||
@@ -1,6 +1,8 @@ | |||
package com.ffii.fpsms.modules.master.web | |||
import com.ffii.fpsms.modules.master.entity.Bom | |||
import com.ffii.fpsms.modules.master.entity.BomRepository | |||
import com.ffii.fpsms.modules.master.entity.projections.BomCombo | |||
import com.ffii.fpsms.modules.master.service.BomService | |||
import org.springframework.core.io.ByteArrayResource | |||
import org.springframework.core.io.Resource | |||
@@ -16,13 +18,18 @@ import java.time.LocalDate | |||
@RestController | |||
@RequestMapping("/bom") | |||
class BomController ( | |||
val bomService: BomService, | |||
val bomService: BomService, private val bomRepository: BomRepository, | |||
) { | |||
@GetMapping | |||
fun getBoms(): List<Bom> { | |||
return bomService.findAll() | |||
} | |||
@GetMapping("/combo") | |||
fun getCombo(): List<BomCombo> { | |||
return bomRepository.findBomComboByDeletedIsFalse(); | |||
} | |||
@PostMapping("/import-bom") | |||
fun importBom(): ResponseEntity<Resource> { | |||
val reportResult = bomService.importBOM() | |||