Kaynağa Gözat

[Job Order & m18 scheduler] JO can gen Pick Order now & m18 po scheduler

master
cyril.tsui 1 ay önce
ebeveyn
işleme
6369797c23
12 değiştirilmiş dosya ile 260 ekleme ve 21 silme
  1. +42
    -0
      src/main/java/com/ffii/core/utils/GsonUtils.kt
  2. +32
    -0
      src/main/java/com/ffii/fpsms/m18/service/M18SchedulerService.kt
  3. +5
    -0
      src/main/java/com/ffii/fpsms/modules/jobOrder/entity/JobOrder.kt
  4. +6
    -4
      src/main/java/com/ffii/fpsms/modules/jobOrder/entity/JobOrderBomMaterial.kt
  5. +37
    -0
      src/main/java/com/ffii/fpsms/modules/jobOrder/entity/JobOrderRepository.kt
  6. +35
    -1
      src/main/java/com/ffii/fpsms/modules/jobOrder/entity/projections/JobOrderInfo.kt
  7. +64
    -0
      src/main/java/com/ffii/fpsms/modules/jobOrder/service/JobOrderService.kt
  8. +17
    -0
      src/main/java/com/ffii/fpsms/modules/jobOrder/web/JobOrderController.kt
  9. +5
    -0
      src/main/java/com/ffii/fpsms/modules/jobOrder/web/model/JobOrderActionRequest.kt
  10. +4
    -11
      src/main/java/com/ffii/fpsms/modules/master/service/ProductionScheduleService.kt
  11. +9
    -3
      src/main/java/com/ffii/fpsms/modules/pickOrder/service/PickOrderService.kt
  12. +4
    -2
      src/main/java/com/ffii/fpsms/modules/pickOrder/web/models/SavePickOrderRequest.kt

+ 42
- 0
src/main/java/com/ffii/core/utils/GsonUtils.kt Dosyayı Görüntüle

@@ -0,0 +1,42 @@
package com.ffii.core.utils

import com.ffii.fpsms.modules.master.entity.projections.DetailedProdScheduleLineInfo
import com.ffii.fpsms.modules.master.service.ProductionScheduleService
import com.google.gson.GsonBuilder
import com.google.gson.JsonDeserializationContext
import com.google.gson.JsonDeserializer
import com.google.gson.JsonElement
import com.google.gson.reflect.TypeToken
import java.lang.reflect.Type

open class GsonUtils {

class BooleanTypeAdapter : JsonDeserializer<Boolean> {
override fun deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): Boolean {
return json.asInt == 1
}
}

companion object {
val gson = GsonBuilder()
.registerTypeAdapter(Boolean::class.javaObjectType, BooleanTypeAdapter())
.create()

/**
* Read from JSON String.
*
* @param content
* JSON String content
*
* @param type
* Type
*
*/
fun <T> stringToJson(content: String?, type: Type): T {
// val type = object : TypeToken<T>() {}.type
val gsonResult: T = gson.fromJson(content, type)

return gsonResult;
}
}
}

+ 32
- 0
src/main/java/com/ffii/fpsms/m18/service/M18SchedulerService.kt Dosyayı Görüntüle

@@ -0,0 +1,32 @@
package com.ffii.fpsms.m18.service

import com.ffii.core.utils.JwtTokenUtil
import com.ffii.fpsms.m18.web.models.M18TestPoRequest
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.scheduling.annotation.Scheduled
import org.springframework.stereotype.Service
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter

@Service
open class M18SchedulerService(
val m18PurchaseOrderService: M18PurchaseOrderService,
val m18MasterDataService: M18MasterDataService,
) {
var logger: Logger = LoggerFactory.getLogger(JwtTokenUtil::class.java)
val dataStringFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd")

@Scheduled(cron = "0 0 0 * * *")
open fun getPos() {
val today = LocalDateTime.now()
val yesterday = today.minusDays(1L)
val request = M18TestPoRequest(
modifiedDateTo = today.format(dataStringFormat),
modifiedDateFrom = yesterday.format(dataStringFormat)
)
m18PurchaseOrderService.savePurchaseOrders(request);
logger.info("today: ${today.format(dataStringFormat)}")
logger.info("yesterday: ${yesterday.format(dataStringFormat)}")
}
}

