2 Commit

2 ha cambiato i file con 254 aggiunte e 1 eliminazioni
  1. +204
    -0
      src/main/java/com/ffii/fpsms/modules/master/service/SchedulingService.kt
  2. +50
    -1
      src/main/java/com/ffii/fpsms/modules/master/web/UomConversionController.kt

+ 204
- 0
src/main/java/com/ffii/fpsms/modules/master/service/SchedulingService.kt Vedi File

@@ -0,0 +1,204 @@
package com.ffii.fpsms.modules.master.service

import com.ffii.core.support.AbstractBaseEntityService
import com.ffii.core.support.JdbcDao
import com.ffii.fpsms.modules.master.entity.*
import com.ffii.fpsms.modules.master.web.models.MessageResponse
import org.springframework.core.io.ClassPathResource
import org.springframework.stereotype.Service
import com.google.gson.Gson
import org.springframework.transaction.annotation.Transactional
import java.io.BufferedReader
import java.io.IOException
import java.io.InputStreamReader
import java.nio.charset.StandardCharsets
import java.sql.DriverManager.println
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import java.util.*
import java.util.regex.Pattern
import kotlin.math.roundToLong
import kotlin.math.ceil

@Service
open class SchedulingService(
private val jdbcDao: JdbcDao,
private val uomConversionRepository: UomConversionRepository,
): AbstractBaseEntityService<UomConversion, Long, UomConversionRepository>(jdbcDao, uomConversionRepository) {
// do mapping with projection

open fun generateRoughScheduleByWeek(fgList : ArrayList<FinishedGood>): HashMap<RoughScheduleObj, Double> {
val roughScheduleOutput: HashMap<RoughScheduleObj, Double> = HashMap();

for(fg:FinishedGood in fgList) {
val roughScheduleRecord: RoughScheduleObj = roughScheduleByItem(fg);
roughScheduleOutput.put(roughScheduleRecord, roughScheduleRecord.totalDifference);
}

//完成初步fg粗排後檢查調整
for (i in 5 until 12) {
var accProductionCount = 0L;

// Sort by totalDifference before processing
val sortedEntries = roughScheduleOutput.entries.sortedBy { it.value }

for ((roughScheduleRecord, totalDifference) in sortedEntries) {
kotlin.io.println("[RUN" + i + "][index:" + totalDifference + "] - " + roughScheduleRecord.fgDetail?.name);

if (accProductionCount + ceil(totalDifference).toLong() < 22000) { //沒有超過每日產量
accProductionCount += ceil(roughScheduleRecord.productionSchedule[i]).toLong() //分開日子算

if(roughScheduleRecord.totalForgoneCount > 0.0){
//優先解決拖欠的數量
if(accProductionCount + ceil(roughScheduleRecord.totalForgoneCount).toLong() <22000){
//可以全做
accProductionCount += ceil(roughScheduleRecord.totalForgoneCount).toLong();
roughScheduleRecord.totalForgoneCount = 0.0;
}
else{
//只能做部分
var maxExtraProduction = 22000L - accProductionCount;
roughScheduleRecord.totalForgoneCount = roughScheduleRecord.totalForgoneCount - maxExtraProduction;
roughScheduleRecord.productionSchedule[i] = roughScheduleRecord.productionSchedule[i] + maxExtraProduction;
accProductionCount += maxExtraProduction;

//update close balance
for (j in i until 12){
roughScheduleRecord.closeBalance[j] = roughScheduleRecord.closeBalance[j] + maxExtraProduction;
}
}
}

roughScheduleRecord.totalDifference += roughScheduleRecord.productionSchedule[i]
roughScheduleOutput[roughScheduleRecord] = roughScheduleRecord.totalDifference
}
else{//超過每日產量
var maxExtraProduction = 22000L - accProductionCount;
roughScheduleRecord.totalForgoneCount = roughScheduleRecord.totalForgoneCount + roughScheduleRecord.productionSchedule[i] - maxExtraProduction;
roughScheduleRecord.productionSchedule[i] = maxExtraProduction.toDouble();
accProductionCount += maxExtraProduction;

//update close balance
roughScheduleRecord.closeBalance[i] = roughScheduleRecord.closeBalance[i] - roughScheduleRecord.productionSchedule[i] + maxExtraProduction.toDouble();
for (j in i+1 until 12){
roughScheduleRecord.closeBalance[j] = roughScheduleRecord.closeBalance[j] - roughScheduleRecord.productionSchedule[i] + maxExtraProduction.toDouble();
}

// Update totalDifference in roughScheduleRecord
roughScheduleRecord.totalDifference += roughScheduleRecord.productionSchedule[i] + maxExtraProduction.toDouble();
roughScheduleOutput[roughScheduleRecord] = roughScheduleRecord.totalDifference
}

kotlin.io.println("========================================");
}
}

return roughScheduleOutput
}

open fun roughScheduleByItem(fg: FinishedGood): RoughScheduleObj{
val minStockCount: Double = fg.lastMonthAvgSalesCount * 1.5
val stockDifference: Double = minStockCount - fg.openBalance
val productionSchedule: Array<Double> = Array<Double>(12, { 0.0 })

//首日粗排產量 —> 取結果,或是fg本身生產上限,並不可小於0
productionSchedule[0] = Math.max(
Math.min(
(stockDifference + fg.lastMonthAvgSalesCount),
fg.fgProductionLimit
),
0.0
)

val closeBalance: Array<Double> = Array<Double>(12, { 0.0 })
closeBalance[0] = fg.openBalance + productionSchedule[0] - fg.lastMonthAvgSalesCount;

for (i in 1 until 12){
//最少庫存-closeBalance 有可能小於0,所以必須要確保輸出>=0
productionSchedule[i] = Math.max(
Math.min(
(minStockCount - closeBalance[i-1] + fg.lastMonthAvgSalesCount),
fg.fgProductionLimit
),
0.0
)
closeBalance[i] = closeBalance[i-1] + productionSchedule[i] - fg.lastMonthAvgSalesCount;
}

var totalProductionCount: Double = 0.0

for (i in 0 until 12) {
totalProductionCount = totalProductionCount + productionSchedule[i];
}

val totalDifference: Double = -(totalProductionCount - fg.openBalance);


return RoughScheduleObj(
fg,
productionSchedule,
closeBalance,
totalDifference,
totalProductionCount,
0.0
);
}

open class FinishedGood {
//var fgDetail: FinishedGood? = null
var id: Long? = null
var name: String? = null
var receipeId: Long? = null
var openBalance: Double = 0.0
var lastMonthAvgSalesCount: Double = 0.0
var fgProductionLimit: Double = 22000.0

constructor(
id: Long?,
name: String?,
receipeId: Long?,
openBalance: Double,
lastMonthAvgSalesCount: Double,
fgProductionLimit: Double
) {
this.id = id
this.name = name
this.receipeId = receipeId
this.openBalance = openBalance
this.lastMonthAvgSalesCount = lastMonthAvgSalesCount
this.fgProductionLimit = fgProductionLimit
}
}

class RoughScheduleObj {
var fgDetail: FinishedGood? = null
var productionSchedule: Array<Double> = Array<Double>(12, { 0.0 })
var closeBalance: Array<Double> = Array(12) { 0.0 };
var totalDifference: Double = 0.0
var totalProductionCount: Double = 0.0
var totalForgoneCount: Double = 0.0

constructor(
fgDetail: FinishedGood?,
productionSchedule: Array<Double>,
closeBalance: Array<Double>,
totalDifference: Double,
totalProductionCount: Double,
totalForgoneCount: Double
) {
this.fgDetail = fgDetail
this.productionSchedule = productionSchedule
this.closeBalance = closeBalance
this.totalDifference = totalDifference
this.totalProductionCount = totalProductionCount
this.totalForgoneCount = totalForgoneCount
}

override fun toString(): String {
return "RoughScheduleObj(fgDetail=$fgDetail, productionSchedule=${productionSchedule.contentToString()}, closeBalance=${closeBalance.contentToString()}, totalDifference=$totalDifference, totalProductionCount=$totalProductionCount, totalForgoneCount=$totalForgoneCount)"
}


}

}

