From bae7ae89ed7d77eba2448b36d482587335e47cf6 Mon Sep 17 00:00:00 2001
From: Arth <65160206@go.buu.ac.th>
Date: Thu, 27 Mar 2025 22:50:14 +0700
Subject: [PATCH] deploy to dekdee

---
 .dockerignore                                 |   3 +
 .gitignore                                    |  24 +-
 docker-compose.yml                            |  49 ++
 dockerfile                                    |  20 +
 node_modules/.package-lock.json               |  37 +-
 node_modules/dotenv/CHANGELOG.md              |  17 +-
 node_modules/dotenv/README.md                 | 151 ++----
 node_modules/dotenv/package.json              |  14 +-
 package-lock.json                             |  38 +-
 package.json                                  |   1 +
 src/app.module.ts                             |  17 +-
 src/main.ts                                   |   9 +-
 src/queues/AutoQueue/Autoqueue.py             | 506 ------------------
 src/queues/AutoQueue/Autoqueuenew.py          | 446 ---------------
 src/queues/AutoQueue/Log copy.py              | 438 ---------------
 src/queues/AutoQueue/Log.py                   |  45 --
 .../__pycache__/Autoqueue.cpython-310.pyc     | Bin 10637 -> 0 bytes
 .../__pycache__/Autoqueue.cpython-311.pyc     | Bin 18940 -> 0 bytes
 .../__pycache__/Autoqueue.cpython-313.pyc     | Bin 16952 -> 0 bytes
 src/queues/AutoQueue/cleandata.py             | 228 --------
 src/queues/AutoQueue/requirements.txt         |   6 -
 src/queues/AutoQueue/testAllapi.py            | 132 -----
 22 files changed, 242 insertions(+), 1939 deletions(-)
 create mode 100644 .dockerignore
 create mode 100644 docker-compose.yml
 create mode 100644 dockerfile
 delete mode 100644 src/queues/AutoQueue/Autoqueue.py
 delete mode 100644 src/queues/AutoQueue/Autoqueuenew.py
 delete mode 100644 src/queues/AutoQueue/Log copy.py
 delete mode 100644 src/queues/AutoQueue/Log.py
 delete mode 100644 src/queues/AutoQueue/__pycache__/Autoqueue.cpython-310.pyc
 delete mode 100644 src/queues/AutoQueue/__pycache__/Autoqueue.cpython-311.pyc
 delete mode 100644 src/queues/AutoQueue/__pycache__/Autoqueue.cpython-313.pyc
 delete mode 100644 src/queues/AutoQueue/cleandata.py
 delete mode 100644 src/queues/AutoQueue/requirements.txt
 delete mode 100644 src/queues/AutoQueue/testAllapi.py

diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 00000000..4c245931
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,3 @@
+node_modules
+dist
+.env.local
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index f94630c5..be863f26 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,25 @@
+# Node.js
 node_modules/
 dist/
-.env
\ No newline at end of file
+*.log
+*.tsbuildinfo
+
+# Docker
+.docker/
+docker-compose.override.yml
+docker-compose.prod.yml
+
+# .env files (สำคัญที่สุด!)
+.env
+.env.local
+.env.docker
+.env.production
+
+# IDE & OS files
+.vscode/
+.idea/
+*.swp
+.DS_Store
+
+# NPM package-lock.json files (จะ add หรือ commit ขึ้นอยู่กับสถานการณ์)
+package-lock.json
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 00000000..b2e0b901
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,49 @@
+services:
+  nestjs:
+    build:
+      context: .  # ✅ ชี้ไปยังโฟลเดอร์ที่มี package.json และ Dockerfile
+      dockerfile: Dockerfile
+    container_name: LOOKOAD_NestJS
+    ports:
+      - "8012:4000"
+    environment:
+      NODE_ENV: docker
+      DB_HOST: mysql
+      DB_PORT: 3306
+      DB_USERNAME: root
+      DB_PASSWORD: Lookoad2024!
+      DB_NAME: water
+    depends_on:
+      - mysql
+    restart: always
+
+  mysql:
+    image: mysql:8.0
+    container_name: lookoad-mysql
+    environment:
+      MYSQL_ROOT_PASSWORD: Lookoad2024!
+      MYSQL_DATABASE: water
+    volumes:
+      - mysql_data:/var/lib/mysql
+    restart: always
+    healthcheck:
+      test: ["CMD", "mysqladmin", "ping", "--silent"]
+      interval: 10s
+      retries: 5
+      start_period: 30s
+      timeout: 20s
+
+  phpmyadmin:
+    image: phpmyadmin/phpmyadmin
+    container_name: LOOKOAD_Phpmyadmin
+    ports:
+      - "8014:80"
+    environment:
+      PMA_HOST: mysql
+      MYSQL_ROOT_PASSWORD: Lookoad2024!
+    depends_on:
+      - mysql
+    restart: always
+
+volumes:
+  mysql_data:
diff --git a/dockerfile b/dockerfile
new file mode 100644
index 00000000..23cef4c6
--- /dev/null
+++ b/dockerfile
@@ -0,0 +1,20 @@
+FROM node:18 AS builder
+WORKDIR /app
+
+COPY package*.json ./
+RUN npm install
+
+COPY . .
+RUN npm run build
+
+FROM node:18
+WORKDIR /app
+
+COPY --from=builder /app/dist ./dist
+COPY --from=builder /app/node_modules ./node_modules
+COPY --from=builder /app/package*.json ./
+
+EXPOSE 4000
+
+# ✅ รันตรง ๆ ด้วย Node ไม่ผ่าน npm
+CMD ["node", "dist/main.js"]
diff --git a/node_modules/.package-lock.json b/node_modules/.package-lock.json
index 41594d94..768931bc 100644
--- a/node_modules/.package-lock.json
+++ b/node_modules/.package-lock.json
@@ -1719,6 +1719,21 @@
         }
       }
     },