+ 5
- 0
src/main/java/com/ffii/fpsms/modules/jobOrder/entity/JobOrder.kt Dosyayı Görüntüle

@@ -1,5 +1,6 @@
package com.ffii.fpsms.modules.jobOrder.entity

import com.fasterxml.jackson.annotation.JsonManagedReference
import com.ffii.core.entity.BaseEntity
import com.ffii.fpsms.modules.master.entity.Bom
import com.ffii.fpsms.modules.master.entity.ProductionScheduleLine
@@ -63,4 +64,8 @@ open class JobOrder : BaseEntity<Long>() {
@JoinColumn(name = "prodScheduleLineId")
// @Column(name = "prodScheduleLineId")
open var prodScheduleLine: ProductionScheduleLine? = null

@JsonManagedReference
@OneToMany(mappedBy = "jobOrder", cascade = [CascadeType.ALL], orphanRemoval = true)
open var jobms: MutableList<JobOrderBomMaterial> = mutableListOf()
}

+ 6
- 4
src/main/java/com/ffii/fpsms/modules/jobOrder/entity/JobOrderBomMaterial.kt Dosyayı Görüntüle

@@ -5,6 +5,7 @@ import com.ffii.core.entity.BaseEntity
import com.ffii.fpsms.modules.master.entity.Items
import com.ffii.fpsms.modules.master.entity.UomConversion
import com.ffii.fpsms.modules.stock.entity.InventoryLotLine
import com.ffii.fpsms.modules.stock.entity.StockOutLine
import com.ffii.fpsms.modules.stock.entity.SuggestedPickLot
import jakarta.persistence.*
import jakarta.validation.constraints.NotNull
@@ -14,6 +15,7 @@ import java.math.BigDecimal
@Entity
@Table(name = "job_order_bom_material")
open class JobOrderBomMaterial : BaseEntity<Long>() {
@JsonBackReference
@NotNull
@ManyToOne
@JoinColumn(name = "jobOrderId", nullable = false)
@@ -33,12 +35,12 @@ open class JobOrderBomMaterial : BaseEntity<Long>() {
@JoinColumn(name = "uomId", nullable = false)
open var uom: UomConversion? = null

@ManyToOne
@JoinColumn(name = "suggestedPickLotId")
open var suggestedPickLot: SuggestedPickLot? = null

@Size(max = 255)
@NotNull
@Column(name = "status", nullable = false)
open var status: String? = null

@ManyToOne
@JoinColumn(name = "stockOutLineId")
open var stockOutLine: StockOutLine? = null
}

+ 37
- 0
src/main/java/com/ffii/fpsms/modules/jobOrder/entity/JobOrderRepository.kt Dosyayı Görüntüle

@@ -1,6 +1,7 @@
package com.ffii.fpsms.modules.jobOrder.entity

import com.ffii.core.support.AbstractRepository
import com.ffii.fpsms.modules.jobOrder.entity.projections.JobOrderDetailWithJsonString
import com.ffii.fpsms.modules.jobOrder.entity.projections.JobOrderInfo
import org.springframework.data.domain.Page
import org.springframework.data.domain.Pageable
@@ -15,4 +16,40 @@ interface JobOrderRepository : AbstractRepository<JobOrder, Long> {
fun findLatestCodeByPrefix(prefix: String): String?

fun findJobOrderInfoByCodeContainsAndBomNameContainsAndDeletedIsFalseOrderByIdDesc(code: String, bomName: String, pageable: Pageable): Page<JobOrderInfo>

@Query(
nativeQuery = true,
value = """
select
jo.id,
jo.code,
b.name,
jo.reqQty,
b.outputQtyUom,
json_arrayagg(
json_object(
'id', jobm.id,
'code', i.code,
'name', i.name,
'lotNo', il.lotNo,
'reqQty', jobm.reqQty,
'uom', uc.udfudesc,
'status', jobm.status
)
) as pickLines,
jo.status
from job_order jo
left join bom b on b.id = jo.bomId
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
left join stock_out_line sol on sol.id = jobm.stockOutLineId
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
limit 1
"""
)
fun findJobOrderDetailById(id: Long): JobOrderDetailWithJsonString?;
}

+ 35
- 1
src/main/java/com/ffii/fpsms/modules/jobOrder/entity/projections/JobOrderInfo.kt Dosyayı Görüntüle

@@ -3,13 +3,47 @@ package com.ffii.fpsms.modules.jobOrder.entity.projections
import org.springframework.beans.factory.annotation.Value
import java.math.BigDecimal

// Job Orders
interface JobOrderInfo {
val id: Long;
val code: String;

@get:Value("#{target.bom.name}")
val name: String;
val reqQty: BigDecimal;

@get:Value("#{target.bom.outputQtyUom}")
val uom: String;
val status: String;
}
}

