feat: add purchase invoice batch print page and related components
- Implemented PurchaseInvoiceBatchPrintPage for printing purchase invoices. - Created InvoicePrintHeader and InvoicePrintFooter components for invoice layout. - Added invoice layout presets for different styles (Classic, Compact, Modern). - Developed PurchaseInvoicePaymentDialog for handling payments against invoices. - Introduced API mocks for company profile and invoice template configuration. - Added validation functions for company profile and purchase invoices. - Defined types for company profile, invoice template configuration, and purchase invoices.
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
// Client-side UX validation only — same thin convention as lib/validations/sales.ts.
|
||||
|
||||
const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
|
||||
|
||||
export function validateCompanyProfile(input: {
|
||||
legalName: string
|
||||
addressLine1: string
|
||||
city: string
|
||||
country: string
|
||||
phone: string
|
||||
email: string
|
||||
}): Record<string, string> {
|
||||
const errors: Record<string, string> = {}
|
||||
if (!input.legalName.trim()) errors.legalName = "Enter the company's legal name"
|
||||
if (!input.addressLine1.trim()) errors.addressLine1 = "Enter an address"
|
||||
if (!input.city.trim()) errors.city = "Enter a city"
|
||||
if (!input.country.trim()) errors.country = "Enter a country"
|
||||
if (!input.phone.trim()) errors.phone = "Enter a phone number"
|
||||
if (!input.email.trim()) errors.email = "Enter an email address"
|
||||
else if (!EMAIL_RE.test(input.email.trim())) errors.email = "Enter a valid email address"
|
||||
return errors
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// Client-side UX validation only — required fields, format/range checks the browser can
|
||||
// already see. Server-authoritative rules (GRN eligibility, vendor match, duplicate vendor
|
||||
// invoice numbers) are never re-implemented here. Same pattern as lib/validations/sales.ts.
|
||||
|
||||
export function validatePurchaseInvoiceHeader(input: {
|
||||
vendorId: number | null
|
||||
vendorInvoiceNo: string
|
||||
vendorInvoiceDate: string
|
||||
grnIds: number[]
|
||||
}): Record<string, string> {
|
||||
const errors: Record<string, string> = {}
|
||||
if (!input.vendorId) errors.vendorId = "Select a vendor"
|
||||
if (!input.vendorInvoiceNo.trim()) errors.vendorInvoiceNo = "Enter the vendor's invoice number"
|
||||
if (!input.vendorInvoiceDate) {
|
||||
errors.vendorInvoiceDate = "Enter the vendor's invoice date"
|
||||
} else if (input.vendorInvoiceDate > new Date().toISOString().slice(0, 10)) {
|
||||
errors.vendorInvoiceDate = "Invoice date cannot be in the future"
|
||||
}
|
||||
if (input.grnIds.length === 0) errors.grnIds = "Select at least one GRN to consolidate"
|
||||
return errors
|
||||
}
|
||||
Reference in New Issue
Block a user