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