feat: add vendor optional fields and configuration hooks

- Implemented VendorOptionalFields component to handle optional vendor details (mobile, email, address) with validation.
- Created useCustomerConfig hook to load optional customer field settings from Sales configuration.
- Developed useProcurementConfig hook to manage Procurement configuration flags.
- Introduced accessConfigApi for managing access configuration settings.
- Added openingBalancesApi for handling opening balances operations.
- Created procurementConfigApi for managing procurement configuration settings.
- Implemented nav-routes for permission-based routing.
- Developed PDF generation for purchase orders with dynamic vendor and item details.
- Added purchase-order tax helpers for tax calculations and formatting.
- Defined types for opening balances and related operations.
This commit is contained in:
Dhananjaya99
2026-10-18 12:46:31 +05:30
parent c27db06880
commit e7b1f270a5
202 changed files with 99906 additions and 1894 deletions
@@ -67,7 +67,8 @@ import { useAuth } from "@/components/auth/AuthProvider"
// `code` must match the seeded NavItem/SubNavItem codes in ERPCore
// (Infra/Persistence/Configurations/NavItemConfiguration.cs / SubNavItemConfiguration.cs)
// so role-based filtering (via GET /auth/me's navCodes) can match entries here.
const navItems: {
// Exported: lib/nav-routes.ts derives the page -> permission map (the route guard) from this same list.
export const navItems: {
title: string
code: string
href: string
@@ -114,6 +115,7 @@ const navItems: {
icon: ClipboardList,
children: [
{ title: "Purchase Orders", code: "procurement.purchase-orders", href: "/dashboard/procurement/purchase-orders", icon: ShoppingCart },
{ title: "PO Approval Queue", code: "procurement.po-approvals", href: "/dashboard/procurement/purchase-orders/approvals", icon: ClipboardCheck },
{ title: "Purchase Returns", code: "procurement.purchase-returns", href: "/dashboard/procurement/purchase-returns", icon: PackageX },
{ title: "Vendors", code: "procurement.vendors", href: "/dashboard/vendors", icon: Truck },
],
@@ -215,6 +217,7 @@ const navItems: {
{ title: "Expenses", code: "accounts.expenses", href: "/dashboard/accounts/expenses", icon: ReceiptText },
{ title: "Expense Setup", code: "accounts.expense-setup", href: "/dashboard/accounts/expense-setup", icon: Tags },
{ title: "Bank Deposits", code: "accounts.bank-deposits", href: "/dashboard/accounts/bank-deposits", icon: PiggyBank },
{ title: "Opening Balances", code: "accounts.opening-balances", href: "/dashboard/accounts/opening-balances", icon: Scale },
],
},
{
@@ -227,6 +230,7 @@ const navItems: {
{ title: "Roles", code: "settings.roles", href: "/dashboard/settings/roles", icon: ShieldCheck },
{ title: "Users", code: "settings.users", href: "/dashboard/settings/users", icon: Users },
{ title: "Approvals", code: "settings.approvals", href: "/dashboard/settings/approvals", icon: ClipboardCheck },
{ title: "Audit Log", code: "settings.audit-logs", href: "/dashboard/settings/audit-logs", icon: ScrollText },
{ title: "Configuration", code: "products.configuration", href: "/dashboard/settings/configuration", icon: SlidersHorizontal },
],
},
@@ -439,32 +443,19 @@ export function AppSidebar() {
// While /auth/me hasn't resolved yet, show nothing rather than briefly
// flashing the full menu to a restricted role. Once resolved, a nav item
// is visible if its own code is granted, or (for parents) if any child is.
//
// "procurement", "hrm", "sales", "production" and "stock" are exempted from that check
// (frontend-only): no role is currently seeded with NAV:procurement/NAV:hrm/NAV:production
// or their children server-side (stock's children specifically have no SubNavItem rows at
// all yet), which would hide the whole section for everyone. Remove each bypass once roles
// are granted the permission properly (Settings → Roles → Sidebar permissions) or a backend
// seed grants it. This is also flagged in 02-SECURITY.md as the AR-09 sidebar-visibility
// stopgap for HRM's salary/PII data — it hides HRM from the UI but doesn't enforce
// anything server-side.
const bypassCodes = new Set(["procurement", "sales", "sales-returns", "hrm", "production", "stock"])
// Every section now has seeded nav rows (HRM and Sales Returns were the last gaps), so there is no
// exemption list any more: what you see is exactly what your role grants (an administrator holds every code).
const visibleItems = loading
? []
: navItems
.filter(
(item) =>
bypassCodes.has(item.code) ||
navCodes.includes(item.code) ||
item.children?.some((c) => navCodes.includes(c.code) || c.altCodes?.some((ac) => navCodes.includes(ac)))
)
.map((item) => ({
...item,
children: (bypassCodes.has(item.code)
? item.children
: item.children?.filter((c) => navCodes.includes(c.code) || c.altCodes?.some((ac) => navCodes.includes(ac)))
),
children: item.children?.filter((c) => navCodes.includes(c.code) || c.altCodes?.some((ac) => navCodes.includes(ac))),
}))
// Close mobile menu on route change
@@ -49,6 +49,7 @@ const PROCUREMENT_TITLES: Record<string, string> = {
"/dashboard/procurement/rfqs/new": "New RFQ",
"/dashboard/procurement/purchase-orders": "Purchase Orders",
"/dashboard/procurement/purchase-orders/new": "New Purchase Order",
"/dashboard/procurement/purchase-orders/approvals": "PO Approval Queue",
"/dashboard/procurement/purchase-returns": "Purchase Returns",
"/dashboard/procurement/purchase-returns/new": "New Purchase Return",
}