geocrop-platform./apps/nextgen/server/seed_inventory.js

165 lines
8.8 KiB
JavaScript

const Database = require('better-sqlite3');
const { v4: uuidv4 } = require('uuid');
const path = require('path');
const dbPath = process.env.DB_PATH || path.join(__dirname, 'data/school.db');
console.log('Seeding database at:', dbPath);
const db = new Database(dbPath);
console.log('Seeding comprehensive inventory catalog and stock levels...');
try {
// Define and immediately execute the transaction
db.transaction(() => {
// 1. Ensure categories exist
const categories = [
{ name: 'Stationery', code: 'STAT' },
{ name: 'Cleaning Supplies', code: 'CLEN' },
{ name: 'Furniture', code: 'FURN' },
{ name: 'Electronics', code: 'ELEC' },
{ name: 'Catering & Kitchen', code: 'KITC' },
{ name: 'Sports & Grounds', code: 'SPRT' },
{ name: 'Bedding & Hostels', code: 'BEDD' }
];
for (const cat of categories) {
const existing = db.prepare('SELECT id FROM item_categories WHERE code = ?').get(cat.code);
if (!existing) {
db.prepare(`
INSERT INTO item_categories (uid, name, code, sync_status)
VALUES (?, ?, ?, 'pending')
`).run(uuidv4(), cat.name, cat.code);
console.log(`Inserted category: ${cat.name} (${cat.code})`);
} else {
console.log(`Category exists: ${cat.name} (${cat.code})`);
}
}
// 2. Ensure suppliers exist
const suppliers = [
{ name: 'Global Supplies Ltd', code: 'SUP01', contact_person: 'John Doe', email: 'john@globalsupplies.com', phone: '0772111222' },
{ name: 'Catering & Bedding Wholesale', code: 'SUP02', contact_person: 'Jane Moyo', email: 'jane@cateringbedding.co.zw', phone: '0773444555' },
{ name: 'Sports Equipment World', code: 'SUP03', contact_person: 'David Sibanda', email: 'david@sportsworld.com', phone: '0712888999' }
];
for (const sup of suppliers) {
const existing = db.prepare('SELECT id FROM suppliers WHERE code = ?').get(sup.code);
if (!existing) {
db.prepare(`
INSERT INTO suppliers (uid, name, code, contact_person, email, phone, sync_status)
VALUES (?, ?, ?, ?, ?, ?, 'pending')
`).run(uuidv4(), sup.name, sup.code, sup.contact_person, sup.email, sup.phone);
console.log(`Inserted supplier: ${sup.name} (${sup.code})`);
} else {
console.log(`Supplier exists: ${sup.name} (${sup.code})`);
}
}
// 3. Ensure store locations exist
const storeLocations = [
{ name: 'Main Warehouse', code: 'WH01', is_warehouse: 1 },
{ name: 'School Store', code: 'ST01', is_warehouse: 0 },
{ name: 'Science Lab Prep Room', code: 'SL01', is_warehouse: 0 }
];
for (const loc of storeLocations) {
const existing = db.prepare('SELECT id FROM store_locations WHERE code = ?').get(loc.code);
if (!existing) {
db.prepare(`
INSERT INTO store_locations (uid, name, code, is_warehouse, sync_status)
VALUES (?, ?, ?, ?, 'pending')
`).run(uuidv4(), loc.name, loc.code, loc.is_warehouse);
console.log(`Inserted store location: ${loc.name} (${loc.code})`);
} else {
console.log(`Store location exists: ${loc.name} (${loc.code})`);
}
}
// Get DB IDs of categories, suppliers, locations to link correctly
const getCatId = (code) => db.prepare('SELECT id FROM item_categories WHERE code = ?').get(code)?.id;
const getSupId = (code) => db.prepare('SELECT id FROM suppliers WHERE code = ?').get(code)?.id;
const getLocId = (code) => db.prepare('SELECT id FROM store_locations WHERE code = ?').get(code)?.id;
// 4. Create Items
const itemsToSeed = [
// Stationery
{ name: 'A4 Notebooks', code: 'STAT-01', barcode: '8901234567890', description: 'Ruled A4 120 pages notebook', catCode: 'STAT', unit: 'pcs', purchase_price: 1.5, reorder_level: 50, supCode: 'SUP01' },
{ name: 'Whiteboard Markers', code: 'STAT-02', barcode: '8901234567891', description: 'Black dry erase whiteboard markers', catCode: 'STAT', unit: 'box', purchase_price: 6.0, reorder_level: 10, supCode: 'SUP01' },
{ name: 'Form 3 Mathematics Textbooks', code: 'STAT-03', barcode: '8901234567892', description: 'NextGen High School Maths textbook', catCode: 'STAT', unit: 'pcs', purchase_price: 12.0, reorder_level: 15, supCode: 'SUP01' },
// Hostel/Bedding
{ name: 'Single Bed Mattress', code: 'BEDD-01', barcode: '8901234567893', description: 'Standard high-density foam single mattress', catCode: 'BEDD', unit: 'pcs', purchase_price: 45.0, reorder_level: 5, supCode: 'SUP02' },
{ name: 'Cotton Pillow', code: 'BEDD-02', barcode: '8901234567894', description: 'Hypoallergenic soft cotton sleeping pillow', catCode: 'BEDD', unit: 'pcs', purchase_price: 8.0, reorder_level: 10, supCode: 'SUP02' },
{ name: 'Woolen Blanket', code: 'BEDD-03', barcode: '8901234567895', description: 'Warm heavy-duty blue woolen blanket', catCode: 'BEDD', unit: 'pcs', purchase_price: 18.0, reorder_level: 8, supCode: 'SUP02' },
// Catering/Kitchen
{ name: 'Industrial Boiling Pot (50L)', code: 'KITC-01', barcode: '8901234567896', description: 'Stainless steel giant pots for bulk cooking', catCode: 'KITC', unit: 'pcs', purchase_price: 120.0, reorder_level: 2, supCode: 'SUP02' },
{ name: 'Serving Plates', code: 'KITC-02', barcode: '8901234567897', description: 'Durable melamine school lunch plates', catCode: 'KITC', unit: 'pcs', purchase_price: 2.2, reorder_level: 100, supCode: 'SUP02' },
{ name: 'Catering Chef Knife', code: 'KITC-03', barcode: '8901234567898', description: 'Professional 10-inch kitchen slicing knife', catCode: 'KITC', unit: 'pcs', purchase_price: 15.0, reorder_level: 4, supCode: 'SUP02' },
// Sports/Grounds
{ name: 'Grass Trimmer Mower', code: 'SPRT-01', barcode: '8901234567899', description: 'Petrol powered outdoor grass trimmer', catCode: 'SPRT', unit: 'pcs', purchase_price: 180.0, reorder_level: 1, supCode: 'SUP03' },
{ name: 'Heavy Duty Wheelbarrow', code: 'SPRT-02', barcode: '8901234567900', description: 'Steel gardening wheelbarrow for soil/trash', catCode: 'SPRT', unit: 'pcs', purchase_price: 35.0, reorder_level: 2, supCode: 'SUP03' },
{ name: 'Leather Soccer Matchball', code: 'SPRT-03', barcode: '8901234567901', description: 'Size 5 hand-stitched professional matchball', catCode: 'SPRT', unit: 'pcs', purchase_price: 25.0, reorder_level: 5, supCode: 'SUP03' }
];
for (const item of itemsToSeed) {
const catId = getCatId(item.catCode);
const supId = getSupId(item.supCode);
// Insert item if it doesn't exist
const existing = db.prepare('SELECT id FROM items WHERE code = ?').get(item.code);
let itemId;
if (!existing) {
const res = db.prepare(`
INSERT INTO items (uid, name, code, barcode, description, category_id, unit, purchase_price, reorder_level, supplier_id, sync_status)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'pending')
`).run(uuidv4(), item.name, item.code, item.barcode, item.description, catId, item.unit, item.purchase_price, item.reorder_level, supId || null);
itemId = res.lastInsertRowid;
console.log(`Inserted item: ${item.name} (${item.code})`);
} else {
itemId = existing.id;
console.log(`Item exists: ${item.name} (${item.code})`);
}
// 5. Populate Stock Levels for each item in School Store or Warehouse
const warehouseId = getLocId('WH01');
const storeId = getLocId('ST01');
if (warehouseId) {
const existingStock = db.prepare('SELECT id FROM item_stock WHERE item_id = ? AND store_id = ? AND is_deleted = 0').get(itemId, warehouseId);
if (existingStock) {
db.prepare(`
UPDATE item_stock SET quantity = ?, sync_status = 'pending', updated_at = CURRENT_TIMESTAMP WHERE id = ?
`).run(250, existingStock.id);
} else {
db.prepare(`
INSERT INTO item_stock (uid, item_id, store_id, quantity, sync_status)
VALUES (?, ?, ?, ?, 'pending')
`).run(uuidv4(), itemId, warehouseId, 250);
}
}
if (storeId) {
const existingStock = db.prepare('SELECT id FROM item_stock WHERE item_id = ? AND store_id = ? AND is_deleted = 0').get(itemId, storeId);
if (existingStock) {
db.prepare(`
UPDATE item_stock SET quantity = ?, sync_status = 'pending', updated_at = CURRENT_TIMESTAMP WHERE id = ?
`).run(50, existingStock.id);
} else {
db.prepare(`
INSERT INTO item_stock (uid, item_id, store_id, quantity, sync_status)
VALUES (?, ?, ?, ?, 'pending')
`).run(uuidv4(), itemId, storeId, 50);
}
}
}
})(); // Invoked the transaction!
console.log('✅ Inventory database seed completed successfully!');
} catch (e) {
console.error('❌ Seeding failed:', e.message);
} finally {
db.close();
}