import { PrismaClient, Role } from "@prisma/client"; import bcrypt from "bcryptjs"; import { ACCOUNTING_CODES } from "./accounting-codes-data"; const db = new PrismaClient(); const hash = (p: string) => bcrypt.hash(p, 12); const d = (daysAgo: number) => new Date(Date.now() - daysAgo * 86_400_000); async function main() { console.log("Seeding database…"); // ─── Users ────────────────────────────────────────────────────────────────── const admin = await db.user.upsert({ where: { email: "admin@pelagia.local" }, update: {}, create: { employeeId: "EMP-001", email: "admin@pelagia.local", name: "System Admin", passwordHash: await hash("admin1234"), role: Role.ADMIN }, }); const manager = await db.user.upsert({ where: { email: "manager@pelagia.local" }, update: {}, create: { employeeId: "EMP-002", email: "manager@pelagia.local", name: "James Hartwell", passwordHash: await hash("manager1234"), role: Role.MANAGER }, }); const manager2 = await db.user.upsert({ where: { email: "manager2@pelagia.local" }, update: {}, create: { employeeId: "EMP-011", email: "manager2@pelagia.local", name: "Lakshmi Iyer", passwordHash: await hash("manager1234"), role: Role.MANAGER }, }); const technical = await db.user.upsert({ where: { email: "tech@pelagia.local" }, update: {}, create: { employeeId: "EMP-003", email: "tech@pelagia.local", name: "Maria Santos", passwordHash: await hash("tech1234"), role: Role.TECHNICAL }, }); const tech2 = await db.user.upsert({ where: { email: "tech2@pelagia.local" }, update: {}, create: { employeeId: "EMP-006", email: "tech2@pelagia.local", name: "Arjun Sharma", passwordHash: await hash("tech1234"), role: Role.TECHNICAL }, }); const tech3 = await db.user.upsert({ where: { email: "tech3@pelagia.local" }, update: {}, create: { employeeId: "EMP-010", email: "tech3@pelagia.local", name: "David Chen", passwordHash: await hash("tech1234"), role: Role.TECHNICAL }, }); const accounts = await db.user.upsert({ where: { email: "accounts@pelagia.local" }, update: {}, create: { employeeId: "EMP-004", email: "accounts@pelagia.local", name: "Chen Wei", passwordHash: await hash("accounts1234"), role: Role.ACCOUNTS }, }); const accounts2 = await db.user.upsert({ where: { email: "accounts2@pelagia.local" }, update: {}, create: { employeeId: "EMP-012", email: "accounts2@pelagia.local", name: "Anita Bose", passwordHash: await hash("accounts1234"), role: Role.ACCOUNTS }, }); const manning = await db.user.upsert({ where: { email: "manning@pelagia.local" }, update: {}, create: { employeeId: "EMP-005", email: "manning@pelagia.local", name: "Raj Patel", passwordHash: await hash("manning1234"), role: Role.MANNING }, }); const manning2 = await db.user.upsert({ where: { email: "manning2@pelagia.local" }, update: {}, create: { employeeId: "EMP-007", email: "manning2@pelagia.local", name: "Fatima Al-Hassan", passwordHash: await hash("manning1234"), role: Role.MANNING }, }); const superuser = await db.user.upsert({ where: { email: "superuser@pelagia.local" }, update: {}, create: { employeeId: "EMP-008", email: "superuser@pelagia.local", name: "Vikram Menon", passwordHash: await hash("super1234"), role: Role.SUPERUSER }, }); await db.user.upsert({ where: { email: "auditor@pelagia.local" }, update: {}, create: { employeeId: "EMP-009", email: "auditor@pelagia.local", name: "Priya Krishnan", passwordHash: await hash("audit1234"), role: Role.AUDITOR }, }); // ─── Sites ─────────────────────────────────────────────────────────────────── const siteBOM = await db.site.upsert({ where: { code: "BOM" }, update: {}, create: { name: "Mumbai Port", code: "BOM", address: "Mumbai Port Trust, Ballard Pier, Mumbai 400001", latitude: 18.9313, longitude: 72.8349 }, }); const siteJNP = await db.site.upsert({ where: { code: "JNP" }, update: {}, create: { name: "JNPT", code: "JNP", address: "Jawaharlal Nehru Port, Nhava Sheva, Navi Mumbai 400707", latitude: 18.9458, longitude: 72.9442 }, }); const siteKDL = await db.site.upsert({ where: { code: "KDL" }, update: {}, create: { name: "Kandla Port", code: "KDL", address: "Deendayal Port, Gandhidham, Kutch, Gujarat 370210", latitude: 23.0275, longitude: 70.2168 }, }); const siteVIZ = await db.site.upsert({ where: { code: "VIZ" }, update: {}, create: { name: "Visakhapatnam Port", code: "VIZ", address: "Port Area, Visakhapatnam, Andhra Pradesh 530035", latitude: 17.6868, longitude: 83.2185 }, }); const siteCHE = await db.site.upsert({ where: { code: "CHE" }, update: {}, create: { name: "Chennai Port", code: "CHE", address: "Rajaji Salai, Royapuram, Chennai, Tamil Nadu 600001", latitude: 13.0921, longitude: 80.2974 }, }); const siteKOC = await db.site.upsert({ where: { code: "KOC" }, update: {}, create: { name: "Kochi Port", code: "KOC", address: "Willingdon Island, Kochi, Kerala 682009", latitude: 9.9614, longitude: 76.2601 }, }); const siteHAL = await db.site.upsert({ where: { code: "HAL" }, update: {}, create: { name: "Haldia Port", code: "HAL", address: "Haldia Dock Complex, Haldia, West Bengal 721607", latitude: 22.0291, longitude: 88.0795 }, }); const sitePAR = await db.site.upsert({ where: { code: "PAR" }, update: {}, create: { name: "Paradip Port", code: "PAR", address: "Paradip Port Trust, Paradip, Odisha 754142", latitude: 20.3162, longitude: 86.6102 }, }); const siteMNG = await db.site.upsert({ where: { code: "MNG" }, update: {}, create: { name: "New Mangalore Port", code: "MNG", address: "Panambur, Mangalore, Karnataka 575010", latitude: 12.9141, longitude: 74.8560 }, }); const siteGOA = await db.site.upsert({ where: { code: "GOA" }, update: {}, create: { name: "Mormugao Port", code: "GOA", address: "Headland Sada, Vasco da Gama, Goa 403802", latitude: 15.4099, longitude: 73.7997 }, }); await db.site.upsert({ where: { code: "TUT" }, update: {}, create: { name: "V.O. Chidambaranar Port", code: "TUT", address: "Port Area, Thoothukudi, Tamil Nadu 628004", latitude: 8.7714, longitude: 78.1348 }, }); await db.site.upsert({ where: { code: "COC" }, update: {}, create: { name: "Cochin Shipyard Dry Dock", code: "COC", address: "Cochin Shipyard Ltd, Perumanoor, Kochi, Kerala 682015", latitude: 9.9419, longitude: 76.2731 }, }); // ─── Vessels (Cost Centres) ────────────────────────────────────────────────── const findOrCreateVessel = async (name: string, code: string) => { const vessel = await db.vessel.findFirst({ where: { name } }); if (vessel) return vessel; return db.vessel.create({ data: { name, code } }); }; const mvStar = await findOrCreateVessel("MV Pelagia Star", "SITE-001"); const mvWind = await findOrCreateVessel("MV Aegean Wind", "SITE-002"); const mvPoseidon = await findOrCreateVessel("MV Poseidon", "SITE-003"); const mvNereid = await findOrCreateVessel("MV Nereid", "SITE-004"); const mvThetis = await findOrCreateVessel("MV Thetis", "SITE-005"); const mvTriton = await findOrCreateVessel("MV Triton", "SITE-006"); const mvAmphitrite = await findOrCreateVessel("MV Amphitrite", "SITE-007"); const mvProteus = await findOrCreateVessel("MV Proteus", "SITE-008"); const mvGalatea = await findOrCreateVessel("MV Galatea", "SITE-009"); const mvCallisto = await findOrCreateVessel("MV Callisto", "SITE-010"); await findOrCreateVessel("MV Doris", "SITE-011"); // ─── Accounting Codes (hierarchical) ───────────────────────────────────────── // Seed in two passes: first create all entries without parentId, then link parents const codeIdMap = new Map(); // Pass 1: upsert all entries without parentId to get their IDs for (const entry of ACCOUNTING_CODES) { const rec = await db.account.upsert({ where: { code: entry.code }, update: { name: entry.name }, create: { code: entry.code, name: entry.name }, }); codeIdMap.set(entry.code, rec.id); } // Pass 2: link parent relationships for (const entry of ACCOUNTING_CODES) { if (entry.parentCode) { const parentId = codeIdMap.get(entry.parentCode); if (parentId) { await db.account.update({ where: { code: entry.code }, data: { parentId }, }); } } } // Convenience variables for PO seed data below (map to real leaf codes) const accTechOps = { id: codeIdMap.get("401012")! }; // Spares- Others const accCrewMgt = { id: codeIdMap.get("500101")! }; // Salary const accFuel = { id: codeIdMap.get("700101")! }; // Diesel const accSafety = { id: codeIdMap.get("401023")! }; // Stores- Safety Equipment & PPE const accPaint = { id: codeIdMap.get("401027")! }; // Stores- Paints const accElect = { id: codeIdMap.get("401028")! }; // Stores- Electrical const accNavig = { id: codeIdMap.get("600201")! }; // Flag Survey fee const accStores = { id: codeIdMap.get("401031")! }; // Stores- Others const accDeck = { id: codeIdMap.get("401030")! }; // Stores- Tools // ─── Vendors ───────────────────────────────────────────────────────────────── const v1 = await db.vendor.upsert({ where: { vendorId: "VND-0001" }, update: {}, create: { name: "Marine Parts International", vendorId: "VND-0001", address: "Plot 12, MIDC Industrial Area, Turbhe, Navi Mumbai 400705", pincode: "400705", gstin: "27AABCM1234A1Z5", isVerified: true, latitude: 19.0144, longitude: 73.0297, contacts: { create: [ { name: "Tony Nguyen", role: "Procurement Head", mobile: "9820123456", email: "tony@marinepartsinternational.com", isPrimary: true }, { name: "Aisha Patel", role: "Sales Executive", mobile: "9820654321", email: "aisha@marinepartsinternational.com", isPrimary: false }, ], }, }, }); const v2 = await db.vendor.upsert({ where: { vendorId: "VND-0002" }, update: {}, create: { name: "Global Crew Supplies", vendorId: "VND-0002", address: "14B, Harbour Street, Mazgaon, Mumbai 400010", pincode: "400010", isVerified: true, latitude: 18.9710, longitude: 72.8431, contacts: { create: [ { name: "Sarah Kim", role: "Director", mobile: "9821234567", email: "sarah@globalcrewsupplies.com", isPrimary: true }, ], }, }, }); const v3 = await db.vendor.upsert({ where: { vendorId: "VND-0003" }, update: {}, create: { name: "Atlas Ship Chandlers", vendorId: "VND-0003", address: "Unit 7, Sassoon Dock, Colaba, Mumbai 400005", pincode: "400005", isVerified: false, latitude: 18.9056, longitude: 72.8265, contacts: { create: [ { name: "Marco Rossi", role: "Manager", mobile: "9833456789", email: "marco@atlaschandlers.com", isPrimary: true }, ], }, }, }); const v4 = await db.vendor.upsert({ where: { vendorId: "VND-0004" }, update: {}, create: { name: "Apar Industries Ltd", vendorId: "VND-0004", address: "18, TTC MIDC Industrial Area, Thane Belapur Road, Navi Mumbai 400701", pincode: "400701", gstin: "27AAACG1840M1ZL", isVerified: true, latitude: 19.0804, longitude: 73.0112, contacts: { create: [ { name: "Nikhil Mumbaikar", role: "Sales Head", mobile: "7208055636", email: "nikhil.mumbaikar@apar.com", isPrimary: true }, { name: "Pradeep Shetty", role: "Accounts", mobile: "7208055637", email: "pradeep.shetty@apar.com", isPrimary: false }, ], }, }, }); const v5 = await db.vendor.upsert({ where: { vendorId: "VND-0005" }, update: {}, create: { name: "Neptune Marine Stores", vendorId: "VND-0005", address: "B-204, Jogeshwari Industrial Estate, Mumbai 400060", pincode: "400060", gstin: "27AADCN5678B1ZK", isVerified: true, latitude: 19.1379, longitude: 72.8450, contacts: { create: [ { name: "Ravi Sharma", role: "Owner", mobile: "9821234567", email: "ravi@neptunemarine.in", isPrimary: true }, { name: "Pooja Sharma", role: "Operations", mobile: "9821234568", email: "pooja@neptunemarine.in", isPrimary: false }, ], }, }, }); const v6 = await db.vendor.upsert({ where: { vendorId: "VND-0006" }, update: {}, create: { name: "Seaview Hydraulics Pvt Ltd", vendorId: "VND-0006", address: "Plot 45, Phase II, Ambad MIDC, Nashik 422010", pincode: "422010", gstin: "27AABCS9876C1ZM", isVerified: true, latitude: 20.0113, longitude: 73.7902, contacts: { create: [ { name: "Anand Pillai", role: "Managing Director", mobile: "9867543210", email: "anand@seaviewhydraulics.com", isPrimary: true }, ], }, }, }); const v7 = await db.vendor.upsert({ where: { vendorId: "VND-0007" }, update: {}, create: { name: "Pacific Safety Equipment", vendorId: "VND-0007", address: "22, Linking Road, Bandra West, Mumbai 400050", pincode: "400050", isVerified: true, latitude: 19.0543, longitude: 72.8295, contacts: { create: [ { name: "Priya Nair", role: "Sales Manager", mobile: "9821098765", email: "priya@pacificsafety.com", isPrimary: true }, { name: "Sunil D'Cruz", role: "Technical Support", mobile: "9821098766", email: "sunil@pacificsafety.com", isPrimary: false }, ], }, }, }); const v8 = await db.vendor.upsert({ where: { vendorId: "VND-0008" }, update: {}, create: { name: "Mumbai Ship Stores", vendorId: "VND-0008", address: "78, Ballard Estate, Fort, Mumbai 400001", pincode: "400001", gstin: "27AAACM4567D1ZJ", isVerified: true, latitude: 18.9314, longitude: 72.8353, contacts: { create: [ { name: "Deepak Mehta", role: "Owner", mobile: "9876543210", email: "deepak@mumbaishipstores.com", isPrimary: true }, { name: "Kavita Mehta", role: "Operations", mobile: "9876543211", email: "kavita@mumbaishipstores.com", isPrimary: false }, ], }, }, }); const v9 = await db.vendor.upsert({ where: { vendorId: "VND-0009" }, update: {}, create: { name: "Bharat Navigation Systems", vendorId: "VND-0009", address: "67, M.G. Road, Pune 411001", pincode: "411001", isVerified: false, latitude: 18.5204, longitude: 73.8567, contacts: { create: [ { name: "Suresh Kumar", role: "Director", mobile: "9823456780", email: "suresh@bharatnav.in", isPrimary: true }, ], }, }, }); const v10 = await db.vendor.upsert({ where: { vendorId: "VND-0010" }, update: {}, create: { name: "Coastal Rope & Rigging", vendorId: "VND-0010", address: "Sector 12, Kandivali East, Mumbai 400101", pincode: "400101", gstin: "27AABCC2345E1ZP", isVerified: true, latitude: 19.2081, longitude: 72.8656, contacts: { create: [ { name: "James D'Souza", role: "Partner", mobile: "9823456789", email: "james@coastalrope.com", isPrimary: true }, ], }, }, }); const v11 = await db.vendor.upsert({ where: { vendorId: "VND-0011" }, update: {}, create: { name: "Indotech Filters & Fluids", vendorId: "VND-0011", address: "E-12, Peenya Industrial Area Phase 1, Bengaluru 560058", pincode: "560058", gstin: "29AABCI5678F1ZL", isVerified: true, latitude: 13.0315, longitude: 77.5260, contacts: { create: [ { name: "Meenakshi Srinivasan", role: "VP Sales", mobile: "9987654321", email: "msrinivasan@indotech.co.in", isPrimary: true }, { name: "Kiran Reddy", role: "Technical", mobile: "9987654322", email: "kiran@indotech.co.in", isPrimary: false }, ], }, }, }); const v12 = await db.vendor.upsert({ where: { vendorId: "VND-0012" }, update: {}, create: { name: "Eastern Electro Marine", vendorId: "VND-0012", address: "12A, Strand Road, Kolkata 700001", pincode: "700001", gstin: "19AABCE6789G1ZK", isVerified: false, latitude: 22.5726, longitude: 88.3639, contacts: { create: [ { name: "Rahul Das", role: "Director", mobile: "9432167890", email: "rahul.das@easternelectro.com", isPrimary: true }, { name: "Moumita Sen", role: "Technical Sales", mobile: "9432167891", email: "moumita.sen@easternelectro.com", isPrimary: false }, ], }, }, }); // ─── Products ───────────────────────────────────────────────────────────────── const pTurboSeal = await db.product.upsert({ where: { code: "PART-TURBO-SEAL" }, update: {}, create: { code: "PART-TURBO-SEAL", name: "Turbocharger Seal Kit", description: "Replacement seal kit for main engine turbocharger", lastPrice: 1200, lastVendorId: v1.id }, }); const pFpPump = await db.product.upsert({ where: { code: "PART-FP-PUMP" }, update: {}, create: { code: "PART-FP-PUMP", name: "High-Pressure Fuel Pump", description: "Main engine high-pressure fuel pump assembly", lastPrice: 4800, lastVendorId: v1.id }, }); const pLifeJkt = await db.product.upsert({ where: { code: "SAFE-LIFEJKT" }, update: {}, create: { code: "SAFE-LIFEJKT", name: "Life Jacket (SOLAS)", description: "SOLAS-approved adult life jacket", lastPrice: 120, lastVendorId: v7.id }, }); const pFireExt = await db.product.upsert({ where: { code: "SAFE-EXTG-9KG" }, update: {}, create: { code: "SAFE-EXTG-9KG", name: "Fire Extinguisher 9kg", description: "Dry powder fire extinguisher, 9kg", lastPrice: 200, lastVendorId: v7.id }, }); const pGearOil = await db.product.upsert({ where: { code: "LUBE-EP80W90" }, update: {}, create: { code: "LUBE-EP80W90", name: "Gear Oil EP 80W90", description: "Eni EP 80W90 gear oil for marine gearboxes", lastPrice: 182, lastVendorId: v5.id }, }); const pHydOil = await db.product.upsert({ where: { code: "LUBE-HYD46" }, update: {}, create: { code: "LUBE-HYD46", name: "Hydraulic Oil ISO 46", description: "Anti-wear hydraulic oil ISO VG 46 for deck machinery", lastPrice: 155, lastVendorId: v5.id }, }); const pMeOil = await db.product.upsert({ where: { code: "LUBE-MEO30" }, update: {}, create: { code: "LUBE-MEO30", name: "Main Engine Oil SAE 30", description: "Trunk piston engine oil SAE 30 for 4-stroke engines", lastPrice: 210, lastVendorId: v5.id }, }); const pOilFilter = await db.product.upsert({ where: { code: "FILT-OIL-ME" }, update: {}, create: { code: "FILT-OIL-ME", name: "Main Engine Lube Oil Filter", description: "Spin-on lube oil filter for main engine", lastPrice: 850, lastVendorId: v11.id }, }); const pFuelFilter = await db.product.upsert({ where: { code: "FILT-FUEL-ME" }, update: {}, create: { code: "FILT-FUEL-ME", name: "Main Engine Fuel Filter", description: "Duplex fuel oil filter element for main engine", lastPrice: 1100, lastVendorId: v11.id }, }); const pAirFilter = await db.product.upsert({ where: { code: "FILT-AIR-ME" }, update: {}, create: { code: "FILT-AIR-ME", name: "Air Filter Element", description: "Air cleaner filter element for main engine air intake", lastPrice: 650, lastVendorId: v11.id }, }); const pORing = await db.product.upsert({ where: { code: "PART-ORING-ASST" }, update: {}, create: { code: "PART-ORING-ASST", name: "O-Ring Assortment Pack", description: "Mixed O-ring kit with Nitrile and Viton rings, 500 pcs", lastPrice: 250, lastVendorId: v1.id }, }); const pGasket = await db.product.upsert({ where: { code: "PART-GASKET-SET" }, update: {}, create: { code: "PART-GASKET-SET", name: "Exhaust Gasket Set", description: "Full set of exhaust manifold gaskets for main engine", lastPrice: 3200, lastVendorId: v1.id }, }); const pNavLamp = await db.product.upsert({ where: { code: "ELEC-LAMP-LED" }, update: {}, create: { code: "ELEC-LAMP-LED", name: "LED Navigation Lamp", description: "SOLAS-compliant LED navigation light, white masthead", lastPrice: 4500, lastVendorId: v12.id }, }); const pBattery = await db.product.upsert({ where: { code: "ELEC-BATT-12V" }, update: {}, create: { code: "ELEC-BATT-12V", name: "Starting Battery 12V 100Ah", description: "Sealed lead-acid starting battery for emergency equipment", lastPrice: 6500, lastVendorId: v4.id }, }); const pCable = await db.product.upsert({ where: { code: "ELEC-CABLE-3C" }, update: {}, create: { code: "ELEC-CABLE-3C", name: "Marine Cable 3-Core 2.5mm²", description: "Tinned copper 3-core marine electrical cable, per metre", lastPrice: 85, lastVendorId: v4.id }, }); const pMooringRope = await db.product.upsert({ where: { code: "ROPE-MOORING-40" }, update: {}, create: { code: "ROPE-MOORING-40", name: "Mooring Rope 40mm × 200m", description: "3-strand polypropylene mooring rope, 40mm dia, 200m coil", lastPrice: 18500, lastVendorId: v10.id }, }); const pPilotRope = await db.product.upsert({ where: { code: "ROPE-PILOT-18" }, update: {}, create: { code: "ROPE-PILOT-18", name: "Pilot Ladder Rope 18mm", description: "Manilla pilot ladder rope, 18mm, certified per metre", lastPrice: 320, lastVendorId: v10.id }, }); const pImmSuit = await db.product.upsert({ where: { code: "SAFE-IMMSUIT" }, update: {}, create: { code: "SAFE-IMMSUIT", name: "Immersion Suit (SOLAS)", description: "SOLAS-approved adult immersion suit, insulated", lastPrice: 5500, lastVendorId: v7.id }, }); const pEpirb = await db.product.upsert({ where: { code: "SAFE-EPIRB" }, update: {}, create: { code: "SAFE-EPIRB", name: "EPIRB (406 MHz)", description: "Category I float-free EPIRB, 406 MHz COSPAS-SARSAT", lastPrice: 45000, lastVendorId: v7.id }, }); const pFlare = await db.product.upsert({ where: { code: "SAFE-FLARE-HAND" }, update: {}, create: { code: "SAFE-FLARE-HAND", name: "Hand Flare (SOLAS)", description: "Red hand flare for distress signalling, pack of 6", lastPrice: 1800, lastVendorId: v7.id }, }); const pAntifoul = await db.product.upsert({ where: { code: "PAINT-ANTIFOUL" }, update: {}, create: { code: "PAINT-ANTIFOUL", name: "Antifouling Paint 20L", description: "Self-polishing antifouling paint for hull below waterline", lastPrice: 8200, lastVendorId: v3.id }, }); const pPrimer = await db.product.upsert({ where: { code: "PAINT-PRIMER" }, update: {}, create: { code: "PAINT-PRIMER", name: "Epoxy Primer 5L", description: "Two-component epoxy primer for steel and aluminium surfaces", lastPrice: 3400, lastVendorId: v3.id }, }); await db.product.upsert({ where: { code: "TOOL-GRINDER-4" }, update: {}, create: { code: "TOOL-GRINDER-4", name: "Angle Grinder 4-inch", description: "Heavy-duty 4-inch angle grinder, 850W, with guard", lastPrice: 2800, lastVendorId: v8.id }, }); const pChart = await db.product.upsert({ where: { code: "CHART-INT-1" }, update: {}, create: { code: "CHART-INT-1", name: "INT Chart Folio Update", description: "Annual update pack for navigational charts, Indian Ocean folio", lastPrice: 950, lastVendorId: v9.id }, }); const pBoilerChem = await db.product.upsert({ where: { code: "CHEM-BOWTREATER" }, update: {}, create: { code: "CHEM-BOWTREATER", name: "Boiler Water Treatment Chemical 25L", description: "Liquid boiler water treatment and scale inhibitor", lastPrice: 3600, lastVendorId: v5.id }, }); // ─── ProductVendorPrice ─────────────────────────────────────────────────────── const pvp = async (productId: string, vendorId: string, price: number) => db.productVendorPrice.upsert({ where: { productId_vendorId: { productId, vendorId } }, update: { price }, create: { productId, vendorId, price }, }); // Turbocharger Seal Kit await pvp(pTurboSeal.id, v1.id, 1200); await pvp(pTurboSeal.id, v8.id, 1350); await pvp(pTurboSeal.id, v5.id, 1180); // High-Pressure Fuel Pump await pvp(pFpPump.id, v1.id, 4800); await pvp(pFpPump.id, v8.id, 5100); // Life Jacket await pvp(pLifeJkt.id, v7.id, 120); await pvp(pLifeJkt.id, v2.id, 115); await pvp(pLifeJkt.id, v3.id, 130); // Fire Extinguisher await pvp(pFireExt.id, v7.id, 200); await pvp(pFireExt.id, v3.id, 220); // Gear Oil EP 80W90 await pvp(pGearOil.id, v5.id, 182); await pvp(pGearOil.id, v6.id, 175); // Hydraulic Oil ISO 46 await pvp(pHydOil.id, v5.id, 155); await pvp(pHydOil.id, v6.id, 148); // Main Engine Oil SAE 30 await pvp(pMeOil.id, v5.id, 210); await pvp(pMeOil.id, v6.id, 205); // Lube Oil Filter await pvp(pOilFilter.id, v1.id, 850); await pvp(pOilFilter.id, v11.id, 820); await pvp(pOilFilter.id, v8.id, 890); // Fuel Filter await pvp(pFuelFilter.id, v1.id, 1100); await pvp(pFuelFilter.id, v11.id, 1050); // Air Filter await pvp(pAirFilter.id, v11.id, 650); await pvp(pAirFilter.id, v1.id, 680); // O-Ring Assortment await pvp(pORing.id, v1.id, 250); await pvp(pORing.id, v8.id, 270); await pvp(pORing.id, v11.id, 240); // Exhaust Gasket Set await pvp(pGasket.id, v1.id, 3200); await pvp(pGasket.id, v8.id, 3500); // LED Navigation Lamp await pvp(pNavLamp.id, v12.id, 4500); await pvp(pNavLamp.id, v8.id, 4800); // Starting Battery await pvp(pBattery.id, v4.id, 6500); await pvp(pBattery.id, v12.id, 6800); // Marine Cable await pvp(pCable.id, v4.id, 85); await pvp(pCable.id, v12.id, 80); // Mooring Rope await pvp(pMooringRope.id, v10.id, 18500); await pvp(pMooringRope.id, v3.id, 19000); // Pilot Ladder Rope await pvp(pPilotRope.id, v10.id, 320); await pvp(pPilotRope.id, v3.id, 340); // Immersion Suit await pvp(pImmSuit.id, v7.id, 5500); await pvp(pImmSuit.id, v2.id, 5200); // EPIRB await pvp(pEpirb.id, v7.id, 45000); await pvp(pEpirb.id, v9.id, 47000); // Hand Flare await pvp(pFlare.id, v7.id, 1800); await pvp(pFlare.id, v2.id, 1750); // Antifouling Paint await pvp(pAntifoul.id, v3.id, 8200); await pvp(pAntifoul.id, v8.id, 8500); // Epoxy Primer await pvp(pPrimer.id, v3.id, 3400); await pvp(pPrimer.id, v8.id, 3600); // Chart Folio await pvp(pChart.id, v9.id, 950); // Boiler Water Treatment await pvp(pBoilerChem.id, v5.id, 3600); await pvp(pBoilerChem.id, v11.id, 3450); // ─── ItemInventory ──────────────────────────────────────────────────────────── const inv = async (productId: string, siteId: string, quantity: number) => db.itemInventory.upsert({ where: { productId_siteId: { productId, siteId } }, update: { quantity }, create: { productId, siteId, quantity }, }); await inv(pTurboSeal.id, siteBOM.id, 3); await inv(pLifeJkt.id, siteBOM.id, 25); await inv(pHydOil.id, siteBOM.id, 200); await inv(pMeOil.id, siteBOM.id, 150); await inv(pOilFilter.id, siteJNP.id, 8); await inv(pFuelFilter.id,siteJNP.id, 4); await inv(pCable.id, siteCHE.id, 500); await inv(pMooringRope.id,siteKOC.id,2); await inv(pMeOil.id, siteVIZ.id, 100); await inv(pImmSuit.id, siteKDL.id, 15); await inv(pAntifoul.id, siteHAL.id, 4); await inv(pBoilerChem.id,sitePAR.id, 3); await inv(pFuelFilter.id,siteMNG.id, 4); await inv(pBattery.id, siteGOA.id, 2); await inv(pORing.id, siteBOM.id, 10); // ─── ItemConsumption ───────────────────────────────────────────────────────── const con = async (productId: string, siteId: string, date: Date, quantity: number, note?: string) => db.itemConsumption.upsert({ where: { productId_siteId_date: { productId, siteId, date } }, update: { quantity, note }, create: { productId, siteId, date, quantity, note, recordedById: technical.id }, }); await con(pHydOil.id, siteBOM.id, new Date("2026-01-10"), 20, "Regular deck machinery top-up"); await con(pMeOil.id, siteBOM.id, new Date("2026-01-15"), 15, "ME running hours service"); await con(pOilFilter.id, siteBOM.id, new Date("2026-02-01"), 2, "500-hr ME service"); await con(pHydOil.id, siteVIZ.id, new Date("2026-01-20"), 30, "Crane hydraulic system fill"); await con(pMeOil.id, siteVIZ.id, new Date("2026-01-25"), 25, "ME periodic change"); await con(pLifeJkt.id, siteJNP.id, new Date("2026-02-10"), 5, "Expired — disposed per drill"); await con(pPilotRope.id, siteKOC.id, new Date("2026-02-15"), 50, "Pilot ladder recertification cut"); await con(pCable.id, siteCHE.id, new Date("2026-01-30"), 100, "Accommodation wiring repair"); await con(pBoilerChem.id,siteBOM.id, new Date("2026-02-20"), 1, "Monthly boiler dosing"); await con(pAntifoul.id, siteHAL.id, new Date("2026-03-01"), 1, "Drydock touch-up"); await con(pFuelFilter.id,siteJNP.id, new Date("2026-02-25"), 2, "Duplex filter element change"); await con(pORing.id, siteBOM.id, new Date("2026-03-05"), 1, "Pump overhaul seals"); await con(pGearOil.id, siteCHE.id, new Date("2026-03-10"), 40, "Shaft gearbox oil change"); await con(pAirFilter.id, siteBOM.id, new Date("2026-03-15"), 1, "3000-hr air cleaner service"); // ─── Purchase Orders ────────────────────────────────────────────────────────── await db.purchaseOrder.upsert({ where: { poNumber: "PO-2026-00001" }, update: {}, create: { poNumber: "PO-2026-00001", title: "Engine Room Spare Parts — MV Pelagia Star", status: "MGR_REVIEW", totalAmount: 9971.0, // (2×1200 + 1×4800 + 5×250) × 1.18 currency: "INR", submittedAt: d(1), submitterId: technical.id, vesselId: mvStar.id, accountId: accTechOps.id, vendorId: v1.id, siteId: siteBOM.id, lineItems: { create: [ { name: "Turbocharger seal kit", quantity: 2, unit: "set", unitPrice: 1200, totalPrice: 2400, sortOrder: 0, productId: pTurboSeal.id }, { name: "High-pressure fuel pump", quantity: 1, unit: "pc", unitPrice: 4800, totalPrice: 4800, sortOrder: 1, productId: pFpPump.id }, { name: "O-ring assortment pack", quantity: 5, unit: "pk", unitPrice: 250, totalPrice: 1250, sortOrder: 2, productId: pORing.id }, ], }, actions: { create: [ { actionType: "CREATED", actorId: technical.id, createdAt: d(3) }, { actionType: "SUBMITTED", actorId: technical.id, createdAt: d(1) }, ], }, }, }); await db.purchaseOrder.upsert({ where: { poNumber: "PO-2026-00002" }, update: {}, create: { poNumber: "PO-2026-00002", title: "Crew Safety Equipment — MV Aegean Wind", status: "DRAFT", totalAmount: 3776.0, // (20×120 + 4×200) × 1.18 currency: "INR", submitterId: technical.id, vesselId: mvWind.id, accountId: accSafety.id, siteId: siteJNP.id, lineItems: { create: [ { name: "Life jackets (SOLAS)", quantity: 20, unit: "pc", unitPrice: 120, totalPrice: 2400, sortOrder: 0, productId: pLifeJkt.id }, { name: "Fire extinguisher — 9kg", quantity: 4, unit: "pc", unitPrice: 200, totalPrice: 800, sortOrder: 1, productId: pFireExt.id }, ], }, actions: { create: [{ actionType: "CREATED", actorId: technical.id, createdAt: d(2) }], }, }, }); await db.purchaseOrder.upsert({ where: { poNumber: "PO-2026-00003" }, update: {}, create: { poNumber: "PO-2026-00003", title: "Navigation Charts Update — Fleet", status: "MGR_APPROVED", totalAmount: 1121.0, // 950 × 1.18 currency: "INR", submittedAt: d(5), approvedAt: d(2), submitterId: technical.id, vesselId: mvStar.id, accountId: accNavig.id, siteId: siteBOM.id, lineItems: { create: [ { name: "INT chart folio update", quantity: 1, unit: "set", unitPrice: 950, totalPrice: 950, sortOrder: 0, productId: pChart.id }, ], }, actions: { create: [ { actionType: "CREATED", actorId: technical.id, createdAt: d(7) }, { actionType: "SUBMITTED", actorId: technical.id, createdAt: d(5) }, { actionType: "APPROVED", actorId: manager.id, createdAt: d(2), note: "Approved — update due before next voyage." }, ], }, }, }); await db.purchaseOrder.upsert({ where: { poNumber: "PO-2026-00004" }, update: {}, create: { poNumber: "PO-2026-00004", title: "Lubricants & Oils Restock — MV Thetis", status: "SUBMITTED", totalAmount: 13440.2, // (50×155 + 20×182) × 1.18 = 11390 × 1.18 currency: "INR", submittedAt: d(1), submitterId: tech2.id, vesselId: mvThetis.id, accountId: accTechOps.id, vendorId: v5.id, siteId: siteKOC.id, lineItems: { create: [ { name: "Hydraulic Oil ISO 46", quantity: 50, unit: "L", unitPrice: 155, totalPrice: 7750, sortOrder: 0, productId: pHydOil.id }, { name: "Gear Oil EP 80W90", quantity: 20, unit: "L", unitPrice: 182, totalPrice: 3640, sortOrder: 1, productId: pGearOil.id }, ], }, actions: { create: [ { actionType: "CREATED", actorId: tech2.id, createdAt: d(2) }, { actionType: "SUBMITTED", actorId: tech2.id, createdAt: d(1) }, ], }, }, }); await db.purchaseOrder.upsert({ where: { poNumber: "PO-2026-00005" }, update: {}, create: { poNumber: "PO-2026-00005", title: "Life Saving Appliances — MV Triton", status: "SENT_FOR_PAYMENT", totalAmount: 181720.0, // (10×5500 + 2×45000 + 5×1800) × 1.18 = 154000 × 1.18 currency: "INR", submittedAt: d(10), approvedAt: d(7), submitterId: technical.id, vesselId: mvTriton.id, accountId: accSafety.id, vendorId: v7.id, siteId: siteVIZ.id, lineItems: { create: [ { name: "Immersion suits (SOLAS)", quantity: 10, unit: "pc", unitPrice: 5500, totalPrice: 55000, sortOrder: 0, productId: pImmSuit.id }, { name: "EPIRB 406 MHz", quantity: 2, unit: "pc", unitPrice: 45000, totalPrice: 90000, sortOrder: 1, productId: pEpirb.id }, { name: "Hand flares (SOLAS) — pack of 6", quantity: 5, unit: "pk", unitPrice: 1800, totalPrice: 9000, sortOrder: 2, productId: pFlare.id }, ], }, actions: { create: [ { actionType: "CREATED", actorId: technical.id, createdAt: d(12) }, { actionType: "SUBMITTED", actorId: technical.id, createdAt: d(10) }, { actionType: "APPROVED", actorId: manager.id, createdAt: d(7), note: "Annual LSA renewal — proceed." }, { actionType: "PAYMENT_SENT", actorId: accounts.id, createdAt: d(3) }, ], }, }, }); await db.purchaseOrder.upsert({ where: { poNumber: "PO-2026-00006" }, update: {}, create: { poNumber: "PO-2026-00006", title: "Deck Mooring Equipment — MV Poseidon", status: "PAID_DELIVERED", totalAmount: 81420.0, // (2×18500 + 100×320) × 1.18 = 69000 × 1.18 currency: "INR", submittedAt: d(20), approvedAt: d(15), paidAt: d(8), submitterId: tech3.id, vesselId: mvPoseidon.id, accountId: accDeck.id, vendorId: v10.id, siteId: siteKDL.id, lineItems: { create: [ { name: "Mooring rope 40mm × 200m", quantity: 2, unit: "coil", unitPrice: 18500, totalPrice: 37000, sortOrder: 0, productId: pMooringRope.id }, { name: "Pilot ladder rope 18mm", quantity: 100, unit: "m", unitPrice: 320, totalPrice: 32000, sortOrder: 1, productId: pPilotRope.id }, ], }, actions: { create: [ { actionType: "CREATED", actorId: tech3.id, createdAt: d(22) }, { actionType: "SUBMITTED", actorId: tech3.id, createdAt: d(20) }, { actionType: "APPROVED", actorId: manager2.id, createdAt: d(15) }, { actionType: "PAYMENT_SENT", actorId: accounts.id, createdAt: d(10) }, { actionType: "RECEIPT_CONFIRMED", actorId: tech3.id, createdAt: d(8) }, ], }, }, }); await db.purchaseOrder.upsert({ where: { poNumber: "PO-2026-00007" }, update: {}, create: { poNumber: "PO-2026-00007", title: "Electrical Spares — MV Nereid", status: "MGR_REVIEW", totalAmount: 51920.0, // (5×4500 + 2×6500 + 100×85) × 1.18 = 44000 × 1.18 currency: "INR", submittedAt: d(2), submitterId: tech2.id, vesselId: mvNereid.id, accountId: accElect.id, vendorId: v12.id, siteId: siteCHE.id, lineItems: { create: [ { name: "LED navigation lamp (masthead)", quantity: 5, unit: "pc", unitPrice: 4500, totalPrice: 22500, sortOrder: 0, productId: pNavLamp.id }, { name: "Starting battery 12V 100Ah", quantity: 2, unit: "pc", unitPrice: 6500, totalPrice: 13000, sortOrder: 1, productId: pBattery.id }, { name: "Marine cable 3-core 2.5mm²", quantity: 100, unit: "m", unitPrice: 85, totalPrice: 8500, sortOrder: 2, productId: pCable.id }, ], }, actions: { create: [ { actionType: "CREATED", actorId: tech2.id, createdAt: d(4) }, { actionType: "SUBMITTED", actorId: tech2.id, createdAt: d(2) }, ], }, }, }); await db.purchaseOrder.upsert({ where: { poNumber: "PO-2026-00008" }, update: {}, create: { poNumber: "PO-2026-00008", title: "Rope & Rigging Restock — MV Callisto", status: "DRAFT", totalAmount: 84370.0, // (3×18500 + 50×320) × 1.18 = 71500 × 1.18 currency: "INR", submitterId: manning.id, vesselId: mvCallisto.id, accountId: accStores.id, siteId: siteGOA.id, lineItems: { create: [ { name: "Mooring rope 40mm × 200m", quantity: 3, unit: "coil", unitPrice: 18500, totalPrice: 55500, sortOrder: 0, productId: pMooringRope.id }, { name: "Pilot ladder rope 18mm", quantity: 50, unit: "m", unitPrice: 320, totalPrice: 16000, sortOrder: 1, productId: pPilotRope.id }, ], }, actions: { create: [{ actionType: "CREATED", actorId: manning.id, createdAt: d(1) }], }, }, }); await db.purchaseOrder.upsert({ where: { poNumber: "PO-2026-00009" }, update: {}, create: { poNumber: "PO-2026-00009", title: "Engine Filter Kit — MV Proteus", status: "SUBMITTED", totalAmount: 10443.0, // (5×850 + 3×1100 + 2×650) × 1.18 = 8850 × 1.18 currency: "INR", submittedAt: d(3), submitterId: technical.id, vesselId: mvProteus.id, accountId: accTechOps.id, vendorId: v11.id, siteId: sitePAR.id, lineItems: { create: [ { name: "Main engine lube oil filter", quantity: 5, unit: "pc", unitPrice: 820, totalPrice: 4100, sortOrder: 0, productId: pOilFilter.id }, { name: "Main engine fuel filter", quantity: 3, unit: "pc", unitPrice: 1050, totalPrice: 3150, sortOrder: 1, productId: pFuelFilter.id }, { name: "Air filter element", quantity: 2, unit: "pc", unitPrice: 650, totalPrice: 1300, sortOrder: 2, productId: pAirFilter.id }, ], }, actions: { create: [ { actionType: "CREATED", actorId: technical.id, createdAt: d(5) }, { actionType: "SUBMITTED", actorId: technical.id, createdAt: d(3) }, ], }, }, }); await db.purchaseOrder.upsert({ where: { poNumber: "PO-2026-00010" }, update: {}, create: { poNumber: "PO-2026-00010", title: "Hull Maintenance — MV Amphitrite Drydock", status: "CLOSED", totalAmount: 116820.0, // (10×8200 + 5×3400) × 1.18 = 99000 × 1.18 currency: "INR", submittedAt: d(30), approvedAt: d(25), paidAt: d(18), closedAt: d(10), submitterId: tech3.id, vesselId: mvAmphitrite.id, accountId: accPaint.id, vendorId: v3.id, siteId: siteHAL.id, lineItems: { create: [ { name: "Antifouling paint 20L", quantity: 10, unit: "drum", unitPrice: 8200, totalPrice: 82000, sortOrder: 0, productId: pAntifoul.id }, { name: "Epoxy primer 5L", quantity: 5, unit: "can", unitPrice: 3400, totalPrice: 17000, sortOrder: 1, productId: pPrimer.id }, ], }, actions: { create: [ { actionType: "CREATED", actorId: tech3.id, createdAt: d(32) }, { actionType: "SUBMITTED", actorId: tech3.id, createdAt: d(30) }, { actionType: "APPROVED", actorId: manager.id, createdAt: d(25), note: "Drydock schedule confirmed." }, { actionType: "PAYMENT_SENT", actorId: accounts2.id, createdAt: d(20) }, { actionType: "RECEIPT_CONFIRMED", actorId: tech3.id, createdAt: d(18) }, { actionType: "CLOSED", actorId: manager.id, createdAt: d(10), note: "All items delivered and consumed." }, ], }, }, }); await db.purchaseOrder.upsert({ where: { poNumber: "PO-2026-00011" }, update: {}, create: { poNumber: "PO-2026-00011", title: "Gasket & Seal Kit — MV Galatea", status: "DRAFT", totalAmount: 7789.6, // (2×3200 + 3×250) × 1.18 = 6750 × 1.18 ≈ 7965 — recalc: (2×3200+3×250)=7150 × 1.18 = 8437 currency: "INR", submitterId: manning2.id, vesselId: mvGalatea.id, accountId: accTechOps.id, siteId: siteMNG.id, lineItems: { create: [ { name: "Exhaust gasket set", quantity: 2, unit: "set", unitPrice: 3200, totalPrice: 6400, sortOrder: 0, productId: pGasket.id }, { name: "O-ring assortment pack", quantity: 3, unit: "pk", unitPrice: 250, totalPrice: 750, sortOrder: 1, productId: pORing.id }, ], }, actions: { create: [{ actionType: "CREATED", actorId: manning2.id, createdAt: d(1) }], }, }, }); await db.purchaseOrder.upsert({ where: { poNumber: "PO-2026-00012" }, update: {}, create: { poNumber: "PO-2026-00012", title: "Boiler Water Treatment — MV Proteus & Galatea", status: "MGR_APPROVED", totalAmount: 12744.0, // (3×3600 + 1×3450) × 1.18 = 14250 × 1.18 — recalc: 3×3600=10800 + 1×3450=3450 = 14250 × 1.18 = 16815 currency: "INR", submittedAt: d(8), approvedAt: d(3), submitterId: superuser.id, vesselId: mvProteus.id, accountId: accTechOps.id, vendorId: v11.id, siteId: sitePAR.id, lineItems: { create: [ { name: "Boiler water treatment chemical 25L", quantity: 3, unit: "can", unitPrice: 3450, totalPrice: 10350, sortOrder: 0, productId: pBoilerChem.id }, { name: "Main engine lube oil filter", quantity: 4, unit: "pc", unitPrice: 820, totalPrice: 3280, sortOrder: 1, productId: pOilFilter.id }, ], }, actions: { create: [ { actionType: "CREATED", actorId: superuser.id, createdAt: d(10) }, { actionType: "SUBMITTED", actorId: superuser.id, createdAt: d(8) }, { actionType: "APPROVED", actorId: manager2.id, createdAt: d(3), note: "Monthly consumables — approve." }, ], }, }, }); console.log("Seed complete.\n"); console.log("Dev login credentials:"); console.log(" Admin: admin@pelagia.local / admin1234"); console.log(" Manager: manager@pelagia.local / manager1234"); console.log(" Manager 2: manager2@pelagia.local / manager1234"); console.log(" Tech: tech@pelagia.local / tech1234"); console.log(" Tech 2: tech2@pelagia.local / tech1234"); console.log(" Tech 3: tech3@pelagia.local / tech1234"); console.log(" Accounts: accounts@pelagia.local / accounts1234"); console.log(" Manning: manning@pelagia.local / manning1234"); console.log(" Manning 2: manning2@pelagia.local / manning1234"); console.log(" Superuser: superuser@pelagia.local / super1234"); console.log(" Auditor: auditor@pelagia.local / audit1234"); } main() .catch((e) => { console.error(e); process.exit(1); }) .finally(() => db.$disconnect());