| @@ -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. | | |||
| @@ -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 <T> demoBlocked(): Mono<T> = | |||
| Mono.error(IllegalStateException("M18 is disabled in demo mode")) | |||
| fun updateToken() : Mono<String>{ | |||
| 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<String, String>, | |||
| customHeaders: Map<String, String>? | |||
| ): Mono<T> { | |||
| if (demoMode) return demoBlocked() | |||
| println("ACCESS TOKEN: ${m18Config.ACCESS_TOKEN}") | |||
| return webClient.get() | |||
| @@ -300,6 +312,7 @@ open class ApiCallerService( | |||
| params: MultiValueMap<String, String>, | |||
| customHeaders: Map<String, String>? | |||
| ): Mono<T> { | |||
| if (demoMode) return demoBlocked() | |||
| println("ACCESS TOKEN: ${m18Config.ACCESS_TOKEN}") | |||
| return webClient.post() | |||
| @@ -344,6 +357,7 @@ open class ApiCallerService( | |||
| bodyJson: String, | |||
| customHeaders: Map<String, String>? = null | |||
| ): Mono<T> { | |||
| 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<String, String>? = null | |||
| ): Mono<T> { | |||
| 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<String, String>? = null | |||
| ): Mono<T> { | |||
| 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) } } | |||
| @@ -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" | |||
| } | |||
| } | |||
| @@ -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"}""") | |||
| } | |||
| } | |||
| @@ -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<Throwable>(ex) { it.cause } | |||
| .filterIsInstance<SQLException>() | |||
| .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") | |||
| } | |||
| } | |||
| @@ -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() | |||
| @@ -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') | |||
| @@ -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') | |||
| @@ -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 | |||
| @@ -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') | |||
| @@ -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), | |||
| @@ -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), | |||
| @@ -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(), | |||
| @@ -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), | |||
| @@ -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<Map<St | |||
| -- 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') | |||
| @@ -1510,28 +1510,28 @@ open fun getCompletedJobOrderPickOrderLotDetails(pickOrderId: Long): List<Map<St | |||
| jpo.match_by as match_by, | |||
| jpo.match_qty as match_qty | |||
| FROM fpsmsdb.pick_order po | |||
| JOIN fpsmsdb.job_order jo ON jo.id = po.joId | |||
| LEFT JOIN fpsmsdb.bom b ON b.id = jo.bomId | |||
| LEFT JOIN fpsmsdb.items fg ON fg.id = b.itemId | |||
| 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 ill.id = COALESCE(spl.actualPickLotLineId, spl.suggestedLotLineId) | |||
| LEFT JOIN fpsmsdb.inventory_lot il ON il.id = ill.inventoryLotId | |||
| LEFT JOIN fpsmsdb.warehouse w ON w.id = ill.warehouseId | |||
| FROM pick_order po | |||
| JOIN job_order jo ON jo.id = po.joId | |||
| LEFT JOIN bom b ON b.id = jo.bomId | |||
| LEFT JOIN items fg ON fg.id = b.itemId | |||
| 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 ill.id = COALESCE(spl.actualPickLotLineId, spl.suggestedLotLineId) | |||
| LEFT JOIN inventory_lot il ON il.id = ill.inventoryLotId | |||
| LEFT JOIN warehouse w ON w.id = ill.warehouseId | |||
| -- no-lot 情況:ill.id 為 null 時,要匹配 sol.inventoryLotLineId IS NULL | |||
| LEFT JOIN fpsmsdb.stock_out_line sol ON sol.pickOrderLineId = pol.id AND sol.deleted = false | |||
| LEFT JOIN stock_out_line sol ON sol.pickOrderLineId = pol.id AND sol.deleted = false | |||
| AND ( | |||
| sol.inventoryLotLineId = ill.id | |||
| OR (sol.inventoryLotLineId IS NULL AND ill.id IS NULL) | |||
| ) | |||
| LEFT JOIN fpsmsdb.jo_pick_order jpo ON jpo.pick_order_id = po.id AND jpo.item_id = pol.itemId | |||
| LEFT JOIN fpsmsdb.item_uom iu ON iu.itemId = b.itemId AND iu.stockUnit = 1 | |||
| LEFT JOIN fpsmsdb.uom_conversion uc_fg ON uc_fg.id = iu.uomId | |||
| LEFT JOIN fpsmsdb.uom_conversion uc_bom ON uc_bom.id = iu.uomId | |||
| LEFT JOIN jo_pick_order jpo ON jpo.pick_order_id = po.id AND jpo.item_id = pol.itemId | |||
| LEFT JOIN item_uom iu ON iu.itemId = b.itemId AND iu.stockUnit = 1 | |||
| LEFT JOIN uom_conversion uc_fg ON uc_fg.id = iu.uomId | |||
| LEFT JOIN uom_conversion uc_bom ON uc_bom.id = iu.uomId | |||
| WHERE po.deleted = false | |||
| AND po.id = :pickOrderId | |||
| AND pol.deleted = false | |||
| @@ -1904,7 +1904,7 @@ open fun getCompletedJobOrderPickOrders(completedDate: LocalDate?): List<Map<Str | |||
| -- 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', 'picking') | |||
| @@ -1936,27 +1936,27 @@ open fun getCompletedJobOrderPickOrders(completedDate: LocalDate?): List<Map<Str | |||
| jpo.match_by as match_by, | |||
| jpo.match_qty as match_qty | |||
| FROM fpsmsdb.pick_order po | |||
| JOIN fpsmsdb.job_order jo ON jo.id = po.joId | |||
| LEFT JOIN fpsmsdb.bom b ON b.id = jo.bomId | |||
| LEFT JOIN fpsmsdb.items fg ON fg.id = b.itemId | |||
| 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 ill.id = COALESCE(spl.actualPickLotLineId, spl.suggestedLotLineId) | |||
| LEFT JOIN fpsmsdb.inventory_lot il ON il.id = ill.inventoryLotId | |||
| LEFT JOIN fpsmsdb.warehouse w ON w.id = ill.warehouseId | |||
| FROM pick_order po | |||
| JOIN job_order jo ON jo.id = po.joId | |||
| LEFT JOIN bom b ON b.id = jo.bomId | |||
| LEFT JOIN items fg ON fg.id = b.itemId | |||
| 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 ill.id = COALESCE(spl.actualPickLotLineId, spl.suggestedLotLineId) | |||
| LEFT JOIN inventory_lot il ON il.id = ill.inventoryLotId | |||
| LEFT JOIN warehouse w ON w.id = ill.warehouseId | |||
| -- no-lot:ill.id 為 null 時,匹配 sol.inventoryLotLineId IS NULL | |||
| LEFT JOIN fpsmsdb.stock_out_line sol ON sol.pickOrderLineId = pol.id AND sol.deleted = false | |||
| LEFT JOIN stock_out_line sol ON sol.pickOrderLineId = pol.id AND sol.deleted = false | |||
| AND ( | |||
| sol.inventoryLotLineId = ill.id | |||
| OR (sol.inventoryLotLineId IS NULL AND ill.id IS NULL) | |||
| ) | |||
| LEFT JOIN fpsmsdb.jo_pick_order jpo ON jpo.pick_order_id = po.id AND jpo.item_id = pol.itemId | |||
| LEFT JOIN fpsmsdb.item_uom iu ON iu.itemId = b.itemId AND iu.stockUnit = 1 | |||
| LEFT JOIN fpsmsdb.uom_conversion uc_fg ON uc_fg.id = iu.uomId | |||
| LEFT JOIN fpsmsdb.uom_conversion uc_bom ON uc_bom.id = iu.uomId | |||
| LEFT JOIN jo_pick_order jpo ON jpo.pick_order_id = po.id AND jpo.item_id = pol.itemId | |||
| LEFT JOIN item_uom iu ON iu.itemId = b.itemId AND iu.stockUnit = 1 | |||
| LEFT JOIN uom_conversion uc_fg ON uc_fg.id = iu.uomId | |||
| LEFT JOIN uom_conversion uc_bom ON uc_bom.id = iu.uomId | |||
| WHERE po.deleted = false | |||
| AND po.id = :pickOrderId | |||
| AND pol.deleted = false | |||
| @@ -2063,7 +2063,7 @@ open fun getCompletedJobOrderPickOrders(completedDate: LocalDate?): List<Map<Str | |||
| -- 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') | |||
| @@ -2094,23 +2094,23 @@ open fun getCompletedJobOrderPickOrders(completedDate: LocalDate?): List<Map<Str | |||
| jpo.match_by as match_by, | |||
| jpo.match_qty as match_qty | |||
| FROM fpsmsdb.pick_order po | |||
| JOIN fpsmsdb.job_order jo ON jo.id = po.joId | |||
| 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 ill.id = COALESCE(spl.actualPickLotLineId, spl.suggestedLotLineId) | |||
| LEFT JOIN fpsmsdb.inventory_lot il ON il.id = ill.inventoryLotId | |||
| LEFT JOIN fpsmsdb.warehouse w ON w.id = ill.warehouseId | |||
| FROM pick_order po | |||
| JOIN job_order jo ON jo.id = po.joId | |||
| 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 ill.id = COALESCE(spl.actualPickLotLineId, spl.suggestedLotLineId) | |||
| LEFT JOIN inventory_lot il ON il.id = ill.inventoryLotId | |||
| LEFT JOIN warehouse w ON w.id = ill.warehouseId | |||
| -- no-lot 情況:ill.id 為 null 時,要匹配 sol.inventoryLotLineId IS NULL 的记录 | |||
| LEFT JOIN fpsmsdb.stock_out_line sol ON sol.pickOrderLineId = pol.id AND sol.deleted = false | |||
| LEFT JOIN stock_out_line sol ON sol.pickOrderLineId = pol.id AND sol.deleted = false | |||
| AND ( | |||
| sol.inventoryLotLineId = ill.id | |||
| OR (sol.inventoryLotLineId IS NULL AND ill.id IS NULL) | |||
| ) | |||
| LEFT JOIN fpsmsdb.jo_pick_order jpo ON jpo.pick_order_id = po.id AND jpo.item_id = pol.itemId | |||
| LEFT JOIN jo_pick_order jpo ON jpo.pick_order_id = po.id AND jpo.item_id = pol.itemId | |||
| WHERE po.deleted = false | |||
| AND po.id = :pickOrderId | |||
| @@ -2196,12 +2196,12 @@ open fun getCompletedJobOrderPickOrders(completedDate: LocalDate?): List<Map<Str | |||
| WHEN LOWER(sol.status) = 'completed' THEN pol.id | |||
| WHEN pol.status = 'COMPLETED' THEN pol.id | |||
| END) AS finishedCount | |||
| FROM fpsmsdb.pick_order po | |||
| JOIN fpsmsdb.pick_order_line pol ON pol.poId = po.id AND pol.deleted = false | |||
| LEFT JOIN fpsmsdb.suggested_pick_lot spl ON pol.id = spl.pickOrderLineId AND spl.deleted = false | |||
| LEFT JOIN fpsmsdb.inventory_lot_line ill ON ill.id = COALESCE(spl.actualPickLotLineId, spl.suggestedLotLineId) AND ill.deleted = false | |||
| LEFT JOIN fpsmsdb.warehouse w ON w.id = ill.warehouseId | |||
| LEFT JOIN fpsmsdb.stock_out_line sol ON sol.pickOrderLineId = pol.id AND sol.deleted = false | |||
| FROM pick_order po | |||
| JOIN pick_order_line pol ON pol.poId = po.id AND pol.deleted = false | |||
| LEFT JOIN suggested_pick_lot spl ON pol.id = spl.pickOrderLineId AND spl.deleted = false | |||
| LEFT JOIN inventory_lot_line ill ON ill.id = COALESCE(spl.actualPickLotLineId, spl.suggestedLotLineId) AND ill.deleted = false | |||
| LEFT JOIN warehouse w ON w.id = ill.warehouseId | |||
| LEFT JOIN stock_out_line sol ON sol.pickOrderLineId = pol.id AND sol.deleted = false | |||
| WHERE po.deleted = false | |||
| AND po.status = 'RELEASED' | |||
| AND po.joId IS NOT NULL | |||
| @@ -2227,9 +2227,9 @@ open fun getCompletedJobOrderPickOrders(completedDate: LocalDate?): List<Map<Str | |||
| WHEN LOWER(sol.status) = 'completed' THEN pol.id | |||
| WHEN pol.status = 'COMPLETED' THEN pol.id | |||
| END) AS finishedCount | |||
| FROM fpsmsdb.pick_order po | |||
| JOIN fpsmsdb.pick_order_line pol ON pol.poId = po.id AND pol.deleted = false | |||
| JOIN fpsmsdb.stock_out_line sol ON sol.pickOrderLineId = pol.id AND sol.deleted = false | |||
| FROM pick_order po | |||
| JOIN pick_order_line pol ON pol.poId = po.id AND pol.deleted = false | |||
| JOIN stock_out_line sol ON sol.pickOrderLineId = pol.id AND sol.deleted = false | |||
| WHERE po.deleted = false | |||
| AND po.status = 'RELEASED' | |||
| AND po.joId IS NOT NULL | |||
| @@ -2249,9 +2249,9 @@ open fun getCompletedJobOrderPickOrders(completedDate: LocalDate?): List<Map<Str | |||
| SELECT | |||
| po.id AS pickOrderId, | |||
| COUNT(DISTINCT sol.id) AS rejectedCount | |||
| FROM fpsmsdb.pick_order po | |||
| JOIN fpsmsdb.pick_order_line pol ON pol.poId = po.id AND pol.deleted = false | |||
| JOIN fpsmsdb.stock_out_line sol ON sol.pickOrderLineId = pol.id AND sol.deleted = false | |||
| FROM pick_order po | |||
| JOIN pick_order_line pol ON pol.poId = po.id AND pol.deleted = false | |||
| JOIN stock_out_line sol ON sol.pickOrderLineId = pol.id AND sol.deleted = false | |||
| WHERE po.deleted = false | |||
| AND po.status = 'RELEASED' | |||
| AND po.joId IS NOT NULL | |||
| @@ -36,7 +36,7 @@ fun findAllByPickOrderIdInAndDeletedFalse(@Param("pickOrderIds") pickOrderIds: L | |||
| @Modifying(clearAutomatically = true, flushAutomatically = true) | |||
| @Query( | |||
| value = """ | |||
| UPDATE fpsmsdb.pick_order_line | |||
| UPDATE pick_order_line | |||
| SET status = 'completed', | |||
| modified = CURRENT_TIMESTAMP | |||
| WHERE id = :pickOrderLineId | |||
| @@ -163,7 +163,7 @@ fun findCompletedWithPlasticBoxCartonQtyInPlanStartRange( | |||
| @Modifying(clearAutomatically = true, flushAutomatically = true) | |||
| @Query( | |||
| value = """ | |||
| UPDATE fpsmsdb.pick_order | |||
| UPDATE pick_order | |||
| SET assignTo = :userId, | |||
| status = :status, | |||
| modified = :modified, | |||
| @@ -186,7 +186,7 @@ fun bulkAssignWorkbenchTicket( | |||
| @Query( | |||
| value = """ | |||
| SELECT id | |||
| FROM fpsmsdb.pick_order | |||
| FROM pick_order | |||
| WHERE deliveryOrderPickOrderId = :dopoId | |||
| AND deleted = 0 | |||
| """, | |||
| @@ -247,7 +247,7 @@ fun findAllReleasedJoWorkbenchPickOrders( | |||
| @Modifying(clearAutomatically = true, flushAutomatically = true) | |||
| @Query( | |||
| value = """ | |||
| UPDATE fpsmsdb.pick_order | |||
| UPDATE pick_order | |||
| SET submittedLines = COALESCE(submittedLines, 0) + 1, | |||
| modified = CURRENT_TIMESTAMP | |||
| WHERE id = :pickOrderId | |||
| @@ -54,8 +54,8 @@ fun assembleHierarchicalFgPayload( | |||
| val linesSql = """ | |||
| WITH target_pol AS ( | |||
| SELECT pol.id | |||
| 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 po.id IN ($inClause) | |||
| AND po.deleted = false | |||
| AND pol.deleted = false | |||
| @@ -63,14 +63,14 @@ fun assembleHierarchicalFgPayload( | |||
| ll AS ( | |||
| SELECT spl.pickOrderLineId, | |||
| COALESCE(spl.actualPickLotLineId, spl.suggestedLotLineId) AS lotLineId | |||
| FROM fpsmsdb.suggested_pick_lot spl | |||
| FROM suggested_pick_lot spl | |||
| JOIN target_pol tp ON tp.id = spl.pickOrderLineId | |||
| WHERE spl.deleted = false | |||
| UNION | |||
| SELECT sol.pickOrderLineId, sol.inventoryLotLineId AS lotLineId | |||
| FROM fpsmsdb.stock_out_line sol | |||
| FROM stock_out_line sol | |||
| JOIN target_pol tp ON tp.id = sol.pickOrderLineId | |||
| WHERE sol.deleted = false | |||
| ), | |||
| @@ -78,7 +78,7 @@ sm AS ( | |||
| SELECT s.pickOrderLineId, | |||
| COALESCE(s.actualPickLotLineId, s.suggestedLotLineId) AS displayLotLineId, | |||
| MAX(s.id) AS maxId | |||
| FROM fpsmsdb.suggested_pick_lot s | |||
| FROM suggested_pick_lot s | |||
| JOIN target_pol tp ON tp.id = s.pickOrderLineId | |||
| WHERE s.deleted = false | |||
| GROUP BY s.pickOrderLineId, COALESCE(s.actualPickLotLineId, s.suggestedLotLineId) | |||
| @@ -145,29 +145,29 @@ SELECT | |||
| WHEN sol.status = 'created' THEN 'pending' | |||
| ELSE 'pending' | |||
| END as processingStatus | |||
| FROM fpsmsdb.pick_order po | |||
| JOIN fpsmsdb.pick_order_line pol ON pol.poId = po.id AND pol.deleted = false | |||
| 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 AND pol.deleted = false | |||
| JOIN items i ON i.id = pol.itemId | |||
| LEFT JOIN uom_conversion uc ON uc.id = pol.uomId | |||
| LEFT JOIN ll ON ll.pickOrderLineId = pol.id | |||
| LEFT JOIN sm | |||
| ON sm.pickOrderLineId = pol.id | |||
| AND sm.displayLotLineId <=> 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 | |||
| @@ -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() | |||
| @@ -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<String, A | |||
| dpo.ShopCode, | |||
| dpo.ShopName, | |||
| dpo.ticket_status as doTicketStatus | |||
| FROM fpsmsdb.do_pick_order dpo | |||
| INNER JOIN fpsmsdb.do_pick_order_line dpol ON dpol.do_pick_order_id = dpo.id AND dpol.deleted = 0 | |||
| INNER JOIN fpsmsdb.pick_order po ON po.id = dpol.pick_order_id | |||
| FROM do_pick_order dpo | |||
| INNER JOIN do_pick_order_line dpol ON dpol.do_pick_order_id = dpo.id AND dpol.deleted = 0 | |||
| INNER JOIN pick_order po ON po.id = dpol.pick_order_id | |||
| WHERE po.assignTo = :userId | |||
| AND po.type = 'do' | |||
| AND EXISTS ( | |||
| SELECT 1 | |||
| FROM fpsmsdb.do_pick_order_line dpol2 | |||
| INNER JOIN fpsmsdb.pick_order po2 ON po2.id = dpol2.pick_order_id | |||
| FROM do_pick_order_line dpol2 | |||
| INNER JOIN pick_order po2 ON po2.id = dpol2.pick_order_id | |||
| WHERE dpol2.do_pick_order_id = dpo.id | |||
| AND dpol2.deleted = 0 | |||
| AND po2.status IN ('assigned', 'released', 'picking') | |||
| @@ -3705,8 +3705,8 @@ open fun getAllPickOrderLotsWithDetailsHierarchical(userId: Long): Map<String, A | |||
| po.consoCode, | |||
| po.status, | |||
| DATE_FORMAT(po.targetDate, '%Y-%m-%d') as targetDate | |||
| FROM fpsmsdb.do_pick_order_line dpol | |||
| INNER JOIN fpsmsdb.pick_order po ON po.id = dpol.pick_order_id | |||
| FROM do_pick_order_line dpol | |||
| INNER JOIN pick_order po ON po.id = dpol.pick_order_id | |||
| WHERE dpol.do_pick_order_id = :doPickOrderId | |||
| AND dpol.deleted = 0 | |||
| AND po.deleted = false | |||
| @@ -3798,37 +3798,37 @@ open fun getAllPickOrderLotsWithDetailsHierarchical(userId: Long): Map<String, A | |||
| WHEN sol.status = 'created' THEN 'pending' | |||
| ELSE 'pending' | |||
| END as processingStatus | |||
| FROM fpsmsdb.pick_order po | |||
| JOIN fpsmsdb.pick_order_line pol ON pol.poId = po.id AND pol.deleted = false | |||
| 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 AND pol.deleted = false | |||
| JOIN items i ON i.id = pol.itemId | |||
| LEFT JOIN uom_conversion uc ON uc.id = pol.uomId | |||
| LEFT JOIN ( | |||
| SELECT spl.pickOrderLineId, | |||
| COALESCE(spl.actualPickLotLineId, spl.suggestedLotLineId) AS lotLineId | |||
| FROM fpsmsdb.suggested_pick_lot spl | |||
| FROM suggested_pick_lot spl | |||
| WHERE spl.deleted = false | |||
| UNION | |||
| SELECT sol.pickOrderLineId, sol.inventoryLotLineId | |||
| FROM fpsmsdb.stock_out_line sol | |||
| FROM stock_out_line sol | |||
| WHERE sol.deleted = false | |||
| ) ll ON ll.pickOrderLineId = pol.id | |||
| LEFT JOIN fpsmsdb.suggested_pick_lot spl | |||
| LEFT JOIN suggested_pick_lot spl | |||
| ON spl.pickOrderLineId = pol.id | |||
| AND spl.deleted = false | |||
| AND COALESCE(spl.actualPickLotLineId, spl.suggestedLotLineId) <=> 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<String, A | |||
| dpo.ShopCode, | |||
| dpo.ShopName, | |||
| dpo.ticket_status as doTicketStatus | |||
| FROM fpsmsdb.do_pick_order dpo | |||
| INNER JOIN fpsmsdb.do_pick_order_line dpol ON dpol.do_pick_order_id = dpo.id AND dpol.deleted = 0 | |||
| INNER JOIN fpsmsdb.pick_order po ON po.id = dpol.pick_order_id | |||
| FROM do_pick_order dpo | |||
| INNER JOIN do_pick_order_line dpol ON dpol.do_pick_order_id = dpo.id AND dpol.deleted = 0 | |||
| INNER JOIN pick_order po ON po.id = dpol.pick_order_id | |||
| WHERE po.assignTo = :userId | |||
| AND po.type = 'do' | |||
| AND EXISTS ( | |||
| SELECT 1 | |||
| FROM fpsmsdb.do_pick_order_line dpol2 | |||
| INNER JOIN fpsmsdb.pick_order po2 ON po2.id = dpol2.pick_order_id | |||
| FROM do_pick_order_line dpol2 | |||
| INNER JOIN pick_order po2 ON po2.id = dpol2.pick_order_id | |||
| WHERE dpol2.do_pick_order_id = dpo.id | |||
| AND dpol2.deleted = 0 | |||
| AND po2.status IN ('assigned', 'released', 'picking') | |||
| @@ -4075,8 +4075,8 @@ open fun getAllPickOrderLotsWithDetailsHierarchical(userId: Long): Map<String, A | |||
| po.consoCode, | |||
| po.status, | |||
| DATE_FORMAT(po.targetDate, '%Y-%m-%d') as targetDate | |||
| FROM fpsmsdb.do_pick_order_line dpol | |||
| INNER JOIN fpsmsdb.pick_order po ON po.id = dpol.pick_order_id | |||
| FROM do_pick_order_line dpol | |||
| INNER JOIN pick_order po ON po.id = dpol.pick_order_id | |||
| WHERE dpol.do_pick_order_id = :doPickOrderId | |||
| AND dpol.deleted = 0 | |||
| AND po.deleted = false | |||
| @@ -4162,32 +4162,32 @@ open fun getAllPickOrderLotsWithDetailsHierarchical(userId: Long): Map<String, A | |||
| WHEN sol.status = 'created' THEN 'pending' | |||
| ELSE 'pending' | |||
| END as processingStatus | |||
| FROM fpsmsdb.pick_order po | |||
| JOIN fpsmsdb.pick_order_line pol ON pol.poId = po.id AND pol.deleted = false | |||
| 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 AND pol.deleted = false | |||
| JOIN items i ON i.id = pol.itemId | |||
| LEFT JOIN uom_conversion uc ON uc.id = pol.uomId | |||
| LEFT JOIN ( | |||
| SELECT spl.pickOrderLineId, | |||
| COALESCE(spl.actualPickLotLineId, spl.suggestedLotLineId) AS lotLineId | |||
| FROM fpsmsdb.suggested_pick_lot spl | |||
| FROM suggested_pick_lot spl | |||
| WHERE spl.deleted = false | |||
| UNION | |||
| SELECT sol.pickOrderLineId, sol.inventoryLotLineId | |||
| FROM fpsmsdb.stock_out_line sol | |||
| FROM stock_out_line sol | |||
| WHERE sol.deleted = false | |||
| ) ll ON ll.pickOrderLineId = pol.id | |||
| LEFT JOIN fpsmsdb.suggested_pick_lot spl | |||
| LEFT JOIN suggested_pick_lot spl | |||
| ON spl.pickOrderLineId = pol.id | |||
| AND spl.deleted = false | |||
| AND COALESCE(spl.actualPickLotLineId, spl.suggestedLotLineId) <=> 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 | |||
| @@ -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 | |||
| @@ -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!!) | |||
| @@ -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 | |||
| @@ -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: "" | |||
| @@ -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'); | |||
| @@ -33,7 +33,7 @@ | |||
| <parameterDescription><![CDATA["lastOutDateStart"]]></parameterDescription> | |||
| </parameter> | |||
| <queryString> | |||
| <![CDATA[select * from fpsmsdb.items , fpsmsdb.stock_out_line]]> | |||
| <![CDATA[select * from items , stock_out_line]]> | |||
| </queryString> | |||
| <field name="id" class="java.lang.Integer"> | |||
| <property name="com.jaspersoft.studio.field.name" value="id"/> | |||
| @@ -33,7 +33,7 @@ | |||
| <parameterDescription><![CDATA["lastOutDateStart"]]></parameterDescription> | |||
| </parameter> | |||
| <queryString> | |||
| <![CDATA[select * from fpsmsdb.items , fpsmsdb.stock_out_line]]> | |||
| <![CDATA[select * from items , stock_out_line]]> | |||
| </queryString> | |||
| <field name="id" class="java.lang.Integer"> | |||
| <property name="com.jaspersoft.studio.field.name" value="id"/> | |||