浏览代码

Merge remote-tracking branch 'origin/master'

master
CANCERYS\kw093 4 天前
父节点
当前提交
7ea1c12840
共有 3 个文件被更改,包括 97 次插入48 次删除
  1. +1
    -1
      src/main/java/com/ffii/fpsms/modules/common/scheduler/service/SchedulerService.kt
  2. +35
    -17
      src/main/java/com/ffii/fpsms/modules/master/service/ProductionScheduleService.kt
  3. +61
    -30
      src/main/java/com/ffii/fpsms/modules/master/web/ProductionScheduleController.kt

+ 1
- 1
src/main/java/com/ffii/fpsms/modules/common/scheduler/service/SchedulerService.kt 查看文件

@@ -164,7 +164,7 @@ open class SchedulerService(

//TODO: update this to receive selectedDate and assignDate from schedule
println("produceAt: $produceAt | today: $today | latestRoughScheduleAt: $latestRoughScheduleAt | assignDate: $assignDate ")
productionScheduleService.generateDetailedScheduleByDay(assignDate, latestRoughScheduleAt.atStartOfDay(), produceAt)
productionScheduleService.generateDetailedScheduleByDay(assignDate, latestRoughScheduleAt.atStartOfDay(), produceAt, 7)
}
} catch (e: Exception) {
throw RuntimeException("Error generate schedule: ${e.message}", e)


+ 35
- 17
src/main/java/com/ffii/fpsms/modules/master/service/ProductionScheduleService.kt 查看文件

@@ -735,7 +735,7 @@ open class ProductionScheduleService(
}
}

