Kaynağa Gözat

[prod schedule] update for rough prod schedule

master
cyril.tsui 1 ay önce
ebeveyn
işleme
faa516ccaa
5 değiştirilmiş dosya ile 160 ekleme ve 37 silme
  1. +87
    -6
      src/main/java/com/ffii/fpsms/modules/master/entity/ProductionScheduleRepository.kt
  2. +45
    -12
      src/main/java/com/ffii/fpsms/modules/master/entity/projections/ProdScheduleInfo.kt
  3. +16
    -10
      src/main/java/com/ffii/fpsms/modules/master/service/ProductionScheduleService.kt
  4. +11
    -8
      src/main/java/com/ffii/fpsms/modules/master/web/ProductionScheduleController.kt
  5. +1
    -1
      src/main/java/com/ffii/fpsms/modules/master/web/models/SearchProdScheduleRequest.kt

+ 87
- 6
src/main/java/com/ffii/fpsms/modules/master/entity/ProductionScheduleRepository.kt Dosyayı Görüntüle

@@ -1,14 +1,12 @@
package com.ffii.fpsms.modules.master.entity

import com.ffii.core.support.AbstractRepository
import com.ffii.fpsms.modules.master.entity.projections.DetailedProdScheduleWithLine
import com.ffii.fpsms.modules.master.entity.projections.ProdScheduleInfo
import com.ffii.fpsms.modules.master.entity.projections.ProdScheduleWithLine
import org.springframework.data.domain.Page
import org.springframework.data.domain.Pageable
import org.springframework.data.jpa.repository.Query
import org.springframework.stereotype.Repository
import java.io.Serializable
import java.time.LocalDate
import java.time.LocalDateTime

@Repository
@@ -44,7 +42,7 @@ interface ProductionScheduleRepository : AbstractRepository<ProductionSchedule,
and (:schedulePeriod = '' or datediff(schedulePeriod, coalesce(:schedulePeriod, schedulePeriod)) = 0)
and (:schedulePeriodTo = '' or datediff(schedulePeriodTo, coalesce(:schedulePeriodTo, schedulePeriodTo)) = 0)
and (:totalEstProdCount is null or :totalEstProdCount = '' or totalEstProdCount = :totalEstProdCount)
and (:type is null or type = :type)
and (coalesce(:types) is null or type in :types)
order by id desc;
""",
countQuery =
@@ -67,7 +65,7 @@ interface ProductionScheduleRepository : AbstractRepository<ProductionSchedule,
and (:schedulePeriod = '' or datediff(schedulePeriod, coalesce(:schedulePeriod, schedulePeriod)) = 0)
and (:schedulePeriodTo = '' or datediff(schedulePeriodTo, coalesce(:schedulePeriodTo, schedulePeriodTo)) = 0)
and (:totalEstProdCount is null or :totalEstProdCount = '' or totalEstProdCount = :totalEstProdCount)
and (:type is null or type = :type)
and (coalesce(:types) is null or type in :types)
order by id desc;
""",
)
@@ -76,7 +74,90 @@ interface ProductionScheduleRepository : AbstractRepository<ProductionSchedule,
schedulePeriod: String?,
schedulePeriodTo: String?,
totalEstProdCount: Double?,
type: String?,
types: List<String>?,
pageable: Pageable
): Page<ProdScheduleInfo>

