|
@@ -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)" |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |