2 Commits

5 changed files with 60 additions and 15 deletions
Unified View
  1. +3
    -0
      src/main/java/com/ffii/fpsms/modules/master/entity/ProductionScheduleLine.kt
  2. +4
    -4
      src/main/java/com/ffii/fpsms/modules/master/service/ItemsService.kt
  3. +48
    -10
      src/main/java/com/ffii/fpsms/modules/master/service/ProductionScheduleService.kt
  4. +1
    -1
      src/main/java/com/ffii/fpsms/modules/master/web/ProductionScheduleController.kt
  5. +4
    -0
      src/main/resources/db/changelog/changes/20250619_01_jason_lam/01_update_production_schedule_line_with_weightingRef.sql

+ 3
- 0
src/main/java/com/ffii/fpsms/modules/master/entity/ProductionScheduleLine.kt View File

@@ -37,4 +37,7 @@ open class ProductionScheduleLine : BaseEntity<Long>() {


@Column(name = "itemPriority") @Column(name = "itemPriority")
open var itemPriority: Long = 0L open var itemPriority: Long = 0L

@Column(name = "weightingRef")
open var weightingRef: Double = 0.0
} }

+ 4
- 4
src/main/java/com/ffii/fpsms/modules/master/service/ItemsService.kt View File

@@ -12,6 +12,7 @@ import org.springframework.transaction.annotation.Transactional
import java.io.IOException import java.io.IOException
import java.time.LocalDateTime import java.time.LocalDateTime
import java.time.format.DateTimeFormatter import java.time.format.DateTimeFormatter
import java.time.temporal.TemporalAdjusters


