pelagia-portal/App/lib/validations/po.ts
Claude (auto-fix) 25d1164d34 feat(po): allow submitter to set an optional PO date
Add an optional PO Date field to the create and edit PO forms.
Submitters can pick any date (back-dated or forward-dated). If left
blank, the exported PO document falls back to the approved date, then
to the creation date.

Changes:
- Prisma schema: add `poDate DateTime?` to PurchaseOrder
- Migration 20260616000000_add_po_date: ALTER TABLE to add the column
- createPoSchema: add optional `poDate` string field
- new-po-form, edit-po-form: add PO Date picker in Order Information
- create/edit actions: persist poDate to DB
- edit action resubmit snapshot: track poDate changes for manager diff
- po-detail: show PO Date in Order Details; include in resubmit diff banner
- export route: use poDate ?? approvedAt ?? createdAt as the date on
  the exported PDF/XLSX document
- validations.test: fix pre-existing costCentreRef→vesselId mismatch
  and add poDate test cases

Fixes #4

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-16 13:06:12 +05:30

84 lines
3.1 KiB
TypeScript

import { z } from "zod";
export const lineItemSchema = z.object({
name: z.string().min(1, "Item name is required"),
description: z.string().optional(),
quantity: z.coerce.number().positive("Quantity must be positive"),
unit: z.string().min(1, "Unit is required"),
size: z.string().optional(),
unitPrice: z.coerce.number().nonnegative("Unit price must be non-negative"),
gstRate: z.coerce.number().min(0).max(1).default(0.18),
productId: z.string().optional(),
accountId: z.string().optional(),
});
export const TC_FIXED_LINE =
"Please quote this purchase order no. for further communications and invoices pertaining to this indent.";
export const TC_FIXED_LINE_2 =
"We encourage bulk packaging and avoid plastic. No asbestos to be used in any product or packing material.";
export const TC_DEFAULTS = {
tcDelivery: "Within 4 to 5 days",
tcDispatch: "To be transported to site address as above. Freight Supplier's A/C",
tcInspection: "NA",
tcTransitInsurance: "NA",
tcPaymentTerms: "Within 30 days from delivery.",
tcOthers: "",
};
export const createPoSchema = z.object({
title: z.string().min(1, "Title is required").max(200),
vesselId: z.string().min(1, "Cost Centre is required"),
accountId: z.string().min(1, "Accounting Code is required"),
companyId: z.string().optional(),
poDate: z.string().optional(),
projectCode: z.string().optional(),
dateRequired: z.string().optional(),
vendorId: z.string().optional(),
currency: z.string().default("INR"),
piQuotationNo: z.string().optional(),
piQuotationDate: z.string().optional(),
requisitionNo: z.string().optional(),
requisitionDate: z.string().optional(),
placeOfDelivery: z.string().optional(),
tcDelivery: z.string().optional(),
tcDispatch: z.string().optional(),
tcInspection: z.string().optional(),
tcTransitInsurance: z.string().optional(),
tcPaymentTerms: z.string().optional(),
tcOthers: z.string().optional(),
lineItems: z.array(lineItemSchema).min(1, "At least one line item is required"),
});
export const approvePoSchema = z.object({
note: z.string().optional(),
});
export const rejectPoSchema = z.object({
note: z.string().min(1, "A rejection reason is required"),
});
export const requestEditsSchema = z.object({
note: z.string().min(1, "Please specify what edits are needed"),
});
export const processPaymentSchema = z.object({
paymentRef: z.string().min(1, "Payment reference is required"),
paymentAmount: z.number().positive("Payment amount must be greater than 0").optional(),
paymentDate: z.coerce
.date({ required_error: "Payment date is required", invalid_type_error: "Payment date is required" })
.refine((d) => {
// Not in the future — compare against end of today (local)
const endOfToday = new Date();
endOfToday.setHours(23, 59, 59, 999);
return d.getTime() <= endOfToday.getTime();
}, "Payment date cannot be in the future"),
});
export const confirmReceiptSchema = z.object({
notes: z.string().optional(),
});
export type CreatePoInput = z.infer<typeof createPoSchema>;
export type LineItemInput = z.infer<typeof lineItemSchema>;