open fun generateDetailedScheduleByDay(assignDate: Int, selectedDate: LocalDateTime, produceAt: LocalDateTime) {
open fun generateDetailedScheduleByDay(assignDate: Int, selectedDate: LocalDateTime, produceAt: LocalDateTime, days: Int) {
val detailedScheduleOutputList = ArrayList<NeedQtyRecord>()

//increasement available
@@ -744,7 +744,7 @@ open class ProductionScheduleService(
var needQtyList = getNeedQty()
//remove the production schedule >= today
clearTodayAndFutureProdSchedule()
clearTodayAndFutureProdSchedule(produceAt)

println("needQtyList - " + needQtyList);
@@ -812,7 +812,7 @@ open class ProductionScheduleService(
saveDetailedScheduleOutput(sortedOutputList, accProdCount, fgCount, produceAt)

//do for 9 days to predict
for (i in 1..8) {
for (i in 1..(days + 1)) {
val targetDate = produceAt.plusDays(i.toLong())
val isSat = targetDate.dayOfWeek == DayOfWeek.SATURDAY
val isFri = targetDate.dayOfWeek == DayOfWeek.FRIDAY
@@ -1495,7 +1495,8 @@ open class ProductionScheduleService(

val matHeaders = listOf(
"Mat Code", "Mat Name", "Required Qty", "Total Qty Need",
"UoM", "Purchased Qty", "On Hand Qty", "Unavailable Qty",
"UoM", "Purchase Qty Need", "Purchase Unit",
"Purchased Qty", "On Hand Qty", "Unavailable Qty",
"Related Item Code", "Related Item Name"
)

@@ -1512,6 +1513,7 @@ open class ProductionScheduleService(
row.heightInPoints = 35f

val totalNeed = asDouble(rowData["totalMatQtyNeed"])
val purchaseQtyNeed = asDouble(rowData["purchaseQtyNeed"])
val purchased = asDouble(rowData["purchasedQty"])
val onHand = asDouble(rowData["onHandQty"])
val requiredQty = (totalNeed - purchased - onHand).coerceAtLeast(0.0)
@@ -1522,6 +1524,8 @@ open class ProductionScheduleService(
requiredQty,
totalNeed,
rowData["uomName"]?.toString() ?: "",
purchaseQtyNeed,
rowData["purchaseUnit"]?.toString() ?: "",
purchased,
onHand,
asDouble(rowData["unavailableQty"]),
@@ -1546,11 +1550,13 @@ open class ProductionScheduleService(
matSheet.setColumnWidth(2, 14 * 256) // Required Qty
matSheet.setColumnWidth(3, 14 * 256) // Total Qty Need
matSheet.setColumnWidth(4, 10 * 256) // UoM
matSheet.setColumnWidth(5, 14 * 256) // Purchased Qty
matSheet.setColumnWidth(6, 14 * 256) // On Hand Qty
matSheet.setColumnWidth(7, 14 * 256) // Unavailable Qty
matSheet.setColumnWidth(8, 22 * 256) // Related Item Code
matSheet.setColumnWidth(9, 40 * 256) // Related Item Name (longest)
matSheet.setColumnWidth(5, 14 * 256) // Purchase Qty Need
matSheet.setColumnWidth(6, 10 * 256) // Purchase UoM
matSheet.setColumnWidth(7, 14 * 256) // Purchased Qty
matSheet.setColumnWidth(8, 14 * 256) // On Hand Qty
matSheet.setColumnWidth(9, 14 * 256) // Unavailable Qty
matSheet.setColumnWidth(10, 22 * 256) // Related Item Code
matSheet.setColumnWidth(11, 40 * 256) // Related Item Name (longest)

// Portrait print setup
val matPrintSetup = matSheet.printSetup
@@ -1735,6 +1741,14 @@ open class ProductionScheduleService(
left join purchase_order on purchase_order_line.purchaseOrderId = purchase_order.id
where purchase_order_line.itemId = itm.id and date(purchase_order.estimatedArrivalDate) >= date(now()) and purchase_order.completeDate is null) as purchasedQty,
bm.uomName,
(select ratioD/ratioN from item_uom where purchaseUnit = 1 and itemId = it.id and item_uom.deleted = 0
) as purchaseRatio,
(select ceil(ratioD/ratioN*sum(bm.qty * psl.batchNeed)) from item_uom where purchaseUnit = 1 and itemId = it.id and item_uom.deleted = 0
) as purchaseQtyNeed,
(select code from item_uom
left join uom_conversion on item_uom.uomId = uom_conversion.id
where item_uom.purchaseUnit = 1 and item_uom.itemId = it.id and item_uom.deleted = 0
) as purchaseUnit,
min(ps.produceAt) as toProdcueFrom,
max(ps.produceAt) as toProdcueAt,
psl.*
@@ -1773,8 +1787,8 @@ open class ProductionScheduleService(
itm.code AS matCode,
itm.name AS matName,
bm.uomName AS uom,
iv.onHandQty,
iv.unavailableQty,
ceil((iv.onHandQty * (itsm.ratioN / itsm.ratioD)) * (itum.ratioD / itum.ratioN)) as onHandQty,
ceil((iv.unavailableQty * (itsm.ratioN / itsm.ratioD)) * (itum.ratioD / itum.ratioN)) as unavailableQty,
COALESCE((
SELECT SUM(pol.qty)
FROM purchase_order_line pol
@@ -1784,13 +1798,15 @@ open class ProductionScheduleService(
AND po.completeDate IS NULL
), 0) AS purchasedQty,
DATE(ps.produceAt) AS produceDate,
SUM(bm.qty * psl.batchNeed) AS qtyNeeded
ceil( SUM(bm.qty * psl.batchNeed) * (itum.ratioD / itum.ratioN) ) AS qtyNeeded
FROM production_schedule_line psl
JOIN production_schedule ps ON psl.prodScheduleId = ps.id
JOIN items it ON psl.itemId = it.id
JOIN bom ON it.id = bom.itemId
JOIN bom_material bm ON bom.id = bm.bomId
JOIN items itm ON bm.itemId = itm.id
JOIN item_uom itum ON itm.id = itum.itemId and itum.purchaseUnit = 1
JOIN item_uom itsm ON itm.id = itsm.itemId and itsm.stockUnit = 1
LEFT JOIN inventory iv ON itm.id = iv.itemId
WHERE DATE(ps.produceAt) >= DATE_ADD(CURDATE(), INTERVAL 1 DAY)
AND DATE(ps.produceAt) < DATE_ADD(CURDATE(), INTERVAL 8 DAY)
@@ -1841,25 +1857,27 @@ open class ProductionScheduleService(
}

@Transactional
open fun clearTodayAndFutureProdSchedule() {
open fun clearTodayAndFutureProdSchedule(produceAt: LocalDateTime) {
val deleteLinesSql = """
DELETE FROM production_schedule_line
WHERE prodScheduleId IN (
SELECT id FROM production_schedule
WHERE DATE(produceAt) >= DATE(NOW())
WHERE DATE(produceAt) >= DATE(:produceAt)
)
""".trimIndent()

val deleteSchedulesSql = """
DELETE FROM production_schedule
WHERE DATE(produceAt) >= DATE(NOW())
WHERE DATE(produceAt) >= DATE(:produceAt)
""".trimIndent()

val params = mapOf("produceAt" to produceAt)

// Execute child delete first
jdbcDao.executeUpdate(deleteLinesSql)
jdbcDao.executeUpdate(deleteLinesSql, params)

// Then delete parent schedules
jdbcDao.executeUpdate(deleteSchedulesSql)
jdbcDao.executeUpdate(deleteSchedulesSql, params)

// Optional: log the action (if you have logging setup)
// logger.info("Cleared all production schedules with produceAt >= today")


+ 61
- 30
src/main/java/com/ffii/fpsms/modules/master/web/ProductionScheduleController.kt 查看文件

@@ -27,6 +27,7 @@ import org.springframework.http.ResponseEntity
import org.springframework.http.HttpHeaders
import org.springframework.http.MediaType
import org.springframework.web.bind.annotation.GetMapping
import java.time.format.DateTimeParseException

@RestController
@RequestMapping("/productionSchedule")
@@ -105,35 +106,53 @@ class ProductionScheduleController(
}

@RequestMapping(value = ["/testDetailedSchedule"], method = [RequestMethod.GET])
fun generateDetailSchedule(request: HttpServletRequest?): Int {
fun generateDetailSchedule(
@RequestParam(name = "startDate", required = false) startDateParam: String?,
@RequestParam(name = "days", required = false, defaultValue = "7") days: Int,
request: HttpServletRequest?
): Int {
try {
// For test
//val genDate = request?.getParameter("genDate")?.let { LocalDate.parse(it).atStartOfDay() }
// ── Determine the generation base date ──
val genDate = startDateParam
?.let { param ->
try {
LocalDate.parse(param).atStartOfDay()
} catch (e: Exception) {
// Invalid format → fallback to today
println("Invalid startDate format: $param → using today")
LocalDateTime.now()
}
}
?: LocalDateTime.now() // default: today

val genDate = LocalDateTime.now()
val today = LocalDateTime.now()

//val latestRoughScheduleAt = productionScheduleService.getLatestScheduleAt("rough");
// val latestRoughScheduleAt = productionScheduleService.getSecondLatestRoughScheduleAt("rough");
// val latestRoughScheduleAt = productionScheduleService.getScheduledAtByDate(genDate?.toLocalDate() ?: today.toLocalDate());
// assume schedule period is monday to sunday
val assignDate = (genDate ?: today).dayOfWeek.value
// val day = 1
// val assignDate = ((genDate ?: today).dayOfWeek.value + day) % 7 + 1

// 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("genDate: $genDate | today: $today | latestRoughScheduleAt: $latestRoughScheduleAt | assignDate: $assignDate ")
//productionScheduleService.generateDetailedScheduleByDay(assignDate, latestRoughScheduleAt ?: LocalDateTime.now(), genDate ?: today)
println("Start generate detailed Schedule")
productionScheduleService.generateDetailedScheduleByDay(assignDate, today, today)
// ── Your existing assignDate logic ──
// (assuming schedule period monday=1 ... sunday=7)
val assignDate = genDate.dayOfWeek.value

// If you want to allow offset / custom day assignment later, you can keep/extend this:
// val day = 1
// val assignDate = ((genDate.dayOfWeek.value + day) % 7) + 1

println("Starting detailed schedule generation")
println(" → genDate : $genDate")
println(" → today : $today")
println(" → assignDate : $assignDate")

// Core generation call – using today's timestamp as "reference time"
// (you can change the last parameter to genDate if business logic requires it)
productionScheduleService.generateDetailedScheduleByDay(
assignDate,
today, // reference time / as-of time
genDate,
days// target / base date for planning
)

return 200
} catch (e: Exception) {
println("Error generating detailed schedule: ${e.message}")
e.printStackTrace()
throw RuntimeException("Error generate schedule: ${e.message}", e)
}
}
@@ -232,16 +251,28 @@ class ProductionScheduleController(
}
}

@PostMapping(
@GetMapping(
value = ["/export-prod-schedule"],
produces = ["application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"]
)
fun exportProdSchedule(): ResponseEntity<ByteArray> {
val data = productionScheduleService.searchExportProdSchedule(LocalDate.now())
val dataMat = productionScheduleService.searchExportProdScheduleMaterial(LocalDate.now())
val dataDaily = productionScheduleService.searchExportDailyMaterial(LocalDate.now())
val excelContent = productionScheduleService.exportProdScheduleToExcel(LocalDate.now(), data, dataMat, dataDaily)
fun exportProdSchedule(
@RequestParam(name = "fromDate", required = false) fromDateParam: String?
): ResponseEntity<ByteArray> {
// Parse fromDate or fall back to today
val fromDate: LocalDate = fromDateParam
?.let {
try {
LocalDate.parse(it)
} catch (e: DateTimeParseException) {
LocalDate.now()
}
}
?: LocalDate.now()

val data = productionScheduleService.searchExportProdSchedule(fromDate)
val dataMat = productionScheduleService.searchExportProdScheduleMaterial(fromDate)
val dataDaily = productionScheduleService.searchExportDailyMaterial(fromDate)
val excelContent = productionScheduleService.exportProdScheduleToExcel(fromDate, data, dataMat, dataDaily)
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=production_schedule.xlsx")


正在加载...
取消
保存