Changeset 591278c


Ignore:
Timestamp:
02/22/26 17:24:14 (7 months ago)
Author:
Klimentina Efremova <klimentina08642@…>
Branches:
finki-main, main
Children:
4dff800
Parents:
69f2a41
Message:

Fixed Product and Category adding

Files:
1 deleted
3 edited

Legend:

Unmodified
Added
Removed
  • database.js

    r69f2a41 r591278c  
    2424database.run('PRAGMA foreign_keys = ON');
    2525
    26 // Helper function to ensure general category exists
     26// Helper function to ensure general category exists with ID 1
    2727function ensureGeneralCategory(callback) {
    28     database.get('SELECT category_id FROM category WHERE name = ?', ['General'], (err, row) => {
     28    // First check if category with ID 1 exists and is named 'General'
     29    database.get('SELECT category_id, name FROM category WHERE category_id = 1', [], (err, row) => {
    2930        if (err) {
    3031            callback(err);
    31         } else if (!row) {
     32        } else if (row && row.name === 'General') {
     33            // Category with ID 1 already exists and is General
     34            console.log('✅ General category exists with ID: 1');
     35            callback(null);
     36        } else if (row && row.name !== 'General') {
     37            // Category with ID 1 exists but has different name - update it
    3238            database.run(
    33                 'INSERT INTO category (name, description) VALUES (?, ?)',
     39                'UPDATE category SET name = ?, description = ? WHERE category_id = 1',
    3440                ['General', 'General products category'],
    3541                function(err) {
    36                     callback(err);
     42                    if (err) {
     43                        callback(err);
     44                    } else {
     45                        console.log('✅ Updated category ID 1 to General');
     46                        callback(null);
     47                    }
    3748                }
    3849            );
    3950        } else {
    40             callback(null);
     51            // No category with ID 1 exists, create it
     52            // First, check if we need to reset the autoincrement sequence
     53            database.run(
     54                'INSERT INTO category (category_id, name, description) VALUES (1, ?, ?)',
     55                ['General', 'General products category'],
     56                function(err) {
     57                    if (err) {
     58                        // If insert fails, try without specifying ID (let SQLite assign it)
     59                        database.run(
     60                            'INSERT INTO category (name, description) VALUES (?, ?)',
     61                            ['General', 'General products category'],
     62                            function(err) {
     63                                if (err) {
     64                                    callback(err);
     65                                } else {
     66                                    console.log('✅ Created General category with auto-assigned ID');
     67                                    callback(null);
     68                                }
     69                            }
     70                        );
     71                    } else {
     72                        console.log('✅ Created General category with ID: 1');
     73                        callback(null);
     74                    }
     75                }
     76            );
    4177        }
    4278    });
    … …  
    4581// Helper function to get the General category ID
    4682function getGeneralCategoryId(callback) {
    47     database.get('SELECT category_id FROM category WHERE name = ?', ['General'], (err, row) => {
     83    // First try to get category with ID 1 that is named 'General'
     84    database.get('SELECT category_id FROM category WHERE category_id = 1 AND name = ?', ['General'], (err, row) => {
    4885        if (err) {
    4986            callback(err, null);
    … …  
    5188            callback(null, row.category_id);
    5289        } else {
    53             // Create General category if it doesn't exist
    54             database.run(
    55                 'INSERT INTO category (name, description) VALUES (?, ?)',
    56                 ['General', 'General products category'],
    57                 function(err) {
    58                     if (err) {
    59                         callback(err, null);
    60                     } else {
    61                         callback(null, this.lastID);
    62                     }
    63                 }
    64             );
     90            // If not found with ID 1, try to find by name
     91            database.get('SELECT category_id FROM category WHERE name = ?', ['General'], (err, row) => {
     92                if (err) {
     93                    callback(err, null);
     94                } else if (row) {
     95                    callback(null, row.category_id);
     96                } else {
     97                    // Create General category if it doesn't exist
     98                    database.run(
     99                        'INSERT INTO category (name, description) VALUES (?, ?)',
     100                        ['General', 'General products category'],
     101                        function(err) {
     102                            if (err) {
     103                                callback(err, null);
     104                            } else {
     105                                const newId = this.lastID;
     106                                console.log(`✅ Created new General category with ID: ${newId}`);
     107                                callback(null, newId);
     108                            }
     109                        }
     110                    );
     111                }
     112            });
    65113        }
    66114    });
    … …  
    84132        database.all(
    85133            `SELECT r.* FROM roles r
    86              JOIN user_roles ur ON r.role_id = ur.role_id
    87              WHERE ur.user_id = ?`,
     134       JOIN user_roles ur ON r.role_id = ur.role_id
     135       WHERE ur.user_id = ?`,
    88136            [id],
    89137            (err, roles) => {
    … …  
    184232function getProducts(categoryId, searchTerm, callback) {
    185233    let query = `
    186         SELECT p.*, c.name as category_name, s.name as store_name
    187         FROM product p
    188         JOIN category c ON p.category_id = c.category_id
    189         JOIN store s ON p.store_id = s.store_id
    190         WHERE 1=1
    191     `;
     234    SELECT p.*, c.name as category_name, s.name as store_name
     235    FROM product p
     236    JOIN category c ON p.category_id = c.category_id
     237    JOIN store s ON p.store_id = s.store_id
     238    WHERE 1=1
     239  `;
    192240    const params = [];
    193241
    … …  
    214262    database.get(
    215263        `SELECT p.*, c.name as category_name, s.name as store_name
    216          FROM product p
    217          JOIN category c ON p.category_id = c.category_id
    218          JOIN store s ON p.store_id = s.store_id
    219          WHERE p.id = ?`,
     264     FROM product p
     265     JOIN category c ON p.category_id = c.category_id
     266     JOIN store s ON p.store_id = s.store_id
     267     WHERE p.id = ?`,
    220268        [id],
    221269        (err, row) => {
    … …  
    256304    database.get(
    257305        `SELECT p.*, c.name as category_name, s.name as store_name
    258          FROM product p
    259          JOIN category c ON p.category_id = c.category_id
    260          JOIN store s ON p.store_id = s.store_id
    261          WHERE p.code = ?`,
     306     FROM product p
     307     JOIN category c ON p.category_id = c.category_id
     308     JOIN store s ON p.store_id = s.store_id
     309     WHERE p.code = ?`,
    262310        [code],
    263311        (err, row) => {
    … …  
    317365        database.run(
    318366            `INSERT INTO product (
    319                 id, code, description, price, availability, weight, dimensions,
    320                 production_time, category_id, store_id, created_at
    321             ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, datetime('now'))`,
     367        id, code, description, price, availability, weight, dimensions,
     368        production_time, category_id, store_id, created_at
     369      ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, datetime('now'))`,
    322370            [
    323371                'PROD_' + Date.now().toString().slice(-8), // Generate a unique ID
    … …  
    341389                    database.run(
    342390                        `INSERT INTO "change" (date_and_time, product_code, changes)
    343                          VALUES (datetime('now'), ?, ?)`,
     391             VALUES (datetime('now'), ?, ?)`,
    344392                        [productData.code, 'Product created'],
    345393                        function(err) {
    … …  
    353401                    database.run(
    354402                        `INSERT INTO makes_change (personal_id, change_date_time, product_code)
    355                          VALUES (?, datetime('now'), ?)`,
     403             VALUES (?, datetime('now'), ?)`,
    356404                        [personalId, productData.code],
    357405                        function(err) {
    … …  
    367415                            database.run(
    368416                                `INSERT INTO image (product_code, image_url, is_primary)
    369                                  VALUES (?, ?, ?)`,
     417                 VALUES (?, ?, ?)`,
    370418                                [productData.code, imageUrl, index === 0 ? 1 : 0],
    371419                                function(err) {
    … …  
    409457        params.push(productData.description);
    410458    }
     459
    411460    if (productData.price !== undefined) {
    412461        updates.push('price = ?');
    413462        params.push(productData.price);
    414463    }
     464
    415465    if (productData.availability !== undefined) {
    416466        updates.push('availability = ?');
    417467        params.push(productData.availability);
    418468    }
     469
    419470    if (productData.weight !== undefined) {
    420471        updates.push('weight = ?');
    421472        params.push(productData.weight);
    422473    }
     474
    423475    if (productData.dimensions !== undefined) {
    424476        updates.push('dimensions = ?');
    425477        params.push(productData.dimensions);
    426478    }
     479
    427480    if (productData.production_time !== undefined) {
    428481        updates.push('production_time = ?');
    429482        params.push(productData.production_time);
    430483    }
     484
    431485    if (productData.category_id !== undefined) {
    432486        updates.push('category_id = ?');
    … …  
    452506                database.run(
    453507                    `INSERT INTO "change" (date_and_time, product_code, changes)
    454                      VALUES (datetime('now'), ?, ?)`,
     508           VALUES (datetime('now'), ?, ?)`,
    455509                    [productData.code, changesDesc],
    456510                    function(err) {
    … …  
    461515                        database.run(
    462516                            `INSERT INTO makes_change (personal_id, change_date_time, product_code)
    463                              VALUES (?, datetime('now'), ?)`,
     517               VALUES (?, datetime('now'), ?)`,
    464518                            [personalId, productData.code],
    465519                            function(err) {
    … …  
    520574        database.run(
    521575            `INSERT INTO "change" (date_and_time, product_code, changes)
    522              VALUES (datetime('now'), ?, ?)`,
     576       VALUES (datetime('now'), ?, ?)`,
    523577            [productCode, 'Product deleted'],
    524578            function(err) {
    … …  
    532586                database.run(
    533587                    `INSERT INTO makes_change (personal_id, change_date_time, product_code)
    534                      VALUES (?, datetime('now'), ?)`,
     588           VALUES (?, datetime('now'), ?)`,
    535589                    [personalId, productCode],
    536590                    function(err) {
    … …  
    571625    database.all(
    572626        `SELECT c1.*, c2.name as parent_name
    573          FROM category c1
    574          LEFT JOIN category c2 ON c1.parent_category_id = c2.category_id
    575          ORDER BY c1.name`,
     627     FROM category c1
     628     LEFT JOIN category c2 ON c1.parent_category_id = c2.category_id
     629     ORDER BY c1.name`,
    576630        [],
    577631        (err, rows) => {
    … …  
    610664    database.all(
    611665        `SELECT p.*, c.name as category_name
    612          FROM product p
    613          JOIN category c ON p.category_id = c.category_id
    614          WHERE p.store_id = ?
    615          ORDER BY p.code`,
     666     FROM product p
     667     JOIN category c ON p.category_id = c.category_id
     668     WHERE p.store_id = ?
     669     ORDER BY p.code`,
    616670        [storeId],
    617671        (err, rows) => {
    … …  
    628682    database.all(
    629683        `SELECT o.*, c.first_name, c.last_name
    630          FROM "order" o
    631          JOIN client c ON o.client_id = c.client_id
    632          WHERE o.store_id = ?
    633          ORDER BY o.order_date DESC`,
     684     FROM "order" o
     685     JOIN client c ON o.client_id = c.client_id
     686     WHERE o.store_id = ?
     687     ORDER BY o.order_date DESC`,
    634688        [storeId],
    635689        (err, rows) => {
    … …  
    649703                    database.all(
    650704                        `SELECT oi.*, p.description
    651                          FROM order_items oi
    652                          JOIN product p ON oi.product_code = p.code
    653                          WHERE oi.order_num = ?`,
     705             FROM order_items oi
     706             JOIN product p ON oi.product_code = p.code
     707             WHERE oi.order_num = ?`,
    654708                        [order.order_num],
    655709                        (err, items) => {
    … …  
    659713                                order.items = [];
    660714                            }
    661 
    662715                            completed++;
    663716                            if (completed === orders.length) {
    … …  
    675728    database.all(
    676729        `SELECT p.*, e.date_of_hire, perm.type as permission_type, perm.authorisation
    677          FROM personal p
    678          JOIN works_in_store w ON p.id = w.personal_id
    679          LEFT JOIN employees e ON p.id = e.employee_id
    680          LEFT JOIN permissions perm ON p.id = perm.personal_id
    681          WHERE w.store_id = ?`,
     730     FROM personal p
     731     JOIN works_in_store w ON p.id = w.personal_id
     732     LEFT JOIN employees e ON p.id = e.employee_id
     733     LEFT JOIN permissions perm ON p.id = perm.personal_id
     734     WHERE w.store_id = ?`,
    682735        [storeId],
    683736        (err, rows) => {
    … …  
    690743    database.all(
    691744        `SELECT * FROM report
    692          WHERE store_id = ?
    693          ORDER BY generated_at DESC`,
     745     WHERE store_id = ?
     746     ORDER BY generated_at DESC`,
    694747        [storeId],
    695748        (err, rows) => {
    … …  
    719772                    database.get(
    720773                        `SELECT SUM(oi.price * oi.quantity) as total_revenue
    721                          FROM order_items oi
    722                          JOIN "order" o ON oi.order_num = o.order_num
    723                          WHERE o.store_id = ?`,
     774             FROM order_items oi
     775             JOIN "order" o ON oi.order_num = o.order_num
     776             WHERE o.store_id = ?`,
    724777                        [storeId],
    725778                        (err, row) => {
    … …  
    729782                            database.get(
    730783                                `SELECT AVG(rating) as avg_rating
    731                                  FROM review r
    732                                  JOIN product p ON r.product_code = p.code
    733                                  WHERE p.store_id = ?`,
     784                 FROM review r
     785                 JOIN product p ON r.product_code = p.code
     786                 WHERE p.store_id = ?`,
    734787                                [storeId],
    735788                                (err, row) => {
    736789                                    stats.avg_rating = row && row.avg_rating ? row.avg_rating : 0;
    737 
    738790                                    callback(null, stats);
    739791                                }
    … …  
    757809        database.run(
    758810            `INSERT INTO "order" (order_num, client_id, order_date, quantity, payment_method,
    759                                  discount, delivery_address, store_id)
    760              VALUES (?, ?, datetime('now'), ?, ?, ?, ?, ?)`,
     811        discount, delivery_address, store_id)
     812       VALUES (?, ?, datetime('now'), ?, ?, ?, ?, ?)`,
    761813            [
    762814                orderData.order_num,
    … …  
    787839                    database.run(
    788840                        `INSERT INTO order_items (order_num, product_code, quantity, price)
    789                          VALUES (?, ?, ?, ?)`,
     841             VALUES (?, ?, ?, ?)`,
    790842                        [orderData.order_num, item.product_code, item.quantity, item.price],
    791843                        function(err) {
    … …  
    817869    database.all(
    818870        `SELECT o.*, s.name as store_name
    819          FROM "order" o
    820          JOIN store s ON o.store_id = s.store_id
    821          WHERE o.client_id = ?
    822          ORDER BY o.order_date DESC`,
     871     FROM "order" o
     872     JOIN store s ON o.store_id = s.store_id
     873     WHERE o.client_id = ?
     874     ORDER BY o.order_date DESC`,
    823875        [clientId],
    824876        (err, rows) => {
    … …  
    838890                    database.all(
    839891                        `SELECT oi.*, p.description
    840                          FROM order_items oi
    841                          JOIN product p ON oi.product_code = p.code
    842                          WHERE oi.order_num = ?`,
     892             FROM order_items oi
     893             JOIN product p ON oi.product_code = p.code
     894             WHERE oi.order_num = ?`,
    843895                        [order.order_num],
    844896                        (err, items) => {
    … …  
    848900                                order.items = [];
    849901                            }
    850 
    851902                            completed++;
    852903                            if (completed === orders.length) {
    … …  
    864915    database.all(
    865916        `SELECT o.*, c.first_name, c.last_name, s.name as store_name
    866          FROM "order" o
    867          JOIN client c ON o.client_id = c.client_id
    868          JOIN store s ON o.store_id = s.store_id
    869          ORDER BY o.order_date DESC`,
     917     FROM "order" o
     918     JOIN client c ON o.client_id = c.client_id
     919     JOIN store s ON o.store_id = s.store_id
     920     ORDER BY o.order_date DESC`,
    870921        [],
    871922        (err, rows) => {
    … …  
    879930    database.run(
    880931        `INSERT INTO review (review_id, client_id, product_code, rating, comment, review_date)
    881          VALUES (?, ?, ?, ?, ?, datetime('now'))`,
     932     VALUES (?, ?, ?, ?, ?, datetime('now'))`,
    882933        [
    883934            'REV' + Date.now().toString().slice(-8),
    … …  
    901952    database.run(
    902953        `INSERT INTO request (request_num, date_and_time, problem, client_id, store_id)
    903          VALUES (?, ?, ?, ?, ?)`,
     954     VALUES (?, ?, ?, ?, ?)`,
    904955        [
    905956            requestData.request_num,
    … …  
    923974    database.run(
    924975        `INSERT INTO refund (refund_id, order_num, amount, reason, request_date)
    925          VALUES (?, ?, ?, ?, datetime('now'))`,
     976     VALUES (?, ?, ?, ?, datetime('now'))`,
    926977        [
    927978            refundData.refund_id,
    … …  
    9511002    database.all(
    9521003        `SELECT o.*, c.first_name, c.last_name
    953          FROM "order" o
    954          JOIN client c ON o.client_id = c.client_id
    955          WHERE o.store_id = ? AND o.status = 'pending'
    956          ORDER BY o.order_date ASC`,
     1004     FROM "order" o
     1005     JOIN client c ON o.client_id = c.client_id
     1006     WHERE o.store_id = ? AND o.status = 'pending'
     1007     ORDER BY o.order_date ASC`,
    9571008        [storeId],
    9581009        (err, rows) => {
    … …  
    9641015            database.all(
    9651016                `SELECT r.*, c.first_name, c.last_name
    966                  FROM request r
    967                  JOIN client c ON r.client_id = c.client_id
    968                  WHERE r.store_id = ? AND r.status = 'pending'
    969                  ORDER BY r.date_and_time ASC`,
     1017         FROM request r
     1018         JOIN client c ON r.client_id = c.client_id
     1019         WHERE r.store_id = ? AND r.status = 'pending'
     1020         ORDER BY r.date_and_time ASC`,
    9701021                [storeId],
    9711022                (err, rows) => {
    … …  
    9771028                    database.all(
    9781029                        `SELECT rf.*, o.client_id, c.first_name, c.last_name
    979                          FROM refund rf
    980                          JOIN "order" o ON rf.order_num = o.order_num
    981                          JOIN client c ON o.client_id = c.client_id
    982                          WHERE o.store_id = ? AND rf.status = 'pending'
    983                          ORDER BY rf.request_date ASC`,
     1030             FROM refund rf
     1031             JOIN "order" o ON rf.order_num = o.order_num
     1032             JOIN client c ON o.client_id = c.client_id
     1033             WHERE o.store_id = ? AND rf.status = 'pending'
     1034             ORDER BY rf.request_date ASC`,
    9841035                        [storeId],
    9851036                        (err, rows) => {
    … …  
    10101061            database.get(
    10111062                `SELECT SUM(oi.price * oi.quantity) as total_spent
    1012                  FROM order_items oi
    1013                  JOIN "order" o ON oi.order_num = o.order_num
    1014                  WHERE o.client_id = ?`,
     1063         FROM order_items oi
     1064         JOIN "order" o ON oi.order_num = o.order_num
     1065         WHERE o.client_id = ?`,
    10151066                [clientId],
    10161067                (err, row) => {
    … …  
    10301081                                (err, row) => {
    10311082                                    stats.delivered_orders = row ? row.delivered_orders : 0;
    1032 
    10331083                                    callback(null, stats);
    10341084                                }
    … …  
    10491099    database.all(
    10501100        `SELECT client_id as id, first_name, last_name, email, 'client' as user_type
    1051          FROM client
    1052          ORDER BY client_id`,
     1101     FROM client
     1102     ORDER BY client_id`,
    10531103        [],
    10541104        (err, rows) => {
    … …  
    10601110            database.all(
    10611111                `SELECT p.id, p.first_name, p.last_name, p.email,
    1062                         CASE WHEN b.boss_id IS NOT NULL THEN 'store_owner'
    1063                              WHEN e.employee_id IS NOT NULL THEN 'store_employee'
    1064                              ELSE 'personal' END as user_type
    1065                  FROM personal p
    1066                  LEFT JOIN boss b ON p.id = b.boss_id
    1067                  LEFT JOIN employees e ON p.id = e.employee_id
    1068                  ORDER BY p.id`,
     1112          CASE WHEN b.boss_id IS NOT NULL THEN 'store_owner'
     1113               WHEN e.employee_id IS NOT NULL THEN 'store_employee'
     1114               ELSE 'personal' END as user_type
     1115         FROM personal p
     1116         LEFT JOIN boss b ON p.id = b.boss_id
     1117         LEFT JOIN employees e ON p.id = e.employee_id
     1118         ORDER BY p.id`,
    10691119                [],
    10701120                (err, rows) => {
    … …  
    10761126                    database.all(
    10771127                        `SELECT id, username, email, user_type
    1078                          FROM users
    1079                          ORDER BY id`,
     1128             FROM users
     1129             ORDER BY id`,
    10801130                        [],
    10811131                        (err, rows) => {
    … …  
    10961146    database.run(
    10971147        `INSERT INTO audit_log (user_id, action, resource_type, resource_id, details, ip_address)
    1098          VALUES (?, ?, ?, ?, ?, ?)`,
     1148     VALUES (?, ?, ?, ?, ?, ?)`,
    10991149        [userId, action, resourceType, resourceId, details, ipAddress],
    11001150        (err) => {
  • interfejs/store-owner.html

    r69f2a41 r591278c  
    151151                    </select>
    152152                </div>
     153
    153154                <div id="custom-date-range" style="display: none;">
    154155                    <div class="form-row">
    … …  
    163164                    </div>
    164165                </div>
     166
    165167                <div class="form-group">
    166168                    <label for="report-type">Report Type</label>
    … …  
    172174                    </select>
    173175                </div>
     176
    174177                <button id="generate-store-report" class="btn-primary">Generate Report</button>
     178
    175179                <div id="report-results" style="margin-top: 2rem;"></div>
    176180            </div>
    … …  
    214218                            <input type="number" id="product-production-time" min="1" required>
    215219                        </div>
    216                         <div class="form-group">
     220                        <div class="form-group category-group">
    217221                            <label for="product-category">Category *</label>
    218                             <select id="product-category" required>
    219                                 <option value="">Select Category</option>
    220                             </select>
     222                            <div class="category-input-group">
     223                                <select id="product-category" required>
     224                                    <option value="">Select Category</option>
     225                                </select>
     226                                <button type="button" id="add-category-btn" class="btn-small btn-secondary">➕ New Category</button>
     227                            </div>
    221228                        </div>
    222229                    </div>
    … …  
    286293</main>
    287294
     295<!-- Edit Product Modal -->
    288296<div id="edit-product-modal" class="modal" style="display: none;">
    289297    <div class="modal-content modal-large">
    … …  
    325333                    <input type="number" id="edit-product-production-time" min="1">
    326334                </div>
    327                 <div class="form-group">
     335                <div class="form-group category-group">
    328336                    <label for="edit-product-category">Category</label>
    329                     <select id="edit-product-category">
    330                         <option value="">Select Category</option>
    331                     </select>
     337                    <div class="category-input-group">
     338                        <select id="edit-product-category">
     339                            <option value="">Select Category</option>
     340                        </select>
     341                        <button type="button" id="edit-add-category-btn" class="btn-small btn-secondary">➕ New Category</button>
     342                    </div>
    332343                </div>
    333344            </div>
    … …  
    348359</div>
    349360
     361<!-- Edit Employee Modal -->
    350362<div id="edit-employee-modal" class="modal" style="display: none;">
    351363    <div class="modal-content">
    … …  
    381393
    382394            <button type="submit" class="btn-primary">Update Employee</button>
     395        </form>
     396    </div>
     397</div>
     398
     399<!-- Add Category Modal -->
     400<div id="add-category-modal" class="modal" style="display: none;">
     401    <div class="modal-content">
     402        <span class="close">&times;</span>
     403        <h2>Create New Category</h2>
     404        <form id="add-category-form" class="form">
     405            <div class="form-group">
     406                <label for="category-name">Category Name *</label>
     407                <input type="text" id="category-name" required>
     408            </div>
     409
     410            <div class="form-group">
     411                <label for="category-description">Description</label>
     412                <textarea id="category-description" rows="3" placeholder="Optional description"></textarea>
     413            </div>
     414
     415            <div class="form-group">
     416                <label for="category-parent">Parent Category (optional)</label>
     417                <select id="category-parent">
     418                    <option value="">None (Top Level Category)</option>
     419                </select>
     420            </div>
     421
     422            <button type="submit" class="btn-primary">Create Category</button>
     423            <button type="button" id="cancel-category-btn" class="btn-secondary">Cancel</button>
    383424        </form>
    384425    </div>
    … …  
    408449    document.addEventListener('DOMContentLoaded', async () => {
    409450        const user = await loadUserData();
     451
    410452        if (!user || user.userType !== 'store_owner') {
    411453            window.location.href = 'index.html';
    … …  
    464506        // Generate report
    465507        document.getElementById('generate-store-report').addEventListener('click', generateStoreReport);
     508
     509        // Add Category button functionality
     510        document.getElementById('add-category-btn').addEventListener('click', () => {
     511            openCategoryModal();
     512        });
     513
     514        document.getElementById('edit-add-category-btn').addEventListener('click', () => {
     515            openCategoryModal('edit');
     516        });
     517
     518        // Category form submission
     519        document.getElementById('add-category-form').addEventListener('submit', createCategory);
     520
     521        // Cancel button
     522        document.getElementById('cancel-category-btn').addEventListener('click', () => {
     523            document.getElementById('add-category-modal').style.display = 'none';
     524        });
    466525    });
    467526
    … …  
    499558            const response = await fetch(`/api/store-products?storeId=${storeId}`);
    500559            const data = await response.json();
    501 
    502560            const tbody = document.getElementById('products-list');
     561
    503562            if (data.success && data.products.length > 0) {
    504563                tbody.innerHTML = data.products.map(product => `
    … …  
    528587            const response = await fetch(`/api/store-orders?storeId=${storeId}`);
    529588            const data = await response.json();
    530 
    531589            const tbody = document.getElementById('orders-list');
     590
    532591            if (data.success && data.orders.length > 0) {
    533592                tbody.innerHTML = data.orders.map(order => {
    … …  
    560619            const response = await fetch(`/api/store-employees?storeId=${storeId}`);
    561620            const data = await response.json();
    562 
    563621            const tbody = document.getElementById('employees-list');
     622
    564623            if (data.success && data.employees.length > 0) {
    565624                tbody.innerHTML = data.employees.map(emp => `
    … …  
    592651            if (data.success) {
    593652                const options = data.categories.map(cat =>
     653                    `<option value="${cat.category_id}">${cat.name}${cat.parent_name ? ` (subcategory of ${cat.parent_name})` : ''}</option>`
     654                ).join('');
     655
     656                document.getElementById('product-category').innerHTML = '<option value="">Select Category</option>' + options;
     657                document.getElementById('edit-product-category').innerHTML = '<option value="">Select Category</option>' + options;
     658
     659                // Also load for category parent dropdown
     660                const parentOptions = data.categories.map(cat =>
    594661                    `<option value="${cat.category_id}">${cat.name}</option>`
    595662                ).join('');
    596 
    597                 document.getElementById('product-category').innerHTML = '<option value="">Select Category</option>' + options;
    598                 document.getElementById('edit-product-category').innerHTML = '<option value="">Select Category</option>' + options;
     663                document.getElementById('category-parent').innerHTML = '<option value="">None (Top Level Category)</option>' + parentOptions;
    599664            }
    600665        } catch (error) {
    601666            console.error('Error loading categories:', error);
     667        }
     668    }
     669
     670    function openCategoryModal(source = 'add') {
     671        // Store which form triggered this
     672        document.getElementById('add-category-modal').dataset.source = source;
     673        document.getElementById('add-category-modal').style.display = 'block';
     674        document.getElementById('add-category-form').reset();
     675    }
     676
     677    async function createCategory(e) {
     678        e.preventDefault();
     679
     680        const categoryName = document.getElementById('category-name').value.trim();
     681        const categoryDescription = document.getElementById('category-description').value.trim();
     682        const parentId = document.getElementById('category-parent').value;
     683
     684        if (!categoryName) {
     685            alert('Please enter a category name');
     686            return;
     687        }
     688
     689        const categoryData = {
     690            name: categoryName,
     691            description: categoryDescription,
     692            parentId: parentId || null
     693        };
     694
     695        try {
     696            const response = await fetch('/api/create-category', {
     697                method: 'POST',
     698                headers: { 'Content-Type': 'application/json' },
     699                body: JSON.stringify(categoryData)
     700            });
     701
     702            const data = await response.json();
     703
     704            if (data.success) {
     705                alert(`Category "${categoryName}" created successfully!`);
     706                document.getElementById('add-category-modal').style.display = 'none';
     707
     708                // Reload categories in all dropdowns
     709                await loadCategories();
     710
     711                // Auto-select the new category if it came from add product form
     712                const source = document.getElementById('add-category-modal').dataset.source;
     713                if (source === 'edit') {
     714                    document.getElementById('edit-product-category').value = data.category.id;
     715                } else {
     716                    document.getElementById('product-category').value = data.category.id;
     717                }
     718            } else {
     719                alert(data.message || 'Failed to create category');
     720            }
     721        } catch (error) {
     722            console.error('Error creating category:', error);
     723            alert('An error occurred while creating the category');
    602724        }
    603725    }
    … …  
    607729
    608730        const storeId = document.getElementById('store-select').value;
     731
    609732        if (!storeId) {
    610733            alert('Please select a store first');
    … …  
    679802
    680803        const storeId = document.getElementById('store-select').value;
     804
    681805        if (!storeId) {
    682806            alert('Please select a store first');
    … …  
    686810        const password = document.getElementById('employee-password').value;
    687811        const passwordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/;
     812
    688813        if (!passwordRegex.test(password)) {
    689814            alert('Password must have at least 8 characters, including uppercase, lowercase, number and special character');
    … …  
    762887
    763888        const storeId = document.getElementById('store-select').value;
     889
    764890        const formData = {
    765891            code: document.getElementById('edit-product-code').value,
    … …  
    860986
    861987        const storeId = document.getElementById('store-select').value;
     988
    862989        const formData = {
    863990            employeeId: document.getElementById('edit-employee-id').value,
    … …  
    8971024
    8981025        let startDate, endDate;
     1026
    8991027        if (period === 'custom') {
    9001028            startDate = document.getElementById('report-start').value;
    9011029            endDate = document.getElementById('report-end').value;
     1030
    9021031            if (!startDate || !endDate) {
    9031032                alert('Please select start and end dates');
  • server.js

    r69f2a41 r591278c  
    1010
    1111const port = process.env.PORT || 3000;
     12
    1213const sessions = new Map();
    1314const verificationCodes = new Map();
    … …  
    3132        }
    3233    };
     34
    3335    emailTransporter = nodemailer.createTransport(emailConfig);
    3436
    … …  
    7375        subject: 'Your Verification Code - Handcraft Marketplace',
    7476        html: `
    75         <div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; background: linear-gradient(135deg, #4169E1 0%, #FF69B4 100%); color: white; padding: 20px; border-radius: 10px;">
    76             <h2 style="text-align: center;">🎨 Handcraft Marketplace</h2>
    77             <div style="background-color: white; color: #333; padding: 20px; border-radius: 8px; margin: 20px 0;">
    78                 <h3 style="color: #4169E1;">Account Verification</h3>
    79                 <p>Your verification code is:</p>
    80                 <div style="background-color: #f5f5f5; padding: 15px; border-radius: 5px; text-align: center; font-size: 24px; font-weight: bold; letter-spacing: 5px; margin: 20px 0; color: #4169E1;">
    81                     ${code}
    82                 </div>
    83                 <p style="color: #e74c3c; font-weight: bold;">⚠️ This code will expire in 30 seconds</p>
    84                 <p style="color: #666; font-size: 12px;">If you didn't request this verification, please ignore this email.</p>
    85             </div>
    86         </div>`
     77      <div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; background: linear-gradient(135deg, #4169E1 0%, #FF69B4 100%); color: white; padding: 20px; border-radius: 10px;">
     78        <h2 style="text-align: center;">🎨 Handcraft Marketplace</h2>
     79        <div style="background-color: white; color: #333; padding: 20px; border-radius: 8px; margin: 20px 0;">
     80          <h3 style="color: #4169E1;">Account Verification</h3>
     81          <p>Your verification code is:</p>
     82          <div style="background-color: #f5f5f5; padding: 15px; border-radius: 5px; text-align: center; font-size: 24px; font-weight: bold; letter-spacing: 5px; margin: 20px 0; color: #4169E1;">
     83            ${code}
     84          </div>
     85          <p style="color: #e74c3c; font-weight: bold;">⚠️ This code will expire in 30 seconds</p>
     86          <p style="color: #666; font-size: 12px;">If you didn't request this verification, please ignore this email.</p>
     87        </div>
     88      </div>`
    8789    };
    8890
    … …  
    104106        subject: 'Your 2FA Code - Handcraft Marketplace',
    105107        html: `
    106         <div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; background: linear-gradient(135deg, #4169E1 0%, #FF69B4 100%); color: white; padding: 20px; border-radius: 10px;">
    107             <h2 style="text-align: center;">🎨 Handcraft Marketplace</h2>
    108             <div style="background-color: white; color: #333; padding: 20px; border-radius: 8px; margin: 20px 0;">
    109                 <h3 style="color: #4169E1;">Two-Factor Authentication</h3>
    110                 <p>Your login verification code is:</p>
    111                 <div style="background-color: #f5f5f5; padding: 15px; border-radius: 5px; text-align: center; font-size: 24px; font-weight: bold; letter-spacing: 5px; margin: 20px 0; color: #4169E1;">
    112                     ${code}
    113                 </div>
    114                 <p style="color: #e74c3c; font-weight: bold;">⚠️ This code will expire in 30 seconds</p>
    115                 <p style="color: #666; font-size: 12px;">If you're not trying to login, please secure your account immediately.</p>
    116             </div>
    117         </div>`
     108      <div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; background: linear-gradient(135deg, #4169E1 0%, #FF69B4 100%); color: white; padding: 20px; border-radius: 10px;">
     109        <h2 style="text-align: center;">🎨 Handcraft Marketplace</h2>
     110        <div style="background-color: white; color: #333; padding: 20px; border-radius: 8px; margin: 20px 0;">
     111          <h3 style="color: #4169E1;">Two-Factor Authentication</h3>
     112          <p>Your login verification code is:</p>
     113          <div style="background-color: #f5f5f5; padding: 15px; border-radius: 5px; text-align: center; font-size: 24px; font-weight: bold; letter-spacing: 5px; margin: 20px 0; color: #4169E1;">
     114            ${code}
     115          </div>
     116          <p style="color: #e74c3c; font-weight: bold;">⚠️ This code will expire in 30 seconds</p>
     117          <p style="color: #666; font-size: 12px;">If you're not trying to login, please secure your account immediately.</p>
     118        </div>
     119      </div>`
    118120    };
    119121
    … …  
    135137        subject: 'Store Registration Verification - Handcraft Marketplace',
    136138        html: `
    137         <div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; background: linear-gradient(135deg, #4169E1 0%, #FF69B4 100%); color: white; padding: 20px; border-radius: 10px;">
    138             <h2 style="text-align: center;">🎨 Handcraft Marketplace</h2>
    139             <div style="background-color: white; color: #333; padding: 20px; border-radius: 8px; margin: 20px 0;">
    140                 <h3 style="color: #4169E1;">Store Registration Verification</h3>
    141                 <p>Thank you for registering your store "<strong>${storeName}</strong>" on Handcraft Marketplace!</p>
    142                 <p>Your verification code is:</p>
    143                 <div style="background-color: #f5f5f5; padding: 15px; border-radius: 5px; text-align: center; font-size: 24px; font-weight: bold; letter-spacing: 5px; margin: 20px 0; color: #4169E1;">
    144                     ${code}
    145                 </div>
    146                 <p style="color: #e74c3c; font-weight: bold;">⚠️ This code will expire in 30 seconds</p>
    147                 <p style="color: #666; font-size: 12px;">If you didn't request this verification, please ignore this email.</p>
    148             </div>
    149         </div>`
     139      <div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; background: linear-gradient(135deg, #4169E1 0%, #FF69B4 100%); color: white; padding: 20px; border-radius: 10px;">
     140        <h2 style="text-align: center;">🎨 Handcraft Marketplace</h2>
     141        <div style="background-color: white; color: #333; padding: 20px; border-radius: 8px; margin: 20px 0;">
     142          <h3 style="color: #4169E1;">Store Registration Verification</h3>
     143          <p>Thank you for registering your store "<strong>${storeName}</strong>" on Handcraft Marketplace!</p>
     144          <p>Your verification code is:</p>
     145          <div style="background-color: #f5f5f5; padding: 15px; border-radius: 5px; text-align: center; font-size: 24px; font-weight: bold; letter-spacing: 5px; margin: 20px 0; color: #4169E1;">
     146            ${code}
     147          </div>
     148          <p style="color: #e74c3c; font-weight: bold;">⚠️ This code will expire in 30 seconds</p>
     149          <p style="color: #666; font-size: 12px;">If you didn't request this verification, please ignore this email.</p>
     150        </div>
     151      </div>`
    150152    };
    151153
    … …  
    350352
    351353    try {
    352         // Check if all tables exist
    353         const checkTablesQuery = `
    354             SELECT table_name
    355             FROM information_schema.tables
    356             WHERE table_schema = 'public'
    357         `;
    358 
     354        // For SQLite, we need to use a different approach to check tables
    359355        const result = await new Promise((resolve, reject) => {
    360             database.database.all(checkTablesQuery, [], (err, rows) => {
    361                 if (err) reject(err);
    362                 else resolve(rows || []);
    363             });
    364         });
    365 
    366         const existingTables = result.map(row => row.table_name);
     356            database.database.all(
     357                "SELECT name FROM sqlite_master WHERE type='table'",
     358                [],
     359                (err, rows) => {
     360                    if (err) reject(err);
     361                    else resolve(rows || []);
     362                }
     363            );
     364        });
     365
     366        const existingTables = result.map(row => row.name);
    367367        const missingTables = requiredTables.filter(table => !existingTables.includes(table));
    368368
    … …  
    409409        // Drop in reverse order of creation (respect foreign keys)
    410410        const dropQueries = [
    411             'DROP TABLE IF EXISTS user_roles CASCADE',
    412             'DROP TABLE IF EXISTS roles CASCADE',
    413             'DROP TABLE IF EXISTS delivery_address CASCADE',
    414             'DROP TABLE IF EXISTS image CASCADE',
    415             'DROP TABLE IF EXISTS color CASCADE',
    416             'DROP TABLE IF EXISTS audit_log CASCADE',
    417             'DROP TABLE IF EXISTS report CASCADE',
    418             'DROP TABLE IF EXISTS refund CASCADE',
    419             'DROP TABLE IF EXISTS request CASCADE',
    420             'DROP TABLE IF EXISTS review CASCADE',
    421             'DROP TABLE IF EXISTS order_items CASCADE',
    422             'DROP TABLE IF EXISTS "order" CASCADE',
    423             'DROP TABLE IF EXISTS permissions CASCADE',
    424             'DROP TABLE IF EXISTS works_in_store CASCADE',
    425             'DROP TABLE IF EXISTS employees CASCADE',
    426             'DROP TABLE IF EXISTS boss CASCADE',
    427             'DROP TABLE IF EXISTS product CASCADE',
    428             'DROP TABLE IF EXISTS personal CASCADE',
    429             'DROP TABLE IF EXISTS users CASCADE',
    430             'DROP TABLE IF EXISTS category CASCADE',
    431             'DROP TABLE IF EXISTS store CASCADE',
    432             'DROP TABLE IF EXISTS client CASCADE'
     411            'DROP TABLE IF EXISTS user_roles',
     412            'DROP TABLE IF EXISTS roles',
     413            'DROP TABLE IF EXISTS delivery_address',
     414            'DROP TABLE IF EXISTS image',
     415            'DROP TABLE IF EXISTS color',
     416            'DROP TABLE IF EXISTS audit_log',
     417            'DROP TABLE IF EXISTS report',
     418            'DROP TABLE IF EXISTS refund',
     419            'DROP TABLE IF EXISTS request',
     420            'DROP TABLE IF EXISTS review',
     421            'DROP TABLE IF EXISTS order_items',
     422            'DROP TABLE IF EXISTS "order"',
     423            'DROP TABLE IF EXISTS permissions',
     424            'DROP TABLE IF EXISTS works_in_store',
     425            'DROP TABLE IF EXISTS employees',
     426            'DROP TABLE IF EXISTS boss',
     427            'DROP TABLE IF EXISTS product',
     428            'DROP TABLE IF EXISTS personal',
     429            'DROP TABLE IF EXISTS users',
     430            'DROP TABLE IF EXISTS category',
     431            'DROP TABLE IF EXISTS store',
     432            'DROP TABLE IF EXISTS client'
    433433        ];
    434434
    … …  
    463463            // Client table (SERIAL ID starting from 1000)
    464464            `CREATE TABLE IF NOT EXISTS client (
    465                                                    client_id SERIAL PRIMARY KEY,
    466                                                    first_name VARCHAR(100) NOT NULL,
    467                 last_name VARCHAR(100) NOT NULL,
    468                 email VARCHAR(255) UNIQUE NOT NULL,
    469                 password VARCHAR(255) NOT NULL,
    470                 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    471                 )`,
     465        client_id INTEGER PRIMARY KEY AUTOINCREMENT,
     466        first_name VARCHAR(100) NOT NULL,
     467        last_name VARCHAR(100) NOT NULL,
     468        email VARCHAR(255) UNIQUE NOT NULL,
     469        password VARCHAR(255) NOT NULL,
     470        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
     471      )`,
    472472
    473473            // Store table (VARCHAR ID)
    474474            `CREATE TABLE IF NOT EXISTS store (
    475                                                   store_id VARCHAR(10) PRIMARY KEY,
    476                 name VARCHAR(255) NOT NULL,
    477                 date_of_founding DATE NOT NULL,
    478                 physical_address TEXT NOT NULL,
    479                 store_email VARCHAR(255) UNIQUE NOT NULL,
    480                 rating DECIMAL(3,2) DEFAULT 0.0
    481                 )`,
     475        store_id VARCHAR(10) PRIMARY KEY,
     476        name VARCHAR(255) NOT NULL,
     477        date_of_founding DATE NOT NULL,
     478        physical_address TEXT NOT NULL,
     479        store_email VARCHAR(255) UNIQUE NOT NULL,
     480        rating DECIMAL(3,2) DEFAULT 0.0
     481      )`,
    482482
    483483            // Category table (SERIAL ID starting from 1)
    484484            `CREATE TABLE IF NOT EXISTS category (
    485                                                      category_id SERIAL PRIMARY KEY,
    486                                                      name VARCHAR(100) NOT NULL,
    487                 description TEXT,
    488                 parent_category_id INTEGER REFERENCES category(category_id) ON DELETE SET NULL
    489                 )`,
     485        category_id INTEGER PRIMARY KEY AUTOINCREMENT,
     486        name VARCHAR(100) NOT NULL,
     487        description TEXT,
     488        parent_category_id INTEGER REFERENCES category(category_id) ON DELETE SET NULL
     489      )`,
    490490
    491491            // Users table (VARCHAR ID)
    492492            `CREATE TABLE IF NOT EXISTS users (
    493                                                   id VARCHAR(50) PRIMARY KEY,
    494                 username VARCHAR(100) UNIQUE NOT NULL,
    495                 email VARCHAR(255) UNIQUE NOT NULL,
    496                 password VARCHAR(255) NOT NULL,
    497                 user_type VARCHAR(50) NOT NULL,
    498                 force_password_change INTEGER DEFAULT 0,
    499                 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    500                 )`,
     493        id VARCHAR(50) PRIMARY KEY,
     494        username VARCHAR(100) UNIQUE NOT NULL,
     495        email VARCHAR(255) UNIQUE NOT NULL,
     496        password VARCHAR(255) NOT NULL,
     497        user_type VARCHAR(50) NOT NULL,
     498        force_password_change INTEGER DEFAULT 0,
     499        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
     500      )`,
    501501
    502502            // Personal table (VARCHAR ID - format: storeId(3) + '001' for owner, storeId(3) + employeeNum(3) for employees)
    503503            `CREATE TABLE IF NOT EXISTS personal (
    504                                                      id VARCHAR(10) PRIMARY KEY,
    505                 first_name VARCHAR(100) NOT NULL,
    506                 last_name VARCHAR(100) NOT NULL,
    507                 ssn VARCHAR(13) UNIQUE NOT NULL,
    508                 email VARCHAR(255) UNIQUE NOT NULL,
    509                 password VARCHAR(255) NOT NULL,
    510                 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    511                 )`,
     504        id VARCHAR(10) PRIMARY KEY,
     505        first_name VARCHAR(100) NOT NULL,
     506        last_name VARCHAR(100) NOT NULL,
     507        ssn VARCHAR(13) UNIQUE NOT NULL,
     508        email VARCHAR(255) UNIQUE NOT NULL,
     509        password VARCHAR(255) NOT NULL,
     510        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
     511      )`,
    512512
    513513            // Product table (VARCHAR ID)
    514514            `CREATE TABLE IF NOT EXISTS product (
    515                                                     id VARCHAR(50) PRIMARY KEY,
    516                 code VARCHAR(20) UNIQUE NOT NULL,
    517                 description TEXT NOT NULL,
    518                 price DECIMAL(10,2) NOT NULL,
    519                 availability INTEGER NOT NULL DEFAULT 0,
    520                 weight DECIMAL(10,2),
    521                 dimensions VARCHAR(50),
    522                 production_time INTEGER,
    523                 category_id INTEGER REFERENCES category(category_id) ON DELETE SET NULL,
    524                 store_id VARCHAR(10) REFERENCES store(store_id) ON DELETE CASCADE,
    525                 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    526                 )`,
     515        id VARCHAR(50) PRIMARY KEY,
     516        code VARCHAR(20) UNIQUE NOT NULL,
     517        description TEXT NOT NULL,
     518        price DECIMAL(10,2) NOT NULL,
     519        availability INTEGER NOT NULL DEFAULT 0,
     520        weight DECIMAL(10,2),
     521        dimensions VARCHAR(50),
     522        production_time INTEGER,
     523        category_id INTEGER REFERENCES category(category_id) ON DELETE SET NULL,
     524        store_id VARCHAR(10) REFERENCES store(store_id) ON DELETE CASCADE,
     525        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
     526      )`,
    527527
    528528            // Boss table (VARCHAR ID - references personal.id)
    529529            `CREATE TABLE IF NOT EXISTS boss (
    530                                                  boss_id VARCHAR(10) PRIMARY KEY REFERENCES personal(id) ON DELETE CASCADE,
    531                 signature TEXT NOT NULL,
    532                 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    533                 )`,
     530        boss_id VARCHAR(10) PRIMARY KEY REFERENCES personal(id) ON DELETE CASCADE,
     531        signature TEXT NOT NULL,
     532        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
     533      )`,
    534534
    535535            // Employees table (VARCHAR ID - references personal.id)
    536536            `CREATE TABLE IF NOT EXISTS employees (
    537                                                       employee_id VARCHAR(10) PRIMARY KEY REFERENCES personal(id) ON DELETE CASCADE,
    538                 date_of_hire DATE NOT NULL,
    539                 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    540                 )`,
     537        employee_id VARCHAR(10) PRIMARY KEY REFERENCES personal(id) ON DELETE CASCADE,
     538        date_of_hire DATE NOT NULL,
     539        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
     540      )`,
    541541
    542542            // Works_in_store table (junction)
    543543            `CREATE TABLE IF NOT EXISTS works_in_store (
    544                                                            personal_id VARCHAR(10) REFERENCES personal(id) ON DELETE CASCADE,
    545                 store_id VARCHAR(10) REFERENCES store(store_id) ON DELETE CASCADE,
    546                 PRIMARY KEY (personal_id, store_id)
    547                 )`,
     544        personal_id VARCHAR(10) REFERENCES personal(id) ON DELETE CASCADE,
     545        store_id VARCHAR(10) REFERENCES store(store_id) ON DELETE CASCADE,
     546        PRIMARY KEY (personal_id, store_id)
     547      )`,
    548548
    549549            // Permissions table
    550550            `CREATE TABLE IF NOT EXISTS permissions (
    551                                                         permission_id SERIAL PRIMARY KEY,
    552                                                         personal_id VARCHAR(10) REFERENCES personal(id) ON DELETE CASCADE,
    553                 type VARCHAR(50) NOT NULL,
    554                 authorisation TEXT,
    555                 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    556                 )`,
     551        permission_id INTEGER PRIMARY KEY AUTOINCREMENT,
     552        personal_id VARCHAR(10) REFERENCES personal(id) ON DELETE CASCADE,
     553        type VARCHAR(50) NOT NULL,
     554        authorisation TEXT,
     555        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
     556      )`,
    557557
    558558            // Order table (VARCHAR ID)
    559559            `CREATE TABLE IF NOT EXISTS "order" (
    560                                                     order_num VARCHAR(20) PRIMARY KEY,
    561                 client_id INTEGER REFERENCES client(client_id) ON DELETE SET NULL,
    562                 order_date TIMESTAMP NOT NULL,
    563                 quantity INTEGER NOT NULL,
    564                 payment_method VARCHAR(50) NOT NULL,
    565                 discount DECIMAL(10,2) DEFAULT 0,
    566                 delivery_address TEXT NOT NULL,
    567                 store_id VARCHAR(10) REFERENCES store(store_id) ON DELETE SET NULL,
    568                 status VARCHAR(50) DEFAULT 'pending',
    569                 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    570                 )`,
     560        order_num VARCHAR(20) PRIMARY KEY,
     561        client_id INTEGER REFERENCES client(client_id) ON DELETE SET NULL,
     562        order_date TIMESTAMP NOT NULL,
     563        quantity INTEGER NOT NULL,
     564        payment_method VARCHAR(50) NOT NULL,
     565        discount DECIMAL(10,2) DEFAULT 0,
     566        delivery_address TEXT NOT NULL,
     567        store_id VARCHAR(10) REFERENCES store(store_id) ON DELETE SET NULL,
     568        status VARCHAR(50) DEFAULT 'pending',
     569        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
     570      )`,
    571571
    572572            // Order_items table
    573573            `CREATE TABLE IF NOT EXISTS order_items (
    574                                                         item_id SERIAL PRIMARY KEY,
    575                                                         order_num VARCHAR(20) REFERENCES "order"(order_num) ON DELETE CASCADE,
    576                 product_code VARCHAR(20) REFERENCES product(code) ON DELETE SET NULL,
    577                 quantity INTEGER NOT NULL,
    578                 price DECIMAL(10,2) NOT NULL,
    579                 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    580                 )`,
     574        item_id INTEGER PRIMARY KEY AUTOINCREMENT,
     575        order_num VARCHAR(20) REFERENCES "order"(order_num) ON DELETE CASCADE,
     576        product_code VARCHAR(20) REFERENCES product(code) ON DELETE SET NULL,
     577        quantity INTEGER NOT NULL,
     578        price DECIMAL(10,2) NOT NULL,
     579        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
     580      )`,
    581581
    582582            // Review table (VARCHAR ID)
    583583            `CREATE TABLE IF NOT EXISTS review (
    584                                                    review_id VARCHAR(20) PRIMARY KEY,
    585                 client_id INTEGER REFERENCES client(client_id) ON DELETE SET NULL,
    586                 product_code VARCHAR(20) REFERENCES product(code) ON DELETE CASCADE,
    587                 rating INTEGER NOT NULL CHECK (rating >= 1 AND rating <= 5),
    588                 comment TEXT,
    589                 review_date TIMESTAMP NOT NULL,
    590                 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    591                 )`,
     584        review_id VARCHAR(20) PRIMARY KEY,
     585        client_id INTEGER REFERENCES client(client_id) ON DELETE SET NULL,
     586        product_code VARCHAR(20) REFERENCES product(code) ON DELETE CASCADE,
     587        rating INTEGER NOT NULL CHECK (rating >= 1 AND rating <= 5),
     588        comment TEXT,
     589        review_date TIMESTAMP NOT NULL,
     590        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
     591      )`,
    592592
    593593            // Request table (VARCHAR ID)
    594594            `CREATE TABLE IF NOT EXISTS request (
    595                                                     request_num VARCHAR(50) PRIMARY KEY,
    596                 date_and_time TIMESTAMP NOT NULL,
    597                 problem TEXT NOT NULL,
    598                 client_id INTEGER REFERENCES client(client_id) ON DELETE SET NULL,
    599                 store_id VARCHAR(10) REFERENCES store(store_id) ON DELETE CASCADE,
    600                 status VARCHAR(50) DEFAULT 'pending',
    601                 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    602                 )`,
     595        request_num VARCHAR(50) PRIMARY KEY,
     596        date_and_time TIMESTAMP NOT NULL,
     597        problem TEXT NOT NULL,
     598        client_id INTEGER REFERENCES client(client_id) ON DELETE SET NULL,
     599        store_id VARCHAR(10) REFERENCES store(store_id) ON DELETE CASCADE,
     600        status VARCHAR(50) DEFAULT 'pending',
     601        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
     602      )`,
    603603
    604604            // Refund table (VARCHAR ID)
    605605            `CREATE TABLE IF NOT EXISTS refund (
    606                                                    refund_id VARCHAR(50) PRIMARY KEY,
    607                 order_num VARCHAR(20) REFERENCES "order"(order_num) ON DELETE CASCADE,
    608                 amount DECIMAL(10,2) NOT NULL,
    609                 reason TEXT NOT NULL,
    610                 status VARCHAR(50) DEFAULT 'pending',
    611                 request_date TIMESTAMP NOT NULL,
    612                 processed_date TIMESTAMP,
    613                 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    614                 )`,
     606        refund_id VARCHAR(50) PRIMARY KEY,
     607        order_num VARCHAR(20) REFERENCES "order"(order_num) ON DELETE CASCADE,
     608        amount DECIMAL(10,2) NOT NULL,
     609        reason TEXT NOT NULL,
     610        status VARCHAR(50) DEFAULT 'pending',
     611        request_date TIMESTAMP NOT NULL,
     612        processed_date TIMESTAMP,
     613        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
     614      )`,
    615615
    616616            // Report table (VARCHAR ID)
    617617            `CREATE TABLE IF NOT EXISTS report (
    618                                                    id VARCHAR(50) PRIMARY KEY,
    619                 store_id VARCHAR(10) REFERENCES store(store_id) ON DELETE CASCADE,
    620                 period VARCHAR(50) NOT NULL,
    621                 start_date DATE NOT NULL,
    622                 end_date DATE NOT NULL,
    623                 type VARCHAR(50) NOT NULL,
    624                 generated_by VARCHAR(10) REFERENCES personal(id) ON DELETE SET NULL,
    625                 generated_at TIMESTAMP NOT NULL,
    626                 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    627                 )`,
     618        id VARCHAR(50) PRIMARY KEY,
     619        store_id VARCHAR(10) REFERENCES store(store_id) ON DELETE CASCADE,
     620        period VARCHAR(50) NOT NULL,
     621        start_date DATE NOT NULL,
     622        end_date DATE NOT NULL,
     623        type VARCHAR(50) NOT NULL,
     624        generated_by VARCHAR(10) REFERENCES personal(id) ON DELETE SET NULL,
     625        generated_at TIMESTAMP NOT NULL,
     626        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
     627      )`,
    628628
    629629            // Audit_log table (SERIAL ID)
    630630            `CREATE TABLE IF NOT EXISTS audit_log (
    631                                                       log_id SERIAL PRIMARY KEY,
    632                                                       user_id VARCHAR(50),
    633                 action VARCHAR(100) NOT NULL,
    634                 resource_type VARCHAR(50),
    635                 resource_id VARCHAR(50),
    636                 details TEXT,
    637                 ip_address VARCHAR(45),
    638                 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    639                 )`,
     631        log_id INTEGER PRIMARY KEY AUTOINCREMENT,
     632        user_id VARCHAR(50),
     633        action VARCHAR(100) NOT NULL,
     634        resource_type VARCHAR(50),
     635        resource_id VARCHAR(50),
     636        details TEXT,
     637        ip_address VARCHAR(45),
     638        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
     639      )`,
    640640
    641641            // Color table (SERIAL ID)
    642642            `CREATE TABLE IF NOT EXISTS color (
    643                                                   color_id SERIAL PRIMARY KEY,
    644                                                   name VARCHAR(50) NOT NULL,
    645                 hex_code VARCHAR(7) NOT NULL,
    646                 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    647                 )`,
     643        color_id INTEGER PRIMARY KEY AUTOINCREMENT,
     644        name VARCHAR(50) NOT NULL,
     645        hex_code VARCHAR(7) NOT NULL,
     646        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
     647      )`,
    648648
    649649            // Image table (SERIAL ID)
    650650            `CREATE TABLE IF NOT EXISTS image (
    651                                                   image_id SERIAL PRIMARY KEY,
    652                                                   product_code VARCHAR(20) REFERENCES product(code) ON DELETE CASCADE,
    653                 image_url TEXT NOT NULL,
    654                 is_primary BOOLEAN DEFAULT FALSE,
    655                 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    656                 )`,
     651        image_id INTEGER PRIMARY KEY AUTOINCREMENT,
     652        product_code VARCHAR(20) REFERENCES product(code) ON DELETE CASCADE,
     653        image_url TEXT NOT NULL,
     654        is_primary BOOLEAN DEFAULT FALSE,
     655        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
     656      )`,
    657657
    658658            // Delivery_address table (SERIAL ID)
    659659            `CREATE TABLE IF NOT EXISTS delivery_address (
    660                                                              address_id SERIAL PRIMARY KEY,
    661                                                              client_id INTEGER REFERENCES client(client_id) ON DELETE CASCADE,
    662                 address TEXT NOT NULL,
    663                 city VARCHAR(100) NOT NULL,
    664                 postcode VARCHAR(20) NOT NULL,
    665                 country VARCHAR(100) NOT NULL,
    666                 is_default BOOLEAN DEFAULT FALSE,
    667                 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    668                 )`,
     660        address_id INTEGER PRIMARY KEY AUTOINCREMENT,
     661        client_id INTEGER REFERENCES client(client_id) ON DELETE CASCADE,
     662        address TEXT NOT NULL,
     663        city VARCHAR(100) NOT NULL,
     664        postcode VARCHAR(20) NOT NULL,
     665        country VARCHAR(100) NOT NULL,
     666        is_default BOOLEAN DEFAULT FALSE,
     667        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
     668      )`,
    669669
    670670            // Roles table (SERIAL ID)
    671671            `CREATE TABLE IF NOT EXISTS roles (
    672                                                   role_id SERIAL PRIMARY KEY,
    673                                                   name VARCHAR(50) UNIQUE NOT NULL,
    674                 description TEXT,
    675                 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    676                 )`,
     672        role_id INTEGER PRIMARY KEY AUTOINCREMENT,
     673        name VARCHAR(50) UNIQUE NOT NULL,
     674        description TEXT,
     675        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
     676      )`,
    677677
    678678            // User_roles table (junction)
    679679            `CREATE TABLE IF NOT EXISTS user_roles (
    680                                                        user_id VARCHAR(50) REFERENCES users(id) ON DELETE CASCADE,
    681                 role_id INTEGER REFERENCES roles(role_id) ON DELETE CASCADE,
    682                 PRIMARY KEY (user_id, role_id)
    683                 )`
     680        user_id VARCHAR(50) REFERENCES users(id) ON DELETE CASCADE,
     681        role_id INTEGER REFERENCES roles(role_id) ON DELETE CASCADE,
     682        PRIMARY KEY (user_id, role_id)
     683      )`
    684684        ];
    685685
    … …  
    766766        console.log('📝 Inserting initial data...');
    767767
    768         // Insert General category (ID will be 1 due to SERIAL)
    769         database.database.run(
    770             `INSERT INTO category (name, description)
    771              VALUES ('General', 'General products category')
    772                  ON CONFLICT DO NOTHING`,
    773             [],
    774             (err) => {
    775                 if (err) {
    776                     console.error('Error inserting General category:', err.message);
    777                 }
    778             }
    779         );
     768        // REMOVED: Category insertion - now handled by database.ensureGeneralCategory()
    780769
    781770        // Insert admin user
    … …  
    785774        database.database.run(
    786775            `INSERT INTO users (id, username, email, password, user_type, force_password_change)
    787              VALUES ($1, $2, $3, $4, $5, $6)
    788                  ON CONFLICT DO NOTHING`,
     776       VALUES ($1, $2, $3, $4, $5, $6)
     777       ON CONFLICT DO NOTHING`,
    789778            [adminId, 'admin', 'admin@handcraft.com', adminPassword, 'admin', 1],
    790779            (err) => {
    … …  
    811800            database.database.run(
    812801                `INSERT INTO roles (name, description)
    813                  VALUES ($1, $2)
    814                      ON CONFLICT DO NOTHING`,
     802         VALUES ($1, $2)
     803         ON CONFLICT DO NOTHING`,
    815804                [role.name, role.description],
    816805                (err) => {
    … …  
    822811                        console.log('✅ Roles inserted');
    823812
    824                         // Check if General category exists
     813                        // Ensure General category exists
    825814                        database.ensureGeneralCategory((err) => {
    826815                            if (err) {
    827816                                console.error('Error ensuring General category:', err.message);
    828817                            } else {
    829                                 console.log('✅ General category exists');
     818                                console.log('✅ General category checked/created');
    830819                            }
    831820                            resolve();
    … …  
    925914            body += chunk.toString();
    926915        });
     916
    927917        req.on('end', () => {
    928918            const { username, email, password, userType, firstName, lastName } = JSON.parse(body);
    … …  
    989979                            console.log('✅ Verification email sent to:', email);
    990980                            database.logAudit(null, 'REGISTER_ATTEMPT', 'user', null, `Registration attempt for ${email} as ${userType}`, ipAddress);
     981
    991982                            res.writeHead(200, { 'Content-Type': 'application/json' });
    992983                            res.end(JSON.stringify({
    … …  
    10161007            body += chunk.toString();
    10171008        });
     1009
    10181010        req.on('end', () => {
    10191011            const formData = JSON.parse(body);
    … …  
    11821174                                        console.log('✅ Store registration email sent to:', formData.ownerEmail);
    11831175                                        database.logAudit(null, 'STORE_REGISTER_ATTEMPT', 'store', null, `Store registration attempt: ${formData.storeName}`, ipAddress);
     1176
    11841177                                        res.writeHead(200, { 'Content-Type': 'application/json' });
    11851178                                        res.end(JSON.stringify({
    … …  
    12141207            body += chunk.toString();
    12151208        });
     1209
    12161210        req.on('end', () => {
    12171211            const { firstName, lastName, email, password, address, city, postcode, country, isDefaultAddress } = JSON.parse(body);
    … …  
    12781272                        console.log('✅ Verification email sent to:', email);
    12791273                        database.logAudit(null, 'CLIENT_REGISTER_ATTEMPT', 'client', null, `Client registration attempt for ${email}`, ipAddress);
     1274
    12801275                        res.writeHead(200, { 'Content-Type': 'application/json' });
    12811276                        res.end(JSON.stringify({
    … …  
    13041299            body += chunk.toString();
    13051300        });
     1301
    13061302        req.on('end', () => {
    13071303            const { email } = JSON.parse(body);
    … …  
    14381434            body += chunk.toString();
    14391435        });
     1436
    14401437        req.on('end', () => {
    14411438            const { email, code } = JSON.parse(body);
    … …  
    16681665            } else {
    16691666                const userId = 'user_' + Date.now().toString().slice(-8);
     1667
    16701668                database.createUser(userId, tempUserData.username, tempUserData.email, tempUserData.password, tempUserData.userType, (err, userId) => {
    16711669                    if (err) {
    … …  
    16981696            body += chunk.toString();
    16991697        });
     1698
    17001699        req.on('end', () => {
    17011700            const { email, password } = JSON.parse(body);
     1701
    17021702            console.log(`🔍 Login attempt for email: ${email}`);
    17031703
    … …  
    17101710                if (client) {
    17111711                    console.log(`🔍 Found client: ${client.email}`);
     1712
    17121713                    if (!client.password) {
    17131714                        console.log('❌ Client has no password set');
    … …  
    17321733                        const sessionId = generateSessionId();
    17331734                        const clientId = client.client_ID;
     1735
    17341736                        sessions.set(sessionId, `client_${clientId}`);
    17351737
    17361738                        console.log(`✅ Client login successful. Session: ${sessionId}, User: client_${clientId}`);
     1739
    17371740                        database.logAudit(clientId, 'LOGIN_SUCCESS', 'auth',
    17381741                            typeof clientId === 'string' ? clientId : String(clientId),
    … …  
    17431746                            'Set-Cookie': `sessionId=${sessionId}; HttpOnly; Path=/; Max-Age=3600; SameSite=Strict`
    17441747                        });
    1745 
    17461748                        res.end(JSON.stringify({
    17471749                            success: true,
    … …  
    17681770                    if (personal) {
    17691771                        console.log(`🔍 Found personal user: ${personal.email}`);
     1772
    17701773                        if (!personal.password) {
    17711774                            console.log('❌ Personal has no password set');
    … …  
    18031806
    18041807                                                const twoFACode = generateVerificationCode();
     1808
    18051809                                                verificationCodes.set(personal.email, {
    18061810                                                    code: twoFACode,
    … …  
    18621866
    18631867                                                        const twoFACode = generateVerificationCode();
     1868
    18641869                                                        verificationCodes.set(personal.email, {
    18651870                                                            code: twoFACode,
    … …  
    19231928
    19241929                                                                const twoFACode = generateVerificationCode();
     1930
    19251931                                                                verificationCodes.set(userByUsername.email, {
    19261932                                                                    code: twoFACode,
    … …  
    19731979
    19741980                                                        const twoFACode = generateVerificationCode();
     1981
    19751982                                                        verificationCodes.set(user.email, {
    19761983                                                            code: twoFACode,
    … …  
    20382045            body += chunk.toString();
    20392046        });
     2047
    20402048        req.on('end', () => {
    20412049            const { email } = JSON.parse(body);
    … …  
    20602068
    20612069                            const newTwoFACode = generateVerificationCode();
     2070
    20622071                            verificationCodes.set(userByUsername.email, {
    20632072                                code: newTwoFACode,
    … …  
    20952104
    20962105                    const newTwoFACode = generateVerificationCode();
     2106
    20972107                    verificationCodes.set(user.email, {
    20982108                        code: newTwoFACode,
    … …  
    21352145            body += chunk.toString();
    21362146        });
     2147
    21372148        req.on('end', () => {
    21382149            const { email, code } = JSON.parse(body);
    … …  
    21732184                    'Set-Cookie': `sessionId=${tempSessionId}; HttpOnly; Path=/; Max-Age=3600; SameSite=Strict`
    21742185                });
    2175 
    21762186                res.end(JSON.stringify({
    21772187                    success: true,
    … …  
    22032213            // Determine redirect based on user type
    22042214            let redirectTo = '';
     2215
    22052216            switch(verificationData.userType) {
    22062217                case 'client':
    … …  
    22262237                'Set-Cookie': `sessionId=${sessionId}; HttpOnly; Path=/; Max-Age=3600; SameSite=Strict`
    22272238            });
    2228 
    22292239            res.end(JSON.stringify({
    22302240                success: true,
    … …  
    22792289            if (userIdStr.startsWith('client_')) {
    22802290                const clientId = parseInt(userIdStr.replace('client_', ''));
     2291
    22812292                database.getClientById(clientId, (err, client) => {
    22822293                    if (err || !client) {
    … …  
    22982309                });
    22992310            }
     2311
    23002312            else if (userIdStr.startsWith('personal_')) {
    23012313                const personalId = userIdStr.replace('personal_', '');
     2314
    23022315                database.getPersonalById(personalId, (err, personal) => {
    23032316                    if (err || !personal) {
    … …  
    23182331                                database.database.all(
    23192332                                    `SELECT s.* FROM store s
    2320                                                          JOIN works_in_store w ON s.store_id = w.store_id
    2321                                      WHERE w.personal_id = $1`,
     2333                   JOIN works_in_store w ON s.store_id = w.store_id
     2334                   WHERE w.personal_id = $1`,
    23222335                                    [personalId],
    23232336                                    (err, stores) => {
    … …  
    23532366                                            database.database.all(
    23542367                                                `SELECT s.* FROM store s
    2355                                                                      JOIN works_in_store w ON s.store_id = w.store_id
    2356                                                  WHERE w.personal_id = $1`,
     2368                         JOIN works_in_store w ON s.store_id = w.store_id
     2369                         WHERE w.personal_id = $1`,
    23572370                                                [personalId],
    23582371                                                (err, stores) => {
    … …  
    24452458                body += chunk.toString();
    24462459            });
     2460
    24472461            req.on('end', () => {
    24482462                const categoryData = JSON.parse(body);
    … …  
    24702484                    } else {
    24712485                        database.logAudit(personalId, 'CATEGORY_CREATED', 'category', category.id.toString(), `New category created: ${category.name}`, ipAddress);
     2486
    24722487                        res.writeHead(200, { 'Content-Type': 'application/json' });
    24732488                        res.end(JSON.stringify({
    … …  
    25262541                body += chunk.toString();
    25272542            });
     2543
    25282544            req.on('end', () => {
    25292545                const orderData = JSON.parse(body);
    2530 
    25312546                const userIdStr = String(userId);
    25322547
    … …  
    26012616            if (userIdStr.startsWith('client_')) {
    26022617                const clientId = parseInt(userIdStr.replace('client_', ''));
     2618
    26032619                database.getOrdersByClient(clientId, (err, orders) => {
    26042620                    if (err) {
    … …  
    26232639                body += chunk.toString();
    26242640            });
     2641
    26252642            req.on('end', () => {
    26262643                const reviewData = JSON.parse(body);
    2627 
    26282644                const userIdStr = String(userId);
    26292645
    26302646                if (userIdStr.startsWith('client_')) {
    26312647                    const clientId = parseInt(userIdStr.replace('client_', ''));
     2648
    26322649                    reviewData.client_id = clientId;
    26332650
    … …  
    26562673                body += chunk.toString();
    26572674            });
     2675
    26582676            req.on('end', () => {
    26592677                const requestData = JSON.parse(body);
    2660 
    26612678                const userIdStr = String(userId);
    26622679
    … …  
    27262743                body += chunk.toString();
    27272744            });
     2745
    27282746            req.on('end', () => {
    27292747                const refundData = JSON.parse(body);
    2730 
    27312748                const userIdStr = String(userId);
    27322749
    … …  
    27452762
    27462763                            const storeId = result[0].store_id;
    2747 
    27482764                            const now = new Date();
    27492765                            const month = (now.getMonth() + 1).toString().padStart(2, '0');
    … …  
    27972813                body += chunk.toString();
    27982814            });
     2815
    27992816            req.on('end', () => {
    28002817                const productData = JSON.parse(body);
    … …  
    28282845                                }
    28292846
     2847                                // FIXED: Changed SQL syntax from SUBSTRING(code FROM 4) to SUBSTR(code, 4) for SQLite compatibility
    28302848                                database.database.get(
    2831                                     'SELECT MAX(CAST(SUBSTRING(code FROM 4) AS INTEGER)) as max_product_num FROM product WHERE store_id = $1',
     2849                                    'SELECT MAX(CAST(SUBSTR(code, 4) AS INTEGER)) as max_product_num FROM product WHERE store_id = $1',
    28322850                                    [storeId],
    28332851                                    (err, result) => {
    … …  
    28632881                                            } else {
    28642882                                                database.logAudit(personalId, 'PRODUCT_ADDED', 'product', productId.toString(), 'New product added', ipAddress);
     2883
    28652884                                                res.writeHead(200, { 'Content-Type': 'application/json' });
    28662885                                                res.end(JSON.stringify({
    … …  
    28882907                body += chunk.toString();
    28892908            });
     2909
    28902910            req.on('end', () => {
    28912911                const productData = JSON.parse(body);
    … …  
    29963016            body += chunk.toString();
    29973017        });
     3018
    29983019        req.on('end', () => {
    29993020            const { currentPassword, newPassword, confirmPassword } = JSON.parse(body);
    … …  
    30893110                        body += chunk.toString();
    30903111                    });
     3112
    30913113                    req.on('end', () => {
    30923114                        const { firstName, lastName, ssn, email, password, storeId, dateOfHire } = JSON.parse(body);
    … …  
    33003322                        body += chunk.toString();
    33013323                    });
     3324
    33023325                    req.on('end', () => {
    33033326                        const { employeeId, storeId } = JSON.parse(body);
    … …  
    34513474                        body += chunk.toString();
    34523475                    });
     3476
    34533477                    req.on('end', () => {
    34543478                        const { employeeId, storeId, status } = JSON.parse(body);
    … …  
    35503574                        body += chunk.toString();
    35513575                    });
     3576
    35523577                    req.on('end', () => {
    35533578                        const { employeeId, storeId, firstName, lastName, email } = JSON.parse(body);
    … …  
    39663991                body += chunk.toString();
    39673992            });
     3993
    39683994            req.on('end', () => {
    39693995                const { productCode, storeId } = JSON.parse(body);
    … …  
    40354061                body += chunk.toString();
    40364062            });
     4063
    40374064            req.on('end', () => {
    40384065                const { storeId, period, startDate, endDate, type } = JSON.parse(body);
Note: See TracChangeset for help on using the changeset viewer.