Order Items
@@ -269,23 +390,12 @@ export function PurchaseOrderForm({ setOpen, refreshData }: PurchaseOrderFormPro
render={({ field }) => (
Item Name
-
+ handleStockItemSelect(index, selectedItemName)}
+ placeholder="Search by SKU or name..."
+ />
)}
@@ -322,9 +432,9 @@ export function PurchaseOrderForm({ setOpen, refreshData }: PurchaseOrderFormPro
name={`items.${index}.costPrice`}
render={({ field }) => (
- Unit Price (ZAR)
+ Unit Price (£ GBP)
- handleItemChange(index, "costPrice", e.target.value)} />
+ handleItemChange(index, "costPrice", e.target.value)} />
diff --git a/src/components/purchase-orders/StockItemSearch.tsx b/src/components/purchase-orders/StockItemSearch.tsx
new file mode 100644
index 0000000..de75bae
--- /dev/null
+++ b/src/components/purchase-orders/StockItemSearch.tsx
@@ -0,0 +1,108 @@
+"use client"
+
+import * as React from "react"
+import { Check, ChevronsUpDown } from "lucide-react"
+
+import { cn } from "@/lib/utils"
+import { Button } from "@/components/ui/button"
+import {
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
+} from "@/components/ui/command"
+import {
+ Popover,
+ PopoverContent,
+ PopoverTrigger,
+} from "@/components/ui/popover"
+
+// Define the type for a stock item
+type StockItem = {
+ id: string
+ name: string
+ sku: string
+ costPrice: number
+ costPriceGBP: number
+}
+
+interface StockItemSearchProps {
+ stockItems: StockItem[];
+ selectedItemName: string;
+ onSelectItem: (itemName: string) => void;
+ placeholder: string;
+}
+
+export function StockItemSearch({ stockItems, selectedItemName, onSelectItem, placeholder }: StockItemSearchProps) {
+ const [open, setOpen] = React.useState(false)
+ const [search, setSearch] = React.useState("")
+
+ return (
+
+
+
+
+
+
+
+
+ No items found.
+
+ {stockItems
+ .filter(item =>
+ item.name.toLowerCase().includes(search.toLowerCase()) ||
+ item.sku.toLowerCase().includes(search.toLowerCase())
+ )
+ .map((item) => (
+ {
+ onSelectItem(value);
+ setOpen(false);
+ }}
+ >
+
+
+
{item.name}
+
+ SKU: {item.sku} | GBP: £{item.costPriceGBP.toFixed(2)} | ZAR: R{item.costPrice.toFixed(2)}
+
+
+
+ ))}
+
+
+
+
+
+ )
+}
diff --git a/src/components/purchase-orders/columns.tsx b/src/components/purchase-orders/columns.tsx
index dea4aa7..dca9a78 100644
--- a/src/components/purchase-orders/columns.tsx
+++ b/src/components/purchase-orders/columns.tsx
@@ -27,8 +27,18 @@ export type PurchaseOrder = {
orderDate: string
status: string
itemCount: number
- items: Array<{ stockItemId: string; itemName: string; quantity: number; sku: string; costPrice: number }> // Added costPrice
+ orderNumber?: string
+ accountRef?: string
+ salesOrderNo?: string
+ carriageCharge?: number
+ items: Array<{ stockItemId: string; itemName: string; quantity: number; sku: string; costPrice: number; costPriceGBP: number }> // Added costPrice and costPriceGBP
quantities: number[]
+ supplier?: {
+ name: string
+ address: string
+ email: string
+ phone: string
+ } | null
}
// Define the props for the actions column
diff --git a/src/components/stock/AddItemForm.tsx b/src/components/stock/AddItemForm.tsx
index 3989213..db2fce8 100644
--- a/src/components/stock/AddItemForm.tsx
+++ b/src/components/stock/AddItemForm.tsx
@@ -24,8 +24,9 @@ const formSchema = z.object({
name: z.string().min(2, { message: "Name must be at least 2 characters." }),
sku: z.string().min(2, { message: "SKU must be at least 2 characters." }),
category: z.string({ required_error: "Please select or create a category." }),
- quantity: z.coerce.number().int().positive({ message: "Quantity must be a positive number." }),
- costPrice: z.coerce.number().positive({ message: "Cost price must be a positive number." }),
+ quantity: z.coerce.number().int().min(0, { message: "Quantity must be 0 or greater." }),
+ costPrice: z.coerce.number().min(0, { message: "Cost price (ZAR) must be 0 or greater." }),
+ costPriceGBP: z.coerce.number().min(0, { message: "Cost price (GBP) must be 0 or greater." }),
sellingPrice: z.coerce.number().positive({ message: "Selling price must be a positive number." }),
})
@@ -64,8 +65,9 @@ export function AddItemForm({ setOpen, refreshData }: AddItemFormProps) {
defaultValues: {
name: "",
sku: "",
- quantity: 1,
+ quantity: 0,
costPrice: 0.00,
+ costPriceGBP: 0.00,
sellingPrice: 0.00,
},
})
@@ -78,6 +80,7 @@ export function AddItemForm({ setOpen, refreshData }: AddItemFormProps) {
category: values.category,
quantity: values.quantity,
cost_price: values.costPrice,
+ cost_price_gbp: values.costPriceGBP,
selling_price: values.sellingPrice,
});
@@ -166,26 +169,41 @@ export function AddItemForm({ setOpen, refreshData }: AddItemFormProps) {
)}
/>
-
-
(
-
- Cost Price
-
-
-
-
-
- )}
- />
+
+
+ (
+
+ Cost Price (£ GBP)
+
+
+
+
+
+ )}
+ />
+ (
+
+ Cost Price (R ZAR)
+
+
+
+
+
+ )}
+ />
+
(
- Selling Price
+ Selling Price (R ZAR)
diff --git a/src/components/stock/EditItemForm.tsx b/src/components/stock/EditItemForm.tsx
index 98b6ba6..954bef1 100644
--- a/src/components/stock/EditItemForm.tsx
+++ b/src/components/stock/EditItemForm.tsx
@@ -25,8 +25,9 @@ const formSchema = z.object({
name: z.string().min(2, { message: "Name must be at least 2 characters." }),
sku: z.string().min(2, { message: "SKU must be at least 2 characters." }),
category: z.string({ required_error: "Please select or create a category." }),
- quantity: z.coerce.number().int().positive({ message: "Quantity must be a positive number." }),
- costPrice: z.coerce.number().positive({ message: "Cost price must be a positive number." }),
+ quantity: z.coerce.number().int().min(0, { message: "Quantity must be 0 or greater." }),
+ costPrice: z.coerce.number().min(0, { message: "Cost price (ZAR) must be 0 or greater." }),
+ costPriceGBP: z.coerce.number().min(0, { message: "Cost price (GBP) must be 0 or greater." }),
sellingPrice: z.coerce.number().positive({ message: "Selling price must be a positive number." }),
})
@@ -69,6 +70,7 @@ export function EditItemForm({ setOpen, refreshData, item }: EditItemFormProps)
category: item.category.toLowerCase(), // Ensure category is lowercase for combobox value
quantity: item.quantity,
costPrice: item.costPrice,
+ costPriceGBP: item.costPriceGBP || 0,
sellingPrice: item.sellingPrice,
},
})
@@ -81,6 +83,7 @@ export function EditItemForm({ setOpen, refreshData, item }: EditItemFormProps)
category: values.category,
quantity: values.quantity,
cost_price: values.costPrice,
+ cost_price_gbp: values.costPriceGBP,
selling_price: values.sellingPrice,
});
showSuccess("Item updated successfully!");
@@ -160,26 +163,41 @@ export function EditItemForm({ setOpen, refreshData, item }: EditItemFormProps)
)}
/>
-
-
(
-
- Cost Price
-
-
-
-
-
- )}
- />
+
+
+ (
+
+ Cost Price (£ GBP)
+
+
+
+
+
+ )}
+ />
+ (
+
+ Cost Price (R ZAR)
+
+
+
+
+
+ )}
+ />
+
(
- Selling Price
+ Selling Price (R ZAR)
diff --git a/src/components/stock/columns.tsx b/src/components/stock/columns.tsx
index baa798d..70e070c 100644
--- a/src/components/stock/columns.tsx
+++ b/src/components/stock/columns.tsx
@@ -29,6 +29,7 @@ export type StockItem = {
category: string
quantity: number
costPrice: number
+ costPriceGBP: number
sellingPrice: number
}
diff --git a/src/pages/PurchaseOrders.tsx b/src/pages/PurchaseOrders.tsx
index ec388fe..a905e53 100644
--- a/src/pages/PurchaseOrders.tsx
+++ b/src/pages/PurchaseOrders.tsx
@@ -26,7 +26,7 @@ const PurchaseOrders = () => {
try {
const records = await pb.collection('purchase_orders').getList(1, 50, {
sort: '-orderDate',
- expand: 'items', // Ensure items are expanded for PDF generation
+ expand: 'items,supplierName', // Expand both items and supplier for PDF generation
});
const formattedData = records.items.map((record) => ({
@@ -35,14 +35,25 @@ const PurchaseOrders = () => {
orderDate: record.orderDate,
status: record.status,
itemCount: record.items?.length || 0,
+ orderNumber: record.order_number || record.id, // Use order_number field
+ accountRef: record.account_ref || '',
+ salesOrderNo: record.sales_order_no || '',
+ carriageCharge: record.carriage_charge || 0,
items: (record.expand?.items || []).map((item: any) => ({
stockItemId: item.id,
itemName: item.name,
quantity: item.quantity, // This is the quantity in stock_items, not the ordered quantity
sku: item.sku,
- costPrice: item.cost_price, // Include costPrice from expanded item
+ costPrice: item.cost_price, // ZAR price
+ costPriceGBP: item.cost_price_gbp || 0, // GBP price
})),
quantities: record.quantities || [], // This array holds the ordered quantities
+ supplier: record.expand?.supplierName ? {
+ name: record.expand.supplierName.supplier_name || '',
+ address: record.expand.supplierName.suppier_address || '', // Note: typo in DB field name "suppier_address"
+ email: record.expand.supplierName.supplier_email || '',
+ phone: record.expand.supplierName.supplier_phone_number || '',
+ } : null,
}));
setPurchaseOrders(formattedData);
diff --git a/src/pages/Stock.tsx b/src/pages/Stock.tsx
index 30dbfb8..65ffdc3 100644
--- a/src/pages/Stock.tsx
+++ b/src/pages/Stock.tsx
@@ -32,6 +32,7 @@ const Stock = () => {
category: item.category,
quantity: item.quantity,
costPrice: item.cost_price,
+ costPriceGBP: item.cost_price_gbp || 0,
sellingPrice: item.selling_price,
}));
setStockItems(formattedData);