+ 50
- 1
src/main/java/com/ffii/fpsms/modules/master/web/UomConversionController.kt Vedi File

@@ -1,16 +1,23 @@
package com.ffii.fpsms.modules.master.web

import com.ffii.fpsms.modules.master.entity.UomConversion
import com.ffii.fpsms.modules.master.service.SchedulingService
import com.ffii.fpsms.modules.master.service.SchedulingService.FinishedGood
import com.ffii.fpsms.modules.master.service.SchedulingService.RoughScheduleObj
import com.ffii.fpsms.modules.master.service.UomConversionService
import jakarta.servlet.http.HttpServletRequest
import org.springframework.web.bind.annotation.*
import java.util.ArrayList
import java.util.HashMap
import kotlin.collections.component1
import kotlin.collections.component2


@RestController
@RequestMapping("/uomConversion")
class UomConversionController(
private val uomConversionService: UomConversionService
private val uomConversionService: UomConversionService,
private val schedulingService: SchedulingService
) {
// @GetMapping
// fun allItems(): List<Items> {
@@ -29,4 +36,46 @@ class UomConversionController(
throw RuntimeException("Error converting BOM: ${e.message}", e)
}
}

@RequestMapping(value = ["/testRoughSchedule"], method = [RequestMethod.GET])
fun generateRoughSchedule(request: HttpServletRequest?): HashMap<RoughScheduleObj, Double> {
try {
val demoFGList = arrayListOf<FinishedGood>(
FinishedGood(
1,
"豆腐花",
3,
91.0,
31.0,
3000.0
),
FinishedGood(
2,
"中湯包",
4,
100.0,
72.5,
3000.0
),
FinishedGood(
3,
"苦瓜炒蛋",
3,
700.0,
300.5,
22000.0
),
);

val result: HashMap<RoughScheduleObj, Double> = schedulingService.generateRoughScheduleByWeek(demoFGList);
val sortedEntries = result.entries.sortedBy { it.value }

for ((roughScheduleRecord, totalDifference) in result) {
println("[totalDifference:" + sortedEntries + "] - " + sortedEntries.toString())
}
return result;
} catch (e: Exception) {
throw RuntimeException("Error genereate schedule: ${e.message}", e)
}
}
}

Caricamento…
Annulla
Salva