From 1321e88aa859fb094c050aac875b4929153e7ec4 Mon Sep 17 00:00:00 2001 From: "vluk@2fi-solutions.com.hk" Date: Mon, 9 Mar 2026 16:37:23 +0800 Subject: [PATCH] added logic for coffee or tea or lemon in scheduling --- .../modules/master/entity/CoffeeOrTea.kt | 23 ++++++++++++ .../master/entity/CoffeeOrTeaRepository.kt | 10 ++++++ .../service/ProductionScheduleService.kt | 35 +++++++++++++------ .../20260309_fai/01_create_coffee_or_tea.sql | 17 +++++++++ .../20260309_fai/02_coffee_or_tea_data.sql | 14 ++++++++ 5 files changed, 89 insertions(+), 10 deletions(-) create mode 100644 src/main/java/com/ffii/fpsms/modules/master/entity/CoffeeOrTea.kt create mode 100644 src/main/java/com/ffii/fpsms/modules/master/entity/CoffeeOrTeaRepository.kt create mode 100644 src/main/resources/db/changelog/changes/20260309_fai/01_create_coffee_or_tea.sql create mode 100644 src/main/resources/db/changelog/changes/20260309_fai/02_coffee_or_tea_data.sql diff --git a/src/main/java/com/ffii/fpsms/modules/master/entity/CoffeeOrTea.kt b/src/main/java/com/ffii/fpsms/modules/master/entity/CoffeeOrTea.kt new file mode 100644 index 0000000..9a2370e --- /dev/null +++ b/src/main/java/com/ffii/fpsms/modules/master/entity/CoffeeOrTea.kt @@ -0,0 +1,23 @@ +package com.ffii.fpsms.modules.master.entity + +import com.ffii.core.entity.BaseEntity +import jakarta.persistence.Column +import jakarta.persistence.Entity +import jakarta.persistence.Table +import jakarta.validation.constraints.Size + +/** + * Lookup table for PS scheduling. Maps itemCode to systemType (e.g. coffee/tea). + */ +@Entity +@Table(name = "coffee_or_tea") +open class CoffeeOrTea : BaseEntity() { + + @Size(max = 100) + @Column(name = "itemCode", length = 100) + open var itemCode: String? = null + + @Size(max = 100) + @Column(name = "systemType", length = 100) + open var systemType: String? = null +} diff --git a/src/main/java/com/ffii/fpsms/modules/master/entity/CoffeeOrTeaRepository.kt b/src/main/java/com/ffii/fpsms/modules/master/entity/CoffeeOrTeaRepository.kt new file mode 100644 index 0000000..3424565 --- /dev/null +++ b/src/main/java/com/ffii/fpsms/modules/master/entity/CoffeeOrTeaRepository.kt @@ -0,0 +1,10 @@ +package com.ffii.fpsms.modules.master.entity + +import com.ffii.core.support.AbstractRepository +import org.springframework.stereotype.Repository + +@Repository +interface CoffeeOrTeaRepository : AbstractRepository { + + fun findByItemCodeAndDeletedFalse(itemCode: String): CoffeeOrTea? +} diff --git a/src/main/java/com/ffii/fpsms/modules/master/service/ProductionScheduleService.kt b/src/main/java/com/ffii/fpsms/modules/master/service/ProductionScheduleService.kt index bdf83a9..2d46ec4 100644 --- a/src/main/java/com/ffii/fpsms/modules/master/service/ProductionScheduleService.kt +++ b/src/main/java/com/ffii/fpsms/modules/master/service/ProductionScheduleService.kt @@ -673,10 +673,14 @@ open class ProductionScheduleService( do.deleted = 0 and dol.itemId = items.id -- AND MONTH(do.estimatedArrivalDate) = MONTH(DATE_SUB(NOW(), INTERVAL 1 MONTH)) - AND do.estimatedArrivalDate >= '2026-01-08' AND do.estimatedArrivalDate < '2026-01-31' + AND do.estimatedArrivalDate >= '2026-02-07' AND do.estimatedArrivalDate < '2026-03-07' GROUP BY do.estimatedArrivalDate) AS d) AS avgQtyLastMonth, (select sum(reqQty) from job_order where bomId = bom.id and status != 'completed') AS pendingJobQty, + + (select count(1) from coffee_or_tea where systemType = 'coffee' and itemCode = items.code) as isCoffee, + (select count(1) from coffee_or_tea where systemType = 'tea' and itemCode = items.code) as isTea, + (select count(1) from coffee_or_tea where systemType = 'lemon' and itemCode = items.code) as isLemon, CASE WHEN item_fake_onhand.onHandQty is not null THEN item_fake_onhand.onHandQty ELSE inventory.onHandQty - 500 END AS stockQty, @@ -727,7 +731,7 @@ open class ProductionScheduleService( LEFT JOIN inventory ON items.id = inventory.itemId left join item_fake_onhand on items.code = item_fake_onhand.itemCode WHERE 1 - and bom.itemId != 16771 + -- and bom.itemId != 16771 ) AS i WHERE 1 and i.avgQtyLastMonth is not null @@ -751,8 +755,10 @@ open class ProductionScheduleService( daysLeft = (row["daysLeft"] as Number).toDouble() batchNeed = row["batchNeed"] as Number priority = row["priority"] as Number - - } + isCoffee = row["isCoffee"] as Number + isTea = row["isTea"] as Number + isLemon = row["isLemon"] as Number + } } } @@ -837,10 +843,10 @@ open class ProductionScheduleService( //do for 9 days to predict for (i in 0..(days)) { val targetDate = produceAt.plusDays(i.toLong()) - val isSat = targetDate.dayOfWeek == DayOfWeek.SATURDAY - val isFri = targetDate.dayOfWeek == DayOfWeek.FRIDAY - - val isSunday = targetDate.dayOfWeek == DayOfWeek.SUNDAY + val dayOfWeek = targetDate.dayOfWeek + val isSat = dayOfWeek == DayOfWeek.SATURDAY + val isFri = dayOfWeek == DayOfWeek.FRIDAY + val isSunday = dayOfWeek == DayOfWeek.SUNDAY val isFriSat = isFri || isSat println("##targetDate:" + targetDate + " isFri:"+ isFri + " isSat:" + isSat + " isSunday:" + isSunday) @@ -849,6 +855,13 @@ open class ProductionScheduleService( fgCount = 0 accProdCount = 0.0 sortedOutputList.forEach { record -> + // isCoffee > 0: only Mon, Wed, Fri; isTea > 0: only Tue, Thu, Sat; isLemon > 0: any day including Sunday + val canProduceOnDay = when { + (record.isLemon.toDouble()) > 0 -> true + (record.isCoffee.toDouble()) > 0 -> dayOfWeek in listOf(DayOfWeek.MONDAY, DayOfWeek.WEDNESDAY, DayOfWeek.FRIDAY) + (record.isTea.toDouble()) > 0 -> dayOfWeek in listOf(DayOfWeek.TUESDAY, DayOfWeek.THURSDAY, DayOfWeek.SATURDAY) + else -> !isSunday + } if(i > 0) record.stockQty = record.stockQty + (record.outputQty * record.needNoOfJobOrder.toInt()) - record.avgQtyLastMonth else @@ -870,8 +883,7 @@ open class ProductionScheduleService( if(record.daysLeft < redLine){ record.needQty = (record.avgQtyLastMonth * safetyStockDay) - record.stockQty; - if(!isSunday && record.needQty > 0.0){ - //if(record.needQty > 0.0){ + if(canProduceOnDay && record.needQty > 0.0){ record.batchNeed = ceil(record.needQty / record.outputQty) record.needNoOfJobOrder = record.batchNeed @@ -987,6 +999,9 @@ open class ProductionScheduleService( open var daysLeft: Double = 0.0 open var batchNeed: Number = 0 open var priority: Number = 0 + open var isCoffee: Number = 0 + open var isTea: Number = 0 + open var isLemon: Number = 0 override fun toString(): String { return "NeedQtyRecord(name=${name}," + diff --git a/src/main/resources/db/changelog/changes/20260309_fai/01_create_coffee_or_tea.sql b/src/main/resources/db/changelog/changes/20260309_fai/01_create_coffee_or_tea.sql new file mode 100644 index 0000000..7fe792b --- /dev/null +++ b/src/main/resources/db/changelog/changes/20260309_fai/01_create_coffee_or_tea.sql @@ -0,0 +1,17 @@ +--liquibase formatted sql + +--changeset fai:create coffee_or_tea table +CREATE TABLE `coffee_or_tea` +( + `id` INT NOT NULL AUTO_INCREMENT, + `created` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + `createdBy` VARCHAR(30) NULL DEFAULT NULL, + `version` INT NOT NULL DEFAULT '0', + `modified` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + `modifiedBy` VARCHAR(30) NULL DEFAULT NULL, + `deleted` TINYINT(1) NOT NULL DEFAULT '0', + `itemCode` VARCHAR(100) NULL, + `systemType` VARCHAR(100) NULL, + CONSTRAINT pk_coffee_or_tea PRIMARY KEY (id), + INDEX idx_coffee_or_tea_itemCode (itemCode) +); diff --git a/src/main/resources/db/changelog/changes/20260309_fai/02_coffee_or_tea_data.sql b/src/main/resources/db/changelog/changes/20260309_fai/02_coffee_or_tea_data.sql new file mode 100644 index 0000000..fe61efa --- /dev/null +++ b/src/main/resources/db/changelog/changes/20260309_fai/02_coffee_or_tea_data.sql @@ -0,0 +1,14 @@ +--liquibase formatted sql + +--changeset fai:add coffee_or_tea data + +INSERT INTO `fpsmsdb`.`coffee_or_tea` (`created`, `createdBy`, `version`, `modified`, `modifiedBy`, `deleted`, `itemCode`, `systemType`) VALUES ('2026-03-09', '1', '0', '2026-03-09', '1', '0', 'PP1175', 'lemon'); +INSERT INTO `fpsmsdb`.`coffee_or_tea` (`created`, `createdBy`, `version`, `modified`, `modifiedBy`, `deleted`, `itemCode`, `systemType`) VALUES ('2026-03-09', '1', '0', '2026-03-09', '1', '0', 'PP1167', 'lemon'); +INSERT INTO `fpsmsdb`.`coffee_or_tea` (`created`, `createdBy`, `version`, `modified`, `modifiedBy`, `deleted`, `itemCode`, `systemType`) VALUES ('2026-03-09', '1', '0', '2026-03-09', '1', '0', 'PP2236', 'tea'); +INSERT INTO `fpsmsdb`.`coffee_or_tea` (`created`, `createdBy`, `version`, `modified`, `modifiedBy`, `deleted`, `itemCode`, `systemType`) VALUES ('2026-03-09', '1', '0', '2026-03-09', '1', '0', 'PP2237', 'coffee'); +INSERT INTO `fpsmsdb`.`coffee_or_tea` (`created`, `createdBy`, `version`, `modified`, `modifiedBy`, `deleted`, `itemCode`, `systemType`) VALUES ('2026-03-09', '1', '0', '2026-03-09', '1', '0', 'PP2238', 'coffee'); +INSERT INTO `fpsmsdb`.`coffee_or_tea` (`created`, `createdBy`, `version`, `modified`, `modifiedBy`, `deleted`, `itemCode`, `systemType`) VALUES ('2026-03-09', '1', '0', '2026-03-09', '1', '0', 'PP2239', 'tea'); +INSERT INTO `fpsmsdb`.`coffee_or_tea` (`created`, `createdBy`, `version`, `modified`, `modifiedBy`, `deleted`, `itemCode`, `systemType`) VALUES ('2026-03-09', '1', '0', '2026-03-09', '1', '0', 'PP2336', 'coffee'); +INSERT INTO `fpsmsdb`.`coffee_or_tea` (`created`, `createdBy`, `version`, `modified`, `modifiedBy`, `deleted`, `itemCode`, `systemType`) VALUES ('2026-03-09', '1', '0', '2026-03-09', '1', '0', 'PP2338', 'tea'); +INSERT INTO `fpsmsdb`.`coffee_or_tea` (`created`, `createdBy`, `version`, `modified`, `modifiedBy`, `deleted`, `itemCode`, `systemType`) VALUES ('2026-03-09', '1', '0', '2026-03-09', '1', '0', 'PP2288', 'lemon'); +