@Service @Service
open class ItemsService( open class ItemsService(
@@ -33,15 +34,14 @@ open class ItemsService(
val lastMonthEnd = now.minusDays(now.dayOfMonth.toLong()).withHour(23).withMinute(59).withSecond(59) // End of last month val lastMonthEnd = now.minusDays(now.dayOfMonth.toLong()).withHour(23).withMinute(59).withSecond(59) // End of last month


val curMonthStart = now.withDayOfMonth(1) // Start of last month val curMonthStart = now.withDayOfMonth(1) // Start of last month
val curMonthEnd = now.withDayOfMonth(31).withHour(23).withMinute(59).withSecond(59) // End of last month
val curMonthEnd = now.with(TemporalAdjusters.lastDayOfMonth()).withHour(23).withMinute(59).withSecond(59) // End of last month


// Format dates if needed // Format dates if needed
val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss") val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")


//TODO: change back to use last month for production
val args = mapOf( val args = mapOf(
"lastMonthStart" to curMonthStart.format(formatter),
"lastMonthEnd" to curMonthEnd.format(formatter)
"lastMonthStart" to lastMonthStart.format(formatter),
"lastMonthEnd" to lastMonthEnd.format(formatter)
) )


println("lastMonthStart:" + args.get("lastMonthStart")) println("lastMonthStart:" + args.get("lastMonthStart"))


+ 48
- 10
src/main/java/com/ffii/fpsms/modules/master/service/ProductionScheduleService.kt View File

@@ -45,8 +45,8 @@ open class ProductionScheduleService(
return jdbcDao.queryForInt(sql.toString(), args); return jdbcDao.queryForInt(sql.toString(), args);
} }


open fun generateDetailScheduleByDay(assignDate: Int, selectedDate: LocalDateTime) {
val detailScheduleOutputList = ArrayList<ProductionScheduleRecord>()
open fun generateDetailedScheduleByDay(assignDate: Int, selectedDate: LocalDateTime) {
val detailedScheduleOutputList = ArrayList<ProductionScheduleRecord>()


//increasement available //increasement available
var idleProductionCount = 22000.0 - getDailyProductionCount(assignDate, selectedDate); var idleProductionCount = 22000.0 - getDailyProductionCount(assignDate, selectedDate);
@@ -63,7 +63,7 @@ open class ProductionScheduleService(
//用缺口決定生產順序 //用缺口決定生產順序
val productionPriorityMap: HashMap<ProductionScheduleRecord, Double> = HashMap(); val productionPriorityMap: HashMap<ProductionScheduleRecord, Double> = HashMap();


//TODO: update to use SQL get shop order record for detail scheduling (real prodQty and openBal)
//TODO: update to use SQL get shop order record for detailed scheduling (real prodQty and openBal)
for (record in scheduledList){ for (record in scheduledList){
println("Object - " + record.toString() ); println("Object - " + record.toString() );
val tempRecord= record; val tempRecord= record;
@@ -86,7 +86,7 @@ open class ProductionScheduleService(
if(idleProductionCount - prodDifference >= 0){ if(idleProductionCount - prodDifference >= 0){
//have enough quoter for adjustment //have enough quoter for adjustment
idleProductionCount -= prodDifference; idleProductionCount -= prodDifference;
detailScheduleOutputList.add(updatedScheduleRecord)
detailedScheduleOutputList.add(updatedScheduleRecord)
accProdCount += updatedScheduleRecord.prodQty accProdCount += updatedScheduleRecord.prodQty
fgCount++ fgCount++
} }
@@ -95,12 +95,20 @@ open class ProductionScheduleService(
} }
} }


saveDetailScheduleOutput(detailScheduleOutputList, accProdCount, fgCount)
// Sort detailedScheduleOutputList by item priority
val sortedOutputList = detailedScheduleOutputList.sortedBy { it.weightingRef }.toMutableList()


//return detailScheduleOutput
// Update itemPriority in the sorted list
var tempPriority = 1L
sortedOutputList.forEach { record ->
record.itemPriority = tempPriority
tempPriority++
}

saveDetailedScheduleOutput(sortedOutputList, accProdCount, fgCount)
} }


open fun saveDetailScheduleOutput(sortedEntries: List<ProductionScheduleRecord>, accProdCount: Double, fgCount: Long) {
open fun saveDetailedScheduleOutput(sortedEntries: List<ProductionScheduleRecord>, accProdCount: Double, fgCount: Long) {
val tempObj = ProductionSchedule() val tempObj = ProductionSchedule()
tempObj.id = -1; tempObj.id = -1;
tempObj.scheduleAt = LocalDateTime.now() tempObj.scheduleAt = LocalDateTime.now()
@@ -128,7 +136,8 @@ open class ProductionScheduleService(
savedItem.prodQty = detailedScheduleObj.prodQty savedItem.prodQty = detailedScheduleObj.prodQty
savedItem.type = "detailed" savedItem.type = "detailed"
savedItem.assignDate = detailedScheduleObj.assignDate; savedItem.assignDate = detailedScheduleObj.assignDate;
savedItem.itemPriority = detailedScheduleObj.itemPriority //TODO: to be updated
savedItem.weightingRef = detailedScheduleObj.weightingRef
savedItem.itemPriority = detailedScheduleObj.itemPriority
productionScheduleLineRepository.saveAndFlush(savedItem) productionScheduleLineRepository.saveAndFlush(savedItem)


} catch (e: Exception) { } catch (e: Exception) {
@@ -140,12 +149,20 @@ open class ProductionScheduleService(
open class ProductionScheduleRecord : ProductionScheduleLine() { open class ProductionScheduleRecord : ProductionScheduleLine() {
//SQL record in general with item name //SQL record in general with item name
open var name: String = "" //item name open var name: String = "" //item name
open var isDark: Number = 0
open var isFloat: Number = 0
open var isDense: Number = 0
open var targetMinStock: Double = 0.0; open var targetMinStock: Double = 0.0;


override fun toString(): String { override fun toString(): String {
return "ProductionScheduleRecord(name='$name', targetMinStock=$targetMinStock)"
return "ProductionScheduleLine(prodScheduleId=$prodScheduleId," +
" itemId=$itemId, lastMonthAvgSales=$lastMonthAvgSales," +
" prodQty=$prodQty, estCloseBal=$estCloseBal, type='$type'," +
" approverId=$approverId, refScheduleId=$refScheduleId," +
" assignDate=$assignDate, itemPriority=$itemPriority)" +
" productionScheduleRecord(name='$name', targetMinStock=$targetMinStock)" +
" isDark=$isDark, isFloat=$isFloat, isDense=$isDense, weightingRef=$weightingRef"
} }

} }


open fun getProductionScheduleRecord(args: Map<String, Any>): List<ProductionScheduleRecord> { open fun getProductionScheduleRecord(args: Map<String, Any>): List<ProductionScheduleRecord> {
@@ -156,6 +173,9 @@ open class ProductionScheduleService(
+ " psl.itemPriority, " + " psl.itemPriority, "
+ " psl.itemId, " + " psl.itemId, "
+ " i.name, " + " i.name, "
+ " COALESCE(b.isDark, 0) AS isDark, "
+ " COALESCE(b.isFloat, 0) AS isFloat, "
+ " COALESCE(b.isDense, 0) AS isDense, "
+ " psl.lastMonthAvgSales, " + " psl.lastMonthAvgSales, "
+ " psl.lastMonthAvgSales*2 AS targetMinStock, " + " psl.lastMonthAvgSales*2 AS targetMinStock, "
+ " psl.prodQty, " + " psl.prodQty, "
@@ -165,6 +185,7 @@ open class ProductionScheduleService(
+ " FROM production_schedule ps " + " FROM production_schedule ps "
+ " LEFT JOIN production_schedule_line psl ON psl.prodScheduleId = ps.id " + " LEFT JOIN production_schedule_line psl ON psl.prodScheduleId = ps.id "
+ " LEFT JOIN items i ON psl.itemId = i.id " + " LEFT JOIN items i ON psl.itemId = i.id "
+ " LEFT JOIN bom b ON i.id = b.itemId "
+ " WHERE ps.deleted = FALSE " + " WHERE ps.deleted = FALSE "
+ " AND psl.deleted = FALSE " + " AND psl.deleted = FALSE "
); );
@@ -186,6 +207,15 @@ open class ProductionScheduleService(


val resultList = jdbcDao.queryForList(sql.toString(), args, ); val resultList = jdbcDao.queryForList(sql.toString(), args, );


val DARK_MAX_VALUE = 1;
val FLOAT_MAX_VALUE = 5;
val DENSE_MAX_VALUE = 5;
val DARK_WEIGHTING = 0.34;
val FLOAT_WEIGHTING = 0.33;
val DENSE_WEIGHTING = 0.33;


//TODO: update here
// Convert the list of maps to a list of ProductionScheduleRecord // Convert the list of maps to a list of ProductionScheduleRecord
return resultList.map { row -> return resultList.map { row ->
ProductionScheduleRecord().apply { ProductionScheduleRecord().apply {
@@ -199,6 +229,14 @@ open class ProductionScheduleService(
this.estCloseBal = row["estCloseBal"].toString().toDouble() this.estCloseBal = row["estCloseBal"].toString().toDouble()
this.type = row["type"] as String this.type = row["type"] as String
this.assignDate = row["assignDate"].toString().toLong() this.assignDate = row["assignDate"].toString().toLong()

this.isDark = row["isDark"].toString().toInt()
this.isDense = row["isDense"].toString().toInt()
this.isFloat = row["isFloat"].toString().toInt()
this.weightingRef =
(DARK_MAX_VALUE - row["isDark"].toString().toInt() ) / DARK_MAX_VALUE.toDouble() * DARK_WEIGHTING +
(DENSE_MAX_VALUE - row["isDense"].toString().toInt()) / DENSE_MAX_VALUE.toDouble() * DENSE_WEIGHTING +
(FLOAT_MAX_VALUE - row["isFloat"].toString().toInt()) / FLOAT_MAX_VALUE.toDouble() * FLOAT_WEIGHTING
} }
} }
} }


+ 1
- 1
src/main/java/com/ffii/fpsms/modules/master/web/ProductionScheduleController.kt View File

@@ -27,7 +27,7 @@ class ProductionScheduleController(
@RequestMapping(value = ["/testDetailSchedule"], method = [RequestMethod.GET]) @RequestMapping(value = ["/testDetailSchedule"], method = [RequestMethod.GET])
fun generateDetailSchedule(request: HttpServletRequest?): Int { fun generateDetailSchedule(request: HttpServletRequest?): Int {
try { try {
productionScheduleService.generateDetailScheduleByDay(1, LocalDateTime.of(2025,5,28,0,0,0))
productionScheduleService.generateDetailedScheduleByDay(1, LocalDateTime.of(2025,6,18,0,0,0))
return 200 return 200
} catch (e: Exception) { } catch (e: Exception) {
throw RuntimeException("Error generate schedule: ${e.message}", e) throw RuntimeException("Error generate schedule: ${e.message}", e)


+ 4
- 0
src/main/resources/db/changelog/changes/20250619_01_jason_lam/01_update_production_schedule_line_with_weightingRef.sql View File

@@ -0,0 +1,4 @@
--liquibase formatted sql
--changeset jason_lam:update production schedule line with weightingRef

ALTER TABLE production_schedule_line ADD `weightingRef` DECIMAL(16,2) NOT NULL DEFAULT 0.0 ;

Loading…
Cancel
Save