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.');
|
console.log('Connected to products database.');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Create tables
|
function runInitAsync(sql, params = []) {
|
||||||
db.serialize(() => {
|
return new Promise((resolve, reject) => {
|
||||||
// Batches table
|
db.run(sql, params, (err) => {
|
||||||
db.run(`CREATE TABLE IF NOT EXISTS batches (
|
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,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
batch_name TEXT NOT NULL UNIQUE,
|
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)
|
// Migration for existing databases: add status column if missing
|
||||||
db.run(`CREATE TABLE IF NOT EXISTS items (
|
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,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
batch_id INTEGER NOT NULL,
|
batch_id INTEGER NOT NULL,
|
||||||
brand TEXT,
|
brand TEXT,
|
||||||
|
|
@ -45,8 +69,7 @@ db.serialize(() => {
|
||||||
FOREIGN KEY (batch_id) REFERENCES batches(id) ON DELETE CASCADE
|
FOREIGN KEY (batch_id) REFERENCES batches(id) ON DELETE CASCADE
|
||||||
)`);
|
)`);
|
||||||
|
|
||||||
// Items_mix table (for mixed MPN items)
|
await runInitAsync(`CREATE TABLE IF NOT EXISTS items_mix (
|
||||||
db.run(`CREATE TABLE IF NOT EXISTS items_mix (
|
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
batch_id INTEGER NOT NULL,
|
batch_id INTEGER NOT NULL,
|
||||||
brand TEXT,
|
brand TEXT,
|
||||||
|
|
@ -58,13 +81,14 @@ db.serialize(() => {
|
||||||
)`);
|
)`);
|
||||||
|
|
||||||
// Create indexes for better performance
|
// Create indexes for better performance
|
||||||
db.run(`CREATE INDEX IF NOT EXISTS idx_items_batch_id ON items(batch_id)`);
|
await runInitAsync(`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)`);
|
await runInitAsync(`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)`);
|
await runInitAsync(`CREATE INDEX IF NOT EXISTS idx_batches_status ON batches(status)`);
|
||||||
db.run(`CREATE INDEX IF NOT EXISTS idx_items_sn ON items(sn)`);
|
await runInitAsync(`CREATE INDEX IF NOT EXISTS idx_items_mpn ON items(mpn)`);
|
||||||
db.run(`CREATE INDEX IF NOT EXISTS idx_items_brand ON items(brand)`);
|
await runInitAsync(`CREATE INDEX IF NOT EXISTS idx_items_sn ON items(sn)`);
|
||||||
db.run(`CREATE INDEX IF NOT EXISTS idx_items_mix_brand ON items_mix(brand)`);
|
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 ====================
|
// ==================== BATCH API ROUTES ====================
|
||||||
|
|
||||||
|
|
@ -220,43 +244,44 @@ app.get('/api/batch/get-all', (req, res) => {
|
||||||
const column = validColumns.includes(sortBy) ? sortBy : 'id';
|
const column = validColumns.includes(sortBy) ? sortBy : 'id';
|
||||||
const order = sortOrder.toUpperCase() === 'ASC' ? 'ASC' : 'DESC';
|
const order = sortOrder.toUpperCase() === 'ASC' ? 'ASC' : 'DESC';
|
||||||
|
|
||||||
let query = 'SELECT * FROM batches';
|
const whereConditions = ['status = 0'];
|
||||||
let countQuery = 'SELECT COUNT(*) as total FROM batches';
|
let searchParams = [];
|
||||||
let params = [];
|
|
||||||
|
|
||||||
if (search) {
|
if (search) {
|
||||||
const searchCondition = `
|
const searchCondition = `
|
||||||
WHERE
|
(
|
||||||
batch_name LIKE ?
|
batch_name LIKE ?
|
||||||
OR id LIKE ?
|
OR id LIKE ?
|
||||||
OR EXISTS (
|
OR EXISTS (
|
||||||
SELECT 1 FROM items
|
SELECT 1 FROM items
|
||||||
WHERE items.batch_id = batches.id
|
WHERE items.batch_id = batches.id
|
||||||
AND sn LIKE ?
|
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
|
whereConditions.push(searchCondition);
|
||||||
WHERE items_mix.batch_id = batches.id
|
|
||||||
AND sn LIKE ?
|
|
||||||
)
|
|
||||||
`;
|
|
||||||
|
|
||||||
query += searchCondition;
|
const searchParam = `%${search}%`;
|
||||||
countQuery += searchCondition;
|
searchParams = [searchParam, searchParam, searchParam, searchParam];
|
||||||
|
}
|
||||||
|
|
||||||
const searchParam = `%${search}%`;
|
const whereClause = ` WHERE ${whereConditions.join(' AND ')}`;
|
||||||
params = [searchParam, searchParam, searchParam, searchParam];
|
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 ?`;
|
db.get(countQuery, countParams, (err, countRow) => {
|
||||||
params.push(limit, offset);
|
|
||||||
|
|
||||||
db.get(countQuery, search ? params.slice(0, 2) : [], (err, countRow) => {
|
|
||||||
if (err) {
|
if (err) {
|
||||||
return res.status(500).json({ error: err.message });
|
return res.status(500).json({ error: err.message });
|
||||||
}
|
}
|
||||||
|
|
||||||
db.all(query, params, (err, batches) => {
|
db.all(query, queryParams, (err, batches) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
return res.status(500).json({ error: err.message });
|
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) => {
|
app.get('/api/batch/get/:id', (req, res) => {
|
||||||
const id = req.params.id;
|
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) {
|
if (err) {
|
||||||
return res.status(500).json({ error: err.message });
|
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) => {
|
app.delete('/api/batch/delete/:id', (req, res) => {
|
||||||
const id = req.params.id;
|
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) {
|
if (err) {
|
||||||
return res.status(500).json({ error: err.message });
|
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' });
|
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;
|
const PORT = process.env.PORT || 4444;
|
||||||
app.listen(PORT, () => {
|
initializeDatabase()
|
||||||
console.log(`Server is running on http://localhost:${PORT}`);
|
.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