@Query(nativeQuery = true,
value =
"""
with prod_equip as (
select
r1.pslId,
json_array(group_concat(json_object(r1.equipName, r1.totalMinute))) as prodTimeInMinute
from (
select
psl.id as pslId,
coalesce(e.name, 'N/A') as equipName,
sum(coalesce(bp.prepTimeInMinute, 0) + coalesce(bp.durationInMinute, 0) + coalesce(bp.postProdTimeInMinute, 0)) as totalMinute
from production_schedule ps
left join production_schedule_line psl on psl.prodScheduleId = ps.id
left join bom b on b.itemId = psl.itemId
left join bom_process bp on bp.bomId = b.id
left join equipment e on bp.equipmentId = e.id
where ps.id = :id and b.id is not null
group by psl.id, e.id
) r1
group by r1.pslId
),
prod_material as (
select
r2.pslId,
json_array(group_concat(json_object('id', r2.id, 'code', r2.code, 'name', r2.name, 'type', r2.`type`, 'availableQty', r2.availableQty, 'demandQty', r2.demandQty))) as bomMaterials
from (
select
psl.id as pslId,
bm.id,
bmi.code,
bmi.name,
bmi.`type`,
coalesce(i.onHandQty, 0) - coalesce(i.onHoldQty, 0) - coalesce(i.unavailableQty, 0) as availableQty,
coalesce(psl.prodQty, 0) as demandQty
from production_schedule ps
left join production_schedule_line psl on psl.prodScheduleId = ps.id
left join bom b on b.itemId = psl.itemId
left join bom_material bm on bm.bomId = b.id
left join items bmi on bmi.id = bm.itemId
left join inventory i on i.itemId = bmi.id
where ps.id = :id and bmi.id is not null
group by ps.id, psl.id, bm.id, i.id
) r2
group by r2.pslId
)
select
prod.id,
prod.scheduleAt,
prod.totalFGType,
prod.totalEstProdCount,
json_array(group_concat(
json_object('id', prod.pslId, 'bomMaterials', prod.bomMaterials, 'jobNo', prod.jobNo, 'code', prod.code, 'name', prod.name, 'type', prod.type, 'demandQty', prod.demandQty, 'prodTimeInMinute', prod.prodTimeInMinute, 'priority', prod.priority)
))
from (
select
ps.id,
ps.scheduleAt,
ps.totalFGType,
ps.totalEstProdCount,
psl.id as pslId,
pm.bomMaterials,
jo.code as jobNo,
psli.code,
psli.name,
psli.`type`,
psl.prodQty as demandQty,
pe.prodTimeInMinute,
psl.itemPriority as priority
from production_schedule ps
left join production_schedule_line psl on psl.prodScheduleId = ps.id
left join items psli on psli.id = psl.itemId
left join job_order jo on jo.prodScheduleLineId = psl.id
left join prod_equip pe on pe.pslId = psl.id
left join prod_material pm on pm.pslId = psl.id
where psl.deleted is false and pe.prodTimeInMinute is not null and pm.bomMaterials is not null
and ps.id = :id
group by psl.id, jo.id
) prod group by prod.id limit 1
"""
)
fun findDetailedProdScheduleWithLine(id: Long): List<DetailedProdScheduleWithLine>
}

+ 45
- 12
src/main/java/com/ffii/fpsms/modules/master/entity/projections/ProdScheduleInfo.kt Dosyayı Görüntüle

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

import org.springframework.beans.factory.annotation.Value
import java.math.BigDecimal
import java.time.LocalDate
import java.time.LocalDateTime
@@ -15,9 +14,43 @@ interface ProdScheduleInfo {
val totalFGType: Long?
val type: String?
}
// Detailed Production Schedule With Line
data class DetailedProdScheduleWithLine(
val id: Long?,
val scheduleAt: LocalDateTime?,
val totalEstProdCount: BigDecimal?,
val totalFGType: Long?,
val prodScheduleLines: List<DetailedProdScheduleLineInfo>?
)

data class DetailedProdScheduleLineInfo(
val id: Long?,
val bomMaterials: List<DetailedProdScheduleLineBomMaterial>?,
val jobNo: String?,
val code: String?,
val name: String?,
val type: String?,
val demandQty: BigDecimal?,
val prodTimeInMinute: List<DetailedProdScheduleLineProdTime>?,
val priority: BigDecimal?,
)

data class DetailedProdScheduleLineBomMaterial (
val id: Long?,
val code: String?,
val name: String?,
val type: String?,
val availableQty: BigDecimal?,
val demandQty: BigDecimal?
)

data class DetailedProdScheduleLineProdTime (
val equipName: String?,
val minutes: BigDecimal?,
)