// Job Order
interface JobOrderDetailWithJsonString {
val id: Long?;
val code: String?;
val name: String?;
val reqQty: BigDecimal?;
val outputQtyUom: String?;
val pickLines: String?;
val status: String?;
}

data class JobOrderDetail(
val id: Long?,
val code: String?,
val name: String?,
val reqQty: BigDecimal?,
val outputQtyUom: String?,
val pickLines: List<JobOrderDetailPickLine>?,
val status: String?
)

data class JobOrderDetailPickLine(
val id: Long?,
val code: String?,
val name: String?,
val lotNo: String?,
val reqQty: BigDecimal?,
val uom: String?,
val status: String?
)

+ 64
- 0
src/main/java/com/ffii/fpsms/modules/jobOrder/service/JobOrderService.kt Dosyayı Görüntüle

@@ -1,28 +1,41 @@
package com.ffii.fpsms.modules.jobOrder.service

import com.ffii.core.response.RecordsRes
import com.ffii.core.utils.GsonUtils
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
import com.ffii.fpsms.modules.jobOrder.entity.projections.JobOrderDetailPickLine
import com.ffii.fpsms.modules.jobOrder.entity.projections.JobOrderInfo
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.entity.ProductionScheduleLineRepository
import com.ffii.fpsms.modules.master.service.BomService
import com.ffii.fpsms.modules.master.web.models.MessageResponse
import com.ffii.fpsms.modules.pickOrder.enums.PickOrderType
import com.ffii.fpsms.modules.pickOrder.service.PickOrderService
import com.ffii.fpsms.modules.pickOrder.web.models.SavePickOrderLineRequest
import com.ffii.fpsms.modules.pickOrder.web.models.SavePickOrderRequest
import com.ffii.fpsms.modules.user.service.UserService
import com.google.gson.reflect.TypeToken
import org.springframework.data.domain.PageRequest
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import java.math.BigDecimal
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import kotlin.jvm.optionals.getOrNull


