feat(procurement): enhance purchase order and GRN functionalities

- Updated purchase order descriptions for clarity on draft and submission processes.
- Implemented submit and delete functionalities for draft purchase orders, allowing users to manage their orders more effectively.
- Added discount and VAT fields to GRN lines, enabling better cost tracking and reporting.
- Enhanced validation for GRN lines to ensure discount and VAT percentages are within acceptable ranges.
- Updated API to support new functionalities, including submitting and deleting purchase orders.
- Improved UI components for better user experience in managing purchase orders and GRNs.
- Documented changes in security and backend phase documentation to reflect new processes and requirements.
This commit is contained in:
2026-07-21 10:08:32 +05:30
parent fe9e8a780f
commit f02c89b3cb
28 changed files with 594 additions and 66 deletions
@@ -8,12 +8,14 @@ import {
Building2,
ChevronRight,
ClipboardList,
FileText,
HelpCircle,
LayoutGrid,
ListTree,
Menu,
Package,
PackageCheck,
PackageX,
Ruler,
Settings,
ShieldCheck,
@@ -59,7 +61,19 @@ const navItems: {
],
},
{ title: "Vendors", code: "vendors", href: "/dashboard/vendors", icon: Truck, chevron: true },
{ title: "Procurement", code: "procurement", href: "/dashboard/procurement", icon: ClipboardList, chevron: true },
{
title: "Procurement",
code: "procurement",
href: "/dashboard/procurement",
icon: ClipboardList,
chevron: true,
children: [
{ title: "Requisitions", code: "procurement.requisitions", href: "/dashboard/procurement/requisitions", icon: ClipboardList },
{ title: "RFQs", code: "procurement.rfqs", href: "/dashboard/procurement/rfqs", icon: FileText },
{ title: "Purchase Orders", code: "procurement.purchase-orders", href: "/dashboard/procurement/purchase-orders", icon: ShoppingCart },
{ title: "Purchase Returns", code: "procurement.purchase-returns", href: "/dashboard/procurement/purchase-returns", icon: PackageX },
],
},
{ title: "Receiving", code: "receiving", href: "/dashboard/receiving/grn", icon: PackageCheck, chevron: true },
{ title: "Stock", code: "stock", href: "/dashboard/stock", icon: Warehouse, chevron: true },
{ title: "Warehouses", code: "warehouses", href: "/dashboard/warehouse", icon: Building2, chevron: true },
+34 -1
View File
@@ -6,7 +6,40 @@ import { Select as SelectPrimitive } from "@base-ui/react/select"
import { cn } from "@/lib/utils"
import { ChevronDownIcon, CheckIcon, ChevronUpIcon } from "lucide-react"
const Select = SelectPrimitive.Root
// Base UI's `Select.Value` renders the raw selected value (e.g. an id) unless the Root is
// given an `items` map to resolve the label from — the popup items are unmounted when closed,
// so their text isn't otherwise available. Rather than pass `items` at all ~60 call sites,
// this wrapper walks its own `SelectItem` children and derives that map automatically, so the
// trigger shows the selected item's label instead of its value.
function collectItems(
children: React.ReactNode,
acc: { value: unknown; label: React.ReactNode }[]
) {
React.Children.forEach(children, (child) => {
if (!React.isValidElement(child)) return
if (child.type === SelectItem) {
const p = child.props as { value?: unknown; children?: React.ReactNode }
acc.push({ value: p.value, label: p.children })
return
}
const nested = (child.props as { children?: React.ReactNode }).children
if (nested) collectItems(nested, acc)
})
}
function Select<Value, Multiple extends boolean | undefined = false>(
props: SelectPrimitive.Root.Props<Value, Multiple>
) {
const { items, children } = props
const derivedItems = React.useMemo(() => {
if (items) return items
const acc: { value: unknown; label: React.ReactNode }[] = []
collectItems(children, acc)
return acc.length ? (acc as ReadonlyArray<{ value: Value; label: React.ReactNode }>) : undefined
}, [items, children])
return <SelectPrimitive.Root {...props} items={derivedItems} />
}
function SelectGroup({ className, ...props }: SelectPrimitive.Group.Props) {
return (