Hiệu chỉnh xóa batch mềm
This commit is contained in:
parent
def35fceff
commit
d7bf701d0e
132
server.js
132
server.js
|
|
@ -24,17 +24,41 @@ const db = new sqlite3.Database('./products.db', (err) => {
|
|||
console.log('Connected to products database.');
|
||||
});
|
||||
|
||||
// Create tables
|
||||
db.serialize(() => {
|
||||
// Batches table
|
||||
db.run(`CREATE TABLE IF NOT EXISTS batches (
|
||||
function runInitAsync(sql, params = []) {
|
||||
return new Promise((resolve, reject) => {
|
||||
db.run(sql, params, (err) => {
|
||||
if (err) reject(err);
|
||||
else resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function allInitAsync(sql, params = []) {
|
||||
return new Promise((resolve, reject) => {
|
||||
db.all(sql, params, (err, rows) => {
|
||||
if (err) reject(err);
|
||||
else resolve(rows);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function initializeDatabase() {
|
||||
await runInitAsync(`CREATE TABLE IF NOT EXISTS batches (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
batch_name TEXT NOT NULL UNIQUE,
|
||||
createdAt DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
createdAt DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
status INTEGER NOT NULL DEFAULT 0
|
||||
)`);
|
||||
|
||||
// Items table (for valid items)
|
||||
db.run(`CREATE TABLE IF NOT EXISTS items (
|
||||
// Migration for existing databases: add status column if missing
|
||||
const columns = await allInitAsync(`PRAGMA table_info(batches)`);
|
||||
const hasStatusColumn = columns.some((col) => col.name === 'status');
|
||||
if (!hasStatusColumn) {
|
||||
await runInitAsync(`ALTER TABLE batches ADD COLUMN status INTEGER NOT NULL DEFAULT 0`);
|
||||
console.log('Added status column to batches table.');
|
||||
}
|
||||
|
||||
await runInitAsync(`CREATE TABLE IF NOT EXISTS items (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
batch_id INTEGER NOT NULL,
|
||||
brand TEXT,
|
||||
|
|
@ -45,8 +69,7 @@ db.serialize(() => {
|
|||
FOREIGN KEY (batch_id) REFERENCES batches(id) ON DELETE CASCADE
|
||||
)`);
|
||||
|
||||
// Items_mix table (for mixed MPN items)
|
||||
db.run(`CREATE TABLE IF NOT EXISTS items_mix (
|
||||
await runInitAsync(`CREATE TABLE IF NOT EXISTS items_mix (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
batch_id INTEGER NOT NULL,
|
||||
brand TEXT,
|
||||
|
|
@ -58,13 +81,14 @@ db.serialize(() => {
|
|||
)`);
|
||||
|
||||
// Create indexes for better performance
|
||||
db.run(`CREATE INDEX IF NOT EXISTS idx_items_batch_id ON items(batch_id)`);
|
||||
db.run(`CREATE INDEX IF NOT EXISTS idx_items_mix_batch_id ON items_mix(batch_id)`);
|
||||
db.run(`CREATE INDEX IF NOT EXISTS idx_items_mpn ON items(mpn)`);
|
||||
db.run(`CREATE INDEX IF NOT EXISTS idx_items_sn ON items(sn)`);
|
||||
db.run(`CREATE INDEX IF NOT EXISTS idx_items_brand ON items(brand)`);
|
||||
db.run(`CREATE INDEX IF NOT EXISTS idx_items_mix_brand ON items_mix(brand)`);
|
||||
});
|
||||
await runInitAsync(`CREATE INDEX IF NOT EXISTS idx_items_batch_id ON items(batch_id)`);
|
||||
await runInitAsync(`CREATE INDEX IF NOT EXISTS idx_items_mix_batch_id ON items_mix(batch_id)`);
|
||||
await runInitAsync(`CREATE INDEX IF NOT EXISTS idx_batches_status ON batches(status)`);
|
||||
await runInitAsync(`CREATE INDEX IF NOT EXISTS idx_items_mpn ON items(mpn)`);
|
||||
await runInitAsync(`CREATE INDEX IF NOT EXISTS idx_items_sn ON items(sn)`);
|
||||
await runInitAsync(`CREATE INDEX IF NOT EXISTS idx_items_brand ON items(brand)`);
|
||||
await runInitAsync(`CREATE INDEX IF NOT EXISTS idx_items_mix_brand ON items_mix(brand)`);
|
||||
}
|
||||
|
||||
// ==================== BATCH API ROUTES ====================
|
||||
|
||||
|
|
@ -220,43 +244,44 @@ app.get('/api/batch/get-all', (req, res) => {
|
|||
const column = validColumns.includes(sortBy) ? sortBy : 'id';
|
||||
const order = sortOrder.toUpperCase() === 'ASC' ? 'ASC' : 'DESC';
|
||||
|
||||
let query = 'SELECT * FROM batches';
|
||||
let countQuery = 'SELECT COUNT(*) as total FROM batches';
|
||||
let params = [];
|
||||
const whereConditions = ['status = 0'];
|
||||
let searchParams = [];
|
||||
|
||||
if (search) {
|
||||
const searchCondition = `
|
||||
WHERE
|
||||
batch_name LIKE ?
|
||||
OR id LIKE ?
|
||||
OR EXISTS (
|
||||
SELECT 1 FROM items
|
||||
WHERE items.batch_id = batches.id
|
||||
AND sn LIKE ?
|
||||
const searchCondition = `
|
||||
(
|
||||
batch_name LIKE ?
|
||||
OR id LIKE ?
|
||||
OR EXISTS (
|
||||
SELECT 1 FROM items
|
||||
WHERE items.batch_id = batches.id
|
||||
AND sn LIKE ?
|
||||
)
|
||||
OR EXISTS (
|
||||
SELECT 1 FROM items_mix
|
||||
WHERE items_mix.batch_id = batches.id
|
||||
AND sn LIKE ?
|
||||
)
|
||||
)
|
||||
OR EXISTS (
|
||||
SELECT 1 FROM items_mix
|
||||
WHERE items_mix.batch_id = batches.id
|
||||
AND sn LIKE ?
|
||||
)
|
||||
`;
|
||||
`;
|
||||
whereConditions.push(searchCondition);
|
||||
|
||||
query += searchCondition;
|
||||
countQuery += searchCondition;
|
||||
const searchParam = `%${search}%`;
|
||||
searchParams = [searchParam, searchParam, searchParam, searchParam];
|
||||
}
|
||||
|
||||
const searchParam = `%${search}%`;
|
||||
params = [searchParam, searchParam, searchParam, searchParam];
|
||||
}
|
||||
const whereClause = ` WHERE ${whereConditions.join(' AND ')}`;
|
||||
const countQuery = `SELECT COUNT(*) as total FROM batches${whereClause}`;
|
||||
const query = `SELECT * FROM batches${whereClause} ORDER BY ${column} ${order} LIMIT ? OFFSET ?`;
|
||||
const countParams = [...searchParams];
|
||||
const queryParams = [...searchParams, limit, offset];
|
||||
|
||||
query += ` ORDER BY ${column} ${order} LIMIT ? OFFSET ?`;
|
||||
params.push(limit, offset);
|
||||
|
||||
db.get(countQuery, search ? params.slice(0, 2) : [], (err, countRow) => {
|
||||
db.get(countQuery, countParams, (err, countRow) => {
|
||||
if (err) {
|
||||
return res.status(500).json({ error: err.message });
|
||||
}
|
||||
|
||||
db.all(query, params, (err, batches) => {
|
||||
db.all(query, queryParams, (err, batches) => {
|
||||
if (err) {
|
||||
return res.status(500).json({ error: err.message });
|
||||
}
|
||||
|
|
@ -320,7 +345,7 @@ app.get('/api/batch/get-all', (req, res) => {
|
|||
app.get('/api/batch/get/:id', (req, res) => {
|
||||
const id = req.params.id;
|
||||
|
||||
db.get('SELECT * FROM batches WHERE id = ?', [id], (err, batch) => {
|
||||
db.get('SELECT * FROM batches WHERE id = ? AND status = 0', [id], (err, batch) => {
|
||||
if (err) {
|
||||
return res.status(500).json({ error: err.message });
|
||||
}
|
||||
|
|
@ -353,11 +378,11 @@ app.get('/api/batch/get/:id', (req, res) => {
|
|||
});
|
||||
});
|
||||
|
||||
// Delete batch (cascade delete items and items_mix)
|
||||
// Soft delete batch (update status from 0 to 1)
|
||||
app.delete('/api/batch/delete/:id', (req, res) => {
|
||||
const id = req.params.id;
|
||||
|
||||
db.run('DELETE FROM batches WHERE id = ?', id, function (err) {
|
||||
db.run('UPDATE batches SET status = 1 WHERE id = ? AND status = 0', [id], function (err) {
|
||||
if (err) {
|
||||
return res.status(500).json({ error: err.message });
|
||||
}
|
||||
|
|
@ -366,7 +391,7 @@ app.delete('/api/batch/delete/:id', (req, res) => {
|
|||
return res.status(404).json({ error: 'Batch not found' });
|
||||
}
|
||||
|
||||
res.json({ success: true, deleted: this.changes });
|
||||
res.json({ success: true, updated: this.changes, deleted: this.changes });
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -428,6 +453,13 @@ app.get('/', (req, res) => {
|
|||
});
|
||||
|
||||
const PORT = process.env.PORT || 4444;
|
||||
app.listen(PORT, () => {
|
||||
console.log(`Server is running on http://localhost:${PORT}`);
|
||||
});
|
||||
initializeDatabase()
|
||||
.then(() => {
|
||||
app.listen(PORT, () => {
|
||||
console.log(`Server is running on http://localhost:${PORT}`);
|
||||
});
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error('Database initialization failed:', err.message);
|
||||
process.exit(1);
|
||||
});
|
||||
Loading…
Reference in New Issue