From e845f8b05b2c5760f4c89636ddfb8b80efd9630b Mon Sep 17 00:00:00 2001
From: Sirapob Lapanakokiat <65160126@go.buu.ac.th>
Date: Wed, 19 Mar 2025 21:12:34 +0700
Subject: [PATCH] Update Stock System

---
 public/css/style.css | 175 ++++++++++++++++++++++++++++++++++++++++++-
 routes/categories.js |   6 +-
 routes/products.js   |  34 ++++-----
 routes/stock.js      |  12 +--
 views/categories.ejs |  64 ----------------
 views/products.ejs   | 127 +------------------------------
 6 files changed, 204 insertions(+), 214 deletions(-)

diff --git a/public/css/style.css b/public/css/style.css
index 1d02294..ac2e2a5 100644
--- a/public/css/style.css
+++ b/public/css/style.css
@@ -72,4 +72,177 @@ th, td {
     display: grid;
     grid-template-columns: 1fr 1fr 1fr auto;
     gap: 10px;
-}
\ No newline at end of file
+}
+.container { padding: 20px; }
+        
+        .form-row {
+            display: flex;
+            gap: 10px;
+            margin-bottom: 10px;
+        }
+
+        .status {
+            padding: 5px 10px;
+            border-radius: 4px;
+            font-weight: bold;
+        }
+
+        .status-out { 
+            background: #dc3545; 
+            color: white; 
+        }
+        
+        .status-low { 
+            background: #ffc107; 
+            color: black; 
+        }
+        
+        .status-normal { 
+            background: #28a745; 
+            color: white; 
+        }
+
+        button {
+            padding: 5px 10px;
+            border-radius: 4px;
+            cursor: pointer;
+        }
+
+        .modal {
+            display: none;
+            position: fixed;
+            top: 0;
+            left: 0;
+            width: 100%;
+            height: 100%;
+            background-color: rgba(0,0,0,0.5);
+            z-index: 1000;
+        }
+
+        .modal-content {
+            background-color: white;
+            margin: 15% auto;
+            padding: 20px;
+            width: 80%;
+            max-width: 600px;
+            border-radius: 5px;
+            position: relative;
+        }
+
+        .form-actions {
+            display: flex;
+            gap: 10px;
+            justify-content: flex-end;
+            margin-top: 20px;
+        }
+
+        .form-actions button {
+            padding: 8px 16px;
+        }
+
+        .form-actions button[type="submit"] {
+            background-color: #28a745;
+            color: white;
+            border: none;
+        }
+
+        .form-actions button[type="button"] {
+            background-color: #dc3545;
+            color: white;
+            border: none;
+        }
+
+        .search-section {
+            margin-bottom: 20px;
+        }
+
+        .search-form {
+            display: flex;
+            gap: 10px;
+            align-items: center;
+        }
+
+        .search-form input {
+            padding: 8px;
+            border: 1px solid #ddd;
+            border-radius: 4px;
+            width: 300px;
+        }
+
+        .search-form button {
+            padding: 8px 16px;
+            background: #007bff;
+            color: white;
+            border: none;
+            border-radius: 4px;
+            cursor: pointer;
+        }
+
+        .clear-search {
+            padding: 8px 16px;
+            background: #6c757d;
+            color: white;
+            text-decoration: none;
+            border-radius: 4px;
+        }
+        .modal {
+            display: none;
+            position: fixed;
+            top: 0;
+            left: 0;
+            width: 100%;
+            height: 100%;
+            background-color: rgba(0,0,0,0.5);
+        }
+
+        .modal-content {
+            background-color: white;
+            margin: 15% auto;
+            padding: 20px;
+            border-radius: 5px;
+            width: 50%;
+            max-width: 500px;
+        }
+
+        .category-form {
+            margin: 20px 0;
+            display: flex;
+            gap: 10px;
+        }
+
+        .category-form input {
+            flex: 1;
+            padding: 8px;
+            border: 1px solid #ddd;
+            border-radius: 4px;
+        }
+
+        table {
+            width: 100%;
+            border-collapse: collapse;
+            margin-top: 20px;
+        }
+
+        th, td {
+            padding: 12px;
+            text-align: left;
+            border-bottom: 1px solid #ddd;
+        }
+
+        .edit-btn, .delete-btn {
+            padding: 5px 10px;
+            margin: 0 5px;
+            border: none;
+            border-radius: 4px;
+            cursor: pointer;
+        }
+
+        .edit-btn {
+            background-color: #ffc107;
+            color: black;
+        }
+
+        .delete-btn {
+            background-color: #dc3545;
+            color: white;
+        }
\ No newline at end of file
diff --git a/routes/categories.js b/routes/categories.js
index 29d21a6..6426487 100644
--- a/routes/categories.js
+++ b/routes/categories.js
@@ -2,7 +2,7 @@ const express = require('express');
 const router = express.Router();
 const db = require('../database/db');
 
