diff --git a/docs/DEMO_BRANCH_SETUP.md b/docs/DEMO_BRANCH_SETUP.md new file mode 100644 index 00000000..5c2f8608 --- /dev/null +++ b/docs/DEMO_BRANCH_SETUP.md @@ -0,0 +1,127 @@ +# Demo branch setup (`debrand`) + +This branch is a white-label demo. It uses a separate database, `fpsms_demo`, filled with fictional data. It must not read or write the live company database `fpsmsdb`, and it must not call the live M18 system. + +Check out `debrand` in both repositories: + +- `FPSMS-backend` +- `FPSMS-frontend` + +Do not merge this branch. Do not start it with `db-local`, `prod`, or `db-toa`. + +## What you get + + +| | | +| -------------- | --------------------------------------------------------------- | +| Site | Frontend on port 3000, API on port 8090 | +| Spring profile | `db-demo` | +| Database | `fpsms_demo` on `127.0.0.1:3306` | +| App login | `demo` / `Demo2026!` | +| Also | `demo.stock` / `Demo2026!` (倉務), `demo.prod` / `Demo2026!` (出品) | + + +`demo` has ADMIN, STOCK, PROD, PACK, and REPORT_MGMT. The UI language switch still works. Item names and other master data are stored in Chinese. + +On the report page, leave the dates empty for most downloads. For 「庫存盤點報告」 choose round 「示範盤點輪次」. For 「送貨訂單與倉存單位不符報告」 use today’s date. + +## 1. Stop anything already on port 8090 + +The frontend on this branch calls `http://localhost:8090/api`. If a normal backend is already listening there, it is the live database. Stop that process before starting the demo. + +## 2. Copy the table structure into `fpsms_demo` + +Liquibase changesets in this repo name the schema `fpsmsdb`. Running them against an empty database, as `root`, would change the live database. Do not do that. + +Use the local `root` account from `application-db-local.yml` only for this one-time copy. Create an empty schema, load the structure (no rows), then copy the Liquibase history so startup treats the schema as already up to date. + +```bash +mysql -h127.0.0.1 -P3306 -uroot -p -e \ + "CREATE DATABASE IF NOT EXISTS fpsms_demo CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;" + +mysqldump --no-data --routines --triggers -h127.0.0.1 -P3306 -uroot -p fpsmsdb \ + > /tmp/fpsms_demo_schema.sql + +mysql -h127.0.0.1 -P3306 -uroot -p fpsms_demo < /tmp/fpsms_demo_schema.sql + +mysqldump -h127.0.0.1 -P3306 -uroot -p fpsmsdb DATABASECHANGELOG DATABASECHANGELOGLOCK \ + > /tmp/fpsms_demo_changelog.sql + +mysql -h127.0.0.1 -P3306 -uroot -p fpsms_demo < /tmp/fpsms_demo_changelog.sql +``` + +`fpsms_demo` should now have tables and Liquibase history, and no company rows. + +## 3. Create a login that cannot see `fpsmsdb` + +`application-db-demo.yml` connects as `fpsms_demo` / `FpsmsDemoOnly2026`. That account is allowed to use `fpsms_demo` only. + +```bash +mysql -h127.0.0.1 -P3306 -uroot -p <<'SQL' +CREATE USER IF NOT EXISTS 'fpsms_demo'@'127.0.0.1' IDENTIFIED BY 'FpsmsDemoOnly2026'; +CREATE USER IF NOT EXISTS 'fpsms_demo'@'localhost' IDENTIFIED BY 'FpsmsDemoOnly2026'; +ALTER USER 'fpsms_demo'@'127.0.0.1' IDENTIFIED BY 'FpsmsDemoOnly2026'; +ALTER USER 'fpsms_demo'@'localhost' IDENTIFIED BY 'FpsmsDemoOnly2026'; +GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, + CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, + CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER + ON fpsms_demo.* TO 'fpsms_demo'@'127.0.0.1'; +GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, + CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, + CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER + ON fpsms_demo.* TO 'fpsms_demo'@'localhost'; +FLUSH PRIVILEGES; +SQL +``` + +Confirm the wall before starting the app. The first command must fail with MySQL error 1142. The second must succeed. + +```bash +mysql -h127.0.0.1 -P3306 -ufpsms_demo -pFpsmsDemoOnly2026 -e "SELECT COUNT(*) FROM fpsmsdb.user;" +mysql -h127.0.0.1 -P3306 -ufpsms_demo -pFpsmsDemoOnly2026 -D fpsms_demo -e "SELECT COUNT(*) FROM user;" +``` + +Do not put `root` back into `application-db-demo.yml`. If this login can read `fpsmsdb`, the demo profile refuses to start. That refusal is the point. + +## 4. Start the backend + +JDK 17. From `FPSMS-backend`, on branch `debrand`: + +```bash +./gradlew bootRun --args='--spring.profiles.active=db-demo' +``` + +The first boot inserts the fictional sandbox (`DemoSandboxSeeder`) and the extra report rows (`src/main/resources/demo/demo-coverage.sql`). Later boots skip both when user `demo` and setting `DEMO.coverage.v1` already exist. + +In the log, expect: + +`Demo database login cannot read live schema fpsmsdb (MySQL error 1142).` + +Do not expect `Token updated`. That line means the process asked the live M18 server for a token. + +M18 screens are hidden. Calling them directly returns 403, for example `GET /api/m18/test/po-by-code`. + +## 5. Start the frontend + +From `FPSMS-frontend`, on branch `debrand`: + +```bash +npm install +npm run dev +``` + +Open `http://localhost:3000`. `.env.development` and `.env.production` on this branch both point at port 8090 on this machine. Do not point `NEXT_PUBLIC_API_URL` at `10.10.0.81` or any other live server. + +Sign in as `demo` / `Demo2026!`. + +## If startup fails + + +| Log | What to do | +| ---------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | +| Can read live schema `fpsmsdb` | The datasource user is too powerful. Recreate `fpsms_demo` as in step 3. Do not bypass the check. | +| Access denied for `fpsms_demo` | The user or password does not match `application-db-demo.yml`, or the grants were not flushed. | +| Liquibase tries to alter `fpsmsdb` | The changelog tables were not copied into `fpsms_demo`. Repeat step 2. With the restricted login this should fail closed, not change live data. | +| Port 8090 already in use | Stop the other backend. Do not point the demo frontend at it. | + + diff --git a/src/main/java/com/ffii/fpsms/api/service/ApiCallerService.kt b/src/main/java/com/ffii/fpsms/api/service/ApiCallerService.kt index cf275ca6..19d3bd19 100644 --- a/src/main/java/com/ffii/fpsms/api/service/ApiCallerService.kt +++ b/src/main/java/com/ffii/fpsms/api/service/ApiCallerService.kt @@ -8,6 +8,7 @@ import com.ffii.fpsms.m18.model.M18TokenResponse import jakarta.annotation.PostConstruct import org.slf4j.Logger import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Value import org.springframework.beans.factory.annotation.Autowired import org.springframework.http.HttpHeaders import org.springframework.http.MediaType @@ -38,6 +39,7 @@ import java.util.concurrent.atomic.AtomicReference @Service open class ApiCallerService( val m18Config: M18Config, + @Value("\${fpsms.demo-mode:false}") @PublishedApi internal val demoMode: Boolean, ) { val logger: Logger = LoggerFactory.getLogger(ApiCallerService::class.java) private val MAX_IN_MEMORY_SIZE = 10 * 1024 * 1024 @@ -70,10 +72,19 @@ open class ApiCallerService( @PostConstruct fun init() { + if (demoMode) { + logger.warn("Demo mode: M18 API is disabled. No token request will be sent.") + return + } updateToken().subscribe() } + @PublishedApi + internal fun demoBlocked(): Mono = + Mono.error(IllegalStateException("M18 is disabled in demo mode")) + fun updateToken() : Mono{ + if (demoMode) return demoBlocked() val params = M18TokenRequest( grant_type = m18Config.GRANT_TYPE, client_id = m18Config.CLIENT_ID, @@ -173,6 +184,7 @@ open class ApiCallerService( params: MultiValueMap, customHeaders: Map? ): Mono { + if (demoMode) return demoBlocked() println("ACCESS TOKEN: ${m18Config.ACCESS_TOKEN}") return webClient.get() @@ -300,6 +312,7 @@ open class ApiCallerService( params: MultiValueMap, customHeaders: Map? ): Mono { + if (demoMode) return demoBlocked() println("ACCESS TOKEN: ${m18Config.ACCESS_TOKEN}") return webClient.post() @@ -344,6 +357,7 @@ open class ApiCallerService( bodyJson: String, customHeaders: Map? = null ): Mono { + if (demoMode) return demoBlocked() val contentType = MediaType.APPLICATION_JSON val utf8Bytes = bodyJson.toByteArray(StandardCharsets.UTF_8) val bodyBuffer: DataBuffer = DefaultDataBufferFactory.sharedInstance.wrap(utf8Bytes) @@ -385,6 +399,7 @@ open class ApiCallerService( bodyJson: String, customHeaders: Map? = null ): Mono { + if (demoMode) return demoBlocked() val encodedParam = URLEncoder.encode(bodyJson, StandardCharsets.UTF_8).replace("+", "%20") val base = m18Config.BASE_URL.removeSuffix("/") val path = urlPath.removePrefix("/") @@ -430,6 +445,7 @@ open class ApiCallerService( body: Any, customHeaders: Map? = null ): Mono { + if (demoMode) return demoBlocked() return webClient.put() .uri { uriBuilder -> uriBuilder.path(urlPath).queryParams(queryParams).build() } .headers { headers -> customHeaders?.forEach { (k, v) -> headers.set(k, v) } } diff --git a/src/main/java/com/ffii/fpsms/modules/common/demo/DemoCoverageSeeder.kt b/src/main/java/com/ffii/fpsms/modules/common/demo/DemoCoverageSeeder.kt new file mode 100644 index 00000000..acf0c41c --- /dev/null +++ b/src/main/java/com/ffii/fpsms/modules/common/demo/DemoCoverageSeeder.kt @@ -0,0 +1,94 @@ +package com.ffii.fpsms.modules.common.demo + +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Value +import org.springframework.boot.ApplicationArguments +import org.springframework.boot.ApplicationRunner +import org.springframework.context.annotation.Profile +import org.springframework.core.annotation.Order +import org.springframework.core.io.ClassPathResource +import org.springframework.jdbc.core.JdbcTemplate +import org.springframework.stereotype.Component +import java.nio.charset.StandardCharsets +import java.sql.Connection +import javax.sql.DataSource + +/** + * Extra fictional rows so demo screens and report downloads have something to show. + * Runs only after the base sandbox exists, and only against fpsms_demo. + */ +@Component +@Profile("db-demo") +@Order(2) +class DemoCoverageSeeder( + @Value("\${spring.datasource.jdbc-url}") private val jdbcUrl: String, + private val dataSource: DataSource, + private val jdbcTemplate: JdbcTemplate, +) : ApplicationRunner { + + private val log = LoggerFactory.getLogger(DemoCoverageSeeder::class.java) + + override fun run(args: ApplicationArguments) { + val configuredName = databaseName(jdbcUrl) + val connectedName = dataSource.connection.use { it.catalog } + if (configuredName != DEMO_DATABASE || !DEMO_DATABASE.equals(connectedName, ignoreCase = true)) { + throw IllegalStateException( + "Demo coverage refused to start. Configured database is '$configuredName', connected database is '$connectedName'.", + ) + } + val already = jdbcTemplate.queryForObject( + "SELECT COUNT(*) FROM settings WHERE name = ?", + Int::class.java, + MARKER, + ) ?: 0 + if (already > 0) { + log.info("Demo coverage data already present.") + return + } + val script = ClassPathResource(SCRIPT).inputStream.use { it.readBytes().toString(StandardCharsets.UTF_8) } + dataSource.connection.use { connection -> + connection.autoCommit = false + try { + executeScript(connection, script) + connection.commit() + } catch (ex: Exception) { + connection.rollback() + throw IllegalStateException("Demo coverage data failed to load.", ex) + } + } + log.info("Demo coverage data loaded.") + } + + private fun executeScript(connection: Connection, script: String) { + val statement = StringBuilder() + connection.createStatement().use { jdbc -> + for (rawLine in script.lineSequence()) { + val line = rawLine.trim() + if (line.isEmpty() || line.startsWith("--")) continue + statement.append(rawLine).append('\n') + if (line.endsWith(";")) { + val sql = statement.toString().trim().removeSuffix(";").trim() + statement.clear() + if (sql.isNotEmpty()) jdbc.execute(sql) + } + } + } + val tail = statement.toString().trim().removeSuffix(";").trim() + if (tail.isNotEmpty()) { + connection.createStatement().use { it.execute(tail) } + } + } + + private fun databaseName(jdbcUrl: String): String? { + val path = jdbcUrl.substringBefore('?').substringAfter("://") + val slash = path.indexOf('/') + if (slash < 0 || slash == path.lastIndex) return null + return path.substring(slash + 1).trim().ifEmpty { null } + } + + companion object { + private const val DEMO_DATABASE = "fpsms_demo" + private const val MARKER = "DEMO.coverage.v1" + private const val SCRIPT = "demo/demo-coverage.sql" + } +} diff --git a/src/main/java/com/ffii/fpsms/modules/common/demo/DemoExternalBlockFilter.kt b/src/main/java/com/ffii/fpsms/modules/common/demo/DemoExternalBlockFilter.kt new file mode 100644 index 00000000..f7770f44 --- /dev/null +++ b/src/main/java/com/ffii/fpsms/modules/common/demo/DemoExternalBlockFilter.kt @@ -0,0 +1,37 @@ +package com.ffii.fpsms.modules.common.demo + +import jakarta.servlet.FilterChain +import jakarta.servlet.http.HttpServletRequest +import jakarta.servlet.http.HttpServletResponse +import org.springframework.beans.factory.annotation.Value +import org.springframework.core.Ordered +import org.springframework.core.annotation.Order +import org.springframework.stereotype.Component +import org.springframework.web.filter.OncePerRequestFilter + +/** + * Demo profile must not read or write the live M18 system, even if a client calls the API directly. + */ +@Component +@Order(Ordered.HIGHEST_PRECEDENCE) +class DemoExternalBlockFilter( + @Value("\${fpsms.demo-mode:false}") private val demoMode: Boolean, +) : OncePerRequestFilter() { + + override fun shouldNotFilter(request: HttpServletRequest): Boolean { + if (!demoMode) return true + val path = request.requestURI + return !path.contains("/m18") && !path.contains("/scheduler/trigger") + } + + override fun doFilterInternal( + request: HttpServletRequest, + response: HttpServletResponse, + filterChain: FilterChain, + ) { + response.status = HttpServletResponse.SC_FORBIDDEN + response.contentType = "application/json" + response.characterEncoding = "UTF-8" + response.writer.write("""{"message":"M18 is disabled in demo mode"}""") + } +} diff --git a/src/main/java/com/ffii/fpsms/modules/common/demo/DemoSandboxSeeder.kt b/src/main/java/com/ffii/fpsms/modules/common/demo/DemoSandboxSeeder.kt new file mode 100644 index 00000000..03554b19 --- /dev/null +++ b/src/main/java/com/ffii/fpsms/modules/common/demo/DemoSandboxSeeder.kt @@ -0,0 +1,684 @@ +package com.ffii.fpsms.modules.common.demo + +import com.ffii.fpsms.m18.entity.M18DataLog +import com.ffii.fpsms.m18.entity.M18DataLogRepository +import com.ffii.fpsms.m18.enums.M18DataLogStatus +import com.ffii.fpsms.modules.deliveryOrder.entity.DeliveryOrder +import com.ffii.fpsms.modules.deliveryOrder.entity.DeliveryOrderLine +import com.ffii.fpsms.modules.deliveryOrder.entity.DeliveryOrderLineRepository +import com.ffii.fpsms.modules.deliveryOrder.entity.DeliveryOrderRepository +import com.ffii.fpsms.modules.deliveryOrder.enums.DeliveryOrderLineStatus +import com.ffii.fpsms.modules.deliveryOrder.enums.DeliveryOrderStatus +import com.ffii.fpsms.modules.jobOrder.entity.JobOrder +import com.ffii.fpsms.modules.jobOrder.entity.JobOrderBomMaterial +import com.ffii.fpsms.modules.jobOrder.entity.JobOrderBomMaterialRepository +import com.ffii.fpsms.modules.jobOrder.entity.JobOrderRepository +import com.ffii.fpsms.modules.jobOrder.enums.JobOrderBomMaterialStatus +import com.ffii.fpsms.modules.jobOrder.enums.JobOrderStatus +import com.ffii.fpsms.modules.master.entity.Bom +import com.ffii.fpsms.modules.master.entity.BomMaterial +import com.ffii.fpsms.modules.master.entity.BomMaterialRepository +import com.ffii.fpsms.modules.master.entity.BomRepository +import com.ffii.fpsms.modules.master.entity.Currency +import com.ffii.fpsms.modules.master.entity.CurrencyRepository +import com.ffii.fpsms.modules.master.entity.ItemUom +import com.ffii.fpsms.modules.master.entity.ItemUomRespository +import com.ffii.fpsms.modules.master.entity.Items +import com.ffii.fpsms.modules.master.entity.ItemsRepository +import com.ffii.fpsms.modules.master.entity.Shop +import com.ffii.fpsms.modules.master.entity.ShopRepository +import com.ffii.fpsms.modules.master.entity.UomConversion +import com.ffii.fpsms.modules.master.entity.UomConversionRepository +import com.ffii.fpsms.modules.master.entity.Warehouse +import com.ffii.fpsms.modules.master.entity.WarehouseRepository +import com.ffii.fpsms.modules.master.enums.BomStatus +import com.ffii.fpsms.modules.master.enums.ShopType +import com.ffii.fpsms.modules.master.web.models.ItemType +import com.ffii.fpsms.modules.pickOrder.entity.PickOrder +import com.ffii.fpsms.modules.pickOrder.entity.PickOrderLine +import com.ffii.fpsms.modules.pickOrder.entity.PickOrderLineRepository +import com.ffii.fpsms.modules.pickOrder.entity.PickOrderRepository +import com.ffii.fpsms.modules.pickOrder.enums.PickOrderLineStatus +import com.ffii.fpsms.modules.pickOrder.enums.PickOrderStatus +import com.ffii.fpsms.modules.pickOrder.enums.PickOrderType +import com.ffii.fpsms.modules.productProcess.entity.ProductProcess +import com.ffii.fpsms.modules.productProcess.entity.ProductProcessRepository +import com.ffii.fpsms.modules.productProcess.enums.ProductProcessStatus +import com.ffii.fpsms.modules.purchaseOrder.entity.PurchaseOrder +import com.ffii.fpsms.modules.purchaseOrder.entity.PurchaseOrderLine +import com.ffii.fpsms.modules.purchaseOrder.entity.PurchaseOrderLineRepository +import com.ffii.fpsms.modules.purchaseOrder.entity.PurchaseOrderRepository +import com.ffii.fpsms.modules.purchaseOrder.enums.PurchaseOrderLineStatus +import com.ffii.fpsms.modules.purchaseOrder.enums.PurchaseOrderStatus +import com.ffii.fpsms.modules.purchaseOrder.enums.PurchaseOrderType +import com.ffii.fpsms.modules.stock.entity.Inventory +import com.ffii.fpsms.modules.stock.entity.InventoryLot +import com.ffii.fpsms.modules.stock.entity.InventoryLotLine +import com.ffii.fpsms.modules.stock.entity.InventoryLotLineRepository +import com.ffii.fpsms.modules.stock.entity.InventoryLotRepository +import com.ffii.fpsms.modules.stock.entity.InventoryRepository +import com.ffii.fpsms.modules.stock.entity.StockIn +import com.ffii.fpsms.modules.stock.entity.StockInLine +import com.ffii.fpsms.modules.stock.entity.StockInLineRepository +import com.ffii.fpsms.modules.stock.entity.StockInRepository +import com.ffii.fpsms.modules.stock.entity.enum.InventoryLotLineStatus +import com.ffii.fpsms.modules.user.entity.User +import com.ffii.fpsms.modules.user.entity.UserRepository +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Value +import org.springframework.boot.ApplicationArguments +import org.springframework.boot.ApplicationRunner +import org.springframework.context.annotation.Profile +import org.springframework.core.annotation.Order +import org.springframework.dao.DataAccessException +import org.springframework.jdbc.core.JdbcTemplate +import org.springframework.stereotype.Component +import org.springframework.transaction.support.TransactionTemplate +import java.math.BigDecimal +import java.sql.SQLException +import java.time.LocalDate +import java.time.LocalDateTime +import javax.sql.DataSource + +/** + * Fictional sandbox for the db-demo profile. Inserts nothing unless the JDBC database is fpsms_demo. + */ +@Component +@Profile("db-demo") +@Order(1) +class DemoSandboxSeeder( + @Value("\${spring.datasource.jdbc-url}") private val jdbcUrl: String, + private val dataSource: DataSource, + private val jdbcTemplate: JdbcTemplate, + private val transactionTemplate: TransactionTemplate, + private val userRepository: UserRepository, + private val currencyRepository: CurrencyRepository, + private val uomRepository: UomConversionRepository, + private val shopRepository: ShopRepository, + private val warehouseRepository: WarehouseRepository, + private val itemsRepository: ItemsRepository, + private val itemUomRepository: ItemUomRespository, + private val bomRepository: BomRepository, + private val bomMaterialRepository: BomMaterialRepository, + private val m18DataLogRepository: M18DataLogRepository, + private val purchaseOrderRepository: PurchaseOrderRepository, + private val purchaseOrderLineRepository: PurchaseOrderLineRepository, + private val stockInRepository: StockInRepository, + private val stockInLineRepository: StockInLineRepository, + private val inventoryRepository: InventoryRepository, + private val inventoryLotRepository: InventoryLotRepository, + private val inventoryLotLineRepository: InventoryLotLineRepository, + private val jobOrderRepository: JobOrderRepository, + private val jobOrderBomMaterialRepository: JobOrderBomMaterialRepository, + private val productProcessRepository: ProductProcessRepository, + private val deliveryOrderRepository: DeliveryOrderRepository, + private val deliveryOrderLineRepository: DeliveryOrderLineRepository, + private val pickOrderRepository: PickOrderRepository, + private val pickOrderLineRepository: PickOrderLineRepository, +) : ApplicationRunner { + + private val log = LoggerFactory.getLogger(DemoSandboxSeeder::class.java) + + override fun run(args: ApplicationArguments) { + val configuredName = databaseName(jdbcUrl) + if (configuredName != DEMO_DATABASE) { + throw IllegalStateException( + "Demo profile refused to start. spring.datasource.jdbc-url database is '$configuredName', expected '$DEMO_DATABASE'.", + ) + } + val connectedName = dataSource.connection.use { it.catalog } + if (!DEMO_DATABASE.equals(connectedName, ignoreCase = true)) { + throw IllegalStateException( + "Demo profile refused to start. Connected database is '$connectedName', expected '$DEMO_DATABASE'.", + ) + } + refuseIfLiveSchemaReadable() + + transactionTemplate.executeWithoutResult { + ensureAuthorities() + val existing = userRepository.findByUsernameAndDeletedFalse(DEMO_USERNAME) + if (existing.isPresent) { + assignDemoAuthorities(existing.get().id) + log.info("Demo sandbox already present (user '{}').", DEMO_USERNAME) + return@executeWithoutResult + } + seed() + log.info("Demo sandbox seeded. Sign in as {} / {}", DEMO_USERNAME, DEMO_PASSWORD) + } + } + + /** + * The demo login must not be able to read the live company schema. + * MySQL error 1142/1044 means access denied; 1049 means that schema is not visible. + */ + private fun refuseIfLiveSchemaReadable() { + try { + jdbcTemplate.queryForObject("SELECT 1 FROM fpsmsdb.`user` LIMIT 1", Int::class.java) + } catch (ex: DataAccessException) { + val code = generateSequence(ex) { it.cause } + .filterIsInstance() + .firstOrNull() + ?.errorCode + if (code == 1142 || code == 1044 || code == 1049) { + log.info("Demo database login cannot read live schema fpsmsdb (MySQL error {}).", code) + return + } + throw IllegalStateException( + "Demo profile could not prove that live schema fpsmsdb is unreachable (MySQL error $code).", + ex, + ) + } + throw IllegalStateException("Demo database login can read the live schema. Refusing to start.") + } + + private fun ensureAuthorities() { + val roles = listOf( + "ADMIN" to "行政", + "STOCK" to "倉務", + "PROD" to "出品", + "PACK" to "包裝", + "REPORT_MGMT" to "報告管理", + ) + for ((code, name) in roles) { + jdbcTemplate.update( + """ + INSERT INTO authority (authority, name) + SELECT ?, ? + WHERE NOT EXISTS (SELECT 1 FROM authority a WHERE a.authority = ?) + """.trimIndent(), + code, + name, + code, + ) + } + } + + private fun assignDemoAuthorities(userId: Long?) { + if (userId == null) return + userRepository.assignAuthoritiesByCodesIfNotExists(userId, DEMO_AUTHORITY_CODES) + } + + private fun seed() { + val now = LocalDateTime.now() + val today = LocalDate.now() + val user = saveDemoUser() + val currency = currencyRepository.save(Currency().apply { + code = "HKD" + name = "HKD" + description = "港幣" + m18Id = 910001L + m18LastModifyDate = now + }) + val kg = uomRepository.save(uom("KG", "公斤", 910011L, now)) + val pcs = uomRepository.save(uom("PCS", "件", 910012L, now)) + val supplier = shopRepository.save(shop("DEMO-SUP", "北風原料供應", ShopType.SUPPLIER, 910021L, now)) + val customer = shopRepository.save(shop("DEMO-SHP", "海港咖啡店", ShopType.SHOP, 910022L, now)) + val aisleA = warehouseRepository.save(warehouse("DEMO-A", "1", "甲倉", "示範貨架甲")) + val aisleB = warehouseRepository.save(warehouse("DEMO-B", "2", "乙倉", "示範貨架乙")) + + val flour = itemsRepository.save(item("DEMO-RM-01", "普通麵粉", ItemType.MATERIAL.type, 910101L, now)) + val milk = itemsRepository.save(item("DEMO-RM-02", "鮮奶", ItemType.MATERIAL.type, 910102L, now)) + val dough = itemsRepository.save(item("DEMO-SF-01", "麵團", ItemType.SFG.type, 910103L, now)) + val loaf = itemsRepository.save(item("DEMO-FG-01", "鄉村麵包", ItemType.FG.type, 910104L, now)) + val bun = itemsRepository.save(item("DEMO-FG-02", "奶包", ItemType.FG.type, 910105L, now)) + + val flourUom = itemUomRepository.save(itemUom(flour, kg, currency, 910111L, now)) + val milkUom = itemUomRepository.save(itemUom(milk, kg, currency, 910112L, now)) + itemUomRepository.save(itemUom(dough, kg, currency, 910113L, now)) + val loafUom = itemUomRepository.save(itemUom(loaf, pcs, currency, 910114L, now)) + itemUomRepository.save(itemUom(bun, pcs, currency, 910115L, now)) + + val bom = bomRepository.save(Bom().apply { + code = "DEMO-BOM-01" + name = "鄉村麵包" + description = "FG" + type = "FG" + item = loaf + outputQty = BigDecimal("10") + outputQtyUom = "PCS" + status = BomStatus.ACTIVE + m18Id = 910201L + m18LastModifyDate = now + }) + bomMaterialRepository.save(bomMaterial(bom, flour, kg, BigDecimal("2"), 910211L, now)) + bomMaterialRepository.save(bomMaterial(bom, milk, kg, BigDecimal("1"), 910212L, now)) + + val dataLog = m18DataLogRepository.save(M18DataLog().apply { + refType = "DEMO" + m18Id = 910001L + status = M18DataLogStatus.SUCCESS + m18LastModifyDate = now + }) + + val poPending = purchaseOrder("DEMO-PO-001", supplier, customer, currency, dataLog, PurchaseOrderStatus.PENDING, now, null) + purchaseLine(poPending, dough, pcs, dataLog, BigDecimal("20"), PurchaseOrderLineStatus.PENDING) + + val poReceiving = purchaseOrder("DEMO-PO-002", supplier, customer, currency, dataLog, PurchaseOrderStatus.RECEIVING, now.minusDays(1), null) + val receivingLine = purchaseLine(poReceiving, flour, kg, dataLog, BigDecimal("25"), PurchaseOrderLineStatus.RECEIVING) + val receivingStockIn = stockIn("DEMO-SI-PO2", supplier, customer, poReceiving, dataLog, "receiving", now.minusDays(1), null) + val receivingSil = stockInLine( + receivingStockIn, flour, receivingLine, null, BigDecimal("25"), BigDecimal("25"), + "received", "DEMO-LOT-FL2", today.plusDays(180), now.minusDays(1), + ) + inventoryLotRepository.save(lot(flour, receivingSil, "DEMO-LOT-FL2", today.plusDays(180), now.minusDays(1))) + + val poDone = purchaseOrder("DEMO-PO-003", supplier, customer, currency, dataLog, PurchaseOrderStatus.COMPLETED, now.minusDays(3), now.minusDays(1)) + val flourLine = purchaseLine(poDone, flour, kg, dataLog, BigDecimal("40"), PurchaseOrderLineStatus.COMPLETED) + val milkLine = purchaseLine(poDone, milk, kg, dataLog, BigDecimal("20"), PurchaseOrderLineStatus.COMPLETED) + val doneStockIn = stockIn("DEMO-SI-PO3", supplier, customer, poDone, dataLog, "completed", now.minusDays(3), now.minusDays(1)) + putAway( + doneStockIn, flour, flourLine, null, flourUom, aisleA, currency, kg, + BigDecimal("40"), "DEMO-LOT-FL1", today.plusDays(180), now.minusDays(1), + ) + putAway( + doneStockIn, milk, milkLine, null, milkUom, aisleA, currency, kg, + BigDecimal("20"), "DEMO-LOT-MK1", today.plusDays(14), now.minusDays(1), + ) + + val joPlanning = jobOrder("DEMO-JO-001", bom, JobOrderStatus.PLANNING, now.plusDays(1), null) + jobMaterial(joPlanning, flour, kg, BigDecimal("20"), JobOrderBomMaterialStatus.PENDING) + jobMaterial(joPlanning, milk, kg, BigDecimal("10"), JobOrderBomMaterialStatus.PENDING) + + val joProcessing = jobOrder("DEMO-JO-002", bom, JobOrderStatus.PROCESSING, now, now) + jobMaterial(joProcessing, flour, kg, BigDecimal("5"), JobOrderBomMaterialStatus.PENDING) + jobMaterial(joProcessing, milk, kg, BigDecimal("2"), JobOrderBomMaterialStatus.PENDING) + productProcessRepository.save(ProductProcess().apply { + productProcessCode = "DEMO-PP-002" + jobOrder = joProcessing + item = loaf + this.bom = bom + status = ProductProcessStatus.IN_PROGRESS + startTime = now + date = today + productionPriority = 50 + submitedBagRecord = false + }) + val joPick = pickOrderRepository.save(PickOrder().apply { + code = "DEMO-PK-JO2" + jobOrder = joProcessing + targetDate = now + type = PickOrderType.JOB_ORDER + status = PickOrderStatus.RELEASED + releasedBy = user + releasedDate = now + }) + pickLine(joPick, flour, kg, BigDecimal("5"), PickOrderLineStatus.PENDING) + pickLine(joPick, milk, kg, BigDecimal("2"), PickOrderLineStatus.PENDING) + + val joStoring = jobOrder("DEMO-JO-003", bom, JobOrderStatus.STORING, now.minusDays(1), now.minusHours(2)) + jobMaterial(joStoring, flour, kg, BigDecimal("2"), JobOrderBomMaterialStatus.COMPLETED) + jobMaterial(joStoring, milk, kg, BigDecimal("1"), JobOrderBomMaterialStatus.COMPLETED) + productProcessRepository.save(ProductProcess().apply { + productProcessCode = "DEMO-PP-003" + jobOrder = joStoring + item = loaf + this.bom = bom + status = ProductProcessStatus.COMPLETED + startTime = now.minusHours(4) + endTime = now.minusHours(2) + date = today + productionPriority = 40 + submitedBagRecord = false + }) + val joStockIn = stockIn("DEMO-SI-JO3", supplier, customer, null, dataLog, "receiving", now.minusHours(2), null) + val joSil = stockInLine( + joStockIn, loaf, null, joStoring, BigDecimal("10"), BigDecimal("10"), + "received", "DEMO-LOT-LF2", today.plusDays(5), now.minusHours(2), + ) + inventoryLotRepository.save(lot(loaf, joSil, "DEMO-LOT-LF2", today.plusDays(5), now.minusHours(2))) + + val fgStockIn = stockIn("DEMO-SI-FG1", supplier, customer, null, dataLog, "completed", now.minusDays(2), now.minusDays(2)) + putAway( + fgStockIn, loaf, null, null, loafUom, aisleB, currency, pcs, + BigDecimal("30"), "DEMO-LOT-LF1", today.plusDays(5), now.minusDays(2), + ) + + val doPending = deliveryOrder("DEMO-DO-001", customer, currency, dataLog, DeliveryOrderStatus.PENDING, now, null) + deliveryLine(doPending, bun, pcs, dataLog, BigDecimal("12"), DeliveryOrderLineStatus.PENDING) + + val doPicking = deliveryOrder("DEMO-DO-002", customer, currency, dataLog, DeliveryOrderStatus.RECEIVING, now, null) + deliveryLine(doPicking, loaf, pcs, dataLog, BigDecimal("4"), DeliveryOrderLineStatus.PICKING) + val doPick = pickOrderRepository.save(PickOrder().apply { + code = "DEMO-PK-DO2" + deliveryOrder = doPicking + targetDate = now + type = PickOrderType.DELIVERY_ORDER + status = PickOrderStatus.RELEASED + releasedBy = user + releasedDate = now + }) + pickLine(doPick, loaf, pcs, BigDecimal("4"), PickOrderLineStatus.PENDING) + + val doDone = deliveryOrder("DEMO-DO-003", customer, currency, dataLog, DeliveryOrderStatus.COMPLETED, now.minusDays(2), now.minusDays(1)) + deliveryLine(doDone, loaf, pcs, dataLog, BigDecimal("6"), DeliveryOrderLineStatus.COMPLETED) + val donePick = pickOrderRepository.save(PickOrder().apply { + code = "DEMO-PK-DO3" + deliveryOrder = doDone + targetDate = now.minusDays(2) + completeDate = now.minusDays(1) + type = PickOrderType.DELIVERY_ORDER + status = PickOrderStatus.COMPLETED + releasedBy = user + releasedDate = now.minusDays(2) + }) + pickLine(donePick, loaf, pcs, BigDecimal("6"), PickOrderLineStatus.COMPLETED) + } + + private fun saveDemoUser(): User { + val user = userRepository.save(User().apply { + username = DEMO_USERNAME + password = org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder().encode(DEMO_PASSWORD) + locked = false + name = "示範管理員" + title = "Demo" + staffNo = DEMO_USERNAME + lotusNotesUser = false + }) + assignDemoAuthorities(user.id) + return user + } + + private fun uom(code: String, desc: String, m18Id: Long, now: LocalDateTime) = UomConversion().apply { + this.code = code + udfudesc = desc + udfShortDesc = code + this.m18Id = m18Id + lastModifyDate = now + } + + private fun shop(code: String, name: String, type: ShopType, m18Id: Long, now: LocalDateTime) = Shop().apply { + this.code = code + this.name = name + this.type = type + this.m18Id = m18Id + m18LastModifyDate = now + } + + private fun warehouse(code: String, orderNo: String, name: String, description: String) = Warehouse().apply { + this.code = code + order = orderNo + this.name = name + this.description = description + capacity = BigDecimal("1000") + store_id = "DEMO" + } + + private fun item(code: String, name: String, type: String, m18Id: Long, now: LocalDateTime) = Items().apply { + this.code = code + this.name = name + description = name + this.type = type + shelfLife = 30.0 + this.m18Id = m18Id + m18LastModifyDate = now + } + + private fun itemUom(item: Items, uom: UomConversion, currency: Currency, m18Id: Long, now: LocalDateTime) = ItemUom().apply { + this.item = item + this.uom = uom + baseUnit = true + stockUnit = true + pickingUnit = true + salesUnit = true + purchaseUnit = true + this.currency = currency + this.m18Id = m18Id + m18LastModifyDate = now + ratioN = BigDecimal.ONE + ratioD = BigDecimal.ONE + } + + private fun bomMaterial(bom: Bom, item: Items, uom: UomConversion, qty: BigDecimal, m18Id: Long, now: LocalDateTime) = + BomMaterial().apply { + this.bom = bom + this.item = item + itemName = item.name + isConsumable = false + this.qty = qty + this.uom = uom + uomName = uom.code + baseUnit = Integer.valueOf(uom.m18Id.toInt()) as Integer + stockUnit = Integer.valueOf(uom.m18Id.toInt()) as Integer + this.m18Id = m18Id + m18LastModifyDate = now + } + + private fun purchaseOrder( + code: String, + supplier: Shop, + shop: Shop, + currency: Currency, + dataLog: M18DataLog, + status: PurchaseOrderStatus, + orderDate: LocalDateTime, + completeDate: LocalDateTime?, + ) = purchaseOrderRepository.save(PurchaseOrder().apply { + this.code = code + this.supplier = supplier + this.shop = shop + this.currency = currency + this.orderDate = orderDate + estimatedArrivalDate = orderDate.plusDays(2) + this.completeDate = completeDate + this.status = status + type = PurchaseOrderType.MATERIAL + m18DataLog = dataLog + m18BeId = 910301L + }) + + private fun purchaseLine( + po: PurchaseOrder, + item: Items, + uom: UomConversion, + dataLog: M18DataLog, + qty: BigDecimal, + status: PurchaseOrderLineStatus, + ) = purchaseOrderLineRepository.save(PurchaseOrderLine().apply { + this.purchaseOrder = po + this.item = item + itemNo = item.code + this.uom = uom + uomM18 = uom + this.qty = qty + qtyM18 = qty + this.status = status + m18DataLog = dataLog + }) + + private fun stockIn( + code: String, + supplier: Shop, + shop: Shop, + purchaseOrder: PurchaseOrder?, + dataLog: M18DataLog, + status: String, + orderDate: LocalDateTime, + completeDate: LocalDateTime?, + ) = stockInRepository.save(StockIn().apply { + this.code = code + this.supplier = supplier + this.shop = shop + this.purchaseOrder = purchaseOrder + m18DataLog = dataLog + this.orderDate = orderDate + this.completeDate = completeDate + this.status = status + }) + + private fun stockInLine( + stockIn: StockIn, + item: Items, + purchaseOrderLine: PurchaseOrderLine?, + jobOrder: JobOrder?, + demandQty: BigDecimal, + acceptedQty: BigDecimal, + status: String, + lotNo: String, + expiry: LocalDate, + receiptDate: LocalDateTime, + ) = stockInLineRepository.save(StockInLine().apply { + this.stockIn = stockIn + this.item = item + itemNo = item.code + this.purchaseOrder = purchaseOrderLine?.purchaseOrder + this.purchaseOrderLine = purchaseOrderLine + this.jobOrder = jobOrder + this.demandQty = demandQty + this.acceptedQty = acceptedQty + this.status = status + this.lotNo = lotNo + expiryDate = expiry + this.receiptDate = receiptDate + }) + + private fun lot(item: Items, stockInLine: StockInLine, lotNo: String, expiry: LocalDate, stockInDate: LocalDateTime): InventoryLot { + val saved = inventoryLotRepository.save(InventoryLot().apply { + this.item = item + this.stockInLine = stockInLine + this.lotNo = lotNo + expiryDate = expiry + this.stockInDate = stockInDate + productionDate = stockInDate + }) + stockInLine.inventoryLot = saved + stockInLineRepository.save(stockInLine) + return saved + } + + private fun putAway( + stockIn: StockIn, + item: Items, + purchaseOrderLine: PurchaseOrderLine?, + jobOrder: JobOrder?, + stockUom: ItemUom, + warehouse: Warehouse, + currency: Currency, + uom: UomConversion, + qty: BigDecimal, + lotNo: String, + expiry: LocalDate, + whenAt: LocalDateTime, + ) { + val line = stockInLine( + stockIn, item, purchaseOrderLine, jobOrder, qty, qty, "completed", lotNo, expiry, whenAt, + ) + val savedLot = lot(item, line, lotNo, expiry, whenAt) + val lotLine = inventoryLotLineRepository.save(InventoryLotLine().apply { + inventoryLot = savedLot + this.warehouse = warehouse + inQty = qty + outQty = BigDecimal.ZERO + holdQty = BigDecimal.ZERO + this.stockUom = stockUom + status = InventoryLotLineStatus.AVAILABLE + }) + line.inventoryLotLine = lotLine + stockInLineRepository.save(line) + // Lot-line insert trigger may already write inventory. Add a row only if it did not. + if (inventoryRepository.findFirstByItemIdAndDeletedIsFalseOrderByIdAsc(item.id!!) == null) { + inventoryRepository.save(Inventory().apply { + this.item = item + onHandQty = qty + onHoldQty = BigDecimal.ZERO + unavailableQty = BigDecimal.ZERO + this.uom = uom + this.currency = currency + status = "available" + }) + } + } + + private fun jobOrder( + code: String, + bom: Bom, + status: JobOrderStatus, + planStart: LocalDateTime, + actualStart: LocalDateTime?, + ) = jobOrderRepository.save(JobOrder().apply { + this.code = code + this.bom = bom + isHidden = false + this.planStart = planStart + this.actualStart = actualStart + planEnd = planStart.plusDays(1) + reqQty = BigDecimal("10") + this.status = status + type = "job" + }) + + private fun jobMaterial(jobOrder: JobOrder, item: Items, uom: UomConversion, qty: BigDecimal, status: JobOrderBomMaterialStatus) { + jobOrderBomMaterialRepository.save(JobOrderBomMaterial().apply { + this.jobOrder = jobOrder + this.item = item + reqQty = qty + this.uom = uom + this.status = status + }) + } + + private fun deliveryOrder( + code: String, + shop: Shop, + currency: Currency, + dataLog: M18DataLog, + status: DeliveryOrderStatus, + orderDate: LocalDateTime, + completeDate: LocalDateTime?, + ) = deliveryOrderRepository.save(DeliveryOrder().apply { + this.code = code + this.shop = shop + this.currency = currency + this.orderDate = orderDate + estimatedArrivalDate = orderDate.plusDays(1) + this.completeDate = completeDate + this.status = status + m18DataLog = dataLog + m18BeId = 910401L + isExtra = false + }) + + private fun deliveryLine( + deliveryOrder: DeliveryOrder, + item: Items, + uom: UomConversion, + dataLog: M18DataLog, + qty: BigDecimal, + status: DeliveryOrderLineStatus, + ) { + deliveryOrderLineRepository.save(DeliveryOrderLine().apply { + this.deliveryOrder = deliveryOrder + this.item = item + itemNo = item.code + this.uom = uom + uomM18 = uom + this.qty = qty + qtyM18 = qty + this.status = status + m18DataLog = dataLog + }) + } + + private fun pickLine(pickOrder: PickOrder, item: Items, uom: UomConversion, qty: BigDecimal, status: PickOrderLineStatus) { + pickOrderLineRepository.save(PickOrderLine().apply { + this.pickOrder = pickOrder + this.item = item + this.qty = qty + this.uom = uom + this.status = status + }) + } + + private fun databaseName(jdbcUrl: String): String? { + val path = jdbcUrl.substringBefore('?').substringAfter("://") + val slash = path.indexOf('/') + if (slash < 0 || slash == path.lastIndex) return null + return path.substring(slash + 1).trim().ifEmpty { null } + } + + companion object { + const val DEMO_DATABASE = "fpsms_demo" + const val DEMO_USERNAME = "demo" + const val DEMO_PASSWORD = "Demo2026!" + val DEMO_AUTHORITY_CODES = listOf("ADMIN", "STOCK", "PROD", "PACK", "REPORT_MGMT") + } +} diff --git a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DeliveryOrderService.kt b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DeliveryOrderService.kt index cee583ca..8d1e745d 100644 --- a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DeliveryOrderService.kt +++ b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DeliveryOrderService.kt @@ -504,10 +504,10 @@ open class DeliveryOrderService( NULLIF(TRIM(dop.handlerName), ''), NULLIF(TRIM(u.name), '') ) AS handler_name - FROM fpsmsdb.delivery_order_pick_order dop - INNER JOIN fpsmsdb.pick_order po + FROM delivery_order_pick_order dop + INNER JOIN pick_order po ON po.deliveryOrderPickOrderId = dop.id AND po.deleted = 0 - LEFT JOIN fpsmsdb.user u + LEFT JOIN user u ON u.id = dop.handledBy AND u.deleted = 0 WHERE dop.deleted = 0 AND po.doId = :doId @@ -518,12 +518,12 @@ open class DeliveryOrderService( NULLIF(TRIM(dop.handlerName), ''), NULLIF(TRIM(u.name), '') ) AS handler_name - FROM fpsmsdb.delivery_order_pick_order dop - INNER JOIN fpsmsdb.pick_order po + FROM delivery_order_pick_order dop + INNER JOIN pick_order po ON po.deliveryOrderPickOrderId = dop.id AND po.deleted = 0 - INNER JOIN fpsmsdb.do_pick_order_line dpol + INNER JOIN do_pick_order_line dpol ON dpol.pick_order_id = po.id AND dpol.deleted = 0 - LEFT JOIN fpsmsdb.user u + LEFT JOIN user u ON u.id = dop.handledBy AND u.deleted = 0 WHERE dop.deleted = 0 AND dpol.do_order_id = :doId @@ -558,8 +558,8 @@ open class DeliveryOrderService( SELECT DISTINCT TRIM(truck_lance_code) AS truck_lance_code FROM ( SELECT NULLIF(TRIM(dop.truckLanceCode), '') AS truck_lance_code - FROM fpsmsdb.delivery_order_pick_order dop - INNER JOIN fpsmsdb.pick_order po + FROM delivery_order_pick_order dop + INNER JOIN pick_order po ON po.deliveryOrderPickOrderId = dop.id AND po.deleted = 0 WHERE dop.deleted = 0 AND po.doId = :doId @@ -567,10 +567,10 @@ open class DeliveryOrderService( UNION SELECT NULLIF(TRIM(dop.truckLanceCode), '') AS truck_lance_code - FROM fpsmsdb.delivery_order_pick_order dop - INNER JOIN fpsmsdb.pick_order po + FROM delivery_order_pick_order dop + INNER JOIN pick_order po ON po.deliveryOrderPickOrderId = dop.id AND po.deleted = 0 - INNER JOIN fpsmsdb.do_pick_order_line dpol + INNER JOIN do_pick_order_line dpol ON dpol.pick_order_id = po.id AND dpol.deleted = 0 WHERE dop.deleted = 0 AND dpol.do_order_id = :doId @@ -837,8 +837,8 @@ open class DeliveryOrderService( // 查询 warehouse 的 order 字段 val sql = """ SELECT w.`order` as warehouseOrder - FROM fpsmsdb.inventory_lot_line ill - JOIN fpsmsdb.warehouse w ON w.id = ill.warehouseId + FROM inventory_lot_line ill + JOIN warehouse w ON w.id = ill.warehouseId WHERE ill.inventoryLotId = :lotId AND ill.deleted = false ORDER BY w.`order` ASC @@ -886,8 +886,8 @@ open class DeliveryOrderService( return inventoryLotId?.let { lotId -> val sql = """ SELECT w.code as warehouseCode - FROM fpsmsdb.inventory_lot_line ill - JOIN fpsmsdb.warehouse w ON w.id = ill.warehouseId + FROM inventory_lot_line ill + JOIN warehouse w ON w.id = ill.warehouseId WHERE ill.inventoryLotId = :lotId AND ill.deleted = false ORDER BY w.`order` ASC @@ -2610,8 +2610,8 @@ val inventoryLotLine = illId?.let { inventoryLotLineMap[it] } COUNT(DISTINCT CASE WHEN i.store_id = '4F' THEN dol.itemId END) AS count_4f, COUNT(DISTINCT CASE WHEN i.store_id = '2F' THEN dol.itemId END) AS count_2f, COUNT(DISTINCT dol.itemId) AS total_items - FROM fpsmsdb.delivery_order_line dol - INNER JOIN fpsmsdb.items i ON i.id = dol.itemId AND i.deleted = 0 + FROM delivery_order_line dol + INNER JOIN items i ON i.id = dol.itemId AND i.deleted = 0 WHERE dol.deliveryOrderId = :doId AND dol.deleted = 0 """.trimIndent() diff --git a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoPickOrderAssignmentService.kt b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoPickOrderAssignmentService.kt index c5ea5f56..47bb5e44 100644 --- a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoPickOrderAssignmentService.kt +++ b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoPickOrderAssignmentService.kt @@ -166,7 +166,7 @@ class DoPickOrderAssignmentService( return try { val totalLinesSql = """ SELECT COUNT(*) as total_lines - FROM fpsmsdb.do_pick_order_line dpol + FROM do_pick_order_line dpol WHERE dpol.do_pick_order_id = :doPickOrderId AND dpol.deleted = 0 """.trimIndent() @@ -180,7 +180,7 @@ class DoPickOrderAssignmentService( val nonIssueLinesSql = """ SELECT COUNT(*) as non_issue_lines - FROM fpsmsdb.do_pick_order_line dpol + FROM do_pick_order_line dpol WHERE dpol.do_pick_order_id = :doPickOrderId AND dpol.deleted = 0 AND (dpol.status IS NULL OR dpol.status != 'issue') diff --git a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoPickOrderQueryService.kt b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoPickOrderQueryService.kt index a92e31ad..cb55f283 100644 --- a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoPickOrderQueryService.kt +++ b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoPickOrderQueryService.kt @@ -171,7 +171,7 @@ val timeGroups = groupedByTime return try { val totalLinesSql = """ SELECT COUNT(*) as total_lines - FROM fpsmsdb.do_pick_order_line dpol + FROM do_pick_order_line dpol WHERE dpol.do_pick_order_id = :doPickOrderId AND dpol.deleted = 0 """.trimIndent() @@ -185,7 +185,7 @@ val timeGroups = groupedByTime val nonIssueLinesSql = """ SELECT COUNT(*) as non_issue_lines - FROM fpsmsdb.do_pick_order_line dpol + FROM do_pick_order_line dpol WHERE dpol.do_pick_order_id = :doPickOrderId AND dpol.deleted = 0 AND (dpol.status IS NULL OR dpol.status != 'issue') @@ -207,7 +207,7 @@ val timeGroups = groupedByTime // First get the record_id from do_pick_order_record val recordSql = """ SELECT record_id - FROM fpsmsdb.do_pick_order_record dpor + FROM do_pick_order_record dpor WHERE dpor.id = :recordId """.trimIndent() @@ -221,7 +221,7 @@ val timeGroups = groupedByTime // Check do_pick_order_line_record table val totalLinesSql = """ SELECT COUNT(*) as total_lines - FROM fpsmsdb.do_pick_order_line_record dpolr + FROM do_pick_order_line_record dpolr WHERE dpolr.record_id = :recordId AND dpolr.deleted = 0 """.trimIndent() @@ -235,7 +235,7 @@ val timeGroups = groupedByTime val nonIssueLinesSql = """ SELECT COUNT(*) as non_issue_lines - FROM fpsmsdb.do_pick_order_line_record dpolr + FROM do_pick_order_line_record dpolr WHERE dpolr.record_id = :recordId AND dpolr.deleted = 0 AND (dpolr.status IS NULL OR dpolr.status != 'issue') diff --git a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoPickOrderService.kt b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoPickOrderService.kt index 71cdb598..acf8cc3f 100644 --- a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoPickOrderService.kt +++ b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoPickOrderService.kt @@ -476,7 +476,7 @@ open class DoPickOrderService( // 1. 获取该 do_pick_order 的所有 do_pick_order_line 数量 val totalLinesSql = """ SELECT COUNT(*) as total_lines - FROM fpsmsdb.do_pick_order_line dpol + FROM do_pick_order_line dpol WHERE dpol.do_pick_order_id = :doPickOrderId AND dpol.deleted = 0 """.trimIndent() @@ -491,7 +491,7 @@ open class DoPickOrderService( // 2. 获取非 "issue" 状态的 lines 数量 val nonIssueLinesSql = """ SELECT COUNT(*) as non_issue_lines - FROM fpsmsdb.do_pick_order_line dpol + FROM do_pick_order_line dpol WHERE dpol.do_pick_order_id = :doPickOrderId AND dpol.deleted = 0 AND (dpol.status IS NULL OR dpol.status != 'issue') @@ -609,10 +609,10 @@ open class DoPickOrderService( dol.deliveryOrderId, w.store_id, SUM(ill.inQty - COALESCE(ill.outQty, 0) - COALESCE(ill.holdQty, 0)) AS total_inventory - FROM fpsmsdb.delivery_order_line dol - LEFT JOIN fpsmsdb.inventory_lot il ON il.itemId = dol.itemId AND il.deleted = 0 - LEFT JOIN fpsmsdb.inventory_lot_line ill ON ill.inventoryLotId = il.id AND ill.deleted = 0 - LEFT JOIN fpsmsdb.warehouse w ON w.id = ill.warehouseId AND w.deleted = 0 + FROM delivery_order_line dol + LEFT JOIN inventory_lot il ON il.itemId = dol.itemId AND il.deleted = 0 + LEFT JOIN inventory_lot_line ill ON ill.inventoryLotId = il.id AND ill.deleted = 0 + LEFT JOIN warehouse w ON w.id = ill.warehouseId AND w.deleted = 0 WHERE dol.deleted = 0 AND dol.deliveryOrderId = :doOrderId GROUP BY dol.deliveryOrderId, w.store_id ORDER BY total_inventory DESC @@ -863,13 +863,13 @@ open class DoPickOrderService( MIN(dop.ticketReleaseTime) AS firstTicketStartTime, SUM(CASE WHEN dop.ticketCompleteDateTime IS NOT NULL THEN 1 ELSE 0 END) AS numberOfTicketsCompleted, MAX(dop.ticketCompleteDateTime) AS lastTicketEndTime - FROM fpsmsdb.delivery_order_pick_order dop + FROM delivery_order_pick_order dop LEFT JOIN ( SELECT po.deliveryOrderPickOrderId AS dopId, COUNT(pol.id) AS cnt - FROM fpsmsdb.pick_order po - INNER JOIN fpsmsdb.pick_order_line pol + FROM pick_order po + INNER JOIN pick_order_line pol ON pol.poId = po.id AND pol.deleted = 0 WHERE po.deleted = 0 diff --git a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoReleaseCoordinatorService.kt b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoReleaseCoordinatorService.kt index c14a25f1..9c9f445e 100644 --- a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoReleaseCoordinatorService.kt +++ b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoReleaseCoordinatorService.kt @@ -145,15 +145,15 @@ class DoReleaseCoordinatorService( val dayOfWeekSql = getDayOfWeekAbbrSql("do.estimatedArrivalDate") val pfCases = doFloorSupplierSettingsService.sqlPreferredFloorCases("s.code") val updateSql = """ - UPDATE fpsmsdb.do_pick_order dpo + UPDATE do_pick_order dpo INNER JOIN ( WITH PreferredFloor AS ( SELECT do.id AS deliveryOrderId, ${pfCases.floorStringCase} AS preferred_floor, ${pfCases.storeIdNumericCase} AS preferred_store_id - FROM fpsmsdb.delivery_order do - LEFT JOIN fpsmsdb.shop s ON s.id = do.supplierId AND s.deleted = 0 + FROM delivery_order do + LEFT JOIN shop s ON s.id = do.supplierId AND s.deleted = 0 WHERE do.deleted = 0 ), TruckSelection AS ( @@ -163,102 +163,102 @@ class DoReleaseCoordinatorService( pf.preferred_floor, $dayOfWeekSql AS day_of_week_abbr, CASE - WHEN (SELECT COUNT(*) FROM fpsmsdb.truck t WHERE t.shopId = do.shopId AND t.deleted = 0 AND t.Store_id = pf.preferred_store_id) > 1 + WHEN (SELECT COUNT(*) FROM truck t WHERE t.shopId = do.shopId AND t.deleted = 0 AND t.Store_id = pf.preferred_store_id) > 1 AND pf.preferred_store_id = 4 AND do.estimatedArrivalDate IS NOT NULL THEN COALESCE( - (SELECT t.DepartureTime FROM fpsmsdb.truck t + (SELECT t.DepartureTime FROM truck t WHERE t.shopId = do.shopId AND t.deleted = 0 AND t.Store_id = pf.preferred_store_id AND t.TruckLanceCode LIKE CONCAT('%', $dayOfWeekSql, '%') ORDER BY t.DepartureTime ASC LIMIT 1), - (SELECT t.DepartureTime FROM fpsmsdb.truck t + (SELECT t.DepartureTime FROM truck t WHERE t.shopId = do.shopId AND t.deleted = 0 AND t.Store_id = pf.preferred_store_id ORDER BY t.DepartureTime ASC LIMIT 1), - (SELECT t.DepartureTime FROM fpsmsdb.truck t + (SELECT t.DepartureTime FROM truck t WHERE t.shopId = do.shopId AND t.deleted = 0 ORDER BY t.DepartureTime ASC LIMIT 1), '23:59:59' ) - WHEN (SELECT COUNT(*) FROM fpsmsdb.truck t WHERE t.shopId = do.shopId AND t.deleted = 0) > 1 THEN + WHEN (SELECT COUNT(*) FROM truck t WHERE t.shopId = do.shopId AND t.deleted = 0) > 1 THEN COALESCE( - (SELECT t.DepartureTime FROM fpsmsdb.truck t + (SELECT t.DepartureTime FROM truck t WHERE t.shopId = do.shopId AND t.deleted = 0 AND t.Store_id = pf.preferred_store_id ORDER BY t.DepartureTime ASC LIMIT 1), - (SELECT t.DepartureTime FROM fpsmsdb.truck t + (SELECT t.DepartureTime FROM truck t WHERE t.shopId = do.shopId AND t.deleted = 0 ORDER BY t.DepartureTime ASC LIMIT 1), '23:59:59' ) ELSE COALESCE( - (SELECT t.DepartureTime FROM fpsmsdb.truck t + (SELECT t.DepartureTime FROM truck t WHERE t.shopId = do.shopId AND t.deleted = 0 ORDER BY t.DepartureTime ASC LIMIT 1), '23:59:59' ) END AS selected_departure_time, CASE - WHEN (SELECT COUNT(*) FROM fpsmsdb.truck t WHERE t.shopId = do.shopId AND t.deleted = 0 AND t.Store_id = pf.preferred_store_id) > 1 + WHEN (SELECT COUNT(*) FROM truck t WHERE t.shopId = do.shopId AND t.deleted = 0 AND t.Store_id = pf.preferred_store_id) > 1 AND pf.preferred_store_id = 4 AND do.estimatedArrivalDate IS NOT NULL THEN COALESCE( - (SELECT t.TruckLanceCode FROM fpsmsdb.truck t + (SELECT t.TruckLanceCode FROM truck t WHERE t.shopId = do.shopId AND t.deleted = 0 AND t.Store_id = pf.preferred_store_id AND t.TruckLanceCode LIKE CONCAT('%', $dayOfWeekSql, '%') ORDER BY t.DepartureTime ASC LIMIT 1), - (SELECT t.TruckLanceCode FROM fpsmsdb.truck t + (SELECT t.TruckLanceCode FROM truck t WHERE t.shopId = do.shopId AND t.deleted = 0 AND t.Store_id = pf.preferred_store_id ORDER BY t.DepartureTime ASC LIMIT 1), - (SELECT t.TruckLanceCode FROM fpsmsdb.truck t + (SELECT t.TruckLanceCode FROM truck t WHERE t.shopId = do.shopId AND t.deleted = 0 ORDER BY t.DepartureTime ASC LIMIT 1), 'ZZ' ) - WHEN (SELECT COUNT(*) FROM fpsmsdb.truck t WHERE t.shopId = do.shopId AND t.deleted = 0) > 1 THEN + WHEN (SELECT COUNT(*) FROM truck t WHERE t.shopId = do.shopId AND t.deleted = 0) > 1 THEN COALESCE( - (SELECT t.TruckLanceCode FROM fpsmsdb.truck t + (SELECT t.TruckLanceCode FROM truck t WHERE t.shopId = do.shopId AND t.deleted = 0 AND t.Store_id = pf.preferred_store_id ORDER BY t.DepartureTime ASC LIMIT 1), - (SELECT t.TruckLanceCode FROM fpsmsdb.truck t + (SELECT t.TruckLanceCode FROM truck t WHERE t.shopId = do.shopId AND t.deleted = 0 ORDER BY t.DepartureTime ASC LIMIT 1), 'ZZ' ) ELSE COALESCE( - (SELECT t.TruckLanceCode FROM fpsmsdb.truck t + (SELECT t.TruckLanceCode FROM truck t WHERE t.shopId = do.shopId AND t.deleted = 0 ORDER BY t.DepartureTime ASC LIMIT 1), 'ZZ' ) END AS selected_truck_lance, COALESCE( - (SELECT t.LoadingSequence FROM fpsmsdb.truck t + (SELECT t.LoadingSequence FROM truck t WHERE t.shopId = do.shopId AND t.deleted = 0 AND t.Store_id = pf.preferred_store_id AND (pf.preferred_store_id != 4 OR do.estimatedArrivalDate IS NULL OR t.TruckLanceCode LIKE CONCAT('%', $dayOfWeekSql, '%')) ORDER BY t.DepartureTime ASC LIMIT 1), - (SELECT t.LoadingSequence FROM fpsmsdb.truck t + (SELECT t.LoadingSequence FROM truck t WHERE t.shopId = do.shopId AND t.deleted = 0 AND t.Store_id = pf.preferred_store_id ORDER BY t.DepartureTime ASC LIMIT 1), - (SELECT t.LoadingSequence FROM fpsmsdb.truck t + (SELECT t.LoadingSequence FROM truck t WHERE t.shopId = do.shopId AND t.deleted = 0 ORDER BY t.DepartureTime ASC LIMIT 1), 999 ) AS loading_sequence - FROM fpsmsdb.delivery_order do + FROM delivery_order do LEFT JOIN PreferredFloor pf ON pf.deliveryOrderId = do.id WHERE do.id IN ( SELECT DISTINCT do_order_id - FROM fpsmsdb.do_pick_order + FROM do_pick_order WHERE ticket_no LIKE 'TEMP-%' AND deleted = 0 ) @@ -283,7 +283,7 @@ class DoReleaseCoordinatorService( dpo2.do_order_id ), 3, '0') ) AS new_ticket_no - FROM fpsmsdb.do_pick_order dpo2 + FROM do_pick_order dpo2 LEFT JOIN TruckSelection ts ON ts.delivery_order_id = dpo2.do_order_id WHERE dpo2.ticket_no LIKE 'TEMP-%' AND dpo2.deleted = 0 @@ -310,8 +310,8 @@ class DoReleaseCoordinatorService( do.id AS deliveryOrderId, ${pfCases.floorStringCase} AS preferred_floor, ${pfCases.storeIdNumericCase} AS preferred_store_id - FROM fpsmsdb.delivery_order do - LEFT JOIN fpsmsdb.shop s ON s.id = do.supplierId AND s.deleted = 0 + FROM delivery_order do + LEFT JOIN shop s ON s.id = do.supplierId AND s.deleted = 0 WHERE do.id IN (${ids.joinToString(",")}) AND do.deleted = 0 ), @@ -324,12 +324,12 @@ class DoReleaseCoordinatorService( pf.preferred_store_id, $dayOfWeekSql AS day_of_week_abbr, CASE - WHEN (SELECT COUNT(*) FROM fpsmsdb.truck t WHERE t.shopId = do.shopId AND t.deleted = 0 AND t.Store_id = pf.preferred_store_id) > 1 + WHEN (SELECT COUNT(*) FROM truck t WHERE t.shopId = do.shopId AND t.deleted = 0 AND t.Store_id = pf.preferred_store_id) > 1 AND pf.preferred_store_id = 4 AND do.estimatedArrivalDate IS NOT NULL THEN COALESCE( (SELECT t.DepartureTime - FROM fpsmsdb.truck t + FROM truck t WHERE t.shopId = do.shopId AND t.deleted = 0 AND t.Store_id = pf.preferred_store_id @@ -337,28 +337,28 @@ class DoReleaseCoordinatorService( ORDER BY t.DepartureTime ASC LIMIT 1), (SELECT t.DepartureTime - FROM fpsmsdb.truck t + FROM truck t WHERE t.shopId = do.shopId AND t.deleted = 0 AND t.Store_id = pf.preferred_store_id ORDER BY t.DepartureTime ASC LIMIT 1), (SELECT t.DepartureTime - FROM fpsmsdb.truck t + FROM truck t WHERE t.shopId = do.shopId AND t.deleted = 0 ORDER BY t.DepartureTime ASC LIMIT 1), '23:59:59' ) - WHEN (SELECT COUNT(*) FROM fpsmsdb.truck t WHERE t.shopId = do.shopId AND t.deleted = 0) > 1 THEN + WHEN (SELECT COUNT(*) FROM truck t WHERE t.shopId = do.shopId AND t.deleted = 0) > 1 THEN COALESCE( (SELECT t.DepartureTime - FROM fpsmsdb.truck t + FROM truck t WHERE t.shopId = do.shopId AND t.deleted = 0 AND t.Store_id = pf.preferred_store_id ORDER BY t.DepartureTime ASC LIMIT 1), (SELECT t.DepartureTime - FROM fpsmsdb.truck t + FROM truck t WHERE t.shopId = do.shopId AND t.deleted = 0 ORDER BY t.DepartureTime ASC LIMIT 1), @@ -367,7 +367,7 @@ class DoReleaseCoordinatorService( ELSE COALESCE( (SELECT t.DepartureTime - FROM fpsmsdb.truck t + FROM truck t WHERE t.shopId = do.shopId AND t.deleted = 0 ORDER BY t.DepartureTime ASC LIMIT 1), @@ -375,12 +375,12 @@ class DoReleaseCoordinatorService( ) END AS selected_departure_time, CASE - WHEN (SELECT COUNT(*) FROM fpsmsdb.truck t WHERE t.shopId = do.shopId AND t.deleted = 0 AND t.Store_id = pf.preferred_store_id) > 1 + WHEN (SELECT COUNT(*) FROM truck t WHERE t.shopId = do.shopId AND t.deleted = 0 AND t.Store_id = pf.preferred_store_id) > 1 AND pf.preferred_store_id = 4 AND do.estimatedArrivalDate IS NOT NULL THEN COALESCE( (SELECT t.TruckLanceCode - FROM fpsmsdb.truck t + FROM truck t WHERE t.shopId = do.shopId AND t.deleted = 0 AND t.Store_id = pf.preferred_store_id @@ -388,28 +388,28 @@ class DoReleaseCoordinatorService( ORDER BY t.DepartureTime ASC LIMIT 1), (SELECT t.TruckLanceCode - FROM fpsmsdb.truck t + FROM truck t WHERE t.shopId = do.shopId AND t.deleted = 0 AND t.Store_id = pf.preferred_store_id ORDER BY t.DepartureTime ASC LIMIT 1), (SELECT t.TruckLanceCode - FROM fpsmsdb.truck t + FROM truck t WHERE t.shopId = do.shopId AND t.deleted = 0 ORDER BY t.DepartureTime ASC LIMIT 1), 'ZZ' ) - WHEN (SELECT COUNT(*) FROM fpsmsdb.truck t WHERE t.shopId = do.shopId AND t.deleted = 0) > 1 THEN + WHEN (SELECT COUNT(*) FROM truck t WHERE t.shopId = do.shopId AND t.deleted = 0) > 1 THEN COALESCE( (SELECT t.TruckLanceCode - FROM fpsmsdb.truck t + FROM truck t WHERE t.shopId = do.shopId AND t.deleted = 0 AND t.Store_id = pf.preferred_store_id ORDER BY t.DepartureTime ASC LIMIT 1), (SELECT t.TruckLanceCode - FROM fpsmsdb.truck t + FROM truck t WHERE t.shopId = do.shopId AND t.deleted = 0 ORDER BY t.DepartureTime ASC LIMIT 1), @@ -418,7 +418,7 @@ class DoReleaseCoordinatorService( ELSE COALESCE( (SELECT t.TruckLanceCode - FROM fpsmsdb.truck t + FROM truck t WHERE t.shopId = do.shopId AND t.deleted = 0 ORDER BY t.DepartureTime ASC LIMIT 1), @@ -427,24 +427,24 @@ class DoReleaseCoordinatorService( END AS selected_truck_lance, COALESCE( (SELECT t.LoadingSequence - FROM fpsmsdb.truck t + FROM truck t WHERE t.shopId = do.shopId AND t.deleted = 0 AND t.Store_id = pf.preferred_store_id AND (pf.preferred_store_id != 4 OR do.estimatedArrivalDate IS NULL OR t.TruckLanceCode LIKE CONCAT('%', $dayOfWeekSql, '%')) ORDER BY t.DepartureTime ASC LIMIT 1), (SELECT t.LoadingSequence - FROM fpsmsdb.truck t + FROM truck t WHERE t.shopId = do.shopId AND t.deleted = 0 AND t.Store_id = pf.preferred_store_id ORDER BY t.DepartureTime ASC LIMIT 1), (SELECT t.LoadingSequence - FROM fpsmsdb.truck t + FROM truck t WHERE t.shopId = do.shopId AND t.deleted = 0 ORDER BY t.DepartureTime ASC LIMIT 1), 999 ) AS loading_sequence - FROM fpsmsdb.delivery_order do + FROM delivery_order do LEFT JOIN PreferredFloor pf ON pf.deliveryOrderId = do.id WHERE do.id IN (${ids.joinToString(",")}) AND do.deleted = 0 @@ -798,7 +798,7 @@ class DoReleaseCoordinatorService( // 1. 获取 do_pick_order 的所有 pick orders 数量 val totalPickOrdersSql = """ SELECT COUNT(*) as total_pick_orders - FROM fpsmsdb.do_pick_order_line dpol + FROM do_pick_order_line dpol WHERE dpol.do_pick_order_id = :doPickOrderId AND dpol.deleted = 0 """.trimIndent() @@ -813,8 +813,8 @@ class DoReleaseCoordinatorService( // 2. 获取有库存问题的 pick orders 数量(通过检查 pick_execution_issue 表) val issuePickOrdersSql = """ SELECT COUNT(DISTINCT dpol.pick_order_id) as issue_pick_orders - FROM fpsmsdb.do_pick_order_line dpol - INNER JOIN fpsmsdb.pick_execution_issue pei ON pei.pick_order_id = dpol.pick_order_id + FROM do_pick_order_line dpol + INNER JOIN pick_execution_issue pei ON pei.pick_order_id = dpol.pick_order_id WHERE dpol.do_pick_order_id = :doPickOrderId AND pei.deleted = 0 AND dpol.deleted = 0 @@ -1153,7 +1153,7 @@ class DoReleaseCoordinatorService( return try { val totalLinesSql = """ SELECT COUNT(*) as total_lines - FROM fpsmsdb.do_pick_order_line dpol + FROM do_pick_order_line dpol WHERE dpol.do_pick_order_id = :doPickOrderId AND dpol.deleted = 0 """.trimIndent() @@ -1162,7 +1162,7 @@ class DoReleaseCoordinatorService( if (totalLines == 0) return true val nonIssueLinesSql = """ SELECT COUNT(*) as non_issue_lines - FROM fpsmsdb.do_pick_order_line dpol + FROM do_pick_order_line dpol WHERE dpol.do_pick_order_id = :doPickOrderId AND dpol.deleted = 0 AND (dpol.status IS NULL OR dpol.status != 'issue') diff --git a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoReplenishmentService.kt b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoReplenishmentService.kt index 81d0010a..eaefe382 100644 --- a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoReplenishmentService.kt +++ b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoReplenishmentService.kt @@ -347,7 +347,7 @@ open class DoReplenishmentService( return jdbcDao.queryForList( """ SELECT deliveryOrderPickOrderId AS dopoId - FROM fpsmsdb.pick_order + FROM pick_order WHERE id = :pickOrderId AND deleted = 0 """.trimIndent(), mapOf("pickOrderId" to pickOrderId), diff --git a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoWorkbenchDopoAssignmentService.kt b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoWorkbenchDopoAssignmentService.kt index fa55cbe0..93a76809 100644 --- a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoWorkbenchDopoAssignmentService.kt +++ b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoWorkbenchDopoAssignmentService.kt @@ -36,7 +36,7 @@ open class DoWorkbenchDopoAssignmentService( val headerRows = jdbcDao.queryForList( """ SELECT id, ticketStatus - FROM fpsmsdb.delivery_order_pick_order + FROM delivery_order_pick_order WHERE id = :id AND deleted = 0 """.trimIndent(), mapOf("id" to request.deliveryOrderPickOrderId) @@ -71,7 +71,7 @@ open class DoWorkbenchDopoAssignmentService( val headerRows = jdbcDao.queryForList( """ SELECT id, ticketStatus - FROM fpsmsdb.delivery_order_pick_order + FROM delivery_order_pick_order WHERE id = :id AND deleted = 0 """.trimIndent(), mapOf("id" to request.deliveryOrderPickOrderId) @@ -121,14 +121,14 @@ open class DoWorkbenchDopoAssignmentService( val sql = StringBuilder( """ SELECT dop.id - FROM fpsmsdb.delivery_order_pick_order dop + FROM delivery_order_pick_order dop WHERE dop.deleted = 0 AND dop.storeId = :storeId AND dop.truckLanceCode = :lance AND dop.ticketStatus IN ('pending', 'released') AND dop.handledBy IS NULL AND EXISTS ( - SELECT 1 FROM fpsmsdb.pick_order po + SELECT 1 FROM pick_order po WHERE po.deliveryOrderPickOrderId = dop.id AND po.deleted = 0 AND po.assignTo IS NULL ) """.trimIndent() @@ -233,13 +233,13 @@ open class DoWorkbenchDopoAssignmentService( val sql = StringBuilder( """ SELECT dop.id - FROM fpsmsdb.delivery_order_pick_order dop + FROM delivery_order_pick_order dop WHERE dop.deleted = 0 AND dop.storeId = :storeId AND dop.truckLanceCode = :lance AND dop.ticketStatus IN ('pending', 'released') AND EXISTS ( - SELECT 1 FROM fpsmsdb.pick_order po + SELECT 1 FROM pick_order po WHERE po.deliveryOrderPickOrderId = dop.id AND po.deleted = 0 AND po.assignTo IS NULL ) """.trimIndent() @@ -337,7 +337,7 @@ open class DoWorkbenchDopoAssignmentService( val (sql, failCode, failMsg) = when (mode) { AssignMode.ATOMIC -> Triple( """ - UPDATE fpsmsdb.delivery_order_pick_order + UPDATE delivery_order_pick_order SET handledBy = :handledBy, handlerName = :handlerName, ticketStatus = 'released', @@ -353,7 +353,7 @@ open class DoWorkbenchDopoAssignmentService( ) AssignMode.LEGACY_V1 -> Triple( """ - UPDATE fpsmsdb.delivery_order_pick_order + UPDATE delivery_order_pick_order SET handledBy = :handledBy, handlerName = :handlerName, ticketStatus = 'released', @@ -402,7 +402,7 @@ open class DoWorkbenchDopoAssignmentService( // Suggestion store scope: use DOPO.storeId when set; Truck X (null) → 2/F or 4/F from DO suppliers. val storeIdRow = jdbcDao.queryForList( - "SELECT storeId FROM fpsmsdb.delivery_order_pick_order WHERE id = :id AND deleted = 0", + "SELECT storeId FROM delivery_order_pick_order WHERE id = :id AND deleted = 0", mapOf("id" to dopoId), ).firstOrNull() val storeIdKey = storeIdRow?.keys?.find { it.equals("storeId", true) } @@ -419,7 +419,7 @@ open class DoWorkbenchDopoAssignmentService( } val ticketNoRow = jdbcDao.queryForList( - "SELECT ticketNo FROM fpsmsdb.delivery_order_pick_order WHERE id = :id AND deleted = 0", + "SELECT ticketNo FROM delivery_order_pick_order WHERE id = :id AND deleted = 0", mapOf("id" to dopoId) ).firstOrNull() val ticketNoKey = ticketNoRow?.keys?.find { it.equals("ticketNo", true) } @@ -453,9 +453,9 @@ open class DoWorkbenchDopoAssignmentService( jdbcDao.queryForList( """ SELECT DISTINCT s.code AS supplierCode - FROM fpsmsdb.pick_order po - INNER JOIN fpsmsdb.delivery_order d ON d.id = po.doId AND d.deleted = 0 - LEFT JOIN fpsmsdb.shop s ON s.id = d.supplierId AND s.deleted = 0 + FROM pick_order po + INNER JOIN delivery_order d ON d.id = po.doId AND d.deleted = 0 + LEFT JOIN shop s ON s.id = d.supplierId AND s.deleted = 0 WHERE po.deliveryOrderPickOrderId = :dopoId AND po.deleted = 0 """.trimIndent(), mapOf("dopoId" to dopoId), diff --git a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoWorkbenchMainService.kt b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoWorkbenchMainService.kt index e1563c53..cb1117b9 100644 --- a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoWorkbenchMainService.kt +++ b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoWorkbenchMainService.kt @@ -719,13 +719,13 @@ return MessageResponse( ORDER BY dop.handlerName SEPARATOR ', ' ) AS handler_names - FROM fpsmsdb.delivery_order_pick_order dop + FROM delivery_order_pick_order dop WHERE dop.deleted = 0 AND dop.storeId = :storeId AND dop.requiredDeliveryDate = :requiredDate AND dop.ticketStatus IN ('pending', 'released') AND EXISTS ( - SELECT 1 FROM fpsmsdb.pick_order po + SELECT 1 FROM pick_order po WHERE po.deliveryOrderPickOrderId = dop.id AND po.deleted = 0 ) $releaseFilterClause @@ -861,14 +861,14 @@ return MessageResponse( val truckXFloorClause = truckXPreferredFloorExistsSql(truckXFloorKey) val defaultCountSql = """ SELECT COUNT(DISTINCT dop.id) AS c - FROM fpsmsdb.delivery_order_pick_order dop + FROM delivery_order_pick_order dop WHERE dop.deleted = 0 AND dop.requiredDeliveryDate = :requiredDate AND dop.ticketStatus IN ('pending', 'released') AND (dop.storeId IS NULL OR TRIM(dop.storeId) = '') AND dop.truckLanceCode = '車線-X' AND EXISTS ( - SELECT 1 FROM fpsmsdb.pick_order po + SELECT 1 FROM pick_order po WHERE po.deliveryOrderPickOrderId = dop.id AND po.deleted = 0 ) $truckXFloorClause @@ -939,34 +939,34 @@ return MessageResponse( THEN CASE WHEN EXISTS ( SELECT 1 - FROM fpsmsdb.pick_order po - INNER JOIN fpsmsdb.delivery_order d ON d.id = po.doId AND d.deleted = 0 - LEFT JOIN fpsmsdb.shop s ON s.id = d.supplierId AND s.deleted = 0 + FROM pick_order po + INNER JOIN delivery_order d ON d.id = po.doId AND d.deleted = 0 + LEFT JOIN shop s ON s.id = d.supplierId AND s.deleted = 0 WHERE po.deliveryOrderPickOrderId = dop.id AND po.deleted = 0 AND ($floorExpr) = '4F' ) AND NOT EXISTS ( SELECT 1 - FROM fpsmsdb.pick_order po2 - INNER JOIN fpsmsdb.delivery_order d2 ON d2.id = po2.doId AND d2.deleted = 0 - LEFT JOIN fpsmsdb.shop s2 ON s2.id = d2.supplierId AND s2.deleted = 0 + FROM pick_order po2 + INNER JOIN delivery_order d2 ON d2.id = po2.doId AND d2.deleted = 0 + LEFT JOIN shop s2 ON s2.id = d2.supplierId AND s2.deleted = 0 WHERE po2.deliveryOrderPickOrderId = dop.id AND po2.deleted = 0 AND (CASE WHEN s2.code IN ($in4) THEN '4F' ELSE '2F' END) <> '4F' ) THEN '4/F' WHEN EXISTS ( SELECT 1 - FROM fpsmsdb.pick_order po - INNER JOIN fpsmsdb.delivery_order d ON d.id = po.doId AND d.deleted = 0 - LEFT JOIN fpsmsdb.shop s ON s.id = d.supplierId AND s.deleted = 0 + FROM pick_order po + INNER JOIN delivery_order d ON d.id = po.doId AND d.deleted = 0 + LEFT JOIN shop s ON s.id = d.supplierId AND s.deleted = 0 WHERE po.deliveryOrderPickOrderId = dop.id AND po.deleted = 0 AND ($floorExpr) = '2F' ) AND NOT EXISTS ( SELECT 1 - FROM fpsmsdb.pick_order po2 - INNER JOIN fpsmsdb.delivery_order d2 ON d2.id = po2.doId AND d2.deleted = 0 - LEFT JOIN fpsmsdb.shop s2 ON s2.id = d2.supplierId AND s2.deleted = 0 + FROM pick_order po2 + INNER JOIN delivery_order d2 ON d2.id = po2.doId AND d2.deleted = 0 + LEFT JOIN shop s2 ON s2.id = d2.supplierId AND s2.deleted = 0 WHERE po2.deliveryOrderPickOrderId = dop.id AND po2.deleted = 0 AND (CASE WHEN s2.code IN ($in4) THEN '4F' ELSE '2F' END) <> '2F' ) @@ -975,13 +975,13 @@ return MessageResponse( END ELSE dop.storeId END AS displayStoreId - FROM fpsmsdb.delivery_order_pick_order dop + FROM delivery_order_pick_order dop WHERE dop.deleted = 0 $etraReleaseFilter AND dop.requiredDeliveryDate = :requiredDate AND dop.ticketStatus IN ('pending', 'released') AND EXISTS ( - SELECT 1 FROM fpsmsdb.pick_order po + SELECT 1 FROM pick_order po WHERE po.deliveryOrderPickOrderId = dop.id AND po.deleted = 0 ) ) base @@ -1193,11 +1193,11 @@ return MessageResponse( GROUP_CONCAT(DISTINCT d.id ORDER BY d.id SEPARATOR ',') AS deliveryOrderIdsStr, GROUP_CONCAT(DISTINCT d.code ORDER BY d.code SEPARATOR ',') AS deliveryNosStr, MIN(po.consoCode) AS consoCode - FROM fpsmsdb.delivery_order_pick_order dop - INNER JOIN fpsmsdb.pick_order po + FROM delivery_order_pick_order dop + INNER JOIN pick_order po ON po.deliveryOrderPickOrderId = dop.id AND po.deleted = 0 - LEFT JOIN fpsmsdb.delivery_order d + LEFT JOIN delivery_order d ON d.id = po.doId AND d.deleted = 0 WHERE dop.deleted = 0 @@ -1344,11 +1344,11 @@ return MessageResponse( GROUP_CONCAT(DISTINCT d.id ORDER BY d.id SEPARATOR ',') AS deliveryOrderIdsStr, GROUP_CONCAT(DISTINCT d.code ORDER BY d.code SEPARATOR ',') AS deliveryNosStr, MIN(po.consoCode) AS consoCode - FROM fpsmsdb.delivery_order_pick_order dop - INNER JOIN fpsmsdb.pick_order po + FROM delivery_order_pick_order dop + INNER JOIN pick_order po ON po.deliveryOrderPickOrderId = dop.id AND po.deleted = 0 - LEFT JOIN fpsmsdb.delivery_order d + LEFT JOIN delivery_order d ON d.id = po.doId AND d.deleted = 0 WHERE dop.deleted = 0 @@ -1495,14 +1495,14 @@ return MessageResponse( dop.requiredDeliveryDate AS requiredDeliveryDate, dop.handlerName AS handlerName, COALESCE(SUM(polCount.cnt), 0) AS numberOfFGItems - FROM fpsmsdb.delivery_order_pick_order dop + FROM delivery_order_pick_order dop LEFT JOIN ( SELECT po.deliveryOrderPickOrderId AS dopId, po.id AS pickOrderId, COUNT(pol.id) AS cnt - FROM fpsmsdb.pick_order po - LEFT JOIN fpsmsdb.pick_order_line pol + FROM pick_order po + LEFT JOIN pick_order_line pol ON pol.poId = po.id AND pol.deleted = 0 WHERE po.deleted = 0 @@ -1717,7 +1717,7 @@ return MessageResponse( val now = LocalDateTime.now() jdbcDao.executeUpdate( """ - UPDATE fpsmsdb.pick_order po + UPDATE pick_order po SET po.assignTo = NULL, po.status = 'pending', po.modified = :modified, @@ -1757,8 +1757,8 @@ return MessageResponse( jdbcDao.queryForList( """ SELECT dop.storeId AS storeId - FROM fpsmsdb.pick_order po - INNER JOIN fpsmsdb.delivery_order_pick_order dop + FROM pick_order po + INNER JOIN delivery_order_pick_order dop ON dop.id = po.deliveryOrderPickOrderId AND dop.deleted = 0 WHERE po.id = :poId AND po.deleted = 0 LIMIT 1 @@ -1779,9 +1779,9 @@ return MessageResponse( jdbcDao.queryForList( """ SELECT DISTINCT s.code AS supplierCode - FROM fpsmsdb.pick_order po - INNER JOIN fpsmsdb.delivery_order d ON d.id = po.doId AND d.deleted = 0 - LEFT JOIN fpsmsdb.shop s ON s.id = d.supplierId AND s.deleted = 0 + FROM pick_order po + INNER JOIN delivery_order d ON d.id = po.doId AND d.deleted = 0 + LEFT JOIN shop s ON s.id = d.supplierId AND s.deleted = 0 WHERE po.id = :poId AND po.deleted = 0 """.trimIndent(), mapOf("poId" to pickOrderId), @@ -1809,9 +1809,9 @@ return MessageResponse( jdbcDao.queryForList( """ SELECT DISTINCT s.code AS supplierCode - FROM fpsmsdb.pick_order po - INNER JOIN fpsmsdb.delivery_order d ON d.id = po.doId AND d.deleted = 0 - LEFT JOIN fpsmsdb.shop s ON s.id = d.supplierId AND s.deleted = 0 + FROM pick_order po + INNER JOIN delivery_order d ON d.id = po.doId AND d.deleted = 0 + LEFT JOIN shop s ON s.id = d.supplierId AND s.deleted = 0 WHERE po.deliveryOrderPickOrderId = :dopoId AND po.deleted = 0 """.trimIndent(), mapOf("dopoId" to dopoId), @@ -1854,17 +1854,17 @@ return MessageResponse( return """ AND EXISTS ( SELECT 1 - FROM fpsmsdb.pick_order po - INNER JOIN fpsmsdb.delivery_order d ON d.id = po.doId AND d.deleted = 0 - LEFT JOIN fpsmsdb.shop s ON s.id = d.supplierId AND s.deleted = 0 + FROM pick_order po + INNER JOIN delivery_order d ON d.id = po.doId AND d.deleted = 0 + LEFT JOIN shop s ON s.id = d.supplierId AND s.deleted = 0 WHERE po.deliveryOrderPickOrderId = dop.id AND po.deleted = 0 AND ($floorExpr) = '$key' ) AND NOT EXISTS ( SELECT 1 - FROM fpsmsdb.pick_order po2 - INNER JOIN fpsmsdb.delivery_order d2 ON d2.id = po2.doId AND d2.deleted = 0 - LEFT JOIN fpsmsdb.shop s2 ON s2.id = d2.supplierId AND s2.deleted = 0 + FROM pick_order po2 + INNER JOIN delivery_order d2 ON d2.id = po2.doId AND d2.deleted = 0 + LEFT JOIN shop s2 ON s2.id = d2.supplierId AND s2.deleted = 0 WHERE po2.deliveryOrderPickOrderId = dop.id AND po2.deleted = 0 AND (CASE WHEN s2.code IN ($in4) THEN '4F' ELSE '2F' END) <> '$key' ) @@ -1903,11 +1903,11 @@ return MessageResponse( dop.truckDepartureTime AS truckDepartureTime, ( SELECT GROUP_CONCAT(DISTINCT d.code ORDER BY d.code SEPARATOR ',') - FROM fpsmsdb.pick_order po - INNER JOIN fpsmsdb.delivery_order d ON d.id = po.doId AND d.deleted = 0 + FROM pick_order po + INNER JOIN delivery_order d ON d.id = po.doId AND d.deleted = 0 WHERE po.deliveryOrderPickOrderId = dop.id AND po.deleted = 0 ) AS doCodesStr - FROM fpsmsdb.delivery_order_pick_order dop + FROM delivery_order_pick_order dop WHERE dop.deleted = 0 AND dop.ticketStatus IN ('pending', 'released') AND $dateClause @@ -2025,14 +2025,14 @@ return MessageResponse( dop.shopCode as ShopCode, dop.shopName as ShopName, dop.ticketStatus as doTicketStatus - FROM fpsmsdb.delivery_order_pick_order dop + FROM delivery_order_pick_order dop WHERE dop.handledBy = :userId AND dop.ticketStatus IN ('pending', 'released') AND dop.deleted = 0 AND EXISTS ( SELECT 1 - FROM fpsmsdb.pick_order po + FROM pick_order po WHERE po.deliveryOrderPickOrderId = dop.id AND po.assignTo = :userId @@ -2096,8 +2096,8 @@ return MessageResponse( po.consoCode, po.status, DATE_FORMAT(po.targetDate, '%Y-%m-%d') as targetDate - FROM fpsmsdb.pick_order po - LEFT JOIN fpsmsdb.delivery_order do_tbl ON do_tbl.id = po.doId + FROM pick_order po + LEFT JOIN delivery_order do_tbl ON do_tbl.id = po.doId WHERE po.deliveryOrderPickOrderId = :doPickOrderId AND po.assignTo = :userId AND po.type = 'do' @@ -2154,7 +2154,7 @@ return MessageResponse( dop.shopCode as ShopCode, dop.shopName as ShopName, dop.ticketStatus as doTicketStatus - FROM fpsmsdb.delivery_order_pick_order dop + FROM delivery_order_pick_order dop WHERE dop.id = :dopoId AND dop.deleted = 0 LIMIT 1 @@ -2172,8 +2172,8 @@ return MessageResponse( po.consoCode, po.status, DATE_FORMAT(po.targetDate, '%Y-%m-%d') as targetDate - FROM fpsmsdb.pick_order po - LEFT JOIN fpsmsdb.delivery_order do_tbl ON do_tbl.id = po.doId + FROM pick_order po + LEFT JOIN delivery_order do_tbl ON do_tbl.id = po.doId WHERE po.deliveryOrderPickOrderId = :dopoId AND po.type = 'do' AND po.deleted = 0 @@ -2228,24 +2228,24 @@ return MessageResponse( GROUP_CONCAT(DISTINCT po.code ORDER BY po.id SEPARATOR ', ') as pickOrderCodes, GROUP_CONCAT(DISTINCT do_tbl.id ORDER BY do_tbl.id) as deliveryOrderIds, GROUP_CONCAT(DISTINCT do_tbl.code ORDER BY do_tbl.id SEPARATOR ', ') as deliveryNos, - (SELECT po2.consoCode FROM fpsmsdb.pick_order po2 WHERE po2.id = MIN(po.id) LIMIT 1) as pickOrderConsoCode, - (SELECT po2.targetDate FROM fpsmsdb.pick_order po2 WHERE po2.id = MIN(po.id) LIMIT 1) as pickOrderTargetDate, - (SELECT po2.status FROM fpsmsdb.pick_order po2 WHERE po2.id = MIN(po.id) LIMIT 1) as pickOrderStatus, - (SELECT do2.orderDate FROM fpsmsdb.delivery_order do2 WHERE do2.id = MIN(do_tbl.id) LIMIT 1) as deliveryDate, + (SELECT po2.consoCode FROM pick_order po2 WHERE po2.id = MIN(po.id) LIMIT 1) as pickOrderConsoCode, + (SELECT po2.targetDate FROM pick_order po2 WHERE po2.id = MIN(po.id) LIMIT 1) as pickOrderTargetDate, + (SELECT po2.status FROM pick_order po2 WHERE po2.id = MIN(po.id) LIMIT 1) as pickOrderStatus, + (SELECT do2.orderDate FROM delivery_order do2 WHERE do2.id = MIN(do_tbl.id) LIMIT 1) as deliveryDate, COUNT(DISTINCT po.id) as numberOfPickOrders, (SELECT SUM(pol_count.line_count) FROM ( SELECT po3.id, COUNT(*) as line_count - FROM fpsmsdb.pick_order po3 - JOIN fpsmsdb.pick_order_line pol3 ON pol3.poId = po3.id AND pol3.deleted = false + FROM pick_order po3 + JOIN pick_order_line pol3 ON pol3.poId = po3.id AND pol3.deleted = false WHERE po3.deliveryOrderPickOrderId = dop.id AND po3.deleted = 0 GROUP BY po3.id ) pol_count ) as numberOfCartons - FROM fpsmsdb.delivery_order_pick_order dop - INNER JOIN fpsmsdb.pick_order po ON po.deliveryOrderPickOrderId = dop.id AND po.deleted = 0 - LEFT JOIN fpsmsdb.delivery_order do_tbl ON do_tbl.id = po.doId - LEFT JOIN fpsmsdb.shop s ON s.id = dop.shopId + FROM delivery_order_pick_order dop + INNER JOIN pick_order po ON po.deliveryOrderPickOrderId = dop.id AND po.deleted = 0 + LEFT JOIN delivery_order do_tbl ON do_tbl.id = po.doId + LEFT JOIN shop s ON s.id = dop.shopId WHERE po.assignTo = :userId AND po.type = 'do' AND po.status IN ('assigned', 'released', 'picking') @@ -2728,7 +2728,7 @@ return MessageResponse( */ private fun tryCompleteDeliveryOrderPickOrderTicketCompleted(poId: Long) { val dopRow = jdbcDao.queryForMap( - "SELECT deliveryOrderPickOrderId AS dopId FROM fpsmsdb.pick_order WHERE id = :poId AND deleted = 0", + "SELECT deliveryOrderPickOrderId AS dopId FROM pick_order WHERE id = :poId AND deleted = 0", mapOf("poId" to poId), ).orElse(null) ?: return val dopId = (dopRow["dopId"] as? Number)?.toLong() ?: return @@ -2737,7 +2737,7 @@ return MessageResponse( val unfinished = jdbcDao.queryForInt( """ SELECT COUNT(1) - FROM fpsmsdb.pick_order po + FROM pick_order po WHERE po.deliveryOrderPickOrderId = :dopId AND po.deleted = 0 AND po.type = 'do' @@ -2757,7 +2757,7 @@ return MessageResponse( jdbcDao.executeUpdate( """ - UPDATE fpsmsdb.delivery_order_pick_order dop + UPDATE delivery_order_pick_order dop SET dop.ticketStatus = 'completed', dop.ticketCompleteDateTime = NOW(), dop.deliveryNoteCode = CASE @@ -2781,7 +2781,7 @@ return MessageResponse( jdbcDao.queryForList( """ SELECT DISTINCT po.doId AS doId - FROM fpsmsdb.pick_order po + FROM pick_order po WHERE po.deliveryOrderPickOrderId = :dopId AND po.deleted = 0 AND po.doId IS NOT NULL @@ -2974,7 +2974,7 @@ return MessageResponse( val rows = jdbcDao.queryForList( """ SELECT po.id AS id, po.code AS code, po.doId AS doId - FROM fpsmsdb.pick_order po + FROM pick_order po WHERE po.deliveryOrderPickOrderId = :dopoId AND po.deleted = 0 """.trimIndent(), diff --git a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoWorkbenchReleaseService.kt b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoWorkbenchReleaseService.kt index f44fe125..e51baff3 100644 --- a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoWorkbenchReleaseService.kt +++ b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoWorkbenchReleaseService.kt @@ -186,7 +186,7 @@ open class DoWorkbenchReleaseService( val statusRows = jdbcDao.queryForList( """ SELECT status - FROM fpsmsdb.delivery_order + FROM delivery_order WHERE id = :id AND deleted = 0 """.trimIndent(), mapOf("id" to deliveryOrderId) @@ -342,7 +342,7 @@ open class DoWorkbenchReleaseService( val statusRows = jdbcDao.queryForList( """ SELECT status - FROM fpsmsdb.delivery_order + FROM delivery_order WHERE id = :id AND deleted = 0 """.trimIndent(), mapOf("id" to deliveryOrderId) @@ -411,10 +411,10 @@ open class DoWorkbenchReleaseService( val floor = storeDisplay.replace("/", "").trim() val prefix = "TI-$ticketLetter-$ymd-$floor-" val sql = """ - SELECT ticket_no AS t FROM fpsmsdb.do_pick_order + SELECT ticket_no AS t FROM do_pick_order WHERE ticket_no LIKE CONCAT(:prefix, '%') UNION ALL - SELECT ticketNo AS t FROM fpsmsdb.delivery_order_pick_order + SELECT ticketNo AS t FROM delivery_order_pick_order WHERE ticketNo LIKE CONCAT(:prefix, '%') """.trimIndent() val rows = try { @@ -473,7 +473,7 @@ open class DoWorkbenchReleaseService( return try { val sql = """ SELECT do.id - FROM fpsmsdb.delivery_order do + FROM delivery_order do WHERE do.deleted = 0 AND do.id IN (${ids.joinToString(",")}) ORDER BY DATE(do.estimatedArrivalDate), do.id @@ -622,9 +622,9 @@ open class DoWorkbenchReleaseService( """ AND NOT EXISTS ( SELECT 1 - FROM fpsmsdb.pick_order po - INNER JOIN fpsmsdb.delivery_order d ON d.id = po.doId AND d.deleted = 0 - LEFT JOIN fpsmsdb.shop s ON s.id = d.supplierId AND s.deleted = 0 + FROM pick_order po + INNER JOIN delivery_order d ON d.id = po.doId AND d.deleted = 0 + LEFT JOIN shop s ON s.id = d.supplierId AND s.deleted = 0 WHERE po.deliveryOrderPickOrderId = delivery_order_pick_order.id AND po.deleted = 0 AND ($floorExpr) <> '$floor' @@ -636,14 +636,14 @@ open class DoWorkbenchReleaseService( """ AND ( NOT EXISTS ( - SELECT 1 FROM fpsmsdb.pick_order po0 + SELECT 1 FROM pick_order po0 WHERE po0.deliveryOrderPickOrderId = delivery_order_pick_order.id AND po0.deleted = 0 ) OR EXISTS ( SELECT 1 - FROM fpsmsdb.pick_order po - INNER JOIN fpsmsdb.delivery_order d ON d.id = po.doId AND d.deleted = 0 - LEFT JOIN fpsmsdb.shop s ON s.id = d.supplierId AND s.deleted = 0 + FROM pick_order po + INNER JOIN delivery_order d ON d.id = po.doId AND d.deleted = 0 + LEFT JOIN shop s ON s.id = d.supplierId AND s.deleted = 0 WHERE po.deliveryOrderPickOrderId = delivery_order_pick_order.id AND po.deleted = 0 AND ($floorExpr) = '$floor' @@ -684,7 +684,7 @@ open class DoWorkbenchReleaseService( val sql = StringBuilder( """ SELECT id, releaseType, ticketNo - FROM fpsmsdb.delivery_order_pick_order + FROM delivery_order_pick_order WHERE deleted = 0 AND shopId = :shopId AND requiredDeliveryDate = :requiredDate @@ -729,7 +729,7 @@ open class DoWorkbenchReleaseService( val sql = StringBuilder( """ SELECT id, releaseType, ticketNo - FROM fpsmsdb.delivery_order_pick_order + FROM delivery_order_pick_order WHERE deleted = 0 AND shopId = :shopId AND requiredDeliveryDate = :requiredDate @@ -768,7 +768,7 @@ open class DoWorkbenchReleaseService( val sql = StringBuilder( """ SELECT id, releaseType, ticketNo - FROM fpsmsdb.delivery_order_pick_order + FROM delivery_order_pick_order WHERE deleted = 0 AND shopId = :shopId AND requiredDeliveryDate = :requiredDate @@ -805,7 +805,7 @@ open class DoWorkbenchReleaseService( val sql = StringBuilder( """ SELECT id, releaseType, ticketNo - FROM fpsmsdb.delivery_order_pick_order + FROM delivery_order_pick_order WHERE deleted = 0 AND shopId = :shopId AND requiredDeliveryDate = :requiredDate @@ -841,7 +841,7 @@ open class DoWorkbenchReleaseService( val sql = StringBuilder( """ SELECT id, releaseType, ticketNo - FROM fpsmsdb.delivery_order_pick_order + FROM delivery_order_pick_order WHERE deleted = 0 AND shopId = :shopId AND requiredDeliveryDate = :requiredDate @@ -868,7 +868,7 @@ open class DoWorkbenchReleaseService( val rows = jdbcDao.queryForList( """ SELECT handledBy - FROM fpsmsdb.delivery_order_pick_order + FROM delivery_order_pick_order WHERE id = :id AND deleted = 0 """.trimIndent(), mapOf("id" to ticketId), @@ -885,7 +885,7 @@ open class DoWorkbenchReleaseService( private fun setRelationshipIdSelf(headerId: Long, actor: String) { jdbcDao.executeUpdate( """ - UPDATE fpsmsdb.delivery_order_pick_order + UPDATE delivery_order_pick_order SET relationshipId = :headerId, modified = :modified, modifiedBy = :modifiedBy @@ -902,7 +902,7 @@ open class DoWorkbenchReleaseService( private fun softDeleteMergedSourceTicket(sourceId: Long, successorId: Long) { jdbcDao.executeUpdate( """ - UPDATE fpsmsdb.delivery_order_pick_order + UPDATE delivery_order_pick_order SET deleted = 1, relationshipId = :successorId, modified = :modified, @@ -921,7 +921,7 @@ open class DoWorkbenchReleaseService( private fun reparentPickOrdersFromHeader(sourceHeaderId: Long, targetHeaderId: Long) { jdbcDao.executeUpdate( """ - UPDATE fpsmsdb.pick_order + UPDATE pick_order SET deliveryOrderPickOrderId = :targetHeaderId WHERE deliveryOrderPickOrderId = :sourceHeaderId AND deleted = 0 """.trimIndent(), @@ -970,7 +970,7 @@ open class DoWorkbenchReleaseService( group.forEach { r -> jdbcDao.executeUpdate( """ - UPDATE fpsmsdb.pick_order + UPDATE pick_order SET deliveryOrderPickOrderId = :headerId WHERE id = :pickOrderId """.trimIndent(), @@ -992,7 +992,7 @@ open class DoWorkbenchReleaseService( val now = LocalDateTime.now() jdbcDao.executeUpdate( """ - INSERT INTO fpsmsdb.delivery_order_pick_order ( + INSERT INTO delivery_order_pick_order ( truckId, shopId, storeId, requiredDeliveryDate, truckDepartureTime, truckLanceCode, shopCode, shopName, loadingSequence, ticketNo, ticketReleaseTime, ticketStatus, releaseType, handledBy, handlerName, @@ -1025,7 +1025,7 @@ open class DoWorkbenchReleaseService( return jdbcDao.queryForList( """ SELECT id - FROM fpsmsdb.delivery_order_pick_order + FROM delivery_order_pick_order WHERE ticketNo = :ticketNo ORDER BY id DESC LIMIT 1 @@ -1267,7 +1267,7 @@ open class DoWorkbenchReleaseService( retireSourceTicketIntoMergeHeader(isExtraDopoId, mergeHeaderId) val mergeTicketNo = jdbcDao.queryForList( - "SELECT ticketNo AS t FROM fpsmsdb.delivery_order_pick_order WHERE id = :id", + "SELECT ticketNo AS t FROM delivery_order_pick_order WHERE id = :id", mapOf("id" to mergeHeaderId), ).firstOrNull()?.let { row -> row.entries.find { it.key.equals("t", true) }?.value?.toString() @@ -1339,11 +1339,11 @@ open class DoWorkbenchReleaseService( dop.loadingSequence AS loadingSequence, ( SELECT GROUP_CONCAT(DISTINCT d.code ORDER BY d.code SEPARATOR ',') - FROM fpsmsdb.pick_order po - INNER JOIN fpsmsdb.delivery_order d ON d.id = po.doId AND d.deleted = 0 + FROM pick_order po + INNER JOIN delivery_order d ON d.id = po.doId AND d.deleted = 0 WHERE po.deliveryOrderPickOrderId = dop.id AND po.deleted = 0 ) AS doCodesStr - FROM fpsmsdb.delivery_order_pick_order dop + FROM delivery_order_pick_order dop WHERE dop.deleted = 0 AND dop.requiredDeliveryDate = :requiredDate AND dop.ticketStatus IN ('pending', 'released') @@ -1495,7 +1495,7 @@ open class DoWorkbenchReleaseService( SELECT id, ticketNo, releaseType, shopId, shopCode, shopName, storeId, truckId, requiredDeliveryDate, truckLanceCode, truckDepartureTime, loadingSequence - FROM fpsmsdb.delivery_order_pick_order + FROM delivery_order_pick_order WHERE id = :id AND deleted = 0 """.trimIndent(), mapOf("id" to id), @@ -1532,7 +1532,7 @@ open class DoWorkbenchReleaseService( val now = LocalDateTime.now() jdbcDao.executeUpdate( """ - INSERT INTO fpsmsdb.delivery_order_pick_order ( + INSERT INTO delivery_order_pick_order ( truckId, shopId, storeId, requiredDeliveryDate, truckDepartureTime, truckLanceCode, shopCode, shopName, loadingSequence, ticketNo, ticketReleaseTime, ticketStatus, releaseType, handledBy, handlerName, @@ -1564,7 +1564,7 @@ open class DoWorkbenchReleaseService( ) return jdbcDao.queryForList( """ - SELECT id FROM fpsmsdb.delivery_order_pick_order + SELECT id FROM delivery_order_pick_order WHERE ticketNo = :ticketNo ORDER BY id DESC LIMIT 1 """.trimIndent(), mapOf("ticketNo" to ticketNo), diff --git a/src/main/java/com/ffii/fpsms/modules/jobOrder/service/JoPickOrderService.kt b/src/main/java/com/ffii/fpsms/modules/jobOrder/service/JoPickOrderService.kt index 4214ee45..f5172056 100644 --- a/src/main/java/com/ffii/fpsms/modules/jobOrder/service/JoPickOrderService.kt +++ b/src/main/java/com/ffii/fpsms/modules/jobOrder/service/JoPickOrderService.kt @@ -175,7 +175,7 @@ open class JoPickOrderService( val joPickOrders = itemIds.map { itemId -> // Get item code from database - 修复:使用 queryForList val itemCodeResult = jdbcDao.queryForList( - "SELECT code FROM fpsmsdb.items WHERE id = :itemId", + "SELECT code FROM items WHERE id = :itemId", mapOf("itemId" to itemId) ) val itemCode = if (itemCodeResult.isNotEmpty()) { @@ -207,7 +207,7 @@ open class JoPickOrderService( val joPickOrderRecords = itemIds.map { itemId -> // Get item code from database - 修复:使用 queryForList val itemCodeResult = jdbcDao.queryForList( - "SELECT code FROM fpsmsdb.items WHERE id = :itemId", + "SELECT code FROM items WHERE id = :itemId", mapOf("itemId" to itemId) ) val itemCode = if (itemCodeResult.isNotEmpty()) { @@ -1102,10 +1102,10 @@ open fun recordSecondScanIssue(request: SecondScanIssueRequest): MessageResponse i.name as itemName, pol.qty as requiredQty, u.name as pickerName - FROM fpsmsdb.pick_order po - JOIN fpsmsdb.pick_order_line pol ON pol.poId = po.id - JOIN fpsmsdb.items i ON i.id = pol.itemId - LEFT JOIN fpsmsdb.user u ON u.id = :createdBy + FROM pick_order po + JOIN pick_order_line pol ON pol.poId = po.id + JOIN items i ON i.id = pol.itemId + LEFT JOIN user u ON u.id = :createdBy WHERE po.id = :pickOrderId AND pol.itemId = :itemId AND pol.deleted = false @@ -1151,10 +1151,10 @@ open fun recordSecondScanIssue(request: SecondScanIssueRequest): MessageResponse ill.id as lotId, il.lotNo as lotNo, w.name as storeLocation - FROM fpsmsdb.suggested_pick_lot spl - JOIN fpsmsdb.inventory_lot_line ill ON ill.id = COALESCE(spl.actualPickLotLineId, spl.suggestedLotLineId) - JOIN fpsmsdb.inventory_lot il ON ill.inventoryLotId = il.id - LEFT JOIN fpsmsdb.warehouse w ON w.id = ill.warehouseId + FROM suggested_pick_lot spl + JOIN inventory_lot_line ill ON ill.id = COALESCE(spl.actualPickLotLineId, spl.suggestedLotLineId) + JOIN inventory_lot il ON ill.inventoryLotId = il.id + LEFT JOIN warehouse w ON w.id = ill.warehouseId WHERE spl.pickOrderLineId = :pickOrderLineId AND spl.deleted = false AND ill.deleted = false @@ -1479,7 +1479,7 @@ open fun getCompletedJobOrderPickOrderLotDetails(pickOrderId: Long): List ll.lotLineId -LEFT JOIN fpsmsdb.suggested_pick_lot spl +LEFT JOIN suggested_pick_lot spl ON spl.id = sm.maxId AND spl.deleted = false -LEFT JOIN fpsmsdb.stock_out_line sol +LEFT JOIN stock_out_line sol ON sol.pickOrderLineId = pol.id AND ((sol.inventoryLotLineId = ll.lotLineId) OR (sol.inventoryLotLineId IS NULL AND ll.lotLineId IS NULL)) AND sol.deleted = false -LEFT JOIN fpsmsdb.inventory_lot_line ill ON ill.id = ll.lotLineId AND ill.deleted = false -LEFT JOIN fpsmsdb.inventory_lot il ON il.id = ill.inventoryLotId AND il.deleted = false -LEFT JOIN fpsmsdb.warehouse w ON w.id = ill.warehouseId +LEFT JOIN inventory_lot_line ill ON ill.id = ll.lotLineId AND ill.deleted = false +LEFT JOIN inventory_lot il ON il.id = ill.inventoryLotId AND il.deleted = false +LEFT JOIN warehouse w ON w.id = ill.warehouseId WHERE po.id IN ($inClause) AND po.deleted = false ORDER BY diff --git a/src/main/java/com/ffii/fpsms/modules/pickOrder/service/PickExecutionIssueService.kt b/src/main/java/com/ffii/fpsms/modules/pickOrder/service/PickExecutionIssueService.kt index 5fd8fcbe..51e7e4a7 100644 --- a/src/main/java/com/ffii/fpsms/modules/pickOrder/service/PickExecutionIssueService.kt +++ b/src/main/java/com/ffii/fpsms/modules/pickOrder/service/PickExecutionIssueService.kt @@ -1619,7 +1619,7 @@ open fun createBatchReleaseIssue( // 查询 delivery order val deliveryOrderSql = """ SELECT do.id, do.code, do.estimatedArrivalDate - FROM fpsmsdb.delivery_order do + FROM delivery_order do WHERE do.id = :deliveryOrderId AND do.deleted = 0 """.trimIndent() @@ -1637,8 +1637,8 @@ open fun createBatchReleaseIssue( // 查询 delivery order lines val linesSql = """ SELECT dol.id, dol.itemId, i.code as itemCode, i.name as itemName, dol.qty - FROM fpsmsdb.delivery_order_line dol - INNER JOIN fpsmsdb.items i ON i.id = dol.itemId + FROM delivery_order_line dol + INNER JOIN items i ON i.id = dol.itemId WHERE dol.deliveryOrderId = :deliveryOrderId AND dol.deleted = 0 """.trimIndent() diff --git a/src/main/java/com/ffii/fpsms/modules/pickOrder/service/PickOrderService.kt b/src/main/java/com/ffii/fpsms/modules/pickOrder/service/PickOrderService.kt index 18560561..dc8b7367 100644 --- a/src/main/java/com/ffii/fpsms/modules/pickOrder/service/PickOrderService.kt +++ b/src/main/java/com/ffii/fpsms/modules/pickOrder/service/PickOrderService.kt @@ -1928,8 +1928,8 @@ open fun checkAndCompletePickOrderByConsoCode(consoCode: String): MessageRespons private fun getPickOrderIdFromPickOrderLineId(pickOrderLineId: Long): Long? { val sql = """ SELECT po.id as pickOrderId - FROM fpsmsdb.pick_order_line pol - JOIN fpsmsdb.pick_order po ON po.id = pol.poId + FROM pick_order_line pol + JOIN pick_order po ON po.id = pol.poId WHERE pol.id = :pickOrderLineId """.trimIndent() @@ -1963,10 +1963,10 @@ open fun checkAndCompletePickOrderByConsoCode(consoCode: String): MessageRespons -- ELSE (COALESCE(ill.inQty, 0) - COALESCE(ill.outQty, 0) - COALESCE(ill.holdQty, 0)) -- END as convertedAvailableQty COALESCE(ill.inQty, 0) - COALESCE(ill.outQty, 0) - COALESCE(ill.holdQty, 0) as convertedAvailableQty - FROM fpsmsdb.suggested_pick_lot spl - JOIN fpsmsdb.inventory_lot_line ill ON ill.id = spl.suggestedLotLineId - JOIN fpsmsdb.inventory_lot il ON il.id = ill.inventoryLotId - LEFT JOIN fpsmsdb.item_uom sales_iu ON sales_iu.itemId = il.itemId AND sales_iu.salesUnit = true AND sales_iu.deleted = false + FROM suggested_pick_lot spl + JOIN inventory_lot_line ill ON ill.id = spl.suggestedLotLineId + JOIN inventory_lot il ON il.id = ill.inventoryLotId + LEFT JOIN item_uom sales_iu ON sales_iu.itemId = il.itemId AND sales_iu.salesUnit = true AND sales_iu.deleted = false WHERE spl.pickOrderLineId = :pickOrderLineId """.trimIndent() @@ -2009,13 +2009,13 @@ open fun checkAndCompletePickOrderByConsoCode(consoCode: String): MessageRespons COUNT(CASE WHEN sol.status IN ('rejected', 'lot-change', 'determine1') THEN 1 END) as problematicStockOutLines, -- 检查单位不一致问题 COUNT(CASE WHEN spl.qty > pol.qty * 100 THEN 1 END) as unitMismatchLots - FROM fpsmsdb.suggested_pick_lot spl - JOIN fpsmsdb.inventory_lot_line ill ON ill.id = spl.suggestedLotLineId - JOIN fpsmsdb.inventory_lot il ON il.id = ill.inventoryLotId - JOIN fpsmsdb.pick_order_line pol ON pol.id = spl.pickOrderLineId + FROM suggested_pick_lot spl + JOIN inventory_lot_line ill ON ill.id = spl.suggestedLotLineId + JOIN inventory_lot il ON il.id = ill.inventoryLotId + JOIN pick_order_line pol ON pol.id = spl.pickOrderLineId -- 添加销售单位转换 - LEFT JOIN fpsmsdb.item_uom sales_iu ON sales_iu.itemId = il.itemId AND sales_iu.salesUnit = true AND sales_iu.deleted = false - LEFT JOIN fpsmsdb.stock_out_line sol ON sol.inventoryLotLineId = ill.id + LEFT JOIN item_uom sales_iu ON sales_iu.itemId = il.itemId AND sales_iu.salesUnit = true AND sales_iu.deleted = false + LEFT JOIN stock_out_line sol ON sol.inventoryLotLineId = ill.id AND sol.pickOrderLineId = spl.pickOrderLineId WHERE spl.pickOrderLineId = :pickOrderLineId """.trimIndent() @@ -2336,7 +2336,7 @@ open fun checkAndCompletePickOrderByConsoCode(consoCode: String): MessageRespons -- Calculate total picked quantity from stock_out_line table COALESCE(( SELECT SUM(sol_picked.qty) - FROM fpsmsdb.stock_out_line sol_picked + FROM stock_out_line sol_picked WHERE sol_picked.pickOrderLineId = pol.id AND sol_picked.deleted = false AND sol_picked.status IN ('completed', 'COMPLETE', 'partially_completed','rejected') @@ -2349,8 +2349,8 @@ open fun checkAndCompletePickOrderByConsoCode(consoCode: String): MessageRespons - COALESCE(inv.onHoldQty, 0) - COALESCE(inv.unavailableQty, 0) ) - FROM fpsmsdb.inventory inv - JOIN fpsmsdb.item_uom iu + FROM inventory inv + JOIN item_uom iu ON iu.itemId = inv.itemId AND iu.uomId = inv.uomId AND iu.baseUnit = 1 @@ -2363,24 +2363,24 @@ open fun checkAndCompletePickOrderByConsoCode(consoCode: String): MessageRespons CASE WHEN EXISTS ( SELECT 1 - FROM fpsmsdb.stock_out_line sol_check + FROM stock_out_line sol_check WHERE sol_check.pickOrderLineId = pol.id AND sol_check.deleted = false AND sol_check.status NOT IN ('completed', 'COMPLETE') ) THEN false WHEN EXISTS ( SELECT 1 - FROM fpsmsdb.stock_out_line sol_check + FROM stock_out_line sol_check WHERE sol_check.pickOrderLineId = pol.id AND sol_check.deleted = false ) THEN true ELSE false END as allLotsCompleted - FROM fpsmsdb.pick_order po - JOIN fpsmsdb.pick_order_line pol ON pol.poId = po.id - JOIN fpsmsdb.items i ON i.id = pol.itemId - LEFT JOIN fpsmsdb.uom_conversion uc ON uc.id = pol.uomId + FROM pick_order po + JOIN pick_order_line pol ON pol.poId = po.id + JOIN items i ON i.id = pol.itemId + LEFT JOIN uom_conversion uc ON uc.id = pol.uomId WHERE po.deleted = false AND po.id IN ($pickOrderIdsStr) AND pol.deleted = false @@ -2390,13 +2390,13 @@ open fun checkAndCompletePickOrderByConsoCode(consoCode: String): MessageRespons AND ( NOT EXISTS ( SELECT 1 - FROM fpsmsdb.stock_out_line sol_all_complete + FROM stock_out_line sol_all_complete WHERE sol_all_complete.pickOrderLineId = pol.id AND sol_all_complete.deleted = false ) OR EXISTS ( SELECT 1 - FROM fpsmsdb.stock_out_line sol_incomplete + FROM stock_out_line sol_incomplete WHERE sol_incomplete.pickOrderLineId = pol.id AND sol_incomplete.deleted = false AND sol_incomplete.status NOT IN ('completed', 'COMPLETE') @@ -2855,7 +2855,7 @@ open fun checkAndCompletePickOrderByConsoCode(consoCode: String): MessageRespons -- Calculate total picked quantity by ALL pick orders for this lot COALESCE(( SELECT SUM(sol_all.qty) - FROM fpsmsdb.stock_out_line sol_all + FROM stock_out_line sol_all WHERE sol_all.inventoryLotLineId = ill.id AND sol_all.deleted = false AND sol_all.status IN ('pending', 'checked', 'partially_completed', 'completed') @@ -2893,15 +2893,15 @@ open fun checkAndCompletePickOrderByConsoCode(consoCode: String): MessageRespons ELSE 'pending' END as processingStatus - FROM fpsmsdb.pick_order po - JOIN fpsmsdb.pick_order_line pol ON pol.poId = po.id - JOIN fpsmsdb.items i ON i.id = pol.itemId - LEFT JOIN fpsmsdb.uom_conversion uc ON uc.id = pol.uomId - LEFT JOIN fpsmsdb.suggested_pick_lot spl ON pol.id = spl.pickOrderLineId - LEFT JOIN fpsmsdb.inventory_lot_line ill ON spl.suggestedLotLineId = ill.id - LEFT JOIN fpsmsdb.inventory_lot il ON il.id = ill.inventoryLotId - LEFT JOIN fpsmsdb.warehouse w ON w.id = ill.warehouseId - LEFT JOIN fpsmsdb.stock_out_line sol ON sol.pickOrderLineId = pol.id AND sol.inventoryLotLineId = ill.id AND sol.deleted = false + FROM pick_order po + JOIN pick_order_line pol ON pol.poId = po.id + JOIN items i ON i.id = pol.itemId + LEFT JOIN uom_conversion uc ON uc.id = pol.uomId + LEFT JOIN suggested_pick_lot spl ON pol.id = spl.pickOrderLineId + LEFT JOIN inventory_lot_line ill ON spl.suggestedLotLineId = ill.id + LEFT JOIN inventory_lot il ON il.id = ill.inventoryLotId + LEFT JOIN warehouse w ON w.id = ill.warehouseId + LEFT JOIN stock_out_line sol ON sol.pickOrderLineId = pol.id AND sol.inventoryLotLineId = ill.id AND sol.deleted = false WHERE po.deleted = false AND po.id IN ($pickOrderIdsStr) AND pol.deleted = false @@ -3494,7 +3494,7 @@ open fun checkAndCompletePickOrderByConsoCode(consoCode: String): MessageRespons -- Calculate total picked quantity by ALL pick orders for this lot COALESCE(( SELECT SUM(sol_all.qty) - FROM fpsmsdb.stock_out_line sol_all + FROM stock_out_line sol_all WHERE sol_all.inventoryLotLineId = ill.id AND sol_all.deleted = false AND sol_all.status IN ('pending', 'checked', 'partially_completed', 'completed') @@ -3532,15 +3532,15 @@ open fun checkAndCompletePickOrderByConsoCode(consoCode: String): MessageRespons ELSE 'pending' END as processingStatus - FROM fpsmsdb.pick_order po -JOIN fpsmsdb.pick_order_line pol ON pol.poId = po.id -JOIN fpsmsdb.items i ON i.id = pol.itemId -LEFT JOIN fpsmsdb.uom_conversion uc ON uc.id = pol.uomId -LEFT JOIN fpsmsdb.suggested_pick_lot spl ON pol.id = spl.pickOrderLineId -LEFT JOIN fpsmsdb.inventory_lot_line ill ON spl.suggestedLotLineId = ill.id -LEFT JOIN fpsmsdb.inventory_lot il ON il.id = ill.inventoryLotId -LEFT JOIN fpsmsdb.warehouse w ON w.id = ill.warehouseId -LEFT JOIN fpsmsdb.stock_out_line sol ON sol.pickOrderLineId = pol.id AND sol.inventoryLotLineId = ill.id AND sol.deleted = false + FROM pick_order po +JOIN pick_order_line pol ON pol.poId = po.id +JOIN items i ON i.id = pol.itemId +LEFT JOIN uom_conversion uc ON uc.id = pol.uomId +LEFT JOIN suggested_pick_lot spl ON pol.id = spl.pickOrderLineId +LEFT JOIN inventory_lot_line ill ON spl.suggestedLotLineId = ill.id +LEFT JOIN inventory_lot il ON il.id = ill.inventoryLotId +LEFT JOIN warehouse w ON w.id = ill.warehouseId +LEFT JOIN stock_out_line sol ON sol.pickOrderLineId = pol.id AND sol.inventoryLotLineId = ill.id AND sol.deleted = false WHERE po.deleted = false AND po.id IN ($pickOrderIdsStr) AND pol.deleted = false @@ -3662,15 +3662,15 @@ open fun getAllPickOrderLotsWithDetailsHierarchical(userId: Long): Map ll.lotLineId -- lots 用(保留原逻辑) - LEFT JOIN fpsmsdb.stock_out_line sol + LEFT JOIN stock_out_line sol ON sol.pickOrderLineId = pol.id AND ( (sol.inventoryLotLineId = ll.lotLineId) OR (sol.inventoryLotLineId IS NULL AND ll.lotLineId IS NULL) ) AND sol.deleted = false - LEFT JOIN fpsmsdb.inventory_lot_line ill ON ill.id = ll.lotLineId AND ill.deleted = false - LEFT JOIN fpsmsdb.inventory_lot il ON il.id = ill.inventoryLotId AND il.deleted = false - LEFT JOIN fpsmsdb.warehouse w ON w.id = ill.warehouseId + LEFT JOIN inventory_lot_line ill ON ill.id = ll.lotLineId AND ill.deleted = false + LEFT JOIN inventory_lot il ON il.id = ill.inventoryLotId AND il.deleted = false + LEFT JOIN warehouse w ON w.id = ill.warehouseId WHERE po.id = :pickOrderId AND po.deleted = false @@ -4040,15 +4040,15 @@ open fun getAllPickOrderLotsWithDetailsHierarchical(userId: Long): Map ll.lotLineId - LEFT JOIN fpsmsdb.stock_out_line sol + LEFT JOIN stock_out_line sol ON sol.pickOrderLineId = pol.id AND ( (sol.inventoryLotLineId = ll.lotLineId) OR (sol.inventoryLotLineId IS NULL AND ll.lotLineId IS NULL) ) AND sol.deleted = false - LEFT JOIN fpsmsdb.inventory_lot_line ill ON ill.id = ll.lotLineId AND ill.deleted = false - LEFT JOIN fpsmsdb.inventory_lot il ON il.id = ill.inventoryLotId AND il.deleted = false - LEFT JOIN fpsmsdb.warehouse w ON w.id = ill.warehouseId + LEFT JOIN inventory_lot_line ill ON ill.id = ll.lotLineId AND ill.deleted = false + LEFT JOIN inventory_lot il ON il.id = ill.inventoryLotId AND il.deleted = false + LEFT JOIN warehouse w ON w.id = ill.warehouseId WHERE po.id IN (:pickOrderIds) AND po.deleted = false ORDER BY diff --git a/src/main/java/com/ffii/fpsms/modules/pickOrder/service/PickOrderWorkbenchService.kt b/src/main/java/com/ffii/fpsms/modules/pickOrder/service/PickOrderWorkbenchService.kt index 6cc90c60..2f6783b6 100644 --- a/src/main/java/com/ffii/fpsms/modules/pickOrder/service/PickOrderWorkbenchService.kt +++ b/src/main/java/com/ffii/fpsms/modules/pickOrder/service/PickOrderWorkbenchService.kt @@ -184,16 +184,16 @@ open class PickOrderWorkbenchService( ill.status AS lotStatus, spl.suggestedPickLotId AS suggestedPickLotId, COALESCE(spl.splQty, sol.qty, 0) AS suggestedQty - FROM fpsmsdb.stock_out_line sol - LEFT JOIN fpsmsdb.inventory_lot_line ill ON ill.id = sol.inventoryLotLineId - LEFT JOIN fpsmsdb.inventory_lot il ON il.id = ill.inventoryLotId - LEFT JOIN fpsmsdb.warehouse w ON w.id = ill.warehouseId + FROM stock_out_line sol + LEFT JOIN inventory_lot_line ill ON ill.id = sol.inventoryLotLineId + LEFT JOIN inventory_lot il ON il.id = ill.inventoryLotId + LEFT JOIN warehouse w ON w.id = ill.warehouseId LEFT JOIN ( SELECT s.stockOutLineId AS solId, MAX(s.id) AS suggestedPickLotId, SUM(COALESCE(s.qty, 0)) AS splQty - FROM fpsmsdb.suggested_pick_lot s + FROM suggested_pick_lot s WHERE s.pickOrderLineId = :pickOrderLineId AND s.deleted = false AND s.stockOutLineId IS NOT NULL @@ -303,15 +303,15 @@ open class PickOrderWorkbenchService( sol.stockOutLineId AS stockOutLineId, sol.stockOutLineStatus AS stockOutLineStatus, COALESCE(sol.stockOutLineQty,0) AS stockOutLineQty - FROM fpsmsdb.inventory_lot_line ill - LEFT JOIN fpsmsdb.inventory_lot il ON il.id = ill.inventoryLotId - LEFT JOIN fpsmsdb.warehouse w ON w.id = ill.warehouseId + FROM inventory_lot_line ill + LEFT JOIN inventory_lot il ON il.id = ill.inventoryLotId + LEFT JOIN warehouse w ON w.id = ill.warehouseId LEFT JOIN ( SELECT COALESCE(s.actualPickLotLineId, s.suggestedLotLineId) AS lotLineId, MAX(s.id) AS suggestedPickLotId, SUM(COALESCE(s.qty,0)) AS requiredQty - FROM fpsmsdb.suggested_pick_lot s + FROM suggested_pick_lot s WHERE s.pickOrderLineId = :pickOrderLineId AND s.deleted = false AND COALESCE(s.actualPickLotLineId, s.suggestedLotLineId) IS NOT NULL @@ -323,7 +323,7 @@ open class PickOrderWorkbenchService( MAX(so.id) AS stockOutLineId, SUBSTRING_INDEX(GROUP_CONCAT(so.status ORDER BY so.id DESC), ',', 1) AS stockOutLineStatus, SUM(COALESCE(so.qty,0)) AS stockOutLineQty - FROM fpsmsdb.stock_out_line so + FROM stock_out_line so WHERE so.pickOrderLineId = :pickOrderLineId AND so.deleted = false AND so.inventoryLotLineId IS NOT NULL @@ -331,13 +331,13 @@ open class PickOrderWorkbenchService( ) sol ON sol.lotLineId = ill.id WHERE ill.id IN ( SELECT DISTINCT COALESCE(s.actualPickLotLineId, s.suggestedLotLineId) - FROM fpsmsdb.suggested_pick_lot s + FROM suggested_pick_lot s WHERE s.pickOrderLineId = :pickOrderLineId AND s.deleted = false AND COALESCE(s.actualPickLotLineId, s.suggestedLotLineId) IS NOT NULL UNION SELECT DISTINCT so.inventoryLotLineId - FROM fpsmsdb.stock_out_line so + FROM stock_out_line so WHERE so.pickOrderLineId = :pickOrderLineId AND so.deleted = false AND so.inventoryLotLineId IS NOT NULL @@ -389,7 +389,7 @@ open class PickOrderWorkbenchService( so.id AS stockOutLineId, so.status AS stockOutLineStatus, COALESCE(so.qty,0) AS stockOutLineQty - FROM fpsmsdb.stock_out_line so + FROM stock_out_line so WHERE so.pickOrderLineId = :pickOrderLineId AND so.deleted = false AND so.inventoryLotLineId IS NULL diff --git a/src/main/java/com/ffii/fpsms/modules/purchaseOrder/web/PurchaseOrderController.kt b/src/main/java/com/ffii/fpsms/modules/purchaseOrder/web/PurchaseOrderController.kt index 6e475304..d2ea361b 100644 --- a/src/main/java/com/ffii/fpsms/modules/purchaseOrder/web/PurchaseOrderController.kt +++ b/src/main/java/com/ffii/fpsms/modules/purchaseOrder/web/PurchaseOrderController.kt @@ -26,6 +26,7 @@ import org.springframework.web.bind.annotation.* import java.io.File import com.ffii.fpsms.modules.purchaseOrder.web.model.PurchaseOrderSummary import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Value @RestController @RequestMapping("/po") @@ -33,6 +34,7 @@ class PurchaseOrderController( private val purchaseOrderService: PurchaseOrderService, private val stockInLineService: StockInLineService, private val m18PurchaseOrderService: M18PurchaseOrderService, + @Value("\${fpsms.demo-mode:false}") private val demoMode: Boolean, ) { private val logger = LoggerFactory.getLogger(PurchaseOrderController::class.java) @GetMapping("/list") @@ -59,7 +61,7 @@ class PurchaseOrderController( val pageNum = request.getParameter("pageNum")?.toIntOrNull()?.coerceAtLeast(1) ?: 1 val rawCode = request.getParameter("code")?.trim() val refreshFromM18 = request.getParameter("refreshFromM18")?.equals("true", ignoreCase = true) == true - if (refreshFromM18 && M18PurchaseOrderService.isStockInLookupPoCode(rawCode)) { + if (!demoMode && refreshFromM18 && M18PurchaseOrderService.isStockInLookupPoCode(rawCode)) { try { logger.info("Stock-in /po/list: M18 refresh for code={}", rawCode) val outcome = m18PurchaseOrderService.refreshForStockInLookup(rawCode!!) diff --git a/src/main/java/com/ffii/fpsms/modules/stock/entity/StockInLineRepository.kt b/src/main/java/com/ffii/fpsms/modules/stock/entity/StockInLineRepository.kt index 98454337..764521b0 100644 --- a/src/main/java/com/ffii/fpsms/modules/stock/entity/StockInLineRepository.kt +++ b/src/main/java/com/ffii/fpsms/modules/stock/entity/StockInLineRepository.kt @@ -173,12 +173,12 @@ fun findLatestLotNoByPrefix(@Param("prefix") prefix: String): String? @Query( """ SELECT sil.jobOrderId AS jobOrderId, sil.lotNo AS lotNo - FROM fpsmsdb.stock_in_line sil + FROM stock_in_line sil WHERE sil.deleted = 0 AND sil.jobOrderId IN (:jobOrderIds) AND sil.id IN ( SELECT MIN(s2.id) - FROM fpsmsdb.stock_in_line s2 + FROM stock_in_line s2 WHERE s2.deleted = 0 AND s2.jobOrderId IN (:jobOrderIds) GROUP BY s2.jobOrderId diff --git a/src/main/resources/application-db-demo.yml b/src/main/resources/application-db-demo.yml new file mode 100644 index 00000000..a04761c1 --- /dev/null +++ b/src/main/resources/application-db-demo.yml @@ -0,0 +1,23 @@ +spring: + datasource: + jdbc-url: jdbc:mysql://127.0.0.1:3306/fpsms_demo?useUnicode=true&characterEncoding=UTF8&serverTimezone=GMT%2B8 + # Login below is granted on fpsms_demo only. It must not be root and must not have any grant on fpsmsdb. + username: fpsms_demo + password: FpsmsDemoOnly2026 + +# Demo sandbox only. Do not point this profile at fpsmsdb. +fpsms: + demo-mode: true + monitoring: + enabled: false + +scheduler: + m18Sync: + enabled: false + m18Grn: + createEnabled: false + sync-alert: + enabled: false + email: + enabled: false + to-addresses: "" diff --git a/src/main/resources/demo/demo-coverage.sql b/src/main/resources/demo/demo-coverage.sql new file mode 100644 index 00000000..9402d914 --- /dev/null +++ b/src/main/resources/demo/demo-coverage.sql @@ -0,0 +1,484 @@ +-- Fictional coverage data for fpsms_demo. Safe to run again. + +SET @user := (SELECT id FROM user WHERE username = 'demo' LIMIT 1); +SET @kg := (SELECT id FROM uom_conversion WHERE code = 'KG' LIMIT 1); +SET @pcs := (SELECT id FROM uom_conversion WHERE code = 'PCS' LIMIT 1); +SET @cur := (SELECT id FROM currency WHERE code = 'HKD' LIMIT 1); +SET @sup := (SELECT id FROM shop WHERE code = 'DEMO-SUP' LIMIT 1); +SET @shp := (SELECT id FROM shop WHERE code = 'DEMO-SHP' LIMIT 1); +SET @log := (SELECT id FROM m18_data_log WHERE refType = 'DEMO' LIMIT 1); +SET @whA := (SELECT id FROM warehouse WHERE code = 'DEMO-A' LIMIT 1); +SET @whB := (SELECT id FROM warehouse WHERE code = 'DEMO-B' LIMIT 1); +SET @flour := (SELECT id FROM items WHERE code = 'DEMO-RM-01' LIMIT 1); +SET @milk := (SELECT id FROM items WHERE code = 'DEMO-RM-02' LIMIT 1); +SET @loaf := (SELECT id FROM items WHERE code = 'DEMO-FG-01' LIMIT 1); +SET @bun := (SELECT id FROM items WHERE code = 'DEMO-FG-02' LIMIT 1); +SET @po3 := (SELECT id FROM purchase_order WHERE code = 'DEMO-PO-003' LIMIT 1); +SET @do3 := (SELECT id FROM delivery_order WHERE code = 'DEMO-DO-003' LIMIT 1); +SET @pkDo3 := (SELECT id FROM pick_order WHERE code = 'DEMO-PK-DO3' LIMIT 1); +SET @pkJo2 := (SELECT id FROM pick_order WHERE code = 'DEMO-PK-JO2' LIMIT 1); +SET @bom := (SELECT id FROM bom WHERE code = 'DEMO-BOM-01' LIMIT 1); + +UPDATE warehouse +SET store_id = '2F', warehouse = 'W201', area = '#A', slot = '01', stockTakeSection = 'A', stockTakeSectionDescription = '甲倉區' +WHERE code = 'DEMO-A'; + +UPDATE warehouse +SET store_id = '4F', warehouse = 'W202', area = '#B', slot = '02', stockTakeSection = 'B', stockTakeSectionDescription = '乙倉區' +WHERE code = 'DEMO-B'; + +INSERT INTO settings (name, value, category, type) +SELECT 'DO.floor.suppliers.2F', 'DEMO-SUP', 'DO', 'csv' +WHERE NOT EXISTS (SELECT 1 FROM settings WHERE name = 'DO.floor.suppliers.2F'); + +INSERT INTO settings (name, value, category, type) +SELECT 'DO.floor.suppliers.4F', 'DEMO-SUP', 'DO', 'csv' +WHERE NOT EXISTS (SELECT 1 FROM settings WHERE name = 'DO.floor.suppliers.4F'); + +INSERT INTO item_category (code, parent, sub, temperature) +SELECT 'DEMO-CAT-BAKE', '食品', '烘焙', '常溫' +WHERE NOT EXISTS (SELECT 1 FROM item_category WHERE code = 'DEMO-CAT-BAKE'); + +INSERT INTO item_category (code, parent, sub, temperature) +SELECT 'DEMO-CAT-DAIRY', '食品', '乳品', '冷藏' +WHERE NOT EXISTS (SELECT 1 FROM item_category WHERE code = 'DEMO-CAT-DAIRY'); + +SET @catBake := (SELECT id FROM item_category WHERE code = 'DEMO-CAT-BAKE' LIMIT 1); +SET @catDairy := (SELECT id FROM item_category WHERE code = 'DEMO-CAT-DAIRY' LIMIT 1); + +UPDATE items SET categoryId = @catBake WHERE code IN ('DEMO-RM-01', 'DEMO-SF-01', 'DEMO-FG-01', 'DEMO-FG-02') AND categoryId IS NULL; +UPDATE items SET categoryId = @catDairy WHERE code = 'DEMO-RM-02' AND categoryId IS NULL; + +INSERT INTO shop (code, name, type, contactName, contactNo, addr1, district, m18Id, m18LastModifyDate) +SELECT 'DEMO-SUP2', '東岸糖廠', 'supplier', '陳小姐', '21110002', '示範大道 8 號', '九龍', 910031, NOW() +WHERE NOT EXISTS (SELECT 1 FROM shop WHERE code = 'DEMO-SUP2'); + +INSERT INTO shop (code, name, type, contactName, contactNo, addr1, district, m18Id, m18LastModifyDate) +SELECT 'DEMO-SHP2', '南風麵包店', 'shop', '林先生', '51110002', '海旁街 18 號', '港島', 910032, NOW() +WHERE NOT EXISTS (SELECT 1 FROM shop WHERE code = 'DEMO-SHP2'); + +INSERT INTO warehouse (code, name, description, capacity, `order`, warehouse, area, slot, store_id, stockTakeSection, stockTakeSectionDescription) +SELECT 'DEMO-C', '丙倉', '示範貨架丙', 800, '3', 'W203', '#C', '03', '2F', 'C', '丙倉區' +WHERE NOT EXISTS (SELECT 1 FROM warehouse WHERE code = 'DEMO-C'); + +INSERT INTO user (username, password, locked, name, title, staffNo, lotusNotesUser) +SELECT 'demo.stock', u.password, 0, '示範倉務', '倉務', 'demo.stock', 0 +FROM user u +WHERE u.username = 'demo' +AND NOT EXISTS (SELECT 1 FROM user x WHERE x.username = 'demo.stock'); + +INSERT INTO user (username, password, locked, name, title, staffNo, lotusNotesUser) +SELECT 'demo.prod', u.password, 0, '示範出品', '出品', 'demo.prod', 0 +FROM user u +WHERE u.username = 'demo' +AND NOT EXISTS (SELECT 1 FROM user x WHERE x.username = 'demo.prod'); + +INSERT INTO user_authority (userId, authId) +SELECT u.id, a.id +FROM user u +JOIN authority a ON a.authority = 'STOCK' +WHERE u.username = 'demo.stock' +AND NOT EXISTS ( + SELECT 1 FROM user_authority ua WHERE ua.userId = u.id AND ua.authId = a.id +); + +INSERT INTO user_authority (userId, authId) +SELECT u.id, a.id +FROM user u +JOIN authority a ON a.authority IN ('PROD', 'PACK') +WHERE u.username = 'demo.prod' +AND NOT EXISTS ( + SELECT 1 FROM user_authority ua WHERE ua.userId = u.id AND ua.authId = a.id +); + +INSERT INTO equipment (code, name, description) +SELECT 'DEMO-EQ-01', '示範烤箱', '示範用熱風烤箱' +WHERE NOT EXISTS (SELECT 1 FROM equipment WHERE code = 'DEMO-EQ-01'); + +INSERT INTO equipment_detail (code, name, description, equipmentCode) +SELECT 'DEMO-EQD-01', '烤箱一號', '二樓示範烤箱', 'DEMO-EQ-01' +WHERE NOT EXISTS (SELECT 1 FROM equipment_detail WHERE code = 'DEMO-EQD-01'); + +INSERT INTO truck (TruckLanceCode, DepartureTime, shopId, ShopName, ShopCode, LoadingSequence, Store_id) +SELECT 'DEMO-AM', '08:00:00', @shp, '海港咖啡店', 'DEMO-SHP', 1, '2F' +WHERE NOT EXISTS (SELECT 1 FROM truck WHERE TruckLanceCode = 'DEMO-AM'); + +INSERT INTO truck (TruckLanceCode, DepartureTime, shopId, ShopName, ShopCode, LoadingSequence, Store_id) +SELECT 'DEMO-PM', '14:30:00', @shp, '海港咖啡店', 'DEMO-SHP', 2, '4F' +WHERE NOT EXISTS (SELECT 1 FROM truck WHERE TruckLanceCode = 'DEMO-PM'); + +INSERT INTO qc_category (code, name, isDefault) +SELECT 'DEMO-QC', '示範品質檢查', 1 +WHERE NOT EXISTS (SELECT 1 FROM qc_category WHERE code = 'DEMO-QC'); + +SET @qcCat := (SELECT id FROM qc_category WHERE code = 'DEMO-QC' LIMIT 1); + +INSERT INTO qc_item (code, name, description) +SELECT 'DEMO-QC-TEMP', '溫度', '入倉溫度' +WHERE NOT EXISTS (SELECT 1 FROM qc_item WHERE code = 'DEMO-QC-TEMP'); + +INSERT INTO qc_item (code, name, description) +SELECT 'DEMO-QC-LOOK', '外觀', '包裝與外觀' +WHERE NOT EXISTS (SELECT 1 FROM qc_item WHERE code = 'DEMO-QC-LOOK'); + +SET @qcTemp := (SELECT id FROM qc_item WHERE code = 'DEMO-QC-TEMP' LIMIT 1); +SET @qcLook := (SELECT id FROM qc_item WHERE code = 'DEMO-QC-LOOK' LIMIT 1); + +INSERT INTO qc_item_category (qcItemId, qcCategoryId, `order`, description) +SELECT @qcTemp, @qcCat, 1, '溫度須低於 8 度' +WHERE NOT EXISTS ( + SELECT 1 FROM qc_item_category WHERE qcItemId = @qcTemp AND qcCategoryId = @qcCat +); + +INSERT INTO qc_item_category (qcItemId, qcCategoryId, `order`, description) +SELECT @qcLook, @qcCat, 2, '包裝完整' +WHERE NOT EXISTS ( + SELECT 1 FROM qc_item_category WHERE qcItemId = @qcLook AND qcCategoryId = @qcCat +); + +INSERT INTO items_qc_category_mapping (itemId, qcCategoryId, type) +SELECT @flour, @qcCat, 'IQC' +WHERE NOT EXISTS ( + SELECT 1 FROM items_qc_category_mapping WHERE itemId = @flour AND type = 'IQC' +); + +INSERT INTO items_qc_category_mapping (itemId, qcCategoryId, type) +SELECT @loaf, @qcCat, 'EPQC' +WHERE NOT EXISTS ( + SELECT 1 FROM items_qc_category_mapping WHERE itemId = @loaf AND type = 'EPQC' +); + +INSERT INTO items (code, name, type, description, categoryId, m18Id, m18LastModifyDate) +SELECT 'DEMO-MAT-01', '高筋麵粉', 'MAT', '報告用材料', @catBake, 910301, NOW() +WHERE NOT EXISTS (SELECT 1 FROM items WHERE code = 'DEMO-MAT-01'); + +INSERT INTO items (code, name, type, description, categoryId, m18Id, m18LastModifyDate) +SELECT 'DEMO-WIP-01', '發酵麵團', 'WIP', '報告用半成品', @catBake, 910302, NOW() +WHERE NOT EXISTS (SELECT 1 FROM items WHERE code = 'DEMO-WIP-01'); + +INSERT INTO items (code, name, type, description, categoryId, m18Id, m18LastModifyDate) +SELECT 'DEMO-FG-03', '牛油包', 'FG', '報告用成品', @catBake, 910303, NOW() +WHERE NOT EXISTS (SELECT 1 FROM items WHERE code = 'DEMO-FG-03'); + +INSERT INTO items (code, name, type, description, categoryId, m18Id, m18LastModifyDate) +SELECT 'DEMO-NM-01', '包裝袋', 'NM', '報告用非耗材', @catBake, 910304, NOW() +WHERE NOT EXISTS (SELECT 1 FROM items WHERE code = 'DEMO-NM-01'); + +INSERT INTO items (code, name, type, description, categoryId, m18Id, m18LastModifyDate) +SELECT 'DEMO-CMB-01', '早餐套餐', 'CMB', '報告用組合', @catBake, 910305, NOW() +WHERE NOT EXISTS (SELECT 1 FROM items WHERE code = 'DEMO-CMB-01'); + +SET @mat := (SELECT id FROM items WHERE code = 'DEMO-MAT-01' LIMIT 1); +SET @wip := (SELECT id FROM items WHERE code = 'DEMO-WIP-01' LIMIT 1); +SET @fg3 := (SELECT id FROM items WHERE code = 'DEMO-FG-03' LIMIT 1); +SET @nm := (SELECT id FROM items WHERE code = 'DEMO-NM-01' LIMIT 1); +SET @cmb := (SELECT id FROM items WHERE code = 'DEMO-CMB-01' LIMIT 1); + +INSERT INTO item_uom (uomId, itemId, baseUnit, stockUnit, pickingUnit, salesUnit, purchaseUnit, ratioN, ratioD, price, currencyId, m18Id, m18LastModifyDate) +SELECT @kg, i.id, 1, 1, 1, 1, 1, 1, 1, 6.50, @cur, 910400 + i.id, NOW() +FROM items i +WHERE i.code IN ('DEMO-MAT-01', 'DEMO-WIP-01', 'DEMO-NM-01') +AND NOT EXISTS (SELECT 1 FROM item_uom iu WHERE iu.itemId = i.id AND iu.stockUnit = 1 AND iu.deleted = 0); + +INSERT INTO item_uom (uomId, itemId, baseUnit, stockUnit, pickingUnit, salesUnit, purchaseUnit, ratioN, ratioD, price, currencyId, m18Id, m18LastModifyDate) +SELECT @pcs, i.id, 1, 1, 1, 1, 1, 1, 1, 12.00, @cur, 910500 + i.id, NOW() +FROM items i +WHERE i.code IN ('DEMO-FG-03', 'DEMO-CMB-01') +AND NOT EXISTS (SELECT 1 FROM item_uom iu WHERE iu.itemId = i.id AND iu.stockUnit = 1 AND iu.deleted = 0); + +INSERT INTO bom (code, name, description, itemId, outputQty, outputQtyUom, type, status, m18Id, m18LastModifyDate) +SELECT 'DEMO-FG-01', '鄉村麵包', 'FG', @loaf, 10, 'PCS', 'FG', 'active', 910211, NOW() +WHERE NOT EXISTS (SELECT 1 FROM bom WHERE code = 'DEMO-FG-01'); + +INSERT INTO bom (code, name, description, itemId, outputQty, outputQtyUom, type, status, m18Id, m18LastModifyDate) +SELECT 'DEMO-FG-03', '牛油包', 'FG', @fg3, 12, 'PCS', 'FG', 'active', 910212, NOW() +WHERE NOT EXISTS (SELECT 1 FROM bom WHERE code = 'DEMO-FG-03'); + +INSERT INTO bom (code, name, description, itemId, outputQty, outputQtyUom, type, status, m18Id, m18LastModifyDate) +SELECT 'DEMO-WIP-01', '發酵麵團', 'WIP', @wip, 8, 'KG', 'WIP', 'active', 910213, NOW() +WHERE NOT EXISTS (SELECT 1 FROM bom WHERE code = 'DEMO-WIP-01'); + +UPDATE stock_in_line +SET dnNo = 'DEMO-DN-FL1', productionDate = DATE_SUB(NOW(), INTERVAL 3 DAY), productLotNo = 'PLOT-FL1' +WHERE lotNo = 'DEMO-LOT-FL1'; + +UPDATE stock_in_line +SET dnNo = 'DEMO-DN-MK1', productionDate = DATE_SUB(NOW(), INTERVAL 3 DAY), productLotNo = 'PLOT-MK1' +WHERE lotNo = 'DEMO-LOT-MK1'; + +UPDATE stock_in_line +SET dnNo = 'DEMO-DN-LF1', productionDate = DATE_SUB(NOW(), INTERVAL 2 DAY), productLotNo = 'PLOT-LF1' +WHERE lotNo = 'DEMO-LOT-LF1'; + +UPDATE stock_in_line +SET dnNo = 'DEMO-DN-LF2', productionDate = DATE_SUB(NOW(), INTERVAL 1 DAY) +WHERE lotNo = 'DEMO-LOT-LF2'; + +UPDATE purchase_order_line pol +JOIN items i ON i.id = pol.itemId +SET pol.up = CASE i.code WHEN 'DEMO-RM-01' THEN 8.50 WHEN 'DEMO-RM-02' THEN 15.00 ELSE pol.up END +WHERE pol.purchaseOrderId = @po3; + +INSERT INTO m18_goods_receipt_note_log (m18_record_id, grn_code, stock_in_line_id, purchase_order_line_id, purchase_order_id, po_code, status, message) +SELECT 910501, 'DEMO-GRN-001', sil.id, sil.purchaseOrderLineId, sil.purchaseOrderId, 'DEMO-PO-003', 1, '示範入倉' +FROM stock_in_line sil +WHERE sil.lotNo = 'DEMO-LOT-FL1' +AND NOT EXISTS (SELECT 1 FROM m18_goods_receipt_note_log WHERE grn_code = 'DEMO-GRN-001'); + +INSERT INTO m18_goods_receipt_note_log (m18_record_id, grn_code, stock_in_line_id, purchase_order_line_id, purchase_order_id, po_code, status, message) +SELECT 910502, 'DEMO-GRN-002', sil.id, sil.purchaseOrderLineId, sil.purchaseOrderId, 'DEMO-PO-003', 1, '示範入倉' +FROM stock_in_line sil +WHERE sil.lotNo = 'DEMO-LOT-MK1' +AND NOT EXISTS (SELECT 1 FROM m18_goods_receipt_note_log WHERE grn_code = 'DEMO-GRN-002'); + +INSERT INTO qc_result (qcItemId, itemId, stockInLineId, failQty, type, remarks, qcPassed) +SELECT @qcLook, @flour, sil.id, 1.00, 'IQC', '包裝略有壓損', 0 +FROM stock_in_line sil +WHERE sil.lotNo = 'DEMO-LOT-FL1' +AND NOT EXISTS ( + SELECT 1 FROM qc_result qr WHERE qr.stockInLineId = sil.id AND qr.qcItemId = @qcLook +); + +INSERT INTO qc_result (qcItemId, itemId, stockInLineId, failQty, type, remarks, qcPassed) +SELECT @qcTemp, @loaf, sil.id, 0.00, 'EPQC', '溫度正常', 1 +FROM stock_in_line sil +WHERE sil.lotNo = 'DEMO-LOT-LF1' +AND NOT EXISTS ( + SELECT 1 FROM qc_result qr WHERE qr.stockInLineId = sil.id AND qr.qcItemId = @qcTemp +); + +INSERT INTO qc_result_measurement (qcResultId, qcType, measureType, value, unit) +SELECT qr.id, 'EPQC', '溫度', 6.50, 'C' +FROM qc_result qr +JOIN stock_in_line sil ON sil.id = qr.stockInLineId +WHERE sil.lotNo = 'DEMO-LOT-LF1' AND qr.qcItemId = @qcTemp +AND NOT EXISTS (SELECT 1 FROM qc_result_measurement m WHERE m.qcResultId = qr.id); + +INSERT INTO delivery_order_pick_order ( + shopId, storeId, requiredDeliveryDate, truckDepartureTime, truckLanceCode, + shopCode, shopName, loadingSequence, ticketNo, ticketReleaseTime, ticketCompleteDateTime, + ticketStatus, handledBy, handlerName, deliveryNoteCode +) +SELECT @shp, '2F', DATE_SUB(CURDATE(), INTERVAL 1 DAY), '08:00:00', 'DEMO-AM', + 'DEMO-SHP', '海港咖啡店', 1, 'DEMO-TK-003', DATE_SUB(NOW(), INTERVAL 1 DAY), DATE_SUB(NOW(), INTERVAL 20 HOUR), + 'completed', @user, '示範倉務', 'DEMO-DN-DO3' +WHERE NOT EXISTS (SELECT 1 FROM delivery_order_pick_order WHERE ticketNo = 'DEMO-TK-003'); + +SET @dopo := (SELECT id FROM delivery_order_pick_order WHERE ticketNo = 'DEMO-TK-003' LIMIT 1); + +UPDATE pick_order +SET deliveryOrderPickOrderId = @dopo +WHERE code = 'DEMO-PK-DO3' AND deliveryOrderPickOrderId IS NULL; + +INSERT INTO stock_out (type, deliveryOrderCode, completeDate, status, handlerId) +SELECT 'do', 'DEMO-DO-003', DATE_SUB(NOW(), INTERVAL 1 DAY), 'completed', @user +WHERE NOT EXISTS (SELECT 1 FROM stock_out WHERE deliveryOrderCode = 'DEMO-DO-003' AND type = 'do'); + +INSERT INTO stock_out (type, consoPickOrderCode, completeDate, status, handlerId) +SELECT 'job', 'DEMO-PK-JO2', DATE_SUB(NOW(), INTERVAL 2 HOUR), 'completed', @user +WHERE NOT EXISTS (SELECT 1 FROM stock_out WHERE consoPickOrderCode = 'DEMO-PK-JO2' AND type = 'job'); + +SET @soDo := (SELECT id FROM stock_out WHERE deliveryOrderCode = 'DEMO-DO-003' AND type = 'do' LIMIT 1); +SET @soJo := (SELECT id FROM stock_out WHERE consoPickOrderCode = 'DEMO-PK-JO2' AND type = 'job' LIMIT 1); +SET @polDo := (SELECT pol.id FROM pick_order_line pol WHERE pol.poId = @pkDo3 LIMIT 1); +SET @polJo := (SELECT pol.id FROM pick_order_line pol JOIN items i ON i.id = pol.itemId WHERE pol.poId = @pkJo2 AND i.code = 'DEMO-RM-01' LIMIT 1); +SET @illLoaf := ( + SELECT ill.id FROM inventory_lot_line ill + JOIN inventory_lot il ON il.id = ill.inventoryLotId + WHERE il.lotNo = 'DEMO-LOT-LF1' LIMIT 1 +); +SET @illFlour := ( + SELECT ill.id FROM inventory_lot_line ill + JOIN inventory_lot il ON il.id = ill.inventoryLotId + WHERE il.lotNo = 'DEMO-LOT-FL1' LIMIT 1 +); + +INSERT INTO stock_out_line (itemId, qty, stockOutId, pickOrderLineId, inventoryLotLineId, status, pickTime, handled_by, endTime) +SELECT @loaf, 6, @soDo, @polDo, @illLoaf, 'completed', DATE_SUB(NOW(), INTERVAL 1 DAY), @user, DATE_SUB(NOW(), INTERVAL 1 DAY) +WHERE NOT EXISTS (SELECT 1 FROM stock_out_line WHERE stockOutId = @soDo AND pickOrderLineId = @polDo); + +INSERT INTO stock_out_line (itemId, qty, stockOutId, pickOrderLineId, inventoryLotLineId, status, pickTime, handled_by, endTime) +SELECT @flour, 5, @soJo, @polJo, @illFlour, 'completed', DATE_SUB(NOW(), INTERVAL 2 HOUR), @user, DATE_SUB(NOW(), INTERVAL 2 HOUR) +WHERE NOT EXISTS (SELECT 1 FROM stock_out_line WHERE stockOutId = @soJo AND pickOrderLineId = @polJo); + +INSERT INTO do_pick_order_record ( + record_id, pick_order_id, do_order_id, shop_id, store_id, RequiredDeliveryDate, + TruckLanceCode, ShopCode, ShopName, delivery_order_code, deliveryNoteCode, pick_order_code, + ticket_no, ticket_release_time, ticketCompleteDateTime, ticket_status, handled_by, handler_name, deleted +) +SELECT 0, @pkDo3, @do3, @shp, '2F', DATE_SUB(CURDATE(), INTERVAL 1 DAY), + 'DEMO-AM', 'DEMO-SHP', '海港咖啡店', 'DEMO-DO-003', 'DEMO-DN-DO3', 'DEMO-PK-DO3', + 'DEMO-TK-003', DATE_SUB(NOW(), INTERVAL 1 DAY), DATE_SUB(NOW(), INTERVAL 20 HOUR), 'completed', @user, '示範倉務', 0 +WHERE NOT EXISTS (SELECT 1 FROM do_pick_order_record WHERE ticket_no = 'DEMO-TK-003'); + +UPDATE do_pick_order_record SET record_id = id WHERE ticket_no = 'DEMO-TK-003' AND record_id = 0; + +SET @dpor := (SELECT id FROM do_pick_order_record WHERE ticket_no = 'DEMO-TK-003' LIMIT 1); + +INSERT INTO do_pick_order_line_record ( + record_id, do_pick_order_id, pick_order_id, do_order_id, pick_order_code, delivery_order_code, status, deleted +) +SELECT @dpor, @dopo, @pkDo3, @do3, 'DEMO-PK-DO3', 'DEMO-DO-003', 'correct', 0 +WHERE @dpor IS NOT NULL +AND NOT EXISTS (SELECT 1 FROM do_pick_order_line_record WHERE record_id = @dpor AND do_order_id = @do3); + +INSERT INTO stock_ledger (date, inventoryId, itemId, itemCode, inQty, outQty, balance, type, modified) +SELECT DATE_SUB(CURDATE(), INTERVAL 20 DAY), inv.id, inv.itemId, i.code, inv.onHandQty, 0, inv.onHandQty, 'IN', DATE_SUB(NOW(), INTERVAL 20 DAY) +FROM inventory inv +JOIN items i ON i.id = inv.itemId +WHERE i.code IN ('DEMO-RM-01', 'DEMO-RM-02', 'DEMO-FG-01') +AND NOT EXISTS ( + SELECT 1 FROM stock_ledger sl WHERE sl.itemCode = i.code AND sl.type = 'IN' AND sl.deleted = 0 +); + +INSERT INTO stock_ledger (date, inventoryId, itemId, itemCode, inQty, outQty, balance, type, stockOutLineId, modified) +SELECT DATE_SUB(CURDATE(), INTERVAL 1 DAY), inv.id, @loaf, 'DEMO-FG-01', 0, 6, inv.onHandQty, 'DO', sol.id, DATE_SUB(NOW(), INTERVAL 1 DAY) +FROM inventory inv +JOIN stock_out_line sol ON sol.stockOutId = @soDo +WHERE inv.itemId = @loaf +AND NOT EXISTS (SELECT 1 FROM stock_ledger sl WHERE sl.itemCode = 'DEMO-FG-01' AND sl.type = 'DO' AND sl.deleted = 0); + +INSERT INTO stock_ledger (date, inventoryId, itemId, itemCode, inQty, outQty, balance, type, stockOutLineId, modified) +SELECT CURDATE(), inv.id, @flour, 'DEMO-RM-01', 0, 5, inv.onHandQty, 'JO', sol.id, DATE_SUB(NOW(), INTERVAL 2 HOUR) +FROM inventory inv +JOIN stock_out_line sol ON sol.stockOutId = @soJo +WHERE inv.itemId = @flour +AND NOT EXISTS (SELECT 1 FROM stock_ledger sl WHERE sl.itemCode = 'DEMO-RM-01' AND sl.type = 'JO' AND sl.deleted = 0); + +INSERT INTO stock_in (code, supplierId, shopId, m18DataLogId, orderDate, completeDate, status) +SELECT 'DEMO-SI-RPT', @sup, @shp, @log, DATE_SUB(NOW(), INTERVAL 40 DAY), DATE_SUB(NOW(), INTERVAL 39 DAY), 'completed' +WHERE NOT EXISTS (SELECT 1 FROM stock_in WHERE code = 'DEMO-SI-RPT'); + +SET @siRpt := (SELECT id FROM stock_in WHERE code = 'DEMO-SI-RPT' LIMIT 1); + +INSERT INTO stock_in_line (itemId, itemNo, stockInId, demandQty, acceptedQty, status, lotNo, expiryDate, receiptDate, productionDate, productLotNo, dnNo) +SELECT i.id, i.code, @siRpt, 20, 20, 'completed', CONCAT('DEMO-LOT-', i.code), DATE_ADD(CURDATE(), INTERVAL 90 DAY), DATE_SUB(NOW(), INTERVAL 39 DAY), DATE_SUB(NOW(), INTERVAL 40 DAY), CONCAT('PLOT-', i.code), CONCAT('DN-', i.code) +FROM items i +WHERE i.code IN ('DEMO-MAT-01', 'DEMO-WIP-01', 'DEMO-FG-03', 'DEMO-NM-01', 'DEMO-CMB-01') +AND NOT EXISTS (SELECT 1 FROM stock_in_line sil WHERE sil.itemId = i.id AND sil.stockInId = @siRpt); + +INSERT INTO inventory_lot (itemId, stockInLineId, expiryDate, lotNo, stockInDate, productionDate) +SELECT sil.itemId, sil.id, sil.expiryDate, sil.lotNo, sil.receiptDate, sil.productionDate +FROM stock_in_line sil +WHERE sil.stockInId = @siRpt +AND NOT EXISTS (SELECT 1 FROM inventory_lot il WHERE il.stockInLineId = sil.id); + +UPDATE stock_in_line sil +JOIN inventory_lot il ON il.stockInLineId = sil.id +SET sil.inventoryLotId = il.id +WHERE sil.stockInId = @siRpt AND sil.inventoryLotId IS NULL; + +INSERT INTO inventory_lot_line (inventoryLotId, warehouseId, stockItemUomId, inQty, outQty, holdQty, status) +SELECT il.id, @whA, iu.id, 20, 0, 0, 'available' +FROM inventory_lot il +JOIN stock_in_line sil ON sil.id = il.stockInLineId +JOIN item_uom iu ON iu.itemId = il.itemId AND iu.stockUnit = 1 AND iu.deleted = 0 +WHERE sil.stockInId = @siRpt +AND NOT EXISTS (SELECT 1 FROM inventory_lot_line ill WHERE ill.inventoryLotId = il.id); + +INSERT INTO stock_ledger (date, inventoryId, itemId, itemCode, inQty, outQty, balance, type, modified) +SELECT DATE_SUB(CURDATE(), INTERVAL 30 DAY), inv.id, inv.itemId, i.code, 20, 0, 20, 'IN', DATE_SUB(NOW(), INTERVAL 30 DAY) +FROM inventory inv +JOIN items i ON i.id = inv.itemId +WHERE i.code IN ('DEMO-MAT-01', 'DEMO-WIP-01', 'DEMO-FG-03', 'DEMO-NM-01', 'DEMO-CMB-01') +AND NOT EXISTS (SELECT 1 FROM stock_ledger sl WHERE sl.itemCode = i.code AND sl.type = 'IN' AND sl.deleted = 0); + +INSERT INTO stock_ledger (date, inventoryId, itemId, itemCode, inQty, outQty, balance, type, modified) +SELECT STR_TO_DATE(CONCAT(YEAR(CURDATE()), '-01-15'), '%Y-%m-%d'), inv.id, i.id, i.code, 0, 4, 16, 'OUT', STR_TO_DATE(CONCAT(YEAR(CURDATE()), '-01-15 10:00:00'), '%Y-%m-%d %H:%i:%s') +FROM items i +JOIN inventory inv ON inv.itemId = i.id +WHERE i.code IN ('DEMO-MAT-01', 'DEMO-WIP-01', 'DEMO-FG-03', 'DEMO-NM-01', 'DEMO-CMB-01') +AND NOT EXISTS (SELECT 1 FROM stock_ledger sl WHERE sl.itemCode = i.code AND sl.type = 'OUT' AND MONTH(sl.modified) = 1); + +INSERT INTO stock_ledger (date, inventoryId, itemId, itemCode, inQty, outQty, balance, type, modified) +SELECT STR_TO_DATE(CONCAT(YEAR(CURDATE()), '-04-15'), '%Y-%m-%d'), inv.id, i.id, i.code, 0, 6, 10, 'OUT', STR_TO_DATE(CONCAT(YEAR(CURDATE()), '-04-15 10:00:00'), '%Y-%m-%d %H:%i:%s') +FROM items i +JOIN inventory inv ON inv.itemId = i.id +WHERE i.code IN ('DEMO-MAT-01', 'DEMO-WIP-01', 'DEMO-FG-03', 'DEMO-NM-01', 'DEMO-CMB-01') +AND NOT EXISTS (SELECT 1 FROM stock_ledger sl WHERE sl.itemCode = i.code AND sl.type = 'OUT' AND MONTH(sl.modified) = 4); + +INSERT INTO stock_ledger (date, inventoryId, itemId, itemCode, inQty, outQty, balance, type, modified) +SELECT STR_TO_DATE(CONCAT(YEAR(CURDATE()), '-07-15'), '%Y-%m-%d'), inv.id, i.id, i.code, 0, 3, 7, 'OUT', STR_TO_DATE(CONCAT(YEAR(CURDATE()), '-07-15 10:00:00'), '%Y-%m-%d %H:%i:%s') +FROM items i +JOIN inventory inv ON inv.itemId = i.id +WHERE i.code IN ('DEMO-MAT-01', 'DEMO-WIP-01', 'DEMO-FG-03', 'DEMO-NM-01', 'DEMO-CMB-01') +AND NOT EXISTS (SELECT 1 FROM stock_ledger sl WHERE sl.itemCode = i.code AND sl.type = 'OUT' AND MONTH(sl.modified) = 7); + +INSERT INTO stock_ledger (date, inventoryId, itemId, itemCode, inQty, outQty, balance, type, modified) +SELECT STR_TO_DATE(CONCAT(YEAR(CURDATE()), '-09-10'), '%Y-%m-%d'), inv.id, i.id, i.code, 0, 5, 2, 'OUT', STR_TO_DATE(CONCAT(YEAR(CURDATE()), '-09-10 10:00:00'), '%Y-%m-%d %H:%i:%s') +FROM items i +JOIN inventory inv ON inv.itemId = i.id +WHERE i.code IN ('DEMO-MAT-01', 'DEMO-WIP-01', 'DEMO-FG-03', 'DEMO-NM-01', 'DEMO-CMB-01') +AND NOT EXISTS (SELECT 1 FROM stock_ledger sl WHERE sl.itemCode = i.code AND sl.type = 'OUT' AND MONTH(sl.modified) = 9); + +INSERT INTO stock_take (code, planStart, planEnd, actualStart, actualEnd, status, stockTakeRoundId, stockTakeRoundName, stockTakeSection) +SELECT 'DEMO-ST-001', DATE_SUB(NOW(), INTERVAL 2 DAY), DATE_SUB(NOW(), INTERVAL 1 DAY), DATE_SUB(NOW(), INTERVAL 2 DAY), DATE_SUB(NOW(), INTERVAL 1 DAY), 'completed', 9001, '示範盤點輪次', 'A' +WHERE NOT EXISTS (SELECT 1 FROM stock_take WHERE code = 'DEMO-ST-001'); + +SET @st := (SELECT id FROM stock_take WHERE code = 'DEMO-ST-001' LIMIT 1); +SET @lotFl := (SELECT id FROM inventory_lot WHERE lotNo = 'DEMO-LOT-FL1' LIMIT 1); +SET @lotMk := (SELECT id FROM inventory_lot WHERE lotNo = 'DEMO-LOT-MK1' LIMIT 1); +SET @lotLf := (SELECT id FROM inventory_lot WHERE lotNo = 'DEMO-LOT-LF1' LIMIT 1); + +INSERT INTO stocktakerecord ( + itemId, lotId, warehouseId, stockTakeId, stockTakeRoundId, stockTakerId, stockTakerName, + approverId, approverName, bookQty, approverStockTakeQty, varianceQty, uom, date, status, + approverTime, itemCode, itemName, lotNo, expiredDate +) +SELECT @flour, @lotFl, @whA, @st, 9001, @user, '示範倉務', @user, '示範管理員', 40, 38, -2, '公斤', DATE_SUB(CURDATE(), INTERVAL 1 DAY), 'completed', DATE_SUB(NOW(), INTERVAL 1 DAY), 'DEMO-RM-01', '普通麵粉', 'DEMO-LOT-FL1', DATE_ADD(CURDATE(), INTERVAL 180 DAY) +WHERE NOT EXISTS (SELECT 1 FROM stocktakerecord WHERE stockTakeId = @st AND lotId = @lotFl); + +INSERT INTO stocktakerecord ( + itemId, lotId, warehouseId, stockTakeId, stockTakeRoundId, stockTakerId, stockTakerName, + bookQty, approverStockTakeQty, varianceQty, uom, date, status, itemCode, itemName, lotNo +) +SELECT @milk, @lotMk, @whA, @st, 9001, @user, '示範倉務', 20, 20, 0, '公斤', DATE_SUB(CURDATE(), INTERVAL 1 DAY), 'completed', 'DEMO-RM-02', '鮮奶', 'DEMO-LOT-MK1' +WHERE NOT EXISTS (SELECT 1 FROM stocktakerecord WHERE stockTakeId = @st AND lotId = @lotMk); + +INSERT INTO stocktakerecord ( + itemId, lotId, warehouseId, stockTakeId, stockTakeRoundId, stockTakerId, stockTakerName, + bookQty, uom, date, status, itemCode, itemName, lotNo +) +SELECT @loaf, @lotLf, @whB, @st, 9001, @user, '示範倉務', 30, '件', CURDATE(), 'pending', 'DEMO-FG-01', '鄉村麵包', 'DEMO-LOT-LF1' +WHERE NOT EXISTS (SELECT 1 FROM stocktakerecord WHERE stockTakeId = @st AND lotId = @lotLf); + +INSERT INTO delivery_order (code, shopId, supplierId, currencyId, orderDate, estimatedArrivalDate, status, m18DataLogId, m18BeId, isExtra) +SELECT 'DEMO-DO-004', @shp, @sup, currencyId, NOW(), CURDATE(), 'pending', m18DataLogId, m18BeId, 0 +FROM delivery_order +WHERE code = 'DEMO-DO-001' +AND NOT EXISTS (SELECT 1 FROM delivery_order WHERE code = 'DEMO-DO-004'); + +SET @do4 := (SELECT id FROM delivery_order WHERE code = 'DEMO-DO-004' LIMIT 1); + +INSERT INTO delivery_order_line (deliveryOrderId, itemId, itemNo, uomId, uomIdM18, qty, qtyM18, status, m18DataLogId) +SELECT @do4, @loaf, 'DEMO-FG-01', @kg, @kg, 3, 3, 'pending', @log +WHERE @do4 IS NOT NULL +AND NOT EXISTS (SELECT 1 FROM delivery_order_line WHERE deliveryOrderId = @do4); + +SET @doLine3 := ( + SELECT dol.id FROM delivery_order_line dol WHERE dol.deliveryOrderId = @do3 LIMIT 1 +); + +INSERT INTO do_replenishment ( + code, deliveryDate, sourceDoId, sourceDoCode, sourceDoLineId, sourceM18DataLogId, sourceM18Id, + itemId, itemNo, itemName, replenishQty, uomId, shopId, shopCode, shopName, truckLaneCode, + status, reason, deliveryOrderPickOrderId, pickOrderLineId +) +SELECT 'DEMO-REPL-001', DATE_SUB(CURDATE(), INTERVAL 1 DAY), @do3, 'DEMO-DO-003', @doLine3, @log, 910601, + @loaf, 'DEMO-FG-01', '鄉村麵包', 2, @pcs, @shp, 'DEMO-SHP', '海港咖啡店', 'DEMO-AM', + 'completed', '示範補貨', @dopo, @polDo +WHERE NOT EXISTS (SELECT 1 FROM do_replenishment WHERE code = 'DEMO-REPL-001'); + +INSERT INTO m18_bom_shop_sync_log (bom_id, finished_item_code, m18_header_code, m18_api_status, synced, message) +SELECT @bom, 'DEMO-FG-01', 'DEMO-BOM-HDR', 1, 1, '示範同步成功' +WHERE NOT EXISTS (SELECT 1 FROM m18_bom_shop_sync_log WHERE finished_item_code = 'DEMO-FG-01' AND synced = 1); + +INSERT INTO m18_bom_shop_sync_log (bom_id, finished_item_code, m18_header_code, m18_api_status, synced, message) +SELECT b.id, 'DEMO-FG-03', 'DEMO-BOM-HDR-2', 0, 0, '示範同步失敗' +FROM bom b +WHERE b.code = 'DEMO-FG-03' +AND NOT EXISTS (SELECT 1 FROM m18_bom_shop_sync_log WHERE finished_item_code = 'DEMO-FG-03' AND synced = 0); + +INSERT INTO settings (name, value, category, type) +SELECT 'DEMO.coverage.v1', 'loaded', 'DEMO', 'marker' +WHERE NOT EXISTS (SELECT 1 FROM settings WHERE name = 'DEMO.coverage.v1'); diff --git a/src/main/resources/jasper/SemiFGProductionAnalysisReport.jrxml b/src/main/resources/jasper/SemiFGProductionAnalysisReport.jrxml index 67a25fe2..e581426a 100644 --- a/src/main/resources/jasper/SemiFGProductionAnalysisReport.jrxml +++ b/src/main/resources/jasper/SemiFGProductionAnalysisReport.jrxml @@ -33,7 +33,7 @@ - + diff --git a/src/main/resources/jasper/StockItemConsumptionTrendReport.jrxml b/src/main/resources/jasper/StockItemConsumptionTrendReport.jrxml index 97e2741c..1ca277dd 100644 --- a/src/main/resources/jasper/StockItemConsumptionTrendReport.jrxml +++ b/src/main/resources/jasper/StockItemConsumptionTrendReport.jrxml @@ -33,7 +33,7 @@ - +