// Production Schedule With Line
data class ProdScheduleWithLine(
// Rough Production Schedule With Line
data class RoughProdScheduleWithLine(
val id: Long?,
val scheduleAt: LocalDateTime?,
val schedulePeriod: LocalDateTime?,
@@ -25,13 +58,13 @@ data class ProdScheduleWithLine(
val totalEstProdCount: BigDecimal?,
val totalFGType: Long?,
val type: String?,
val prodScheduleLinesByFg: List<ProdScheduleLineInfoByFg>,
val prodScheduleLinesByFgByDate: Map<Long?, List<ProdScheduleLineInfoByFg>>,
val prodScheduleLinesByBom: List<ProdScheduleLineInfoByBom>,
val prodScheduleLinesByBomByDate: Map<Long?, List<ProdScheduleLineInfoByBomByDate>>
val prodScheduleLinesByFg: List<RoughProdScheduleLineInfoByFg>,
val prodScheduleLinesByFgByDate: Map<Long?, List<RoughProdScheduleLineInfoByFg>>,
val prodScheduleLinesByBom: List<RoughProdScheduleLineInfoByBom>,
val prodScheduleLinesByBomByDate: Map<Long?, List<RoughProdScheduleLineInfoByBomByDate>>
)

data class ProdScheduleLineInfoByFg(
data class RoughProdScheduleLineInfoByFg(
val id: Long?,
val code: String?,
val name: String?,
@@ -41,11 +74,11 @@ data class ProdScheduleLineInfoByFg(
val lastMonthAvgSales: BigDecimal?,
val estCloseBal: BigDecimal?,
val priority: Long?,
val bomMaterials: List<ProdScheduleLineBomMaterialInfoByFg>?,
val bomMaterials: List<RoughProdScheduleLineBomMaterialInfoByFg>?,
val assignDate: Long?,
)

data class ProdScheduleLineBomMaterialInfoByFg(
data class RoughProdScheduleLineBomMaterialInfoByFg(
val id: Long?,
val code: String?,
val name: String?,
@@ -55,7 +88,7 @@ data class ProdScheduleLineBomMaterialInfoByFg(
val uomName: String?
)

data class ProdScheduleLineInfoByBom(
data class RoughProdScheduleLineInfoByBom(
val id: Long?,
val code: String?,
val name: String?,
@@ -72,7 +105,7 @@ data class ProdScheduleLineInfoByBom(
val uomName: String?,
)

data class ProdScheduleLineInfoByBomByDate(
data class RoughProdScheduleLineInfoByBomByDate(
val id: Long?,
val code: String?,
val name: String?,


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

@@ -45,7 +45,7 @@ open class ProductionScheduleService(
schedulePeriod = request.schedulePeriod,
schedulePeriodTo = request.schedulePeriodTo,
totalEstProdCount = request.totalEstProdCount,
type = request.type,
types = request.types,
pageable = pageable
)

@@ -54,7 +54,7 @@ open class ProductionScheduleService(
return RecordsRes<ProdScheduleInfo>(records, total.toInt());
}

open fun prodScheduleDetail(id: Long): ProdScheduleWithLine {
open fun roughProdScheduleDetail(id: Long): RoughProdScheduleWithLine {
val zero = BigDecimal.ZERO
val prodSchedule = productionScheduleRepository.findById(id).getOrNull() ?: throw NoSuchElementException()
val dayOfWeekValue =
@@ -77,7 +77,7 @@ open class ProductionScheduleService(

val demandQty = bm.qty?.times(proportion) ?: zero

ProdScheduleLineBomMaterialInfoByFg(
RoughProdScheduleLineBomMaterialInfoByFg(
id = bm.id,
code = bm.item?.code,
name = bm.item?.name,
@@ -90,7 +90,7 @@ open class ProductionScheduleService(
)
}

ProdScheduleLineInfoByFg(
RoughProdScheduleLineInfoByFg(
id = line.id,
code = line.item.code,
name = line.item.name,
@@ -115,7 +115,7 @@ open class ProductionScheduleService(
.flatMap { it.bomMaterials ?: mutableListOf() }
.groupBy { it.code }
.map { (code, bm) ->
ProdScheduleLineBomMaterialInfoByFg(
RoughProdScheduleLineBomMaterialInfoByFg(
id = if (bm.isNotEmpty()) bm[0].id else null,
code = if (bm.isNotEmpty()) bm[0].code else null,
name = if (bm.isNotEmpty()) bm[0].name else null,
@@ -126,7 +126,7 @@ open class ProductionScheduleService(
)
}

ProdScheduleLineInfoByFg(
RoughProdScheduleLineInfoByFg(
id = if (infos.isNotEmpty()) infos[0].assignDate else null,
code = if (infos.isNotEmpty()) infos[0].code else null,
name = if (infos.isNotEmpty()) infos[0].name else null,
@@ -159,7 +159,7 @@ open class ProductionScheduleService(

val demandQty = bm.qty?.times(proportion) ?: zero

ProdScheduleLineInfoByBomByDate(
RoughProdScheduleLineInfoByBomByDate(
id = bm.item?.id,
code = bm.item?.code,
name = bm.item?.name,
@@ -181,7 +181,7 @@ open class ProductionScheduleService(
val prodScheduleLinesInfoByBom = prodScheduleLinesInfoByBom7Days
.groupBy { Pair(it.assignDate, it.code) }
.map { (key, line) ->
ProdScheduleLineInfoByBomByDate(
RoughProdScheduleLineInfoByBomByDate(
id = if (line.isNotEmpty()) line[0].id else null,
code = if (line.isNotEmpty()) line[0].code else null,
name = if (line.isNotEmpty()) line[0].name else null,
@@ -199,7 +199,7 @@ open class ProductionScheduleService(
val sumProdScheduleLinesInfoByBom = prodScheduleLinesInfoByBom7Days
.groupBy { it.code }
.map { (_, line) ->
ProdScheduleLineInfoByBom(
RoughProdScheduleLineInfoByBom(
id = if (line.isNotEmpty()) line[0].id else null,
code = if (line.isNotEmpty()) line[0].code else null,
name = if (line.isNotEmpty()) line[0].name else null,
@@ -217,8 +217,10 @@ open class ProductionScheduleService(
)
}



// ---------------------------------- Response ----------------------------------//
return ProdScheduleWithLine(
return RoughProdScheduleWithLine(
id = prodSchedule.id,
scheduleAt = prodSchedule.scheduleAt,
schedulePeriod = schedulePeriod,
@@ -233,6 +235,10 @@ open class ProductionScheduleService(
)
}

open fun detailedProdScheduleDetail(id: Long): RoughProdScheduleWithLine? {
return null
}

//====================細排相關 START====================//

open fun getDailyProductionCount(assignDate: Int, selectedDate: LocalDateTime): Int {


+ 11
- 8
src/main/java/com/ffii/fpsms/modules/master/web/ProductionScheduleController.kt Dosyayı Görüntüle

@@ -4,7 +4,7 @@ import com.ffii.core.response.RecordsRes
import com.ffii.core.utils.CriteriaArgsBuilder
import com.ffii.fpsms.modules.master.entity.ProductionScheduleRepository
import com.ffii.fpsms.modules.master.entity.projections.ProdScheduleInfo
import com.ffii.fpsms.modules.master.entity.projections.ProdScheduleWithLine
import com.ffii.fpsms.modules.master.entity.projections.RoughProdScheduleWithLine
import com.ffii.fpsms.modules.master.service.ProductionScheduleService
import com.ffii.fpsms.modules.master.service.ProductionScheduleService.FinishedGood
import com.ffii.fpsms.modules.master.service.ProductionScheduleService.RoughScheduleObj
@@ -42,8 +42,8 @@ class ProductionScheduleController(
}

@GetMapping("/detail/{id}")
fun getScheduleDetail(@PathVariable id: Long): ProdScheduleWithLine {
return productionScheduleService.prodScheduleDetail(id)
fun getScheduleDetail(@PathVariable id: Long): RoughProdScheduleWithLine {
return productionScheduleService.roughProdScheduleDetail(id)
}

@GetMapping("/getRecordByPage")
@@ -54,16 +54,19 @@ class ProductionScheduleController(
@RequestMapping(value = ["/testDetailSchedule"], method = [RequestMethod.GET])
fun generateDetailSchedule(request: HttpServletRequest?): Int {
try {
// For test
val genDate = request?.getParameter("genDate").let { LocalDateTime.parse(it) }

val today = LocalDateTime.now()
val latestRoughScheduleAt = productionScheduleService.getLatestScheduleAt("rough")
val assignDate = abs(Duration.between(latestRoughScheduleAt, today).toDays() % 7)
val finalAssignDate = if (assignDate.toInt() == 0) {
1
} else assignDate.toInt()
val assignDate = abs(Duration.between(latestRoughScheduleAt, today).toDays() % 7) + 1
// val finalAssignDate = if (assignDate.toInt() == 0) {
// 1
// } else assignDate.toInt()
//TODO: update this to receive selectedDate and assignDate from schedule
// productionScheduleService.generateDetailedScheduleByDay(1, LocalDateTime.of(2025,6,25,0,0,0))
println("today: $today | latestRoughScheduleAty: $latestRoughScheduleAt | assignDate: $assignDate ")
productionScheduleService.generateDetailedScheduleByDay(finalAssignDate, LocalDateTime.now())
productionScheduleService.generateDetailedScheduleByDay(assignDate.toInt(), genDate ?: LocalDateTime.now())
return 200
} catch (e: Exception) {
throw RuntimeException("Error generate schedule: ${e.message}", e)


+ 1
- 1
src/main/java/com/ffii/fpsms/modules/master/web/models/SearchProdScheduleRequest.kt Dosyayı Görüntüle

@@ -8,7 +8,7 @@ data class SearchProdScheduleRequest (
val schedulePeriod: String?,
val schedulePeriodTo: String?,
val totalEstProdCount: Double?,
val type: String?,
val types: List<String>?,
val pageSize: Int?,
val pageNum: Int?,
)

Yükleniyor…
İptal
Kaydet