@Service
open class JobOrderService(
val jobOrderRepository: JobOrderRepository,
val bomService: BomService,
val userService: UserService,
val productionScheduleLineRepository: ProductionScheduleLineRepository,
val pickOrderService: PickOrderService,
) {
open fun allJobOrdersByPage(request: SearchJobOrderInfoRequest): RecordsRes<JobOrderInfo> {
val pageable = PageRequest.of(request.pageNum ?: 0, request.pageSize ?: 10);
@@ -37,6 +50,22 @@ open class JobOrderService(
val total = response.totalElements
return RecordsRes<JobOrderInfo>(records, total.toInt());
}

open fun jobOrderDetail(id: Long): JobOrderDetail {
val sqlResult = jobOrderRepository.findJobOrderDetailById(id) ?: throw NoSuchElementException();

val type = object : TypeToken<List<JobOrderDetailPickLine>>() {}.type
val jsonResult = sqlResult.pickLines?.let { GsonUtils.stringToJson<List<JobOrderDetailPickLine>>(it, type) }
return JobOrderDetail(
id = sqlResult.id,
code = sqlResult.code,
name = sqlResult.name,
reqQty = sqlResult.reqQty,
outputQtyUom = sqlResult.outputQtyUom,
pickLines = jsonResult,
status = sqlResult.status
)
}
open fun assignJobNo(): String {
val suffixFormat = "%03d"
val pattern = "yyyyMMdd"
@@ -89,4 +118,39 @@ open class JobOrderService(
errorPosition = null
)
}

@Transactional(rollbackFor = [Exception::class])
open fun releaseJobOrder(request: JobOrderReleaseRequest): MessageResponse {
val jo = request.id.let { jobOrderRepository.findById(it).getOrNull() } ?: throw NoSuchElementException()
jo.apply {
status = "pending"
}
jobOrderRepository.save(jo)

val pols = jo.jobms.map {
SavePickOrderLineRequest(
itemId = it.item?.id,
qty = it.reqQty ?: BigDecimal.ZERO,
uomId = it.uom?.id,
)
}
val po = SavePickOrderRequest(
joId = jo.id,
type = PickOrderType.JOB_ORDER,
targetDate = jo.planStart?.toLocalDate() ?: LocalDate.now(),
pickOrderLine = pols
)

pickOrderService.create(po)

return MessageResponse(
id = jo.id,
code = jo.code,
name = jo.bom?.name,
type = null,
message = null,
errorPosition = null,
entity = mapOf("status" to jo.status)
)
}
}

+ 17
- 0
src/main/java/com/ffii/fpsms/modules/jobOrder/web/JobOrderController.kt Dosyayı Görüntüle

@@ -1,11 +1,18 @@
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.JobOrderService
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
import jakarta.validation.Valid
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.ModelAttribute
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController

@@ -19,4 +26,14 @@ class JobOrderController(
fun allJobOrdersByPage(@ModelAttribute request: SearchJobOrderInfoRequest): RecordsRes<JobOrderInfo> {
return jobOrderService.allJobOrdersByPage(request);
}

@GetMapping("/detail/{id}")
fun jobOrderDetail(@PathVariable id: Long): JobOrderDetail {
return jobOrderService.jobOrderDetail(id);
}

@PostMapping("/release")
fun releaseJobOrder(@Valid @RequestBody request: JobOrderReleaseRequest): MessageResponse {
return jobOrderService.releaseJobOrder(request)
}
}

+ 5
- 0
src/main/java/com/ffii/fpsms/modules/jobOrder/web/model/JobOrderActionRequest.kt Dosyayı Görüntüle

@@ -0,0 +1,5 @@
package com.ffii.fpsms.modules.jobOrder.web.model

data class JobOrderReleaseRequest(
val id: Long,
)

+ 4
- 11
src/main/java/com/ffii/fpsms/modules/master/service/ProductionScheduleService.kt Dosyayı Görüntüle

@@ -3,6 +3,7 @@ package com.ffii.fpsms.modules.master.service
import com.ffii.core.response.RecordsRes
import com.ffii.core.support.AbstractBaseEntityService
import com.ffii.core.support.JdbcDao
import com.ffii.core.utils.GsonUtils
import com.ffii.fpsms.modules.common.SecurityUtils
import com.ffii.fpsms.modules.jobOrder.service.JobOrderBomMaterialService
import com.ffii.fpsms.modules.jobOrder.service.JobOrderProcessService
@@ -265,21 +266,13 @@ open class ProductionScheduleService(
)
}

class BooleanTypeAdapter: JsonDeserializer<Boolean> {
override fun deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): Boolean {
// println(json)
return json.asInt == 1
}
}