+    "node_modules/@nestjs/config": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/@nestjs/config/-/config-4.0.2.tgz",
+      "integrity": "sha512-McMW6EXtpc8+CwTUwFdg6h7dYcBUpH5iUILCclAsa+MbCEvC9ZKu4dCHRlJqALuhjLw97pbQu62l4+wRwGeZqA==",
+      "license": "MIT",
+      "dependencies": {
+        "dotenv": "16.4.7",
+        "dotenv-expand": "12.0.1",
+        "lodash": "4.17.21"
+      },
+      "peerDependencies": {
+        "@nestjs/common": "^10.0.0 || ^11.0.0",
+        "rxjs": "^7.1.0"
+      }
+    },
     "node_modules/@nestjs/core": {
       "version": "10.3.3",
       "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-10.3.3.tgz",
@@ -4321,9 +4336,25 @@
       }
     },
     "node_modules/dotenv": {
-      "version": "16.4.5",
-      "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz",
-      "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==",
+      "version": "16.4.7",
+      "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz",
+      "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==",
+      "license": "BSD-2-Clause",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://dotenvx.com"
+      }
+    },
+    "node_modules/dotenv-expand": {
+      "version": "12.0.1",
+      "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-12.0.1.tgz",
+      "integrity": "sha512-LaKRbou8gt0RNID/9RoI+J2rvXsBRPMV7p+ElHlPhcSARbCPDYcYG2s1TIzAfWv4YSgyY5taidWzzs31lNV3yQ==",
+      "license": "BSD-2-Clause",
+      "dependencies": {
+        "dotenv": "^16.4.5"
+      },
       "engines": {
         "node": ">=12"
       },
diff --git a/node_modules/dotenv/CHANGELOG.md b/node_modules/dotenv/CHANGELOG.md
index e35152ae..e3e40d6e 100644
--- a/node_modules/dotenv/CHANGELOG.md
+++ b/node_modules/dotenv/CHANGELOG.md
@@ -2,13 +2,26 @@
 
 All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
 
-## [Unreleased](https://github.com/motdotla/dotenv/compare/v16.4.5...master)
+## [Unreleased](https://github.com/motdotla/dotenv/compare/v16.4.7...master)
+
+## [16.4.7](https://github.com/motdotla/dotenv/compare/v16.4.6...v16.4.7 (2024-12-03)
+
+### Changed
+
+- Ignore `.tap` folder when publishing. (oops, sorry about that everyone. - @motdotla) [#848](https://github.com/motdotla/dotenv/pull/848)
+
+## [16.4.6](https://github.com/motdotla/dotenv/compare/v16.4.5...v16.4.6) (2024-12-02)
+
+### Changed
+
+- Clean up stale dev dependencies [#847](https://github.com/motdotla/dotenv/pull/847)
+- Various README updates clarifying usage and alternative solutions using [dotenvx](https://github.com/dotenvx/dotenvx)
 
 ## [16.4.5](https://github.com/motdotla/dotenv/compare/v16.4.4...v16.4.5) (2024-02-19)
 
 ### Changed
 
-- 🐞 fix recent regression when using `path` option. return to historical behavior: do not attempt to auto find `.env` if `path` set. (regression was introduced in `16.4.3`) [#814](https://github.com/motdotla/dotenv/pull/814)
+- 🐞 Fix recent regression when using `path` option. return to historical behavior: do not attempt to auto find `.env` if `path` set. (regression was introduced in `16.4.3`) [#814](https://github.com/motdotla/dotenv/pull/814)
 
 ## [16.4.4](https://github.com/motdotla/dotenv/compare/v16.4.3...v16.4.4) (2024-02-13)
 
diff --git a/node_modules/dotenv/README.md b/node_modules/dotenv/README.md
index e54075ee..3bd511c4 100644
--- a/node_modules/dotenv/README.md
+++ b/node_modules/dotenv/README.md
@@ -33,16 +33,6 @@
     <sup>Add Single Sign-On, Multi-Factor Auth, and more, in minutes instead of months.</sup>
   </div>
 </a>
-<br/>
-<a href="https://runalloy.com/?utm_source=github&utm_medium=referral&utm_campaign=1224_dotenv">
-  <div>
-    <img src="https://res.cloudinary.com/dotenv-org/image/upload/c_crop,g_center,h_65,w_290,x_0,y_0/v1704258787/AlloyAutomation-logo_dqin8c.svg" width="370" alt="Alloy Automation">
-  </div>
-  <b>Launch user-facing integrations faster</b>
-  <div>
-    <sup>Easily spin up hundreds of integrations. Sign up free or read our docs first</sup>
-  </div>
-</a>
 <hr>
 </div>
 
@@ -59,7 +49,7 @@ Dotenv is a zero-dependency module that loads environment variables from a `.env
 * [🌱 Install](#-install)
 * [🏗️ Usage (.env)](#%EF%B8%8F-usage)
 * [🌴 Multiple Environments 🆕](#-manage-multiple-environments)
-* [🚀 Deploying (.env.vault) 🆕](#-deploying)
+* [🚀 Deploying (encryption) 🆕](#-deploying)
 * [📚 Examples](#-examples)
 * [📖 Docs](#-documentation)
 * [❓ FAQ](#-faq)
@@ -83,7 +73,7 @@ Or installing with yarn? `yarn add dotenv`
 </div>
 </a>
 
-Create a `.env` file in the root of your project:
+Create a `.env` file in the root of your project (if using a monorepo structure like `apps/backend/app.js`, put it in the root of the folder where your `app.js` process runs):
 
 ```dosini
 S3_BUCKET="YOURS3BUCKET"
@@ -107,6 +97,7 @@ That's it. `process.env` now has the keys and values you defined in your `.env`
 
 ```javascript
 require('dotenv').config()
+// or import 'dotenv/config' if you're using ES6
 
 ...
 
@@ -186,23 +177,41 @@ $ DOTENV_CONFIG_ENCODING=latin1 DOTENV_CONFIG_DEBUG=true node -r dotenv/config y
 
 You need to add the value of another variable in one of your variables? Use [dotenv-expand](https://github.com/motdotla/dotenv-expand).
 
+### Command Substitution
+
+Use [dotenvx](https://github.com/dotenvx/dotenvx) to use command substitution.
+
+Add the output of a command to one of your variables in your .env file.
+
+```ini
+# .env
+DATABASE_URL="postgres://$(whoami)@localhost/my_database"
+```
+```js
+// index.js
+console.log('DATABASE_URL', process.env.DATABASE_URL)
+```
+```sh
+$ dotenvx run --debug -- node index.js
+[dotenvx@0.14.1] injecting env (1) from .env
+DATABASE_URL postgres://yourusername@localhost/my_database
+```
+
 ### Syncing
 
-You need to keep `.env` files in sync between machines, environments, or team members? Use [dotenv-vault](https://github.com/dotenv-org/dotenv-vault).
+You need to keep `.env` files in sync between machines, environments, or team members? Use [dotenvx](https://github.com/dotenvx/dotenvx) to encrypt your `.env` files and safely include them in source control. This still subscribes to the twelve-factor app rules by generating a decryption key separate from code.
 
 ### Multiple Environments
 
-You need to manage your secrets across different environments and apply them as needed? Use a `.env.vault` file with a `DOTENV_KEY`.
+Use [dotenvx](https://github.com/dotenvx/dotenvx) to generate `.env.ci`, `.env.production` files, and more.
 
 ### Deploying
 
-You need to deploy your secrets in a cloud-agnostic manner? Use a `.env.vault` file. See [deploying `.env.vault` files](https://github.com/motdotla/dotenv/tree/master#-deploying).
+You need to deploy your secrets in a cloud-agnostic manner? Use [dotenvx](https://github.com/dotenvx/dotenvx) to generate a private decryption key that is set on your production server.
 
 ## 🌴 Manage Multiple Environments
 
-Use [dotenvx](https://github.com/dotenvx/dotenvx) or [dotenv-vault](https://github.com/dotenv-org/dotenv-vault).
-
-### dotenvx
+Use [dotenvx](https://github.com/dotenvx/dotenvx)
 
 Run any environment locally. Create a `.env.ENVIRONMENT` file and use `--env-file` to load it. It's straightforward, yet flexible.
 
@@ -228,78 +237,23 @@ Hello local
 
 [more environment examples](https://dotenvx.com/docs/quickstart/environments)
 
-### dotenv-vault
-
-Edit your production environment variables.
-
-```bash
-$ npx dotenv-vault open production
-```
-
-Regenerate your `.env.vault` file.
-
-```bash
-$ npx dotenv-vault build
-```
-
-*ℹ️  🔐 Vault Managed vs 💻 Locally Managed: The above example, for brevity's sake, used the 🔐 Vault Managed solution to manage your `.env.vault` file. You can instead use the 💻 Locally Managed solution. [Read more here](https://github.com/dotenv-org/dotenv-vault#how-do-i-use--locally-managed-dotenv-vault). Our vision is that other platforms and orchestration tools adopt the `.env.vault` standard as they did the `.env` standard. We don't expect to be the only ones providing tooling to manage and generate `.env.vault` files.*
-
-<a href="https://github.com/dotenv-org/dotenv-vault#-manage-multiple-environments">Learn more at dotenv-vault: Manage Multiple Environments</a>
-
 ## 🚀 Deploying
 
-Use [dotenvx](https://github.com/dotenvx/dotenvx) or [dotenv-vault](https://github.com/dotenv-org/dotenv-vault).
+Use [dotenvx](https://github.com/dotenvx/dotenvx).
 
-### dotenvx
+Add encryption to your `.env` files with a single command. Pass the `--encrypt` flag.
 
-Encrypt your secrets to a `.env.vault` file and load from it (recommended for production and ci).
-
-```bash
-$ echo "HELLO=World" > .env
-$ echo "HELLO=production" > .env.production
+```
+$ dotenvx set HELLO Production --encrypt -f .env.production
 $ echo "console.log('Hello ' + process.env.HELLO)" > index.js
 
-$ dotenvx encrypt
-[dotenvx][info] encrypted to .env.vault (.env,.env.production)
-[dotenvx][info] keys added to .env.keys (DOTENV_KEY_PRODUCTION,DOTENV_KEY_PRODUCTION)
-
-$ DOTENV_KEY='<dotenv_key_production>' dotenvx run -- node index.js
-[dotenvx][info] loading env (1) from encrypted .env.vault
-Hello production
-^ :-]
+$ DOTENV_PRIVATE_KEY_PRODUCTION="<.env.production private key>" dotenvx run -- node index.js
+[dotenvx] injecting env (2) from .env.production
+Hello Production
 ```
 
 [learn more](https://github.com/dotenvx/dotenvx?tab=readme-ov-file#encryption)
 
-### dotenv-vault
-
-*Note: Requires dotenv >= 16.1.0*
-
-Encrypt your `.env.vault` file.
-
-```bash
-$ npx dotenv-vault build
-```
-
-Fetch your production `DOTENV_KEY`.
-
-```bash
-$ npx dotenv-vault keys production
-```
-
-Set `DOTENV_KEY` on your server.
-
-```bash
-# heroku example
-heroku config:set DOTENV_KEY=dotenv://:key_1234…@dotenvx.com/vault/.env.vault?environment=production
-```
-
-That's it! On deploy, your `.env.vault` file will be decrypted and its secrets injected as environment variables – just in time.
-
-*ℹ️ A note from [Mot](https://github.com/motdotla): Until recently, we did not have an opinion on how and where to store your secrets in production. We now strongly recommend generating a `.env.vault` file. It's the best way to prevent your secrets from being scattered across multiple servers and cloud providers – protecting you from breaches like the [CircleCI breach](https://techcrunch.com/2023/01/05/circleci-breach/). Also it unlocks interoperability WITHOUT native third-party integrations. Third-party integrations are [increasingly risky](https://coderpad.io/blog/development/heroku-github-breach/) to our industry. They may be the 'du jour' of today, but we imagine a better future.*
-
-<a href="https://github.com/dotenv-org/dotenv-vault#-deploying">Learn more at dotenv-vault: Deploying</a>
-
 ## 📚 Examples
 
 See [examples](https://github.com/dotenv-org/examples) of using dotenv with various frameworks, languages, and configurations.
@@ -308,7 +262,6 @@ See [examples](https://github.com/dotenv-org/examples) of using dotenv with vari
 * [nodejs (debug on)](https://github.com/dotenv-org/examples/tree/master/usage/dotenv-nodejs-debug)
 * [nodejs (override on)](https://github.com/dotenv-org/examples/tree/master/usage/dotenv-nodejs-override)
 * [nodejs (processEnv override)](https://github.com/dotenv-org/examples/tree/master/usage/dotenv-custom-target)
-* [nodejs (DOTENV_KEY override)](https://github.com/dotenv-org/examples/tree/master/usage/dotenv-vault-custom-target)
 * [esm](https://github.com/dotenv-org/examples/tree/master/usage/dotenv-esm)
 * [esm (preload)](https://github.com/dotenv-org/examples/tree/master/usage/dotenv-esm-preload)
 * [typescript](https://github.com/dotenv-org/examples/tree/master/usage/dotenv-typescript)
@@ -409,20 +362,10 @@ Specify an object to write your secrets to. Defaults to `process.env` environmen
 const myObject = {}
 require('dotenv').config({ processEnv: myObject })
 
-console.log(myObject) // values from .env or .env.vault live here now.
+console.log(myObject) // values from .env
 console.log(process.env) // this was not changed or written to
 ```
 
-##### DOTENV_KEY
-
-Default: `process.env.DOTENV_KEY`
-
-Pass the `DOTENV_KEY` directly to config options. Defaults to looking for `process.env.DOTENV_KEY` environment variable. Note this only applies to decrypting `.env.vault` files. If passed as null or undefined, or not passed at all, dotenv falls back to its traditional job of parsing a `.env` file.
-
-```js
-require('dotenv').config({ DOTENV_KEY: 'dotenv://:key_1234…@dotenvx.com/vault/.env.vault?environment=production' })
-```
-
 ### Parse
 
 The engine which parses the contents of your file containing environment
@@ -493,22 +436,6 @@ Default: `false`
 
 Override any environment variables that have already been set.
 
-### Decrypt
-
-The engine which decrypts the ciphertext contents of your .env.vault file is available for use. It accepts a ciphertext and a decryption key. It uses AES-256-GCM encryption.
-
-For example, decrypting a simple ciphertext:
-
-```js
-const dotenv = require('dotenv')
-const ciphertext = 's7NYXa809k/bVSPwIAmJhPJmEGTtU0hG58hOZy7I0ix6y5HP8LsHBsZCYC/gw5DDFy5DgOcyd18R'
-const decryptionKey = 'ddcaa26504cd70a6fef9801901c3981538563a1767c297cb8416e8a38c62fe00'
-
-const decrypted = dotenv.decrypt(ciphertext, decryptionKey)
-
-console.log(decrypted) // # development@v6\nALPHA="zeta"
-```
-
 ## ❓ FAQ
 
 ### Why is the `.env` file not loading my environment variables successfully?
@@ -532,7 +459,7 @@ password than your development database.
 
 ### Should I have multiple `.env` files?
 
-We recommend creating on `.env` file per environment. Use `.env` for local/development, `.env.production` for production and so on. This still follows the twelve factor principles as each is attributed individually to its own environment. Avoid custom set ups that work in inheritance somehow (`.env.production` inherits values form `.env` for example). It is better to duplicate values if necessary across each `.env.environment` file.
+We recommend creating one `.env` file per environment. Use `.env` for local/development, `.env.production` for production and so on. This still follows the twelve factor principles as each is attributed individually to its own environment. Avoid custom set ups that work in inheritance somehow (`.env.production` inherits values form `.env` for example). It is better to duplicate values if necessary across each `.env.environment` file.
 
 > In a twelve-factor app, env vars are granular controls, each fully orthogonal to other env vars. They are never grouped together as “environments”, but instead are independently managed for each deploy. This is a model that scales up smoothly as the app naturally expands into more deploys over its lifetime.
 >
@@ -685,11 +612,7 @@ Try [dotenv-expand](https://github.com/motdotla/dotenv-expand)
 
 ### What about syncing and securing .env files?
 
-Use [dotenv-vault](https://github.com/dotenv-org/dotenv-vault)
-
-### What is a `.env.vault` file?
-
-A `.env.vault` file is an encrypted version of your development (and ci, staging, production, etc) environment variables. It is paired with a `DOTENV_KEY` to deploy your secrets more securely than scattering them across multiple platforms and tools. Use [dotenv-vault](https://github.com/dotenv-org/dotenv-vault) to manage and generate them.
+Use [dotenvx](https://github.com/dotenvx/dotenvx)
 
 ### What if I accidentally commit my `.env` file to code?
 
diff --git a/node_modules/dotenv/package.json b/node_modules/dotenv/package.json
index bb06025b..528426b4 100644
--- a/node_modules/dotenv/package.json
+++ b/node_modules/dotenv/package.json
@@ -1,6 +1,6 @@
 {
   "name": "dotenv",
-  "version": "16.4.5",
+  "version": "16.4.7",
   "description": "Loads environment variables from .env file",
   "main": "lib/main.js",
   "types": "lib/main.d.ts",
@@ -21,10 +21,9 @@
   "scripts": {
     "dts-check": "tsc --project tests/types/tsconfig.json",
     "lint": "standard",
-    "lint-readme": "standard-markdown",
     "pretest": "npm run lint && npm run dts-check",
-    "test": "tap tests/*.js --100 -Rspec",
-    "test:coverage": "tap --coverage-report=lcov",
+    "test": "tap run --allow-empty-coverage --disable-coverage --timeout=60000",
+    "test:coverage": "tap run --show-full-coverage --timeout=60000 --coverage-report=lcov",
     "prerelease": "npm test",
     "release": "standard-version"
   },
@@ -45,15 +44,12 @@
   "readmeFilename": "README.md",
   "license": "BSD-2-Clause",
   "devDependencies": {
-    "@definitelytyped/dtslint": "^0.0.133",
     "@types/node": "^18.11.3",
-    "decache": "^4.6.1",
+    "decache": "^4.6.2",
     "sinon": "^14.0.1",
     "standard": "^17.0.0",
-    "standard-markdown": "^7.1.0",
     "standard-version": "^9.5.0",
-    "tap": "^16.3.0",
-    "tar": "^6.1.11",
+    "tap": "^19.2.0",
     "typescript": "^4.8.4"
   },
   "engines": {
diff --git a/package-lock.json b/package-lock.json
index 582dfb79..26a4d461 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -10,6 +10,7 @@
       "license": "UNLICENSED",
       "dependencies": {
         "@nestjs/common": "^10.3.3",
+        "@nestjs/config": "^4.0.2",
         "@nestjs/core": "^10.0.0",
         "@nestjs/jwt": "^10.2.0",
         "@nestjs/platform-express": "^10.0.0",
@@ -1770,6 +1771,21 @@
         }
       }
     },
+    "node_modules/@nestjs/config": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/@nestjs/config/-/config-4.0.2.tgz",
+      "integrity": "sha512-McMW6EXtpc8+CwTUwFdg6h7dYcBUpH5iUILCclAsa+MbCEvC9ZKu4dCHRlJqALuhjLw97pbQu62l4+wRwGeZqA==",
+      "license": "MIT",
+      "dependencies": {
+        "dotenv": "16.4.7",
+        "dotenv-expand": "12.0.1",
+        "lodash": "4.17.21"
+      },
+      "peerDependencies": {
+        "@nestjs/common": "^10.0.0 || ^11.0.0",
+        "rxjs": "^7.1.0"
+      }
+    },
     "node_modules/@nestjs/core": {
       "version": "10.3.3",
       "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-10.3.3.tgz",
@@ -4372,9 +4388,25 @@
       }
     },
     "node_modules/dotenv": {
-      "version": "16.4.5",
-      "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz",
-      "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==",
+      "version": "16.4.7",
+      "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz",
+      "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==",
+      "license": "BSD-2-Clause",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://dotenvx.com"
+      }
+    },
+    "node_modules/dotenv-expand": {
+      "version": "12.0.1",
+      "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-12.0.1.tgz",
+      "integrity": "sha512-LaKRbou8gt0RNID/9RoI+J2rvXsBRPMV7p+ElHlPhcSARbCPDYcYG2s1TIzAfWv4YSgyY5taidWzzs31lNV3yQ==",
+      "license": "BSD-2-Clause",
+      "dependencies": {
+        "dotenv": "^16.4.5"
+      },
       "engines": {
         "node": ">=12"
       },
diff --git a/package.json b/package.json
index 48563146..fdc6c1ac 100644
--- a/package.json
+++ b/package.json
@@ -22,6 +22,7 @@
   },
   "dependencies": {
     "@nestjs/common": "^10.3.3",
+    "@nestjs/config": "^4.0.2",
     "@nestjs/core": "^10.0.0",
     "@nestjs/jwt": "^10.2.0",
     "@nestjs/platform-express": "^10.0.0",
diff --git a/src/app.module.ts b/src/app.module.ts
index eeb0491d..5be3db30 100644
--- a/src/app.module.ts
+++ b/src/app.module.ts
@@ -6,6 +6,7 @@ import { join } from 'path';
 import { DataSource } from 'typeorm';
 import { AppController } from './app.controller';
 import { AppService } from './app.service';
+import { ConfigModule } from '@nestjs/config'; // เพิ่ม ConfigModule
 
 // Import Modules
 import { UsersModule } from './users/users.module';
@@ -55,13 +56,18 @@ import { ProductionTarget } from './production_targets/entities/production_targe
 import { QueueType } from './queue-types/entities/queue-type.entity';
 @Module({
   imports: [
+    ConfigModule.forRoot({
+      isGlobal: true, // ทำให้ใช้ได้ทั่วทั้งแอป
+      envFilePath:
+        process.env.NODE_ENV === 'docker' ? '.env.docker' : '.env.local', // หรือ '.env.local' / '.env.docker' ตามที่ต้องการ
+    }),
     TypeOrmModule.forRoot({
       type: 'mysql',
-      host: 'localhost',
-      port: 3306,
-      username: 'root',
-      password: '',
-      database: 'water',
+      host: process.env.DB_HOST,
+      port: parseInt(process.env.DB_PORT || '3306'),
+      username: process.env.DB_USERNAME || 'root',
+      password: process.env.DB_PASSWORD || '',
+      database: process.env.DB_NAME,
       entities: [
         User,
         Role,
@@ -86,6 +92,7 @@ import { QueueType } from './queue-types/entities/queue-type.entity';
         QueueType,
       ],
       synchronize: true,
+      autoLoadEntities: true,
     }),
     ServeStaticModule.forRoot({
       rootPath: join(__dirname, '..', 'public'),
diff --git a/src/main.ts b/src/main.ts
index 5d8d8da9..f28f67cf 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -5,6 +5,13 @@ import { ValidationPipe } from '@nestjs/common';
 import { exec } from 'child_process';
 
 async function bootstrap() {
+  console.log('✅ NestJS is running on http://localhost:4000');
+  console.log('🌱 ENV Loaded:');
+  console.log('DB_HOST:', process.env.DB_HOST);
+  console.log('DB_PORT:', process.env.DB_PORT);
+  console.log('DB_USERNAME:', process.env.DB_USERNAME);
+  console.log('DB_PASSWORD:', process.env.DB_PASSWORD);
+  console.log('DB_NAME:', process.env.DB_NAME);
   const app = await NestFactory.create(AppModule);
 
   // 🔹 เพิ่ม Swagger API Documentation
@@ -45,7 +52,7 @@ async function bootstrap() {
   // );
   // 🔹 Start NestJS
   await app.listen(4000);
-  console.log('✅ NestJS is running on http://localhost:4000');
+
   // console.log('✅ FastAPI started successfully: http://localhost:9000');
 }
 
diff --git a/src/queues/AutoQueue/Autoqueue.py b/src/queues/AutoQueue/Autoqueue.py
deleted file mode 100644
index cbc993e2..00000000
--- a/src/queues/AutoQueue/Autoqueue.py
+++ /dev/null
@@ -1,506 +0,0 @@
-import simpy
-from datetime import datetime, timedelta
-import math
-from fastapi import FastAPI
-from fastapi.middleware.cors import CORSMiddleware
-
-# ==============================================
-# 1) ข้อมูลเครื่องจักร (machines_info)
-# ==============================================
-machines_info = [
-    {
-        "machine_id": "MC001",
-        "machine_name": "เครื่องเป่าขวด",
-        "function": "เป่า",
-        "materials": ["Preform"],  # ใช้วัตถุดิบ Preform
-        "bottle_size": ["600 ml", "1500 ml"],
-        "speed": [2200, 1100],  # 600 ml => 2200 ขวด/ชม, 1500 ml => 1100 ขวด/ชม
-        "changeover_time": [3, 3],
-        "status": "พร้อมใช้งาน"
-    },
-    {
-        "machine_id": "MC002",
-        "machine_name": "เครื่องเป่าขวด 350ml",
-        "function": "เป่า",
-        "materials": ["Preform"],
-        "bottle_size": ["350 ml"],
-        "speed": [2000],
-        "changeover_time": [0],
-        "status": "พร้อมใช้งาน"
-    },
-    {
-        "machine_id": "MC003",
-        "machine_name": "เครื่องสวมฉลาก",
-        "function": "สวมฉลาก",
-        "materials": ["Label", "EmptyBottle"],
-        "bottle_size": ["350 ml", "600 ml", "1500 ml"],
-        "speed": [4000, 4000, 2000],
-        "changeover_time": [0, 0, 0],
-        "status": "พร้อมใช้งาน"
-    },
-    {
-        "machine_id": "MC004",
-        "machine_name": "เครื่องบรรจุ + แพ็ค",
-        "function": "บรรจุ, แพ็ค",
-        "materials": ["EmptyBottleLabeled", "Cap", "PE_film"],
-        "bottle_size": ["350 ml", "600 ml", "1500 ml"],
-        "speed": [2400, 2400, 2400],
-        "changeover_time": [0.5, 0.5, 0.5],
-        "status": "พร้อมใช้งาน"
-    }
-]
-
-# ==============================================
-# 2) สต็อกวัตถุดิบ
-# ==============================================
-raw_material_stock = {
-    "Preform": 20000,
-    "Label_A": 20000,
-    "Label_B": 20000,
-    "Cap_A":   20000,
-    "Cap_B":   20000,
-    # 1 roll => 9600 ขวด
-    "PE_film_roll": 20
-}
-
-# ==============================================
-# 3) Orders ลูกค้า (ตัวอย่าง)
-# ==============================================
-customer_orders = [
-    {
-        "customer": "Wittaya",  
-        "type": "water",
-        "size": "600 ml",
-        "brand": "A",
-        "quantity_bottles": 8400,
-        "due_date": "2025-01-08",
-        "priority": 2
-    },
-    {
-        "customer": "Aof",
-        "type": "water",
-        "size": "600 ml",
-        "brand": "A",
-        "quantity_bottles": 3600,
-        "due_date": "2025-01-07",
-        "priority": 1
-    }
-]
-
-# ==============================================
-# 4) ตาราง config Buffer Stock
-# ==============================================
-buffer_config = [
-    {"type": "water",  "size": "350 ml",  "brand": "A", "want_to_store": 0,    "current_store": 0},
-    {"type": "water",  "size": "600 ml",  "brand": "A", "want_to_store": 8000, "current_store": 0},
-    {"type": "water",  "size": "1500 ml", "brand": "A", "want_to_store": 6000, "current_store": 0},
-    {"type": "water",  "size": "350 ml",  "brand": "B", "want_to_store": 0,    "current_store": 0},
-    {"type": "water",  "size": "600 ml",  "brand": "B", "want_to_store": 6000, "current_store": 0},
-    {"type": "water",  "size": "1500 ml", "brand": "B", "want_to_store": 6000, "current_store": 0},
-    {"type": "bottle", "size": "350 ml",  "brand": None,"want_to_store": 0,    "current_store": 0},
-    {"type": "bottle", "size": "600 ml",  "brand": None,"want_to_store": 6000, "current_store": 0},
-    {"type": "bottle", "size": "1500 ml", "brand": None,"want_to_store": 6000, "current_store": 0}
-]
-
-# ==============================================
-# 5) ตาราง priority ของการผลิตเผื่อ
-# ==============================================
-buffer_priority = [
-    {"priority": 1, "type": "water",  "size": "600 ml",  "brand": "A"},
-    {"priority": 2, "type": "water",  "size": "1500 ml", "brand": "A"},
-    {"priority": 3, "type": "water",  "size": "350 ml",  "brand": "A"},
-    {"priority": 4, "type": "water",  "size": "600 ml",  "brand": "B"},
-    {"priority": 5, "type": "water",  "size": "1500 ml", "brand": "B"},
-    {"priority": 6, "type": "water",  "size": "350 ml",  "brand": "B"},
-    {"priority": 7, "type": "bottle", "size": "600 ml",  "brand": None},
-    {"priority": 8, "type": "bottle", "size": "1500 ml", "brand": None},
-    {"priority": 9, "type": "bottle", "size": "350 ml",  "brand": None}
-]
-
-# ==============================================
-# 6) เวลา และ Block การทำงาน
-# ==============================================
-WORK_START_1 = 8
-WORK_END_1   = 12
-WORK_START_2 = 13
-WORK_END_2   = 17
-MIN_BLOCK_LEFT = 0.5  # ถ้าบล็อกเหลือ < 0.5 ชม => ข้าม
-
-def get_current_datetime(env):
-    start_sim = datetime(2025, 1, 1, 8, 0, 0)
-    return start_sim + timedelta(hours=env.now)
-
-def skip_to_next_work_time(env):
-    while True:
-        now_dt = get_current_datetime(env)
-        wd = now_dt.weekday()
-        hr = now_dt.hour
-        if wd >= 5:  # เสาร์/อาทิตย์
-            days_to_monday = 7 - wd
-            next_mon_8 = datetime(now_dt.year, now_dt.month, now_dt.day, 8) + timedelta(days=days_to_monday)
-            yield env.timeout((next_mon_8 - now_dt).total_seconds()/3600)
-            continue
-
-        if hr < WORK_START_1:
-            next_8 = datetime(now_dt.year, now_dt.month, now_dt.day, WORK_START_1)
-            yield env.timeout((next_8 - now_dt).total_seconds()/3600)
-            continue
-
-        if WORK_END_1 <= hr < WORK_START_2:
-            next_13 = datetime(now_dt.year, now_dt.month, now_dt.day, WORK_START_2)
-            yield env.timeout((next_13 - now_dt).total_seconds()/3600)
-            continue
-
-        if hr >= WORK_END_2:
-            next_day_8 = datetime(now_dt.year, now_dt.month, now_dt.day, WORK_START_1) + timedelta(days=1)
-            yield env.timeout((next_day_8 - now_dt).total_seconds()/3600)
-            continue
-
-        # อยู่ในเวลางานแล้ว
-        break
-
-def get_time_to_block_end(env):
-    now_dt = get_current_datetime(env)
-    hr = now_dt.hour
-    if WORK_START_1 <= hr < WORK_END_1:
-        block_end = datetime(now_dt.year, now_dt.month, now_dt.day, WORK_END_1)
-    else:
-        block_end = datetime(now_dt.year, now_dt.month, now_dt.day, WORK_END_2)
-    return (block_end - now_dt).total_seconds()/3600
-
-# ==============================================
-# 7) Machine Resource + Log
-# ==============================================
-class MachineResource:
-    def __init__(self, env, machine_id):
-        self.env = env
-        self.machine_id = machine_id
-        self.resource = simpy.PriorityResource(env, capacity=1)
-        self.last_size_run = None  # เก็บ track ว่าล่าสุดผลิตขนาดไหน
-
-production_log = []
-queue_counter = 0
-
-def log_event(machine_id, order_id, page_id,
-              start_dt, finish_dt,
-              bottle_size, produced_qty, duration_hrs):
-    """
-    เก็บ Log ในรูปแบบเบื้องต้นก่อน
-    """
-    global queue_counter
-    queue_counter += 1
-    production_log.append({
-        "QueueID": queue_counter,
-        "MachineID": machine_id,
-        "OrderID": order_id,  # -1 สำหรับงานเผื่อ, -2 สำหรับ Changeover
-        "PageID": page_id,
-        "startTime": start_dt.strftime("%Y-%m-%d %H:%M:%S"),
-        "finishTime": finish_dt.strftime("%Y-%m-%d %H:%M:%S"),
-        "status": "Completed",
-        "bottleSize": bottle_size,
-        "producedQuantity": int(produced_qty),
-        "durationHours": round(duration_hrs, 2)
-    })
-
-def create_machines(env):
-    d = {}
-    for mc in machines_info:
-        d[mc["machine_id"]] = MachineResource(env, mc["machine_id"])
-    return d
-
-# ==============================================
-# 8) ฟังก์ชัน check/consume วัตถุดิบ
-# ==============================================
-def check_raw_materials(item_type, brand, size, quantity):
-    if item_type == "bottle":
-        # จะใช้ preform 1 ชิ้น/ขวด
-        if raw_material_stock["Preform"] < quantity:
-            return False
-    elif item_type == "water":
-        # สุดท้ายจะใช้ preform, label, cap, pe film
-        if raw_material_stock["Preform"] < quantity:
-            return False
-        label_key = f"Label_{brand}"
-        if label_key not in raw_material_stock or raw_material_stock[label_key] < quantity:
-            return False
-        cap_key = f"Cap_{brand}"
-        if cap_key not in raw_material_stock or raw_material_stock[cap_key] < quantity:
-            return False
-        rolls_needed = math.ceil(quantity / 9600)
-        if raw_material_stock["PE_film_roll"] < rolls_needed:
-            return False
-    return True
-
-def consume_raw_materials(item_type, brand, size, quantity):
-    if item_type == "bottle":
-        raw_material_stock["Preform"] -= quantity
-    elif item_type == "water":
-        raw_material_stock["Preform"] -= quantity
-        raw_material_stock[f"Label_{brand}"] -= quantity
-        raw_material_stock[f"Cap_{brand}"]   -= quantity
-        rolls_needed = math.ceil(quantity / 9600)
-        raw_material_stock["PE_film_roll"]   -= rolls_needed
-
-# ==============================================
-# 9) do_split_task: ทำงานจริง แบ่งเป็นบล็อก
-# ==============================================
-def do_split_task(env, machine_id, order_id, page_id,
-                  bottle_size, rate, hours_needed):
-    remain = hours_needed
-    while remain > 0:
-        # ข้ามเวลาจนกว่าจะเข้าสู่ช่วงเวลาทำงาน
-        yield from skip_to_next_work_time(env)
-
-        block_left = get_time_to_block_end(env)
-        if block_left < MIN_BLOCK_LEFT:
-            # ถ้าช่วงเวลาทำงานเหลือน้อยกว่า 0.5 ชม ให้ข้ามไปก่อน
-            yield env.timeout(block_left)
-            continue
-
-        work_hrs = min(remain, block_left)
-        start_dt = get_current_datetime(env)
-        yield env.timeout(work_hrs)
-        finish_dt = get_current_datetime(env)
-
-        remain -= work_hrs
-        produced = rate * work_hrs if rate>0 else 0
-        dur_hrs = (finish_dt - start_dt).total_seconds()/3600
-
-        # บันทึก event
-        log_event(machine_id, order_id, page_id, start_dt, finish_dt,
-                  bottle_size, produced, dur_hrs)
-
-# ==============================================
-# 10) Pipeline สำหรับ Orders ลูกค้า
-# ==============================================
-def customer_pipeline(env, order, machines):
-    order_id = order["customer"]
-    item_type = order["type"]
-    brand = order["brand"]
-    size = order["size"]
-    qty = order["quantity_bottles"]
-    priority = order["priority"]
-
-    # ตรวจสอบวัตถุดิบก่อน
-    if not check_raw_materials(item_type, brand, size, qty):
-        print(f"** วัตถุดิบไม่พอสำหรับ Order {order_id} => skip **")
-        return
-    consume_raw_materials(item_type, brand, size, qty)
-
-    # เลือก Pipeline
-    if item_type == "water":
-        if size == "350 ml":
-            pipeline_seq = ["MC002", "MC003", "MC004"]
-        else:
-            pipeline_seq = ["MC001", "MC003", "MC004"]
-    else:
-        if size == "350 ml":
-            pipeline_seq = ["MC002"]
-        else:
-            pipeline_seq = ["MC001"]
-
-    remain_qty = qty
-    for mc_id in pipeline_seq:
-        mc_info = next(m for m in machines_info if m["machine_id"]==mc_id)
-        idx = mc_info["bottle_size"].index(size)
-        rate = mc_info["speed"][idx]
-        cng = mc_info["changeover_time"][idx]
-
-        mc_res = machines[mc_id]
-        with mc_res.resource.request(priority=priority) as req:
-            yield req
-            # === ทำ Changeover แยกเป็น orderID = -2 ===
-            if mc_res.last_size_run != size:
-                if mc_res.last_size_run is not None:
-                    yield env.process(
-                        do_split_task(env, mc_id, -2, "Changeover", size, 0, cng)
-                    )
-                mc_res.last_size_run = size
-
-            hours_needed = remain_qty / rate
-            yield env.process(
-                do_split_task(env, mc_id, order_id, mc_id, size, rate, hours_needed)
-            )
-
-# ==============================================
-# 11) Pipeline สำหรับการผลิต “เผื่อ”
-# ==============================================
-def buffer_pipeline(env, item, machines, priority):
-    order_id = -1  # หมายถึงงานผลิตเพื่อ buffer
-    item_type = item["type"]
-    brand = item["brand"]
-    size = item["size"]
-
-    can_store = item["want_to_store"] - item["current_store"]
-    if can_store <= 0:
-        return
-
-    # ตรวจสอบวัตถุดิบ
-    if not check_raw_materials(item_type, brand, size, can_store):
-        return
-
-    # ตัดสต็อก
-    consume_raw_materials(item_type, brand, size, can_store)
-
-    # Pipeline
-    if item_type == "water":
-        if size == "350 ml":
-            pipeline_seq = ["MC002", "MC003", "MC004"]
-        else:
-            pipeline_seq = ["MC001", "MC003", "MC004"]
-    else:
-        if size == "350 ml":
-            pipeline_seq = ["MC002"]
-        else:
-            pipeline_seq = ["MC001"]
-
-    remain_qty = can_store
-    for mc_id in pipeline_seq:
-        mc_info = next(m for m in machines_info if m["machine_id"]==mc_id)
-        idx = mc_info["bottle_size"].index(size)
-        rate = mc_info["speed"][idx]
-        cng = mc_info["changeover_time"][idx]
-
-        mc_res = machines[mc_id]
-        with mc_res.resource.request(priority=priority) as req:
-            yield req
-            if mc_res.last_size_run != size:
-                if mc_res.last_size_run is not None:
-                    yield env.process(
-                        do_split_task(env, mc_id, -2, "Changeover", size, 0, cng)
-                    )
-                mc_res.last_size_run = size
-
-            hours_needed = remain_qty / rate
-            yield env.process(
-                do_split_task(env, mc_id, order_id, f"Buffer-{mc_id}", size, rate, hours_needed)
-            )
-
-    item["current_store"] += can_store
-
-# ==============================================
-# 12) Process หลักในการผลิตเผื่อ
-# ==============================================
-def buffer_production_flow(env, machines):
-    done = False
-    while not done:
-        done = True
-        for bf in sorted(buffer_priority, key=lambda x: x["priority"]):
-            bf_type = bf["type"]
-            bf_size = bf["size"]
-            bf_brand = bf["brand"]
-            item = next((it for it in buffer_config
-                         if it["type"]==bf_type and it["size"]==bf_size and it["brand"]==bf_brand),
-                        None)
-            if item is None:
-                continue
-
-            need = item["want_to_store"] - item["current_store"]
-            if need>0:
-                old_val = item["current_store"]
-                yield env.process(buffer_pipeline(env, item, machines, priority=9999))
-                if item["current_store"]>old_val:
-                    done = False
-
-# ==============================================
-# 13) run_simulation
-# ==============================================
-def run_simulation():
-    env = simpy.Environment()
-    machines = create_machines(env)
-
-    # สั่งผลิตตามลำดับ priority ของ order
-    sorted_orders = sorted(customer_orders, key=lambda x: x["priority"])
-    for od in sorted_orders:
-        env.process(customer_pipeline(env, od, machines))
-
-    # สั่งผลิต buffer
-    env.process(buffer_production_flow(env, machines))
-
-    # run จนถึง 2000 ชั่วโมง (เผื่อพอสำหรับคำสั่งทั้งหมด)
-    env.run(until=2000)
-
-    return production_log
-
-# ==============================================
-# ฟังก์ชันเสริม: แปลงโครงสร้าง production_log
-# ==============================================
-from datetime import datetime
-
-def transform_production_log(prod_log):
-    """
-    แปลงข้อมูลให้อยู่ใน structure ตามต้องการ
-    - orderID == -1 → "ผลิตเผื่อ"
-    - orderID == -2 → "เปลี่ยนขนาด"
-    - Mapping machineID (MC001 → MC1, etc.)
-    - แก้ format ของเวลาเป็น d/m/YYYY HH:MM
-    - ตัด space ออกจาก bottleSize เช่น "600 ml" -> "600ml"
-    """
-
-    # Mapping ค่าของ MachineID
-    machine_map = {
-        "MC001": "MC1",
-        "MC002": "MC2",
-        "MC003": "MC3",
-        "MC004": "MC4"
-    }
-
-    new_log = []
-    for row in prod_log:
-        # แปลง string "YYYY-mm-dd HH:MM:SS" เป็น datetime object
-        start_dt = datetime.strptime(row["startTime"], "%Y-%m-%d %H:%M:%S")
-        finish_dt = datetime.strptime(row["finishTime"], "%Y-%m-%d %H:%M:%S")
-
-        # format วัน-เวลาให้เป็น d/m/YYYY HH:MM
-        start_time_str  = f"{start_dt.day}/{start_dt.month}/{start_dt.year} {start_dt.hour:02d}:{start_dt.minute:02d}"
-        finish_time_str = f"{finish_dt.day}/{finish_dt.month}/{finish_dt.year} {finish_dt.hour:02d}:{finish_dt.minute:02d}"
-
-        # แปลง orderID ตามเงื่อนไขที่กำหนด
-        if row["OrderID"] == -1:
-            order_id = "ผลิตเผื่อ"
-        elif row["OrderID"] == -2:
-            order_id = "เปลี่ยนขนาด"
-        else:
-            order_id = row["OrderID"]
-
-        new_log.append({
-            "queueID": row["QueueID"],
-            "machineID": machine_map.get(row["MachineID"], row["MachineID"]),  # Map ค่า MachineID
-            "orderID": order_id,  # ใช้ค่าเปลี่ยนชื่อ orderID
-            "pageNumber": 1,  # Fix เป็น 1 ตามที่กำหนด
-            "status": row["status"],  
-            "startTime": start_time_str,
-            "finishTime": finish_time_str,
-            "bottleSize": row["bottleSize"].replace(" ", ""),  # ตัด space ใน bottleSize เช่น "600 ml" -> "600ml"
-            "producedQuantity": row["producedQuantity"],
-        })
-
-    return new_log
-
-
-
-
-# ==============================================
-# 14) FastAPI
-# ==============================================
-app = FastAPI()
-app.add_middleware(
-    CORSMiddleware,
-    allow_origins=["http://localhost:5173"],  # หรือใช้ ["*"] ถ้าต้องการอนุญาตทุกที่
-    allow_credentials=True,
-    allow_methods=["*"],
-    allow_headers=["*"],
-)
-
-@app.post("/run-simulation/")
-def run_simulation_endpoint():
-    # เรียก simulation
-    prod_log = run_simulation()
-    # แปลง log ให้ได้โครงสร้างตามที่ต้องการ
-    transformed_log = transform_production_log(prod_log)
-    return {
-        "message": "Simulation completed",
-        "production_log": transformed_log,
-        "buffer_config": buffer_config,
-        "raw_material_stock": raw_material_stock
-    }
diff --git a/src/queues/AutoQueue/Autoqueuenew.py b/src/queues/AutoQueue/Autoqueuenew.py
deleted file mode 100644
index ba87ba86..00000000
--- a/src/queues/AutoQueue/Autoqueuenew.py
+++ /dev/null
@@ -1,446 +0,0 @@
-###########################
-# app.py (FastAPI)
-###########################
-
-import sys
-import os
-import requests
-import json
-from fastapi import FastAPI, Body
-from fastapi.middleware.cors import CORSMiddleware
-from typing import List, Dict, Any, Optional, Tuple
-from dataclasses import dataclass, field
-from datetime import datetime, timedelta
-
-###########################
-# 0) CONFIG
-###########################
-if os.name == "nt":
-    # ให้รองรับภาษาไทย + emoji บน Windows
-    sys.stdout.reconfigure(encoding='utf-8')
-
-API_BASE = "http://localhost:4000"  # TODO: ปรับตามจริง
-URLS = {
-    "products": f"{API_BASE}/products",
-    "materials": f"{API_BASE}/materials",
-    "machines": f"{API_BASE}/machines",
-    "stock_configs": f"{API_BASE}/stock-config",
-    # ถ้าจะโพสต์กลับ NestJS ก็เพิ่ม:
-    # "queues_batch": f"{API_BASE}/queues/batch",
-    # "production_targets_many": f"{API_BASE}/production-targets/many",
-}
-
-# เราจะใช้ fastAPI
-app = FastAPI()
-app.add_middleware(
-    CORSMiddleware,
-    allow_origins=["*"],  # หรือกำหนด origin ตามต้องการ
-    allow_credentials=True,
-    allow_methods=["*"],
-    allow_headers=["*"],
-)
-
-###########################
-# 1) DATACLASSES
-###########################
-@dataclass
-class ProductData:
-    ProductID: int
-    brand: str
-    size: str
-    unit: str
-    status: str
-    lowStockLevel: int
-    quantityInStock: int
-    pricePerUnit: str
-    name: str = field(init=False)
-
-    def __post_init__(self):
-        self.name = f"{self.brand} {self.size} ({self.unit})"
-
-
-@dataclass
-class MaterialData:
-    MaterialID: int
-    name: str
-    size: str
-    brand: str
-    quantityInStock: int
-    lowStockLevel: int
-    status: str
-    ReorderLevel: int
-    unit: str
-    pricePerUnit: str
-    LastUpdate: str
-
-@dataclass
-class IngredientData:
-    recipeIngredientID: int
-    quantityNeed: str
-    material: Dict[str,Any]  # ถ้าอยาก map เป็น MaterialData ก็ได้
-
-@dataclass
-class RecipeData:
-    recipeID: int
-    outputItemID: int
-    outputItemType: str
-    outputQuantity: int
-    ingredients: List[IngredientData]
-
-@dataclass
-class MachineDetailData:
-    MachineDetailID: int
-    outputRate: int
-    changOver: float
-    recipes: List[RecipeData]
-
-@dataclass
-class MachineData:
-    MachineID: int
-    name: str
-    type: str
-    lastMaintenanceDate: Optional[str]
-    status: str
-    notes: Optional[str]
-    machineDetails: List[MachineDetailData]
-
-@dataclass
-class StockConfigData:
-    stockConfigID: int
-    itemID: int
-    itemType: str
-    priorityLevel: int
-    targetStockLevel: int
-    status: str
-    lastUpdated: str
-    page: Any = None
-    itemName: Optional[str] = None
-    itemDetail: Optional[Dict[str,Any]] = None
-
-
-###########################
-# 2) LOAD & CLEAN FUNCTIONS
-###########################
-
-def load_products() -> List[ProductData]:
-    resp = requests.get(URLS["products"])
-    data_list = resp.json()
-    cleaned = []
-    for d in data_list:
-        # filter key
-        f = {
-            "ProductID": d.get("ProductID",0),
-            "brand": d.get("brand",""),
-            "size": d.get("size",""),
-            "unit": d.get("unit",""),
-            "status": d.get("status","ปกติ"),
-            "lowStockLevel": int(d.get("lowStockLevel",0)),
-            "quantityInStock": int(d.get("quantityInStock",0)),
-            "pricePerUnit": d.get("pricePerUnit","0.00"),
-        }
-        obj = ProductData(**f)
-        cleaned.append(obj)
-    return cleaned
-
-def load_materials() -> List[MaterialData]:
-    resp = requests.get(URLS["materials"])
-    data_list = resp.json()
-    cleaned = []
-    for d in data_list:
-        f = {
-            "MaterialID": d.get("MaterialID",0),
-            "name": d.get("name","Unknown"),
-            "size": d.get("size","any"),
-            "brand": d.get("brand","any"),
-            "quantityInStock": int(d.get("quantityInStock",0)),
-            "lowStockLevel": int(d.get("lowStockLevel",0)),
-            "status": d.get("status","ปกติ"),
-            "ReorderLevel": int(d.get("ReorderLevel",0)),
-            "unit": d.get("unit","ชิ้น"),
-            "pricePerUnit": d.get("pricePerUnit","0.00"),
-            "LastUpdate": d.get("LastUpdate","2023-01-01T00:00:00Z")
-        }
-        cleaned.append(MaterialData(**f))
-    return cleaned
-
-def load_machines() -> List[MachineData]:
-    resp = requests.get(URLS["machines"])
-    raw_list = resp.json()
-    machines = []
-    for mc in raw_list:
-        # filter machine
-        m = MachineData(
-            MachineID=mc.get("MachineID",0),
-            name=mc.get("name","Unknown"),
-            type=mc.get("type","Unknown"),
-            lastMaintenanceDate=mc.get("lastMaintenanceDate"),
-            status=mc.get("status","ACTIVE"),
-            notes=mc.get("notes"),
-            machineDetails=[]
-        )
-        md_list = mc.get("machineDetails",[])
-        for md in md_list:
-            detail = MachineDetailData(
-                MachineDetailID=md.get("MachineDetailID",0),
-                outputRate=md.get("outputRate",1000),
-                changOver=float(md.get("changOver",0)),
-                recipes=[]
-            )
-            for r in md.get("recipes",[]):
-                recipe = RecipeData(
-                    recipeID=r.get("recipeID",0),
-                    outputItemID=r.get("outputItemID",0),
-                    outputItemType=r.get("outputItemType","MATERIAL"),
-                    outputQuantity=r.get("outputQuantity",1),
-                    ingredients=[]
-                )
-                for ing in r.get("ingredients",[]):
-                    iobj = IngredientData(
-                        recipeIngredientID=ing.get("recipeIngredientID",0),
-                        quantityNeed=ing.get("quantityNeed","1.0"),
-                        material=ing.get("material",{})
-                    )
-                    recipe.ingredients.append(iobj)
-                detail.recipes.append(recipe)
-            m.machineDetails.append(detail)
-        machines.append(m)
-    return machines
-
-def load_stockconfigs() -> List[StockConfigData]:
-    resp = requests.get(URLS["stock_configs"])
-    data_list = resp.json()
-    cleaned = []
-    for sc in data_list:
-        # rename key
-        scid = sc.get("StockConfigID",0)
-        f = {
-            "stockConfigID": scid,
-            "itemID": sc.get("itemID",0),
-            "itemType": sc.get("itemType","PRODUCT"),
-            "priorityLevel": int(sc.get("priorityLevel",1)),
-            "targetStockLevel": int(sc.get("targetStockLevel",0)),
-            "status": sc.get("status","Active"),
-            "lastUpdated": sc.get("lastUpdated","2023-01-01T00:00:00Z"),
-            "page": sc.get("page"),
-            "itemName": sc.get("itemName"),
-            "itemDetail": sc.get("itemDetail"),
-        }
-        cleaned.append(StockConfigData(**f))
-    return cleaned
-
-###########################
-# 3) BFS + SCHEDULING
-###########################
-@dataclass
-class PipelineStep:
-    machine_id: int
-    machine_detail_id: int
-    item_id: int
-    item_type: str
-
-# dict -> (rate, co)
-machine_detail_map: Dict[Tuple[int,int],Tuple[int,float]] = {}
-
-def build_machine_detail_map(machines: List[MachineData]):
-    machine_detail_map.clear()
-    for mc in machines:
-        for md in mc.machineDetails:
-            machine_detail_map[(mc.MachineID, md.MachineDetailID)] = (
-                md.outputRate,
-                md.changOver
-            )
-    return machine_detail_map
-
-def find_recipe_for_item(machines: List[MachineData], item_id: int, item_type: str):
-    found = []
-    for mc in machines:
-        for md in mc.machineDetails:
-            for r in md.recipes:
-                if r.outputItemID == item_id and r.outputItemType.upper() == item_type.upper():
-                    found.append((mc, md, r))
-    return found
-
-def build_pipeline(machines: List[MachineData], item_id:int, item_type:str, visited=None)->List[PipelineStep]:
-    if visited is None:
-        visited = set()
-    key_ = f"{item_type}:{item_id}"
-    if key_ in visited:
-        return []
-    visited.add(key_)
-
-    matched = find_recipe_for_item(machines, item_id, item_type)
-    if not matched:
-        return []  # raw
-
-    # pick first
-    mc, md, recipe = matched[0]
-    # BFS for ingredient
-    for ing in recipe.ingredients:
-        mat_id = ing.material.get("MaterialID",0)
-        # assum item_type= "MATERIAL"
-        build_pipeline(machines, mat_id, "MATERIAL", visited)
-
-    # add final step
-    step = PipelineStep(machine_id=mc.MachineID,
-                        machine_detail_id=md.MachineDetailID,
-                        item_id=item_id,
-                        item_type=item_type)
-    return [step]
-
-# scheduling
-WORKBLOCKS = [(8,12),(13,17)]
-MIN_BLOCK_LEFT = 0.5
-
-def is_weekend(dt: datetime)->bool:
-    return dt.weekday() >= 5
-
-def next_work_time(dt: datetime)->datetime:
-    while True:
-        if is_weekend(dt):
-            add_days = 7 - dt.weekday()
-            dt = datetime(dt.year, dt.month, dt.day, 8,0,0) + timedelta(days=add_days)
-            return dt
-        hr = dt.hour
-        if hr < 8:
-            return datetime(dt.year, dt.month, dt.day, 8,0,0)
-        if 8<=hr<12:
-            return dt
-        if hr<13:
-            return datetime(dt.year, dt.month, dt.day, 13,0,0)
-        if hr<17:
-            return dt
-        dt = datetime(dt.year, dt.month, dt.day, 8,0,0) + timedelta(days=1)
-
-def get_block_end(dt: datetime)->datetime:
-    hr = dt.hour
-    if 8<=hr<12:
-        return datetime(dt.year, dt.month, dt.day, 12,0,0)
-    else:
-        return datetime(dt.year, dt.month, dt.day, 17,0,0)
-
-def get_rate_co(machine_id:int, md_id:int)->Tuple[int,float]:
-    if (machine_id,md_id) in machine_detail_map:
-        return machine_detail_map[(machine_id,md_id)]
-    return (1000,0)
-
-def schedule_pipeline(pipeline:List[PipelineStep], qty:int, start_dt:datetime, order_id:int):
-    """Return (events, finishTime)"""
-    events = []
-    current_dt = start_dt
-    for step in pipeline:
-        rate, co = get_rate_co(step.machine_id, step.machine_detail_id)
-        if rate<=0:
-            continue
-
-        hours_needed = qty / rate
-        remain = hours_needed
-        while remain>0:
-            current_dt = next_work_time(current_dt)
-            block_end = get_block_end(current_dt)
-            block_left = (block_end - current_dt).total_seconds()/3600
-            if block_left<MIN_BLOCK_LEFT:
-                current_dt = block_end
-                continue
-            used = min(remain, block_left)
-            st = current_dt
-            ft = st + timedelta(hours=used)
-            remain-=used
-            current_dt=ft
-
-            produced = rate*used
-            events.append({
-                "startTime": st.isoformat(),
-                "finishTime": ft.isoformat(),
-                "machineID": step.machine_id,
-                "itemID": step.item_id,
-                "itemType": step.item_type,
-                "producedQuantity": int(produced),
-                "orderID": order_id,
-                # "status": "Pending" # TODO: อาจใส่
-                # "bottleSize": "???" # TODO: ถ้าอยาก mapping size/brand
-            })
-    return events, current_dt
-
-
-###########################
-# 4) ตัวอย่าง Endpoint FastAPI
-###########################
-@app.post("/run-simulation")
-def run_simulation_endpoint(payload: dict = Body(...)):
-    """
-    ตัวอย่าง endpoint ที่ front-end จะยิงมา
-    เช่น JSON: {
-      "itemID": 12,
-      "itemType": "MATERIAL",
-      "qty": 5000,
-      "startDate": "2025-03-25T08:00:00",
-      "orderID": 1
-    }
-    """
-
-    item_id = payload.get("itemID",12)
-    item_type = payload.get("itemType","MATERIAL")
-    qty = payload.get("qty",1000)
-    startDateStr = payload.get("startDate","2025-03-25T08:00:00")
-    order_id = payload.get("orderID",1)
-
-    start_dt = datetime.fromisoformat(startDateStr)
-
-    # 1) load data
-    products = load_products()
-    materials = load_materials()
-    machines = load_machines()
-    stockconfigs = load_stockconfigs()
-
-    # 2) build machine_detail_map
-    build_machine_detail_map(machines)
-
-    # TODO: ตัวอย่างถ้ามี Logic เช็คของใน stock ว่าพอไหม => skip ถ้าไม่พอ
-    # (ยกตัวอย่างเล็กๆ)
-    # material_2 = next((m for m in materials if m.MaterialID==2), None)
-    # if material_2 and material_2.quantityInStock<qty:
-    #     return {"message":"Not enough raw material for item #2. Skip."}
-
-    # 3) BFS pipeline
-    pipeline = build_pipeline(machines, item_id, item_type)
-
-    # 4) schedule
-    events, finish_dt = schedule_pipeline(pipeline, qty, start_dt, order_id)
-
-    # 5) สร้าง ProductionTarget mock-up
-    production_target = {
-        "OrderID": order_id,
-        "itemID": item_id,
-        "itemType": item_type,
-        "TargetProduced": qty,
-        "ActualProduced": 0,
-        "Status": "กำลังรอ",
-        "Date": start_dt.strftime("%Y-%m-%d"),
-        # "startTime": start_dt.isoformat(),
-        # "endTime": finish_dt.isoformat()
-    }
-
-    # 6) ถ้าจะ POST ต่อไป NestJS => uncomment
-    # r1 = requests.post(URLS["production_targets_many"], json={"productionTargets":[production_target]})
-    # r2 = requests.post(URLS["queues_batch"], json=events)
-    # etc...
-
-    return {
-        "message": "Simulation completed",
-        "pipelineSteps": [f"{s.machine_id}:{s.machine_detail_id} => item {s.item_id}" for s in pipeline],
-        "queueEvents": events,
-        "productionTargetExample": production_target,
-        "finishedAt": finish_dt.isoformat()
-    }
-
-
-###########################
-# 5) ตัวอย่างวิธีรัน
-###########################
-# - เซฟไฟล์นี้เป็น app.py
-# - รันด้วยคำสั่ง: uvicorn app:app --reload
-#
-# แล้วลอง POST มาที่:
-# http://127.0.0.1:8000/run-simulation
-# ด้วย JSON ตามตัวอย่าง
-
diff --git a/src/queues/AutoQueue/Log copy.py b/src/queues/AutoQueue/Log copy.py
deleted file mode 100644
index dae9ed6b..00000000
--- a/src/queues/AutoQueue/Log copy.py	
+++ /dev/null
@@ -1,438 +0,0 @@
-import requests
-import json
-import sys
-import os
-from dataclasses import dataclass, field
-from typing import List, Optional, Dict, Any
-
-# =======================================================
-# 0) CONFIG
-# =======================================================
-if os.name == "nt":
-    sys.stdout.reconfigure(encoding='utf-8')
-
-API_BASE = "http://localhost:4000"
-URLS = {
-    "products": f"{API_BASE}/products",
-    "materials": f"{API_BASE}/materials",
-    "machines": f"{API_BASE}/machines",
-    "stock_configs": f"{API_BASE}/stock-config",
-    "orders": f"{API_BASE}/orders",
-    "order_prio": f"{API_BASE}/orderpiorities"
-}
-
-# =======================================================
-# 1) DATACLASSES
-# =======================================================
-
-# ---------- 1.1 Product ----------
-@dataclass
-class ProductData:
-    ProductID: int
-    brand: str
-    size: str
-    unit: str
-    status: str
-    lowStockLevel: int
-    quantityInStock: int
-    pricePerUnit: str  # อาจเป็น string
-    name: str = field(init=False)
-
-    def __post_init__(self):
-        # เช่น รวม brand + size + unit เป็น name
-        self.name = f"{self.brand} {self.size} ({self.unit})"
-
-# ---------- 1.2 Material ----------
-@dataclass
-class MaterialData:
-    MaterialID: int
-    name: str
-    size: str
-    brand: str
-    quantityInStock: int
-    lowStockLevel: int
-    status: str
-    ReorderLevel: int
-    unit: str
-    pricePerUnit: str
-    LastUpdate: str
-    display_name: str = field(init=False)
-
-    def __post_init__(self):
-        self.display_name = f"{self.name} {self.size} {self.brand} ({self.unit})"
-
-# ---------- 1.3 Ingredient (Recipe_Ingredient) ----------
-@dataclass
-class IngredientData:
-    recipeIngredientID: int
-    quantityNeed: str  # เช่น "1.000000"
-    material: MaterialData
-
-# ---------- 1.4 Recipe ----------
-@dataclass
-class RecipeData:
-    recipeID: int
-    outputItemID: int
-    outputItemType: str  # 'PRODUCT' | 'MATERIAL'
-    outputQuantity: int
-    ingredients: List[IngredientData]
-
-# ---------- 1.5 MachineDetail ----------
-@dataclass
-class MachineDetailData:
-    MachineDetailID: int
-    outputRate: int
-    changOver: float
-    recipes: List[RecipeData]
-
-# ---------- 1.6 Machine ----------
-@dataclass
-class MachineData:
-    MachineID: int
-    name: str
-    type: str
-    lastMaintenanceDate: Optional[str]
-    status: str
-    notes: Optional[str]
-    machineDetails: List[MachineDetailData]
-
-# ---------- 1.7 StockConfigData ----------
-@dataclass
-class StockConfigData:
-    stockConfigID: int
-    itemID: int
-    itemType: str
-    priorityLevel: int
-    targetStockLevel: int
-    status: str
-    lastUpdated: str
-    # สมมุติ page เป็นอะไรก็ได้ (object/dict) หรือ int
-    page: Any = None
-    itemName: Optional[str] = None
-    itemDetail: Optional[Dict[str, Any]] = None
-
-# ---------- 1.8 Order ----------
-@dataclass
-class OrderData:
-    OrderID: int
-    status: str
-    quantity: int
-    totalPriceall: int
-    # คุณอาจใส่ฟิลด์อื่น เช่น date/time, customerID, ฯลฯ
-
-# ---------- 1.9 OrderPriority ----------
-@dataclass
-class OrderPriorityData:
-    orderPriorityID: int
-    Priority: int
-    OrderID: int
-    PageID: Optional[int] = None  # ให้มี default = None
-
-# =======================================================
-# 2) HELPER LOAD & CLEAN FUNCTIONS
-# =======================================================
-
-def rename_keys_if_needed(d: dict, old_key: str, new_key: str):
-    """ถ้าใน d มี old_key ให้ย้ายไป new_key"""
-    if old_key in d:
-        d[new_key] = d[old_key]
-        del d[old_key]
-
-# ---------- load & clean Products ----------
-def load_and_clean_products() -> List[ProductData]:
-    resp = requests.get(URLS["products"])
-    raw_list = resp.json()
-
-    allowed_keys = {
-        "ProductID","brand","size","unit",
-        "status","lowStockLevel","quantityInStock",
-        "pricePerUnit"
-    }
-    cleaned_list = []
-    for r in raw_list:
-        # filter
-        f = {k:r[k] for k in r if k in allowed_keys}
-        # fill defaults
-        if "status" not in f:
-            f["status"] = "ปกติ"
-        if "lowStockLevel" not in f:
-            f["lowStockLevel"] = 0
-        if "quantityInStock" not in f:
-            f["quantityInStock"] = 0
-        if "pricePerUnit" not in f:
-            f["pricePerUnit"] = "0.00"
-        # convert if needed
-        f["lowStockLevel"] = int(f["lowStockLevel"])
-        f["quantityInStock"] = int(f["quantityInStock"])
-        # create dataclass
-        obj = ProductData(**f)
-        cleaned_list.append(obj)
-    return cleaned_list
-
-# ---------- load & clean Materials ----------
-def load_and_clean_materials() -> List[MaterialData]:
-    resp = requests.get(URLS["materials"])
-    raw_list = resp.json()
-
-    allowed_keys = {
-        "MaterialID","name","size","brand","quantityInStock","lowStockLevel",
-        "status","ReorderLevel","unit","pricePerUnit","LastUpdate"
-    }
-    cleaned_list = []
-    for r in raw_list:
-        f = {k:r[k] for k in r if k in allowed_keys}
-
-        # fill default
-        if "status" not in f:
-            f["status"] = "ปกติ"
-        if "lowStockLevel" not in f:
-            f["lowStockLevel"] = 0
-        if "quantityInStock" not in f:
-            f["quantityInStock"] = 0
-        if "ReorderLevel" not in f:
-            f["ReorderLevel"] = 0
-        if "pricePerUnit" not in f:
-            f["pricePerUnit"] = "0.00"
-        if "LastUpdate" not in f:
-            f["LastUpdate"] = "2023-01-01T00:00:00.000Z"
-
-        # cast
-        f["lowStockLevel"] = int(f["lowStockLevel"])
-        f["quantityInStock"] = int(f["quantityInStock"])
-        f["ReorderLevel"] = int(f["ReorderLevel"])
-
-        obj = MaterialData(**f)
-        cleaned_list.append(obj)
-    return cleaned_list
-
-# ---------- load & clean Machines (มี machineDetails -> recipes -> ingredients) ----------
-def load_and_clean_machines() -> List[MachineData]:
-    resp = requests.get(URLS["machines"])
-    raw_list = resp.json()
-
-    # ฟิลด์ของ Machine
-    machine_allowed_keys = {
-        "MachineID","name","type","lastMaintenanceDate","status","notes","machineDetails"
-    }
-
-    # ฟิลด์ของ MachineDetail
-    detail_allowed_keys = {
-        "MachineDetailID","outputRate","changOver","recipes"
-    }
-
-    # ฟิลด์ของ Recipe
-    recipe_allowed_keys = {
-        "recipeID","outputItemID","outputItemType","outputQuantity","ingredients"
-    }
-
-    # ฟิลด์ของ Ingredient
-    ingredient_allowed_keys = {
-        "recipeIngredientID","quantityNeed","material"
-    }
-
-    # ฟิลด์ของ Material ภายใน Ingredient
-    ing_mat_allowed_keys = {
-        "MaterialID","name","size","brand","quantityInStock","lowStockLevel",
-        "status","ReorderLevel","unit","pricePerUnit","LastUpdate"
-    }
-
-    cleaned_machines = []
-    for mc in raw_list:
-        # filter machine level
-        m = {k:mc[k] for k in mc if k in machine_allowed_keys}
-
-        # ถ้าไม่มี machineDetails ให้เป็น []
-        if "machineDetails" not in m or not m["machineDetails"]:
-            m["machineDetails"] = []
-
-        # ตอนนี้ m["machineDetails"] เป็น list
-        new_details = []
-        for md in m["machineDetails"]:
-            # filter detail
-            md_f = {k:md[k] for k in md if k in detail_allowed_keys}
-
-            # fill default
-            if "changOver" not in md_f:
-                md_f["changOver"] = 0.0
-
-            # recipes
-            if "recipes" not in md_f or not md_f["recipes"]:
-                md_f["recipes"] = []
-
-            new_recipes = []
-            for r in md_f["recipes"]:
-                r_f = {k:r[k] for k in r if k in recipe_allowed_keys}
-                # fill default
-                if "ingredients" not in r_f or not r_f["ingredients"]:
-                    r_f["ingredients"] = []
-
-                new_ingredients = []
-                for ing in r_f["ingredients"]:
-                    ing_f = {k:ing[k] for k in ing if k in ingredient_allowed_keys}
-
-                    # material inside ingredient
-                    if "material" in ing_f and ing_f["material"]:
-                        mat_in_ing = ing_f["material"]
-                        mat_filtered = {mk:mat_in_ing[mk] for mk in mat_in_ing if mk in ing_mat_allowed_keys}
-                        # fill default if needed
-                        if "status" not in mat_filtered:
-                            mat_filtered["status"] = "ปกติ"
-                        if "lowStockLevel" not in mat_filtered:
-                            mat_filtered["lowStockLevel"] = 0
-                        if "quantityInStock" not in mat_filtered:
-                            mat_filtered["quantityInStock"] = 0
-                        ing_f["material"] = mat_filtered
-                    else:
-                        ing_f["material"] = {
-                            "MaterialID":0,"name":"Unnamed"
-                        }
-
-                    new_ingredients.append(IngredientData(**ing_f))
-                r_f["ingredients"] = new_ingredients
-
-                new_recipes.append(RecipeData(**r_f))
-            md_f["recipes"] = new_recipes
-
-            new_details.append(MachineDetailData(**md_f))
-        m["machineDetails"] = new_details
-
-        # fill default
-        if "notes" not in m:
-            m["notes"] = None
-        if "lastMaintenanceDate" not in m:
-            m["lastMaintenanceDate"] = None
-
-        # cast if needed
-        obj = MachineData(**m)
-        cleaned_machines.append(obj)
-
-    return cleaned_machines
-
-# ---------- load & clean StockConfigs ----------
-def load_and_clean_stockconfigs() -> List[StockConfigData]:
-    resp = requests.get(URLS["stock_configs"])
-    raw_list = resp.json()
-
-    allowed_keys = {
-        "stockConfigID","itemID","itemType","priorityLevel","targetStockLevel",
-        "status","lastUpdated","page","itemName","itemDetail"
-    }
-    cleaned_list = []
-    for sc in raw_list:
-        f = {k:sc[k] for k in sc if k in allowed_keys}
-
-        # fill default
-        if "stockConfigID" not in f:
-            f["stockConfigID"] = 0
-        if "status" not in f:
-            f["status"] = "Active"
-        if "priorityLevel" not in f:
-            f["priorityLevel"] = 1
-        if "targetStockLevel" not in f:
-            f["targetStockLevel"] = 0
-
-        # cast
-        f["priorityLevel"] = int(f["priorityLevel"])
-        f["targetStockLevel"] = int(f["targetStockLevel"])
-
-        obj = StockConfigData(**f)
-        cleaned_list.append(obj)
-    return cleaned_list
-
-# ---------- load & clean Orders ----------
-def load_and_clean_orders() -> List[OrderData]:
-    resp = requests.get(URLS["orders"])
-    raw_list = resp.json()
-
-    allowed_keys = {
-        "OrderID","status","quantity","totalPriceall"
-    }
-    cleaned_list = []
-    for od in raw_list:
-        f = {k:od[k] for k in od if k in allowed_keys}
-
-        # fill default
-        if "status" not in f:
-            f["status"] = "NEW"
-        if "quantity" not in f:
-            f["quantity"] = 0
-        if "totalPriceall" not in f:
-            f["totalPriceall"] = 0
-
-        obj = OrderData(**f)
-        cleaned_list.append(obj)
-    return cleaned_list
-
-# ---------- load & clean OrderPriorities ----------
-def load_and_clean_order_prio() -> List[OrderPriorityData]:
-    resp = requests.get(URLS["order_prio"])
-    if resp.status_code != 200:
-        # เผื่อกรณีไม่มี API ให้
-        print("No order priorities found or 404 not found")
-        return []
-
-    raw_list = resp.json()
-    allowed_keys = {
-        "orderPriorityID","Priority","OrderID","PageID"
-    }
-    cleaned_list = []
-    for op in raw_list:
-        f = {k:op[k] for k in op if k in allowed_keys}
-        # fill default
-        if "Priority" not in f:
-            f["Priority"] = 999
-        if "OrderID" not in f:
-            f["OrderID"] = 0
-
-        obj = OrderPriorityData(**f)
-        cleaned_list.append(obj)
-    return cleaned_list
-
-
-# =======================================================
-# 3) MAIN DEMO
-# =======================================================
-def main():
-    print("=== Loading & Cleaning Data from NestJS ===")
-
-    products = load_and_clean_products()
-    print(">>> Products:")
-    for p in products:
-        print(p)
-    print("==========================================\n")
-
-    materials = load_and_clean_materials()
-    print(">>> Materials:")
-    for m in materials:
-        print(m)
-    print("==========================================\n")
-
-    machines = load_and_clean_machines()
-    print(">>> Machines:")
-    for mc in machines:
-        print(mc)
-    print("==========================================\n")
-
-    stockconfigs = load_and_clean_stockconfigs()
-    print(">>> StockConfigs:")
-    for sc in stockconfigs:
-        print(sc)
-    print("==========================================\n")
-
-    orders = load_and_clean_orders()
-    print(">>> Orders:")
-    for od in orders:
-        print(od)
-    print("==========================================\n")
-
-    order_prios = load_and_clean_order_prio()
-    print(">>> OrderPriorities:")
-    for op in order_prios:
-        print(op)
-    print("==========================================\n")
-
-    print("All data cleaned successfully! 🎉")
-
-
-if __name__ == "__main__":
-    main()
diff --git a/src/queues/AutoQueue/Log.py b/src/queues/AutoQueue/Log.py
deleted file mode 100644
index 9557e43d..00000000
--- a/src/queues/AutoQueue/Log.py
+++ /dev/null
@@ -1,45 +0,0 @@
-import requests
-import json
-import sys
-import os
-
-# ให้รองรับภาษาไทยและ emoji บน Windows
-if os.name == "nt":
-    sys.stdout.reconfigure(encoding="utf-8")
-
-API_BASE = "http://localhost:4000"
-URLS = {
-    "products": f"{API_BASE}/products",
-    "materials": f"{API_BASE}/materials",
-    "machines": f"{API_BASE}/machines",
-    "stock_configs": f"{API_BASE}/stock-config",
-}
-
-def log_json_from_api(name: str, url: str):
-    print(f"\n📦 ดึงข้อมูลจาก API: {name} -> {url}")
-    try:
-        response = requests.get(url)
-        response.raise_for_status()
-        data = response.json()
-
-        # แสดงจำนวนรายการ
-        print(f"✅ ได้ข้อมูลทั้งหมด: {len(data)} รายการ")
-
-        # แสดงเฉพาะ 1-2 รายการแรก
-        preview_count = min(2, len(data))
-        print(f"\n🔍 แสดงตัวอย่าง {preview_count} รายการแรก:")
-        for i in range(preview_count):
-            print(f"\n🔹 {name} #{i+1}")
-            print(json.dumps(data[i], indent=2, ensure_ascii=False))
-
-    except Exception as e:
-        print(f"❌ เกิดข้อผิดพลาดในการดึง {name}: {e}")
-
-def main():
-    log_json_from_api("Products", URLS["products"])
-    log_json_from_api("Materials", URLS["materials"])
-    log_json_from_api("Machines", URLS["machines"])
-    log_json_from_api("Stock Configs", URLS["stock_configs"])
-
-if __name__ == "__main__":
-    main()
diff --git a/src/queues/AutoQueue/__pycache__/Autoqueue.cpython-310.pyc b/src/queues/AutoQueue/__pycache__/Autoqueue.cpython-310.pyc
deleted file mode 100644
index 890596d9249b96652c7a5c93ae31b40707cb30d9..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 10637
zcmd1j<>g{vU|_JidO7`$KLf*K5C<9aF)%PVFfcF_A7Wx)NMT4}%wdQE(M&mvxr|Ya
zxlB<^j37Q^4s#T93PTEW4ofa;6f0PaC5J7SJ&K)?A%!)CErmUWBb_mYGleUiDTO<Q
zC!HyUH-$HyDTObEe-1~AK#Cw#g-|+Uif}q(3PU<0R8AyCG({{$JVhd%DV-rjauH)X
zLy8oblwJf=Ba<SVBA3pPA`cdas8Im36=7=9S)w>nl;BV~MP&|K6laQRidqV1ih7Dh
zie`#diuN4#6dkCDZi-%tK1d{;DT*saEk!6rJq6@fgE_2F6^1DcDG(l4ih7C>oF|lG
zjH1#QNscQ8!81t_N@0YnG)du1VT7wRN#R29(mA8JQ}m&>n$BTK(MnNE0oe&+^FrMQ
zVw-{07^i^P=3q4twgp%Xgl(Auu?eKcDg|N>h;5w$agXU7mUPZ2o)oJn-V~cCz7*Ri
z{uH|?ffV~F!4!uS#}<Ytp%kYS=N5)2;S`q?*A|8-5qE|Zw-omlh7|W^rYO;LhA6QV
zhD7lcj}*@qhA4>?uN3bVhA7DtpA_E~hA62NzZCx#hA8QjfRw-%hA5eopp@VihA7#T
zkd)9ChA6p|u$1r?hA8=zh?K|{hA4#;hLk8sdShfriB5@WVTe*pWo>4NQc6|IQch)0
ziA`rriA#x3X9VMfURFkiRHX$fDTxaiQ<74WTNs)dqf}EEgBdhaUV>7$pC;2Sj+Dfb
z)RN5H)LWb&G9@*qBvF&`7Q0(wafxGqrzYbqK4<@+VBgG?l$_M^#G=$&tiH|$28N|t
z3=9kpb~ZfN(ehx&;s-mnKiJvvV8_}AJKDj5v%%a=4|X&?*s=V<jwz))Fy&C0TkHWv
zscHE|xxd)V3=9-<bAGWKnt~abGdLI+GJRMW7+x|nFff!Vf^_bf2eM^nC)kRG4|X;`
z*wOU>#BG1DW7C5jGc`GGapfi^XJqE3#%HEP@xa)5iMgq_IMPb<l1no4^P)I&6H8Ky
zG81!(Z*eE(mz3nB#usN+rQTvKE=WyHxy7HHk(igBnqQV$6b}lGTWrN8i6y1Q5I-B0
z8i1Taw4W7>O$~B$ez6&wg8cXL0y_f(#2{llfwyB7IKUP@*wOi5$5OE88cRh%_F|KX
zV)aQ(O3jJlcFip)sdNJSNRzoph=GBjhyz4$GB7Y`GQV8F&%jUwGNniuEKtM<l7tfw
zXPJ~5gY3cTza6tc;SY-Fjt4t-C}=A@*xC4C$GitS+aK&`DU}83Lsg=KqC%57N(jk`
zU`MB>L@_%j7DTZJxW=bt=HzNJzf9m{U?>s?ISoW;GCv2UQU-<x_C*pPK@gFt;K#u5
zQUv4+wjy>028Jkhuxas*FoshUt8-#Oyd#8iy2S%EKfWkGCnt(MJhP-Eu`=-%YdI(>
z++uXhyr96qP{n0rU}UOmV5n<g@sbH-I{Ph-<kI4j{M^){TP!7&1*x}KAW0>uC^0YP
zmOx=?VqQsRNo71F9Ti7$q?D${gL2a?j)J1h{G!Z~$|z>X{Ir(>d?@CdzXXN5CTo#A
z$WIC&0+hsW@s=m%mBg3i#}}967p30fO)f1eO3f>Qa5Ej`85lAP#2FZFF*@C1gV?Fb
zQlt#hj%v_L76t}}m#iRy4Mczf=_M#JyaXkNm!ORJk{2W)2+|7*(`1l?AVJN*0P;LY
zi!-RYQ(|CXC}BupOkql4N?}f6NnvSbt7WWVEMcr+$YM%i?PU~a2xib^^UHk6&cINl
z3Nld-M1V}xWW2?ikzZO=tjSyiGPMYloo_Mc<(F$R-C|D7D~sYRE=epZi7(E~UCB^n
z#=yYv%f`hjCZH%kD>b<!CMhvFJ2fu_P8Sy?#}t;PmZlcRIF^>=2ZESj7FbZPpz@YT
zdTL2LEZjg*0m{UUAdi5;M2Jy<vB-jffdR$8pg;iyRx(JL5+egcBLgQx2}2D-Gb6~S
z3m6wN)H2mDW--+=*D$3pWwRC;rZCqqNifv1lrYyYX0g;TX0g^VX0fHPG_#bj*RViB
zrIxjZVF5=CYYn3W!vfBQ3@L2V3=0{<7#JA}8EcqJxUw0Fd{Fh5a5b~kvVnE6VbfK@
zUBk@6z|4@%SQJ*mlg&_+pU1?=kSC623QsdjEj!p0c5J59FqiOVvljKE>EZ&pJ%t_W
zb`G$94s7~UK=IAt7gD4Rie_C90g7-<##<~YiIv4gDj*S1I?&_;hxIM?^3>Gql*Gzg
zETFUiP6)SHDpM1SZn5U(=appKVoph{gd`1iP;}*&mfYek$uCLFi7!q~&d*CJzQq&n
zALJb$9O4)h5^s2m3(Rx%bBQ-ZkugG&G1BBLGG$<3xW$&2Uml-Qa*L@v<rY&$Q4}A@
zk)TYLo1d4GSQ*8Yms(L0pPQc-ZxO`?W?MwDgK0x!sANiFWxNGAbwUVpkhx;T*_j0(
zbHHlL^NX^<6-Fy45rM*ksey@+gOP)g4NS^0N-#1paxjU2X$dIJ!2}U!VJ`AOPnDqb
z3QCpWT$ljPg|HNv#aPQ!!c@ZqO$&l0%-IY@a^SSUT>?*yHH=y8CCtq%waj^3Xrde-
z(HdrW>@rG&;*`k`9Cw;r;Aktd2F0Tzh;RZC;QVU?V%dTSI}qUlB0#NTO%`xq7rBB2
z+(BhBXHrgna&~-bUJ4}4KzX|e9B`tbEDDNeP~gE;EdqrbsAK|#m;|F3qX?4#W05B)
zRAA*2j0U*`WN9&|4oGE)VoYI(Vgi*=Eeui2Da^qPnk={YeIZSOpw#00(xT+lWKhWi
zGXTT}1ur;g)fgBUY8Y!6;u&g~Y8c`fOPI2lYZyVs^@8{;DGW6X@vPuP&+G>--!vI-
zaU>@eBqnE;RBEz8JkAYD60F6UxdoL`0s+v%A7=S2jv}ZtZt><M7K4hrs?_+R(mYM(
zTP($?IcW$p&;yGjK0Y%qvm`!#Jp%(nF{lh@V`O6#VB}(~l0fsK9!#m9Cd)03_;^sm
zCqDibSA2YKeoARhYJB`Hp7{8}(!?ByOi=(RvcU0zAV4ux<i)_iunuG&D3CZ9co@MV
z$spTdK?q`lx<ue01f>s99bwLp$WX$#fC*G~)-cvE)i5t$PGMTeSi=ILQ<!U5OIT{y
zni)%2YuHm*nwe5q=Ws1#WMoKT3ue${FO6bgVBk_vP*4E3AREDLi&+Xj`RNMa_TEfz
z3uNbm9kao0k690P%mOQ%1#WyoT88Zpc1#5~3uivq(FksWu6?j$CfHDL<oyy<jnq}m
z)m2SVQ1!4<^|ewBj^cFA&n?JFElEu&0<~i_xo)w8s}@g}Tb$59_H?<$?q8IWTIA^x
z#TJm5o(hr!*Igl?mNQpcW?p7-28dlG07?p6koq|o)U*^RD9TSMO-@Y-gf<wWcvDJ?
z5<$&T4^ZXkr^$AU7hHqIC+C;um82Hk;)7@bDT&X?Prt>MSWu9fmvW1vxTGizly`11
zXXcgMVlB!q%}debC;}%xj(m^<<1<rku@@w!gId8L^`PoCrQ{YT#D(!GB}JgBKZ*xp
zLuyKVVM%2a56nUF8AZkDX^=A~KRrIREH$rW2PjcUF)%Q2u(L2SK_RG+1F=B`9nZI-
zG*FfWRsOJ~0?KXhf=q*ffgzKjma&Avg&~%=mI>61s9{QBlw@dT0woy`%Z8zlr3TbT
zVe$ieOq1yrFSIpZ9G{t&mJd#jn#|x_bBi%0iYYf4-Oc>TMX8A;sqrv<XF)CpC0Z6n
z4n_$^7RI7XkUK#M9Oh0?lLy2HC+S(BQh_0bF`KD~uY@6mNs^%kRLJsxikB45V1^oo
z6qanJB5x!)DX<)C4dZNvxlFYzH7q3zWsJp|B@8tzP~F;K6>LxytTn7)6;>q-HLOq-
zHXs$CEL6js!VYRK)UuT@q;N<w)UahU6nTSWLAGmh`4wq`axciuZbj0d6vqZ>1m9u-
zHGN+;s4_4Vfnq9TCG#zzqQvreSic9<noQ2V#gdy?l5vYAIW;p!ll>NFW=U#pJgALZ
z1Zs&Ef!d_EIA9IjD9#*EA0s|HwK9r5Ik5o5xWxl%Oc%%JrKYB&VwCa1$r-81+40Es
z7GDEJ0jN32!N|kJ!pOqM@fk#OF^Vv<FhWQ^Mjl2MP~?=LM-C_f!6T;)Epk{HK*49h
zz|3I704k_!7*d$CnTi}ik%KH(!jQrO34AnBXr!TtGA>}MVTQEXYFSDcQrN+=EC^db
zHfeGoMFcn=in2iQk_{qqKm;fbigH2S3D%-QkN`Y<i;6(pVi18^{@xNz&d)0@%}qrO
zzgM8}1NG}T7)2O47zG%`7{wU*K%w`$s1y`lpu_-6%%HNF6C?=Iw21-KrmbPCWv^jR
zVa#SJ3I~<Y&5W)LDGVMAj0~Vm*vweVQNvNfl+92iTf?w`xrPJUR%I?>sbR0-XlAPA
zEMWz=K)As2oDg}a7<UbO4W|V|Eqe_s*an*#)*4O`hCId;##){l?iwx$h6QX38B&;}
z8ESb;*g;vnhPj5ThP#HPhNp(NnS+r5;<jRTP`HAyCbJ);lL~53YH}2TT1emq!7V;t
zPrrC4AAe`>cpq1{kRp3f`e)9~%!4#sKy3qXF{H@{E+W8%NKq0fpg~Q1aQSzOr6{o^
z^%f7PMG8yAQEWx2xrv#1QCyH#Nlt27NfZaTWd|x1Q$Pl!g4#A5u(C6XJ*Bh=Tan3|
zk{@4Okds*wUy@jy{T&nupmqjR0}B%eBOen76DSWbF>--uQ2UTcgi(NzhnbC$<-fq2
zqAF0tfr?F7Y=UAP)HVY3^@<z7JrqzAMUtTw)Kp=TWT<7SVN79`WT<7WVN79>WT<7U
zVN79_1jPqq3Y#QDEeEI=s$s2Rt6^_uDb^}sOkuBKp3RWLF_*a+RR1yrGn6pZu)tI>
zGSsl7aAq?VIoGhIaAh+U*`+h2a4%x4<;)XEXGq}zv$&yh-YLB4AQ|QqJ`i2QUdvU(
z>B113-N{hG+|H23n8KeT(85u|;=<6(*vweVUBjIsD9NyZwT5jWICZ25Nix*%NHWy&
z)^Mi?L)m;aOdSl847L0<{8?;S>@^%IBE5|L7PSI30-!!r4SyC#4O=#I(Hsyfg`t$O
zXl4z=0?rby8io!A&_HPoTZ(uMUo$%-oz}3`@W*r1aMkciGt>$qRMs$eFx0Ts@YV>z
zRE9I8Ft9MNFf=nWGURa>G8FG9XJljm!AMZwEeM=8CH#uyK<NS8@kV56Q1J%tk(YvM
z5iKo+2cWU9ji5Hkj%g2e?0B$a%7YzS!0ncn2Rjym+b8qDBU-B-?AZKZ$7*m3XXAq%
zvlPIs4TUOh1zS4>P*+1iOAAuKfD*$><|1(49n=CY5@TRsSjk)j>gpH41t9VuF_gY8
zsO=0&S)g&A&!AGik)ehmmK)U1O<|B^=wQfZDq^aE^ir8X1BEM@z}d$ST*0nny2Yet
zaEmc_C1Vt8ZgPAkwBQG|8gFshq^IVkRumN3889+1d<K=)Obv1jRVuJSl=y<og4CSM
zyi`4#oc!d(oMJmYxE64xECQ8UMf@P|FoHwz<-h;`|KH+rhL6dC3j|H>B2fKsi?yIA
zGp__(_T6I1ORXp=N(U7LteJT!sTD=OAU1nZYGG+=aY>OMm{(AgpPX7;49;MhLg2#T
z7Av^bbc+MlQh*c`s6}-Yb74s(*hRN^V4jFCPA$B}1t~E=ZKzx9pa98B%fH2(nNm?y
z0kV)eIWPSdTW)fEQEKrm=AzWXqDoMr0T=g8AQm{_1Tg|ggpq-v7}PvxY5=vaV3?0t
zfRTlfkCB6!gOLkVcrbA=vN3^*6i`LL!^p$P!6d-Q#>mCQ#mK@a#K`uajhTZ9#Nzlb
z^OdQA<!8|}P|*U48mvW2AGl~qVFVW^pkf77oPdfIP;mk(R@foMN)5PBkzfE-87b`9
zj774bOaW@gfC`uzj%Jo(HLwUHq(A|QFf!Dzrf_6471`IYgNqicbcPfza6tkpQXqv3
zH&o6&g$GoW<S|2vmKqLdk&@TRP{IT*QutE%TR2LXk%|-nNrnY1HSEwLMG#tyfQl4Y
z@q%2Wux7E<FsBIjGWJ^|6)EgB?AgpkGivy=*uh20RM0R;2`9Kn5lIoPVNYR4DpJ^M
z_~Y4;iWClr${Lmwu?_}ME3k$gZ^5!1rC{*`g(|p_!C?+>%4mxFz5M_G|9{9(A)=rG
z)h0#ipd<upY9k7UqH2&>4Tu025O@oKqFRu;IuHR)lJy`KI9-Cdpu}0!%)r2q&d9(}
z)WX2PP^FYqnwFMYL_$t30u6{1fm&=u?I07_oxmpOYI1=yF*x@Yb%HDgW!|DL5DS!b
zi@HH9P_`}V0kJ@JA}q_YfLg0XeIQ{_jfgeJawaF{fttESsYU%Dg%d!;L=Z6vM1Znq
z(PR*73W%5rBCzF6el!nzAaW+CCjrWt0!$pBT*=JB$j3}DXELJZObJGg|1#g08btVt
zW`c4isCb6uOm+qa22c|Y<i+A`;3ixOV=Yq+Q*mSpQ!P^oLkS~jK(>V;g|(N-g(23p
zmKoGwm1O7yHC)*x89Etjm_dC9NS<kDY-dVi2F*Ld@=XduGq|6U!cfXkWKhUo!;-=+
z399&cBpD<?O$pW%-fWhlkQ$a0P~{97m}CJp_i8|m4ZalqUKVK83YM>71E~eMu#mro
zsR%q`0xAPE1^nDXQ0gF1iUoNzn1O-eGY7OSFUb(hu#(9ST*yM|8pd0U6<`*G0HwxT
z95y+Lxk)LBb}gVP24n~aLzM<Bj*39tY;d1BEhoPmsg{9iTFH2eIXkryl9xc0AGouF
z;x>?xu==qWG*a9MsvpJS^&=Ccegt(>J3yU7rW!_2=Mb&l1dl<XSp%s-HJOSUKs5tX
zX30wCD2}AGc<^LG6njz{cpeJO0QbXCvtS1(-GN3Hm>Sp^xEPuKLona}DoujEhgHi(
zsD(x*zd8d0ID2Zc-C`@wFDe1ef5A<I%wK@B<}F^RXmWmDT4p*VLxR$)COfze1!u)u
zEGhYUsZmTxX+<+Yjbs*3&oGKTKPM%=EHMWXhl@ek3>=YSP!l07X?UE0+P1}@c}1oM
zP(P3b+|vPNGBHLbCYFC3%uI}+>;~$>gL;Zg4Lt9QR)8`NEYpB!Q1u4NJfJ36aSV9m
z6g-9xYT<&%^h=maSU>}OEet8ly-c7i<pOF0G1o9GU@c**VE~PcHZz09r3!_>V(c{x
zHH^(nAdwn|ERGcL2tOl32`6~w10?|=C+;H9C_>R}kf*`1IS0-Hb3p-7G>?ISVJ@hA
zoewG<6^cspK$9V*IpE<T%p_d20AvPu3Xd_0wKT6JGe?uF$OjbQ+^%_LnML_|xv6<2
z;L(kuC7_hX4{u$78#=|1*aNi#z#(^wxu`U+C>GQ~g^uBZ%GD@dNP38e=!s&=hqm<K
z4!^~R>eLyq1PY2R0cKDiRe+g?nT4rnHOOp6@UTBhNP)^WP=gN~O?-?DkVz(HP~gsC
zsbx$DO}c<ai7IQEOBfb_$}%=dh7|UNOrY*Kn9l*_v(~U=G0kR3;jCfFVusQzvl&vj
zYFM&ZQ@Cfdr0~?RWU+x*b2)3-YFMGFS)r;~vmmNj;i_5Ts@ZFpQ+OpAQuwl&ib7KO
zYdP|Gp&|m=OhvINg0&oZED(`ejvA%~AoZa32IB$_Q2PQjFahe)EMx+8U}~6CL?uDp
z4Uj4^NrnZSDO@Sy3qj?zgd{_X<Qz^=5-a4cVG3r@lqy}x2p<k@1PywEW`o;76Y8L8
z@3o-*!;YPxDPquE_-gQ==h_E57CqRp6V$H&3C>g~E-5NaE-5WaRRH%vHi0!k21vm(
z^*b8D6U>Xj1EjhN;OO>rQLwdD&^1(e)HX>$>A{XUAUi<4mZ{*;);ZwOR?t+x5*A%X
zP+dD4U@qPYat+8?GeJ(@F%xXz6qsJ$#Dap%ymSR<^V`!!K?A(H0Bnq}v!RYcYDu!5
zCe$YIxNqZwot+Axg#(Et3Sc9_J^@*{9PH9fU}w$-j~>rdNYT&LkBp3rRPgYy^7Vz8
zvt#Om9UC9)n4(ZzkeCb#oVDOySmT2o9bor0Dj)`MA*0b<U~kM+P=YL0P*Tvf1G95;
zAYO@L_H{M{5k?@w7(|$8vOs!e;HDU&YZd{@!yzCd5;Wt<sQ-&mA&S|+DCHNURZ%!d
zd^!UILn&xj4^QZW8&#0C5g@<M2Kya*U>Ajg3=IPjpoux~5Oon~u>BT8Q8Xxfaz?R(
z2cSJ&Kno<mizqx@qS&FyA&Lt$p6pkeo0M7v(F^tg$njuPAZBoZvp8tTxu^g%L|p`)
zA_7kqfv1f?^GUbZax?QvOHzyCKt&UCdTPln_M+5+oW$f*O-|6Pd439LygP~;njGSD
zLCXX3Qp-W2x0s9a%Zm`hFnr+g_jr(9@x>)YQT)&$ZkPb1T?j6*zyzqgy(Ljnl$cix
zN<HyNbx%%y`Z`bn2CDIyctE4sOpI)QSlBrj1(*aF^_ca*gEKs!$vh?&CN@SP@YpvS
znB)WXxW2RS6oJ}kRiYUsB?VUc`rsaJMt*ULm8qe*amX!3Elrjv-o%`o{POtxqRjNn
zyy7T92sgPXH6=B#1hggvrXn}BBqKki7{<*=O-xBGDy|aHFDlK`EzZn^)(`ri@hni4
z2gabb3uv4aT%gK;>%C@%TG;3wV+v^2o~eX6g=r2;FoPzuUzJEO+$4o$*c6B+%PscY
z)Z*gA^i*)QP_zt`Z1O;<gaurdgZ+sl%2c!kRQ>S712z>LhmaZ{5%A)u^#y2VupmD(
zujD-_+(GpKsISVz1PlA3ogf?4z*QSKVSy)zi}FEMv8N>#mn0Ts7J+K|C~+uHFBiT-
zNiR9SsJI9e7T_U)B9QBgR)YKi_RLZc3o)|^3a=vYRAw1S0+a?2gN@+121r1FniAk~
zMM&)m8iRmzUqF2maL*dthzD1zh>*I)oLEp0#g~|p5|40T6iY#VaS7OuNa2JCEDjsU
zoShx0IZ^xuG~>b`z{tS}>f<x9gTjb~5i}79N`Wjtn7AP#kR}roBTNLM0$B~R2+Knz
zeULsdW@7uv#1CeH(=-z!%TFdQR6ff$K1n`CRLJt3M*!p|WX$rNg&*P)7Df&x4i*ks
rJ{}f!Fk6&^lS71qmqV7rgu{YEf=7gdiOm8ulLWymjBLL-IQSR=X?WMO

diff --git a/src/queues/AutoQueue/__pycache__/Autoqueue.cpython-311.pyc b/src/queues/AutoQueue/__pycache__/Autoqueue.cpython-311.pyc
deleted file mode 100644
index cfbd03aa3caea8a42257690736d8716b154f84e8..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 18940
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

diff --git a/src/queues/AutoQueue/__pycache__/Autoqueue.cpython-313.pyc b/src/queues/AutoQueue/__pycache__/Autoqueue.cpython-313.pyc
deleted file mode 100644
index 7918080c8ceba2fa002c7a2a0f4d7019e9a94089..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 16952
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
C?%*;2

diff --git a/src/queues/AutoQueue/cleandata.py b/src/queues/AutoQueue/cleandata.py
deleted file mode 100644
index 34d8c578..00000000
--- a/src/queues/AutoQueue/cleandata.py
+++ /dev/null
@@ -1,228 +0,0 @@
-import requests
-import sys
-import os
-from dataclasses import dataclass, field
-from typing import List, Optional
-
-# ปรับ encoding สำหรับ Windows ให้รองรับภาษาไทยและ emoji
-if os.name == "nt":
-    sys.stdout.reconfigure(encoding="utf-8")
-
-# กำหนด API endpoints
-API_BASE = "http://localhost:4000"
-URLS = {
-    "products": f"{API_BASE}/products",
-    "materials": f"{API_BASE}/materials",
-    "machines": f"{API_BASE}/machines",
-    "stock_configs": f"{API_BASE}/stock-config",
-}
-
-# ========================
-# Data Model Definitions
-# ========================
-
-@dataclass
-class Product:
-    ProductID: int
-    brand: str
-    size: str
-    unit: str
-    status: str
-    lowStockLevel: int
-    quantityInStock: int
-    pricePerUnit: str  # API ส่งมาเป็น string
-    name: str = field(init=False)
-    
-    def __post_init__(self):
-        self.name = f"{self.brand} {self.size} ({self.unit})"
-
-@dataclass
-class Material:
-    MaterialID: int
-    name: str
-    size: str
-    brand: str
-    quantityInStock: int
-    lowStockLevel: int
-    status: str
-    ReorderLevel: int
-    unit: str
-    pricePerUnit: str  # API ส่งมาเป็น string
-    LastUpdate: str
-    display_name: str = field(init=False)
-    
-    def __post_init__(self):
-        self.display_name = f"{self.name} {self.size} {self.brand} ({self.unit})"
-
-@dataclass
-class Ingredient:
-    recipeIngredientID: int
-    quantityNeed: str  # API ส่งมาเป็น string (เช่น "1.000000")
-    material: Material
-
-@dataclass
-class Recipe:
-    recipeID: int
-    outputItemID: int
-    outputItemType: str  # คาดว่าจะเป็น "PRODUCT" หรือ "MATERIAL"
-    outputQuantity: int
-    ingredients: List[Ingredient]
-
-@dataclass
-class MachineDetail:
-    MachineDetailID: int
-    outputRate: int
-    changOver: Optional[float]
-    recipes: List[Recipe]
-
-@dataclass
-class Machine:
-    MachineID: int
-    name: str
-    type: str
-    lastMaintenanceDate: Optional[str]
-    status: str
-    notes: Optional[str]
-    machineDetails: List[MachineDetail]
-
-@dataclass
-class StockConfig:
-    stockConfigID: int
-    itemID: int
-    itemType: str  # "PRODUCT" หรือ "MATERIAL"
-    targetStockLevel: int
-    status: str
-    lastUpdated: str
-
-@dataclass
-class CleanDataSet:
-    products: List[Product]
-    materials: List[Material]
-    machines: List[Machine]
-    stock_configs: List[StockConfig]
-
-# ========================
-# Loader Functions
-# ========================
-
-def load_products() -> List[Product]:
-    products_data = requests.get(URLS["products"]).json()
-    # JSON ควรมี: ProductID, brand, size, unit, status, lowStockLevel, quantityInStock, pricePerUnit
-    return [Product(**p) for p in products_data]
-
-def load_materials() -> List[Material]:
-    materials_data = requests.get(URLS["materials"]).json()
-    # JSON ควรมี: MaterialID, name, size, brand, quantityInStock, lowStockLevel, status, ReorderLevel, unit, pricePerUnit, LastUpdate
-    return [Material(**m) for m in materials_data]
-
-def load_machines() -> List[Machine]:
-    machines_data = requests.get(URLS["machines"]).json()
-    machines = []
-    for m in machines_data:
-        machine_details = []
-        for md in m.get("machineDetails", []):
-            recipes = []
-            for r in md.get("recipes", []):
-                ingredients = []
-                for ing in r.get("ingredients", []):
-                    # สร้าง Material object จากข้อมูลใน ingredient
-                    mat_obj = Material(**ing["material"])
-                    ingredient_obj = Ingredient(
-                        recipeIngredientID=ing["recipeIngredientID"],
-                        quantityNeed=ing["quantityNeed"],
-                        material=mat_obj
-                    )
-                    ingredients.append(ingredient_obj)
-                recipe_obj = Recipe(
-                    recipeID=r["recipeID"],
-                    outputItemID=r["outputItemID"],
-                    outputItemType=r["outputItemType"],
-                    outputQuantity=r["outputQuantity"],
-                    ingredients=ingredients
-                )
-                recipes.append(recipe_obj)
-            md_obj = MachineDetail(
-                MachineDetailID=md["MachineDetailID"],
-                outputRate=md["outputRate"],
-                changOver=md.get("changOver"),
-                recipes=recipes
-            )
-            machine_details.append(md_obj)
-        machine_obj = Machine(
-            MachineID=m["MachineID"],
-            name=m["name"],
-            type=m["type"],
-            lastMaintenanceDate=m.get("lastMaintenanceDate"),
-            status=m["status"],
-            notes=m.get("notes"),
-            machineDetails=machine_details
-        )
-        machines.append(machine_obj)
-    return machines
-
-def load_stock_configs() -> List[StockConfig]:
-    configs_data = requests.get(URLS["stock_configs"]).json()
-    # JSON ควรมี: stockConfigID, itemID, itemType, targetStockLevel, status, lastUpdated
-    return [StockConfig(**cfg) for cfg in configs_data]
-
-def load_clean_dataset() -> CleanDataSet:
-    products = load_products()
-    materials = load_materials()
-    machines = load_machines()
-    stock_configs = load_stock_configs()
-    return CleanDataSet(
-        products=products,
-        materials=materials,
-        machines=machines,
-        stock_configs=stock_configs
-    )
-
-# ========================
-# ตัวอย่างการใช้งานและแสดงผล (Algorithm Sample)
-# ========================
-
-def main():
-    print("Loading clean dataset...")
-    data = load_clean_dataset()
-
-    # แสดง mapping ของ Products
-    print("\n=== Products Mapping ===")
-    for p in data.products:
-        print(f"ProductID: {p.ProductID} -> {p.name}")
-
-    # แสดง mapping ของ Materials
-    print("\n=== Materials Mapping ===")
-    for m in data.materials:
-        print(f"MaterialID: {m.MaterialID} -> {m.display_name}")
-
-    # แสดงสรุปของ Machine พร้อมรายละเอียด
-    print("\n=== Machines Summary ===")
-    for machine in data.machines:
-        print(f"\nMachineID: {machine.MachineID}, Name: {machine.name}, Type: {machine.type}, Status: {machine.status}")
-        for md in machine.machineDetails:
-            print(f"  MachineDetailID: {md.MachineDetailID}, OutputRate: {md.outputRate}, ChangeOver: {md.changOver}")
-            for r in md.recipes:
-                # Map ชื่อ output item จาก Product หรือ Material ตาม outputItemType
-                if r.outputItemType.upper() == "PRODUCT":
-                    output_name = next((p.name for p in data.products if p.ProductID == r.outputItemID), "Unknown")
-                elif r.outputItemType.upper() == "MATERIAL":
-                    output_name = next((m.display_name for m in data.materials if m.MaterialID == r.outputItemID), "Unknown")
-                else:
-                    output_name = "Unknown"
-                print(f"    RecipeID: {r.recipeID}, Produces: {output_name} ({r.outputItemType}) x {r.outputQuantity}")
-                for ing in r.ingredients:
-                    print(f"      Ingredient: {ing.material.display_name} x {ing.quantityNeed}")
-
-    # แสดงข้อมูล Stock Config ที่ map กับ Product/Material
-    print("\n=== Stock Configurations ===")
-    for sc in data.stock_configs:
-        if sc.itemType.upper() == "PRODUCT":
-            item_name = next((p.name for p in data.products if p.ProductID == sc.itemID), "Unknown")
-        elif sc.itemType.upper() == "MATERIAL":
-            item_name = next((m.display_name for m in data.materials if m.MaterialID == sc.itemID), "Unknown")
-        else:
-            item_name = "Unknown"
-        print(f"ConfigID: {sc.stockConfigID}, Item: {item_name} (ItemID: {sc.itemID}, {sc.itemType}), TargetStock: {sc.targetStockLevel}, Status: {sc.status}, LastUpdated: {sc.lastUpdated}")
-
-if __name__ == "__main__":
-    main()
diff --git a/src/queues/AutoQueue/requirements.txt b/src/queues/AutoQueue/requirements.txt
deleted file mode 100644
index 1af22b69..00000000
--- a/src/queues/AutoQueue/requirements.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-simpy
-pandas
-matplotlib
-numpy
-fastapi
-uvicorn
\ No newline at end of file
diff --git a/src/queues/AutoQueue/testAllapi.py b/src/queues/AutoQueue/testAllapi.py
deleted file mode 100644
index d4d4bc09..00000000
--- a/src/queues/AutoQueue/testAllapi.py
+++ /dev/null
@@ -1,132 +0,0 @@
-import requests
-import sys
-import os
-
-# ปรับ encoding สำหรับ Windows ให้รองรับภาษาไทยและ emoji
-if os.name == "nt":
-    sys.stdout.reconfigure(encoding="utf-8")
-
-# กำหนด API endpoints
-API_BASE = "http://localhost:4000"
-URLS = {
-    "products": f"{API_BASE}/products",
-    "materials": f"{API_BASE}/materials",
-    "machines": f"{API_BASE}/machines",
-    "stock_configs": f"{API_BASE}/stock-config",
-}
-
-# Dictionary สำหรับเก็บ mapping
-# สำหรับ Products: key คือ ProductID, value คือ ชื่อผลิตภัณฑ์
-product_map = {}
-# สำหรับ Materials: key คือ MaterialID, value คือ ชื่อวัสดุ
-material_map = {}
-
-def preload_items():
-    """โหลดข้อมูล Products และ Materials ก่อน เพื่อใช้ในการ map itemID"""
-    print("📥 กำลังโหลด Products...")
-    try:
-        products = requests.get(URLS["products"]).json()
-        for p in products:
-            # ตัวอย่างชื่อผลิตภัณฑ์: "A 350 ml (ขวด)"
-            name = f"{p['brand']} {p['size']} ({p['unit']})"
-            product_map[p['ProductID']] = name
-    except Exception as e:
-        print("❌ ไม่สามารถโหลด Products ได้:", e)
-    
-    print("📥 กำลังโหลด Materials...")
-    try:
-        materials = requests.get(URLS["materials"]).json()
-        for m in materials:
-            # ตัวอย่างชื่อวัสดุ: "Preform (ขวด) any any (ขวด)"
-            name = f"{m['name']} {m['size']} {m['brand']} ({m['unit']})"
-            material_map[m['MaterialID']] = name
-    except Exception as e:
-        print("❌ ไม่สามารถโหลด Materials ได้:", e)
-
-def log_item_mappings():
-    """แสดงผล mapping ของ Products และ Materials เพื่อตรวจสอบ itemID กับ itemType"""
-    print("\n==== Mapping ของ Products ====")
-    for pid, name in product_map.items():
-        print(f"  - ProductID: {pid} -> {name}")
-        
-    print("\n==== Mapping ของ Materials ====")
-    for mid, name in material_map.items():
-        print(f"  - MaterialID: {mid} -> {name}")
-
-def log_machines():
-    """แสดงข้อมูลของ Machines พร้อมรายละเอียด (machineDetails + recipes)"""
-    try:
-        machines = requests.get(URLS["machines"]).json()
-    except Exception as e:
-        print("❌ ไม่สามารถโหลด Machines ได้:", e)
-        return
-
-    # แสดงข้อมูลสรุปของแต่ละเครื่อง
-    for i, machine in enumerate(machines, 1):
-        print(f"\n🚀 Machine #{i}")
-        print(f" - MachineID: {machine['MachineID']}")
-        print(f" - Name: {machine['name']}")
-        print(f" - Type: {machine['type']}")
-        print(f" - Status: {machine['status']}")
-    
-    # แสดงรายละเอียด machineDetails และ recipes
-    print("\n🔧 รายละเอียดเครื่องจักร (MachineDetails + Recipes):")
-    for machine in machines:
-        for detail in machine.get("machineDetails", []):
-            print(f"\n🛠️ MachineDetailID: {detail['MachineDetailID']}")
-            print(f" - Machine: {machine['name']} (ID {machine['MachineID']})")
-            print(f" - OutputRate: {detail['outputRate']} units/hr")
-            print(f" - ChangeOver: {detail['changOver']} min")
-            for recipe in detail.get("recipes", []):
-                output_id = recipe["outputItemID"]
-                output_type = recipe["outputItemType"]
-                # ตรวจสอบ itemType เพื่อ map ชื่อผลิตภัณฑ์หรือวัสดุ
-                if output_type.upper() == "PRODUCT":
-                    output_name = product_map.get(output_id, "❓ไม่ทราบชื่อ")
-                elif output_type.upper() == "MATERIAL":
-                    output_name = material_map.get(output_id, "❓ไม่ทราบชื่อ")
-                else:
-                    output_name = "ไม่ทราบ"
-                print(f"\n   📦 RecipeID: {recipe['recipeID']}")
-                print(f"    - ผลิต: {output_name} ({output_type})")
-                print(f"    - จำนวนที่ผลิต: {recipe['outputQuantity']}")
-                print("    - วัตถุดิบ:")
-                for ing in recipe.get("ingredients", []):
-                    mat = ing["material"]
-                    # สามารถเพิ่มข้อมูลอื่นๆ ของวัสดุจาก mapping ถ้าต้องการ
-                    print(f"      · {mat['name']} ({mat['size']}, {mat['brand']}) x {ing['quantityNeed']}")
-                    
-def log_stock_configs():
-    """แสดงข้อมูล Stock Config พร้อมแปล itemID และ itemType ให้เข้าใจง่าย"""
-    try:
-        configs = requests.get(URLS["stock_configs"]).json()
-    except Exception as e:
-        print("❌ ไม่สามารถโหลด Stock Configs ได้:", e)
-        return
-
-    print("\n📦 Stock Configuration:")
-    for i, cfg in enumerate(configs, 1):
-        item_id = cfg["itemID"]
-        item_type = cfg["itemType"].upper()
-        # map ตาม itemType ว่าใช้ product_map หรือ material_map
-        if item_type == "PRODUCT":
-            name = product_map.get(item_id, "❓ไม่ทราบชื่อ")
-        elif item_type == "MATERIAL":
-            name = material_map.get(item_id, "❓ไม่ทราบชื่อ")
-        else:
-            name = "ไม่ทราบ"
-        print(f"\n🔧 Config #{i}")
-        print(f" - Item: {name} (ItemID: {item_id}, {item_type})")
-        print(f" - เป้าหมายสต๊อก: {cfg['targetStockLevel']}")
-        print(f" - สถานะ: {cfg['status']}")
-        print(f" - แก้ไขล่าสุด: {cfg['lastUpdated']}")
-
-if __name__ == "__main__":
-    # โหลดข้อมูลสินค้าและวัสดุก่อน
-    preload_items()
-    # แสดงผล mapping เพื่อตรวจสอบ
-    log_item_mappings()
-    # แสดงข้อมูลเครื่องจักรและสูตรการผลิต
-    log_machines()
-    # แสดงข้อมูล Stock Config
-    log_stock_configs()
-- 
GitLab