- update(i, "description", e.target.value)}
- className="w-full rounded border border-neutral-200 px-2 py-1.5 text-sm focus:border-primary-500 focus:outline-none"
- placeholder="Item description"
+ productId={row.productId}
+ onChange={(desc, pid, price) => updateDescription(i, desc, pid, price)}
/>
diff --git a/App/pelagia-portal/lib/permissions.ts b/App/pelagia-portal/lib/permissions.ts
index 11e91c7..a0af759 100644
--- a/App/pelagia-portal/lib/permissions.ts
+++ b/App/pelagia-portal/lib/permissions.ts
@@ -22,8 +22,12 @@ export type Permission =
const ROLE_PERMISSIONS: Record = {
TECHNICAL: ["create_po", "submit_po", "edit_own_draft_po", "view_own_pos", "confirm_receipt"],
MANNING: ["create_po", "submit_po", "edit_own_draft_po", "view_own_pos", "confirm_receipt"],
- ACCOUNTS: ["view_all_pos", "process_payment"],
+ ACCOUNTS: ["view_all_pos", "process_payment", "manage_vendors"],
MANAGER: [
+ "create_po",
+ "submit_po",
+ "edit_own_draft_po",
+ "view_own_pos",
"view_all_pos",
"approve_po",
"reject_po",
@@ -31,6 +35,7 @@ const ROLE_PERMISSIONS: Record = {
"request_vendor_id",
"view_analytics",
"export_reports",
+ "manage_vendors",
],
SUPERUSER: [
"create_po",
diff --git a/App/pelagia-portal/lib/po-state-machine.ts b/App/pelagia-portal/lib/po-state-machine.ts
index b3270d6..1ff691a 100644
--- a/App/pelagia-portal/lib/po-state-machine.ts
+++ b/App/pelagia-portal/lib/po-state-machine.ts
@@ -31,7 +31,7 @@ const TRANSITIONS: Partial> = {
DRAFT: {
submit: {
to: "SUBMITTED",
- allowedRoles: ["TECHNICAL", "MANNING", "SUPERUSER"],
+ allowedRoles: ["TECHNICAL", "MANNING", "MANAGER", "SUPERUSER"],
requiresNote: false,
sideEffects: ["EMAIL_MANAGER"],
},
@@ -74,7 +74,7 @@ const TRANSITIONS: Partial> = {
VENDOR_ID_PENDING: {
provide_vendor_id: {
to: "MGR_REVIEW",
- allowedRoles: ["TECHNICAL", "MANNING", "SUPERUSER", "MANAGER"],
+ allowedRoles: ["TECHNICAL", "MANNING", "ACCOUNTS", "MANAGER", "SUPERUSER"],
requiresNote: false,
sideEffects: ["EMAIL_MANAGER"],
},
@@ -82,7 +82,7 @@ const TRANSITIONS: Partial> = {
EDITS_REQUESTED: {
submit: {
to: "SUBMITTED",
- allowedRoles: ["TECHNICAL", "MANNING", "SUPERUSER"],
+ allowedRoles: ["TECHNICAL", "MANNING", "MANAGER", "SUPERUSER"],
requiresNote: false,
sideEffects: ["EMAIL_MANAGER"],
},
diff --git a/App/pelagia-portal/lib/validations/po.ts b/App/pelagia-portal/lib/validations/po.ts
index ab4d290..82e78bf 100644
--- a/App/pelagia-portal/lib/validations/po.ts
+++ b/App/pelagia-portal/lib/validations/po.ts
@@ -7,6 +7,7 @@ export const lineItemSchema = z.object({
size: z.string().optional(),
unitPrice: z.coerce.number().nonnegative("Unit price must be non-negative"),
gstRate: z.coerce.number().min(0).max(1).default(0.18),
+ productId: z.string().optional(),
});
export const TC_FIXED_LINE =
diff --git a/App/pelagia-portal/prisma/seed.ts b/App/pelagia-portal/prisma/seed.ts
index 866e524..31d0cf9 100644
--- a/App/pelagia-portal/prisma/seed.ts
+++ b/App/pelagia-portal/prisma/seed.ts
@@ -116,6 +116,8 @@ async function main() {
vendorId: "VND-0001",
contactName: "Tony Nguyen",
contactEmail: "tnguyen@marinepartsinternational.com",
+ address: "Plot 12, MIDC Industrial Area, Turbhe, Navi Mumbai 400705",
+ gstin: "27AABCM1234A1Z5",
isVerified: true,
},
});
@@ -128,6 +130,7 @@ async function main() {
vendorId: "VND-0002",
contactName: "Sarah Kim",
contactEmail: "sarah@globalcrewsupplies.com",
+ address: "14B, Harbour Street, Mazgaon, Mumbai 400010",
isVerified: true,
},
});
@@ -140,6 +143,137 @@ async function main() {
vendorId: "VND-0003",
contactName: "Marco Rossi",
contactEmail: "marco@atlaschandlers.com",
+ address: "Unit 7, Sassoon Dock, Colaba, Mumbai 400005",
+ isVerified: false,
+ },
+ });
+
+ await db.vendor.upsert({
+ where: { vendorId: "VND-0004" },
+ update: {},
+ create: {
+ name: "Apar Industries Ltd",
+ vendorId: "VND-0004",
+ contactName: "Nikhil Mumbaikar",
+ contactMobile: "7208055636",
+ contactEmail: "nikhil.mumbaikar@apar.com",
+ address: "18, TTC MIDC Industrial Area, Thane Belapur Road, Opp Rabale Railway Stn, Navi Mumbai 400701",
+ gstin: "27AAACG1840M1ZL",
+ isVerified: true,
+ },
+ });
+
+ await db.vendor.upsert({
+ where: { vendorId: "VND-0005" },
+ update: {},
+ create: {
+ name: "Neptune Marine Stores",
+ vendorId: "VND-0005",
+ contactName: "Ravi Sharma",
+ contactMobile: "9821234567",
+ contactEmail: "ravi@neptunemarine.in",
+ address: "B-204, Jogeshwari Industrial Estate, Mumbai 400060",
+ gstin: "27AADCN5678B1ZK",
+ isVerified: true,
+ },
+ });
+
+ await db.vendor.upsert({
+ where: { vendorId: "VND-0006" },
+ update: {},
+ create: {
+ name: "Seaview Hydraulics Pvt Ltd",
+ vendorId: "VND-0006",
+ contactName: "Anand Pillai",
+ contactMobile: "9867543210",
+ contactEmail: "anand@seaviewhydraulics.com",
+ address: "Plot 45, Phase II, Ambad MIDC, Nashik 422010",
+ gstin: "27AABCS9876C1ZM",
+ isVerified: true,
+ },
+ });
+
+ await db.vendor.upsert({
+ where: { vendorId: "VND-0007" },
+ update: {},
+ create: {
+ name: "Pacific Safety Equipment",
+ vendorId: "VND-0007",
+ contactName: "Priya Nair",
+ contactEmail: "priya@pacificsafety.com",
+ address: "22, Linking Road, Bandra West, Mumbai 400050",
+ isVerified: true,
+ },
+ });
+
+ await db.vendor.upsert({
+ where: { vendorId: "VND-0008" },
+ update: {},
+ create: {
+ name: "Mumbai Ship Stores",
+ vendorId: "VND-0008",
+ contactName: "Deepak Mehta",
+ contactMobile: "9876543210",
+ contactEmail: "deepak@mumbaishipstores.com",
+ address: "78, Ballard Estate, Fort, Mumbai 400001",
+ gstin: "27AAACM4567D1ZJ",
+ isVerified: true,
+ },
+ });
+
+ await db.vendor.upsert({
+ where: { vendorId: "VND-0009" },
+ update: {},
+ create: {
+ name: "Bharat Navigation Systems",
+ vendorId: "VND-0009",
+ contactName: "Suresh Kumar",
+ contactEmail: "suresh@bharatnav.in",
+ address: "67, M.G. Road, Pune 411001",
+ isVerified: false,
+ },
+ });
+
+ await db.vendor.upsert({
+ where: { vendorId: "VND-0010" },
+ update: {},
+ create: {
+ name: "Coastal Rope & Rigging",
+ vendorId: "VND-0010",
+ contactName: "James D'Souza",
+ contactMobile: "9823456789",
+ contactEmail: "james@coastalrope.com",
+ address: "Sector 12, Kandivali East, Mumbai 400101",
+ gstin: "27AABCC2345E1ZP",
+ isVerified: true,
+ },
+ });
+
+ await db.vendor.upsert({
+ where: { vendorId: "VND-0011" },
+ update: {},
+ create: {
+ name: "Indotech Filters & Fluids",
+ vendorId: "VND-0011",
+ contactName: "Meenakshi Srinivasan",
+ contactEmail: "msrinivasan@indotech.co.in",
+ address: "E-12, Peenya Industrial Area Phase 1, Bengaluru 560058",
+ gstin: "29AABCI5678F1ZL",
+ isVerified: true,
+ },
+ });
+
+ await db.vendor.upsert({
+ where: { vendorId: "VND-0012" },
+ update: {},
+ create: {
+ name: "Eastern Electro Marine",
+ vendorId: "VND-0012",
+ contactName: "Rahul Das",
+ contactMobile: "9432167890",
+ contactEmail: "rahul.das@easternelectro.com",
+ address: "12A, Strand Road, Kolkata 700001",
+ gstin: "19AABCE6789G1ZK",
isVerified: false,
},
});
@@ -152,6 +286,7 @@ async function main() {
code: "PART-TURBO-SEAL",
name: "Turbocharger Seal Kit",
description: "Replacement seal kit for main engine turbocharger",
+ lastPrice: 1200,
},
});
@@ -162,6 +297,7 @@ async function main() {
code: "PART-FP-PUMP",
name: "High-Pressure Fuel Pump",
description: "Main engine high-pressure fuel pump assembly",
+ lastPrice: 4800,
},
});
@@ -172,6 +308,7 @@ async function main() {
code: "SAFE-LIFEJKT",
name: "Life Jacket (SOLAS)",
description: "SOLAS-approved adult life jacket",
+ lastPrice: 120,
},
});
@@ -182,6 +319,238 @@ async function main() {
code: "SAFE-EXTG-9KG",
name: "Fire Extinguisher 9kg",
description: "Dry powder fire extinguisher, 9kg",
+ lastPrice: 200,
+ },
+ });
+
+ 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,
+ },
+ });
+
+ 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,
+ },
+ });
+
+ 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,
+ },
+ });
+
+ 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,
+ },
+ });
+
+ 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,
+ },
+ });
+
+ 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,
+ },
+ });
+
+ 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,
+ },
+ });
+
+ 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,
+ },
+ });
+
+ 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,
+ },
+ });
+
+ 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,
+ },
+ });
+
+ 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,
+ },
+ });
+
+ 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,
+ },
+ });
+
+ 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,
+ },
+ });
+
+ 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,
+ },
+ });
+
+ 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,
+ },
+ });
+
+ 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,
+ },
+ });
+
+ 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,
+ },
+ });
+
+ 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,
+ },
+ });
+
+ 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,
+ },
+ });
+
+ 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,
+ },
+ });
+
+ 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,
},
});