open fun detailedProdScheduleDetail(id: Long): DetailedProdScheduleWithLine {
val sqlResult = productionScheduleRepository.findDetailedProdScheduleWithLine(id) ?: throw NoSuchElementException()

val gson = GsonBuilder()
.registerTypeAdapter(Boolean::class.javaObjectType, BooleanTypeAdapter())
.create()
val type = object : TypeToken<List<DetailedProdScheduleLineInfo>?>() {}.type
val gsonResult: List<DetailedProdScheduleLineInfo>? = gson.fromJson(sqlResult.prodScheduleLines, type)
// val gsonResult: List<DetailedProdScheduleLineInfo>? = gson.fromJson(sqlResult.prodScheduleLines, type)
val gsonResult: List<DetailedProdScheduleLineInfo>? = GsonUtils.stringToJson(sqlResult.prodScheduleLines, type)


return DetailedProdScheduleWithLine(
id = sqlResult.id,


+ 9
- 3
src/main/java/com/ffii/fpsms/modules/pickOrder/service/PickOrderService.kt Dosyayı Görüntüle

@@ -4,6 +4,7 @@ import com.ffii.core.response.RecordsRes
import com.ffii.core.support.AbstractBaseEntityService
import com.ffii.core.support.JdbcDao
import com.ffii.fpsms.modules.common.SecurityUtils
import com.ffii.fpsms.modules.jobOrder.entity.JobOrderRepository
import com.ffii.fpsms.modules.master.entity.ItemsRepository
import com.ffii.fpsms.modules.master.entity.UomConversionRepository
import com.ffii.fpsms.modules.master.web.models.MessageResponse
@@ -53,20 +54,25 @@ open class PickOrderService(
private val inventoryService: InventoryService,
private val stockOutRepository: StockOutRepository,
private val itemsRepository: ItemsRepository,
private val uomConversionRepository: UomConversionRepository
private val uomConversionRepository: UomConversionRepository,
private val jobOrderRepository: JobOrderRepository
): AbstractBaseEntityService<PickOrder, Long, PickOrderRepository>(jdbcDao, pickOrderRepository) {
open fun create(request: SavePickOrderRequest): MessageResponse {
val code = assignPickCode()
val jo = request.joId?.let { jobOrderRepository.findById(it).getOrNull() }
val pickOrder = PickOrder().apply {
this.code = code
this.jobOrder = jo
this.targetDate = request.targetDate.atStartOfDay()
this.type = request.type
this.status = PickOrderStatus.PENDING
}
val savedPickOrder = saveAndFlush(pickOrder)
val polEntries = request.pickOrderLine.map {
val item = itemsRepository.findById(it.itemId).orElseThrow()
val uom = uomConversionRepository.findByCodeAndDeletedFalse(it.uom)
// val item = itemsRepository.findById(it.itemId).orElseThrow()
val uom = it.uom?.let { uomCode -> uomConversionRepository.findByCodeAndDeletedFalse(uomCode) }
?: it.uomId?.let { uomId -> uomConversionRepository.findById(uomId).orElseThrow() }
val item = it.itemId?.let { itemId -> itemsRepository.findById(itemId).orElseThrow() }
PickOrderLine().apply {
this.pickOrder = savedPickOrder
this.item = item


+ 4
- 2
src/main/java/com/ffii/fpsms/modules/pickOrder/web/models/SavePickOrderRequest.kt Dosyayı Görüntüle

@@ -6,12 +6,14 @@ import java.time.LocalDate
import java.time.LocalDateTime

data class SavePickOrderLineRequest (
val itemId: Long,
val itemId: Long?,
val qty: BigDecimal,
// val uomId: Long
val uom: String,
val uom: String? = null,
val uomId: Long? = null
)
data class SavePickOrderRequest (
val joId: Long? = null,
val type: PickOrderType,
var targetDate: LocalDate,
val pickOrderLine: List<SavePickOrderLineRequest>


Yükleniyor…
İptal
Kaydet