pelagia-portal/App/pelagia-portal/lib/permissions.ts
Hardik bea798324c feat(inventory): Sites, GST lookup, distance sorting, cart, inventory tracking
Schema:
- Site model (name, code, address, lat/lng, isActive)
- ItemInventory model (quantity per product per site, unique[productId,siteId])
- ItemConsumption model (daily usage per product per site)
- Vendor: add latitude, longitude
- Vessel: add siteId (home port)
- PurchaseOrder: add siteId (delivery site)

Permissions: add manage_sites to MANAGER and ADMIN

Sidebar: Inventory section (Vendors, Items, Vessels, Sites, Cart)
for MANAGER and ADMIN; old admin items reorganised

Lib:
- lib/geo.ts: Haversine distance + Nominatim pincode geocoding
- lib/gst-lookup.ts: AbhiAPI GSTIN lookup (ABHIAPI_KEY env var)
- lib/cart.ts: localStorage cart (add/remove/clear + cart-updated event)

API: GET /api/gst?gstin= — validates GSTIN, fetches via AbhiAPI,
  geocodes pincode via Nominatim, returns name/address/lat/lng

Vendor form: GSTIN "Look up" button auto-fills name, address,
  and lat/lng; lat/lng fields editable as override

Sites: full CRUD at /admin/sites; detail page with inventory
  table, consumption recording form, BarChart (stock) +
  LineChart (30-day consumption), linked vessels, recent POs

Vessels: detail page at /admin/vessels/[id] with "Create PO"
  button, PO history and spend summary; accessible to MANAGER

Items detail: price comparison BarChart; site distance filter
  (dropdown → re-render sorted by Haversine distance); "Add to
  Cart" per vendor row; stock-by-site section

Cart: /inventory/cart — localStorage CartView; qty edit, remove,
  clear; "Create PO →" encodes cart into /po/new?cart=...

Receipt/delivery: confirmReceipt now upserts ItemInventory
  (increment qty) for each linked line item, using PO siteId or
  vessel home site as the delivery location

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 11:50:11 +05:30

84 lines
2.1 KiB
TypeScript

import type { Role } from "@prisma/client";
export type Permission =
| "create_po"
| "submit_po"
| "edit_own_draft_po"
| "view_own_pos"
| "view_all_pos"
| "approve_po"
| "reject_po"
| "request_edits"
| "request_vendor_id"
| "process_payment"
| "confirm_receipt"
| "view_analytics"
| "export_reports"
| "manage_users"
| "manage_vendors"
| "manage_vessels_accounts"
| "manage_products"
| "manage_sites";
const ROLE_PERMISSIONS: Record<Role, Permission[]> = {
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", "manage_vendors"],
MANAGER: [
"create_po",
"submit_po",
"edit_own_draft_po",
"view_own_pos",
"view_all_pos",
"approve_po",
"reject_po",
"request_edits",
"request_vendor_id",
"view_analytics",
"export_reports",
"manage_vendors",
"manage_products",
"manage_sites",
],
SUPERUSER: [
"create_po",
"submit_po",
"edit_own_draft_po",
"view_own_pos",
"view_all_pos",
"approve_po",
"reject_po",
"request_edits",
"request_vendor_id",
"process_payment",
"confirm_receipt",
"view_analytics",
"export_reports",
],
AUDITOR: ["view_own_pos", "view_all_pos", "view_analytics", "export_reports"],
ADMIN: [
"view_own_pos",
"view_all_pos",
"view_analytics",
"export_reports",
"manage_users",
"manage_vendors",
"manage_vessels_accounts",
"manage_products",
"manage_sites",
],
};
export function hasPermission(role: Role, permission: Permission): boolean {
return ROLE_PERMISSIONS[role]?.includes(permission) ?? false;
}
export function requirePermission(role: Role, permission: Permission): void {
if (!hasPermission(role, permission)) {
throw new Error(`Forbidden: role ${role} lacks permission ${permission}`);
}
}
export function getPermissions(role: Role): Permission[] {
return ROLE_PERMISSIONS[role] ?? [];
}