feat: add warranty tracking for items and GRN lines
- Enhanced ItemService to include warranty and warranty period months in item DTOs. - Implemented validation for warranty periods in ItemService. - Updated frontend item detail and new item pages to handle warranty selection and input. - Added warranty number handling in GRN creation and detail pages. - Introduced new GrnLineWarrantyNumber entity to capture warranty numbers for received items. - Created Warranty enum and associated allowed months for warranty coverage. - Updated validation logic for GRN lines to ensure warranty numbers are captured correctly.
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
// (over-receipt tolerance, referential existence, concurrency) are never
|
||||
// re-implemented here; the server's ProblemDetails is the final word (§3.3).
|
||||
import { z } from "zod"
|
||||
import { TrackingMode } from "@/types/master-data"
|
||||
import { Warranty } from "@/types/master-data"
|
||||
|
||||
export const grnHeaderSchema = z.object({
|
||||
warehouseId: z.number({ error: "Select a warehouse" }).positive("Select a warehouse"),
|
||||
@@ -17,9 +17,8 @@ export function validateLine(input: {
|
||||
unitCost: string
|
||||
discountPct: string
|
||||
vatPct: string
|
||||
trackingMode: TrackingMode | null
|
||||
batchNo: string
|
||||
serialNumbersText: string
|
||||
warranty: Warranty | null
|
||||
warrantyNumbers: string[]
|
||||
}): Record<string, string> {
|
||||
const errors: Record<string, string> = {}
|
||||
|
||||
@@ -39,27 +38,16 @@ export function validateLine(input: {
|
||||
if (input.vatPct !== "" && (Number.isNaN(vatPct) || vatPct < 0 || vatPct > 100))
|
||||
errors.vatPct = "VAT must be 0–100%"
|
||||
|
||||
if (input.trackingMode === "Batch" && !input.batchNo.trim()) {
|
||||
errors.batchNo = "Batch number is required for this item"
|
||||
}
|
||||
|
||||
if (input.trackingMode === "Serial") {
|
||||
const serials = splitSerials(input.serialNumbersText)
|
||||
if (serials.length === 0) {
|
||||
errors.serialNumbers = "Enter one serial number per unit"
|
||||
} else if (!Number.isNaN(qty) && serials.length !== qty) {
|
||||
errors.serialNumbers = `Enter exactly ${qty || 0} serial number(s) — got ${serials.length}`
|
||||
} else if (new Set(serials).size !== serials.length) {
|
||||
errors.serialNumbers = "Serial numbers must be unique"
|
||||
if (input.warranty === "Warranty") {
|
||||
const numbers = input.warrantyNumbers.map((s) => s.trim()).filter((s) => s.length > 0)
|
||||
if (numbers.length === 0) {
|
||||
errors.warrantyNumbers = "Enter one warranty number per unit"
|
||||
} else if (!Number.isNaN(qty) && numbers.length !== qty) {
|
||||
errors.warrantyNumbers = `Enter exactly ${qty || 0} warranty number(s) — got ${numbers.length}`
|
||||
} else if (new Set(numbers.map((s) => s.toLowerCase())).size !== numbers.length) {
|
||||
errors.warrantyNumbers = "Warranty numbers must be unique"
|
||||
}
|
||||
}
|
||||
|
||||
return errors
|
||||
}
|
||||
|
||||
export function splitSerials(text: string): string[] {
|
||||
return text
|
||||
.split(/[\n,]/)
|
||||
.map((s) => s.trim())
|
||||
.filter((s) => s.length > 0)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user