-// Middleware to check if user is logged in
+
 const isAuthenticated = (req, res, next) => {
     if (req.session.userId) {
         next();
@@ -11,7 +11,7 @@ const isAuthenticated = (req, res, next) => {
     }
 };
 
-// Get all categories
+
 router.get('/', isAuthenticated, async (req, res) => {
     try {
         const [categories] = await db.query('SELECT * FROM categories');
@@ -50,7 +50,7 @@ router.put('/:id', isAuthenticated, async (req, res) => {
 // Delete category
 router.delete('/:id', isAuthenticated, async (req, res) => {
     try {
-        // Check if category has products
+       
         const [products] = await db.query(
             'SELECT COUNT(*) as count FROM products WHERE category_id = ?', 
             [req.params.id]
diff --git a/routes/products.js b/routes/products.js
index a11fa05..fd5a6bc 100644
--- a/routes/products.js
+++ b/routes/products.js
@@ -2,7 +2,7 @@ const express = require('express');
 const router = express.Router();
 const db = require('../database/db');
 
-// Middleware to check if user is logged in
+
 const isAuthenticated = (req, res, next) => {
     if (req.session.userId) {
         next();
@@ -16,7 +16,7 @@ router.get('/', isAuthenticated, async (req, res) => {
     try {
         const { search } = req.query;
         
-        // Build query with search condition
+        
         let sql = `
             SELECT p.*, c.name as category_name 
             FROM products p
@@ -29,11 +29,11 @@ router.get('/', isAuthenticated, async (req, res) => {
             params = [`%${search}%`, `%${search}%`];
         }
         
-        // Execute query
+        
         const [products] = await db.query(sql, params);
         const [categories] = await db.query('SELECT * FROM categories');
 
-        // Add helper function to be available in template
+        
         const getStockStatus = (current, minimum) => {
             current = parseInt(current) || 0;
             minimum = parseInt(minimum) || 0;
@@ -47,12 +47,12 @@ router.get('/', isAuthenticated, async (req, res) => {
             return { text: 'ปกติ', class: 'status-normal' };
         };
         
-        // Pass search value back to template
+        
         res.render('products', { 
             products, 
             categories,
             searchQuery: search || '',
-            getStockStatus // Pass the function to the template
+            getStockStatus 
         });
     } catch (err) {
         console.error(err);
@@ -99,7 +99,7 @@ router.post('/', isAuthenticated, async (req, res) => {
     }
 });
 
-// Get edit form
+
 router.get('/edit/:id', isAuthenticated, async (req, res) => {
     try {
         const [products] = await db.query(
@@ -122,7 +122,7 @@ router.get('/edit/:id', isAuthenticated, async (req, res) => {
     }
 });
 
-// Get product by ID
+
 router.get('/:id', isAuthenticated, async (req, res) => {
     try {
         const [products] = await db.query(
@@ -141,7 +141,7 @@ router.get('/:id', isAuthenticated, async (req, res) => {
     }
 });
 
-// Update product
+
 router.put('/:id', isAuthenticated, async (req, res) => {
     try {
         const { 
@@ -179,7 +179,7 @@ router.put('/:id', isAuthenticated, async (req, res) => {
     }
 });
 
-// Delete product
+
 router.delete('/:id', isAuthenticated, async (req, res) => {
     try {
         await db.query('DELETE FROM products WHERE id = ?', [req.params.id]);
@@ -197,13 +197,13 @@ router.post('/stock/add', isAuthenticated, async (req, res) => {
         
         await db.query('START TRANSACTION');
         
-        // บันทึกการเพิ่มสต็อก
+        
         await db.query(
             'INSERT INTO stock_movements (product_id, quantity, type, user_id, description) VALUES (?, ?, "in", ?, ?)',
             [product_id, quantity, req.session.userId, description]
         );
         
-        // อัพเดตจำนวนสต็อก
+        
         await db.query(
             'UPDATE products SET stock_quantity = stock_quantity + ? WHERE id = ?',
             [quantity, product_id]
@@ -218,14 +218,14 @@ router.post('/stock/add', isAuthenticated, async (req, res) => {
     }
 });
 
-// ตัดสต็อก
+
 router.post('/stock/remove', isAuthenticated, async (req, res) => {
     try {
         const { product_id, quantity, description } = req.body;
         
         await db.query('START TRANSACTION');
         
-        // ตรวจสอบจำนวนสต็อก
+        
         const [product] = await db.query(
             'SELECT stock_quantity FROM products WHERE id = ?',
             [product_id]
@@ -236,13 +236,13 @@ router.post('/stock/remove', isAuthenticated, async (req, res) => {
             return res.status(400).json({ error: 'Insufficient stock' });
         }
         
-        // บันทึกการตัดสต็อก
+        
         await db.query(
             'INSERT INTO stock_movements (product_id, quantity, type, user_id, description) VALUES (?, ?, "out", ?, ?)',
             [product_id, quantity, req.session.userId, description]
         );
         
-        // อัพเดตจำนวนสต็อก
+        
         await db.query(
             'UPDATE products SET stock_quantity = stock_quantity - ? WHERE id = ?',
             [quantity, product_id]
@@ -257,7 +257,7 @@ router.post('/stock/remove', isAuthenticated, async (req, res) => {
     }
 });
 
-// ดูประวัติการเคลื่อนไหวของสต็อก
+
 router.get('/stock/history/:productId', isAuthenticated, async (req, res) => {
     try {
         const [movements] = await db.query(`
diff --git a/routes/stock.js b/routes/stock.js
index fe00590..eba0e54 100644
--- a/routes/stock.js
+++ b/routes/stock.js
@@ -9,13 +9,13 @@ router.post('/add', async (req, res) => {
         
         await db.query('START TRANSACTION');
 
-        // บันทึกการเคลื่อนไหว
+       
         await db.query(
             'INSERT INTO stock_movements (product_id, quantity, type, user_id, description) VALUES (?, ?, "in", ?, ?)',
             [product_id, quantity, req.session.userId, description]
         );
 
-        // อัพเดตจำนวนสต็อก
+       
         await db.query(
             'UPDATE products SET stock_quantity = stock_quantity + ?, last_restock_date = CURRENT_TIMESTAMP WHERE id = ?',
             [quantity, product_id]
@@ -37,7 +37,7 @@ router.post('/remove', async (req, res) => {
 
         await db.query('START TRANSACTION');
 
-        // ตรวจสอบสต็อกคงเหลือ
+        
         const [product] = await db.query(
             'SELECT stock_quantity FROM products WHERE id = ?',
             [product_id]
@@ -48,13 +48,13 @@ router.post('/remove', async (req, res) => {
             return res.status(400).json({ error: 'สินค้าในสต็อกไม่เพียงพอ' });
         }
 
-        // บันทึกการเคลื่อนไหว
+       
         await db.query(
             'INSERT INTO stock_movements (product_id, quantity, type, user_id, description) VALUES (?, ?, "out", ?, ?)',
             [product_id, quantity, req.session.userId, description]
         );
 
-        // อัพเดตจำนวนสต็อก
+        
         await db.query(
             'UPDATE products SET stock_quantity = stock_quantity - ? WHERE id = ?',
             [quantity, product_id]
@@ -69,7 +69,7 @@ router.post('/remove', async (req, res) => {
     }
 });
 
-// ดูประวัติการเคลื่อนไหวของสินค้า
+
 router.get('/history/:productId', async (req, res) => {
     try {
         const [movements] = await db.query(`
diff --git a/views/categories.ejs b/views/categories.ejs
index 7dad304..210a4df 100644
--- a/views/categories.ejs
+++ b/views/categories.ejs
@@ -99,69 +99,5 @@
             }
         };
     </script>
-
-    <style>
-        .modal {
-            display: none;
-            position: fixed;
-            top: 0;
-            left: 0;
-            width: 100%;
-            height: 100%;
-            background-color: rgba(0,0,0,0.5);
-        }
-
-        .modal-content {
-            background-color: white;
-            margin: 15% auto;
-            padding: 20px;
-            border-radius: 5px;
-            width: 50%;
-            max-width: 500px;
-        }
-
-        .category-form {
-            margin: 20px 0;
-            display: flex;
-            gap: 10px;
-        }
-
-        .category-form input {
-            flex: 1;
-            padding: 8px;
-            border: 1px solid #ddd;
-            border-radius: 4px;
-        }
-
-        table {
-            width: 100%;
-            border-collapse: collapse;
-            margin-top: 20px;
-        }
-
-        th, td {
-            padding: 12px;
-            text-align: left;
-            border-bottom: 1px solid #ddd;
-        }
-
-        .edit-btn, .delete-btn {
-            padding: 5px 10px;
-            margin: 0 5px;
-            border: none;
-            border-radius: 4px;
-            cursor: pointer;
-        }
-
-        .edit-btn {
-            background-color: #ffc107;
-            color: black;
-        }
-
-        .delete-btn {
-            background-color: #dc3545;
-            color: white;
-        }
-    </style>
 </body>
 </html>
\ No newline at end of file
diff --git a/views/products.ejs b/views/products.ejs
index fd50d82..f371d38 100644
--- a/views/products.ejs
+++ b/views/products.ejs
@@ -4,7 +4,6 @@
     <title>จัดการสินค้า</title>
     <link rel="stylesheet" href="/css/style.css">
     <script>
-        // Define getStockStatus function first
         function getStockStatus(current, minimum) {
             current = parseInt(current) || 0;
             minimum = parseInt(minimum) || 0;
@@ -21,7 +20,7 @@
 </head>
 <body>
     <div class="container">
-        <!-- ส่วนหัว -->
+        
         <div class="header">
             <h1>จัดการสต็อกสินค้า</h1>
             <nav>
@@ -31,7 +30,7 @@
         </div>
 
        
-        <!-- แก้ไขส่วนค้นหา -->
+        
         <div class="search-section">
             <form action="/products" method="GET" class="search-form">
                 <input 
@@ -47,7 +46,7 @@
             </form>
         </div>
 
-        <!-- เพิ่มสินค้า -->
+       
         <div class="add-product-section">
             <form action="/products" method="POST">
                 <div class="form-row">
@@ -185,10 +184,8 @@
     </div>
 
     <script>
-        // ฟังก์ชันจัดการสินค้า
         const editModal = document.getElementById('editModal');
         let currentProductId = null;
-
         function editProduct(id) {
             currentProductId = id;
             fetch(`/products/${id}`)
@@ -296,133 +293,17 @@
                         <td>${m.user_name}</td>
                         <td>${m.description || '-'}</td>
                     </tr>
-                `).join('');
-                
+                `).join('');        
                 document.getElementById('historyModal').style.display = 'block';
             } catch (err) {
                 console.error(err);
                 alert('เกิดข้อผิดพลาด');
             }
         }
-
         function closeHistoryModal() {
             document.getElementById('historyModal').style.display = 'none';
         }
     </script>
 
-    <style>
-        .container { padding: 20px; }
-        
-        .form-row {
-            display: flex;
-            gap: 10px;
-            margin-bottom: 10px;
-        }
-
-        .status {
-            padding: 5px 10px;
-            border-radius: 4px;
-            font-weight: bold;
-        }
-
-        .status-out { 
-            background: #dc3545; 
-            color: white; 
-        }
-        
-        .status-low { 
-            background: #ffc107; 
-            color: black; 
-        }
-        
-        .status-normal { 
-            background: #28a745; 
-            color: white; 
-        }
-
-        button {
-            padding: 5px 10px;
-            border-radius: 4px;
-            cursor: pointer;
-        }
-
-        .modal {
-            display: none;
-            position: fixed;
-            top: 0;
-            left: 0;
-            width: 100%;
-            height: 100%;
-            background-color: rgba(0,0,0,0.5);
-            z-index: 1000;
-        }
-
-        .modal-content {
-            background-color: white;
-            margin: 15% auto;
-            padding: 20px;
-            width: 80%;
-            max-width: 600px;
-            border-radius: 5px;
-            position: relative;
-        }
-
-        .form-actions {
-            display: flex;
-            gap: 10px;
-            justify-content: flex-end;
-            margin-top: 20px;
-        }
-
-        .form-actions button {
-            padding: 8px 16px;
-        }
-
-        .form-actions button[type="submit"] {
-            background-color: #28a745;
-            color: white;
-            border: none;
-        }
-
-        .form-actions button[type="button"] {
-            background-color: #dc3545;
-            color: white;
-            border: none;
-        }
-
-        .search-section {
-            margin-bottom: 20px;
-        }
-
-        .search-form {
-            display: flex;
-            gap: 10px;
-            align-items: center;
-        }
-
-        .search-form input {
-            padding: 8px;
-            border: 1px solid #ddd;
-            border-radius: 4px;
-            width: 300px;
-        }
-
-        .search-form button {
-            padding: 8px 16px;
-            background: #007bff;
-            color: white;
-            border: none;
-            border-radius: 4px;
-            cursor: pointer;
-        }
-
-        .clear-search {
-            padding: 8px 16px;
-            background: #6c757d;
-            color: white;
-            text-decoration: none;
-            border-radius: 4px;
-        }
-    </style>
 </body>
 </html>
\ No newline at end of file
-- 
GitLab