finish bills , po , jobcards relational fields creation
This commit is contained in:
@@ -16,8 +16,11 @@ import { useResourceForm } from "@/shared/hooks/use-resource-form"
|
||||
import { useFormMutation } from "@/shared/hooks/use-form-mutation"
|
||||
import { toId, toRelation } from "@/shared/lib/utils"
|
||||
import { useAuthApi } from "@/shared/useApi"
|
||||
import { BillStatus, BILL_ROUTES, DEPARTMENT_ROUTES, JOB_CARD_ROUTES, PAYMENT_TERM_ROUTES, VENDOR_ROUTES } from "@garage/api"
|
||||
import { BillStatus, BILL_ROUTES, DEPARTMENT_ROUTES, JOB_CARD_ROUTES, PAYMENT_TERM_ROUTES, PURCHASE_ORDER_ROUTES, VENDOR_ROUTES } from "@garage/api"
|
||||
import { toast } from "sonner"
|
||||
import { PartsSelectorField } from "@/modules/parts/parts-selector-field"
|
||||
import { ServicesSelectorField } from "@/modules/services/services-selector-field"
|
||||
import { ExpenseItemsSelectorField } from "@/modules/expense-items/expense-items-selector-field"
|
||||
|
||||
import { billFormSchema, type BillFormValues } from "./bill.schema"
|
||||
|
||||
@@ -29,14 +32,19 @@ export type BillFormProps = {
|
||||
|
||||
const DEFAULT_VALUES: BillFormValues = {
|
||||
vendor: null,
|
||||
purchase_order: null,
|
||||
job_card: null,
|
||||
payment_term: null,
|
||||
department: null,
|
||||
title: "",
|
||||
bill_number: "",
|
||||
bill_date: "",
|
||||
bill_due_date: "",
|
||||
status: "draft",
|
||||
notes: "",
|
||||
part_items: [],
|
||||
service_items: [],
|
||||
expense_items: [],
|
||||
}
|
||||
|
||||
const STATUS_OPTIONS = BillStatus.map((value) => ({
|
||||
@@ -56,14 +64,37 @@ function mapToFormValues(data: unknown): BillFormValues {
|
||||
|
||||
return {
|
||||
vendor: toRelation(d.vendor_id, d.vendor_name),
|
||||
purchase_order: toRelation(d.purchase_order_id, d.purchase_order_number ?? d.purchase_order_title),
|
||||
job_card: toRelation(d.job_card_id, d.job_card_number ?? d.job_card_name),
|
||||
payment_term: toRelation(d.payment_terms_id, d.payment_terms_name),
|
||||
department: toRelation(d.department_id, d.department_name),
|
||||
title: d.title || "",
|
||||
bill_number: d.bill_number || "",
|
||||
bill_date: d.bill_date || "",
|
||||
bill_due_date: d.bill_due_date || "",
|
||||
status: d.status || "draft",
|
||||
notes: d.notes || "",
|
||||
part_items: (d.parts ?? []).map((p: any) => ({
|
||||
part_id: p.part_id ?? p.id,
|
||||
title: p.part?.title ?? p.title ?? "",
|
||||
quantity: Number(p.quantity) || 1,
|
||||
rate: Number(p.rate) || 0,
|
||||
description: p.description ?? "",
|
||||
})),
|
||||
service_items: (d.services ?? []).map((s: any) => ({
|
||||
service_id: s.service_id ?? s.id,
|
||||
title: s.service?.labor_name ?? s.labor_name ?? s.title ?? "",
|
||||
quantity: Number(s.quantity) || 1,
|
||||
rate: Number(s.rate) || 0,
|
||||
description: s.description ?? "",
|
||||
})),
|
||||
expense_items: (d.expenses ?? []).map((e: any) => ({
|
||||
expense_id: e.expense_id ?? e.id,
|
||||
title: e.expense?.item_name ?? e.item_name ?? e.title ?? "",
|
||||
quantity: Number(e.quantity) || 1,
|
||||
rate: Number(e.rate) || 0,
|
||||
description: e.description ?? "",
|
||||
})),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,13 +102,33 @@ function mapFormToPayload(values: BillFormValues) {
|
||||
return {
|
||||
title: values.title,
|
||||
vendor_id: toId(values.vendor),
|
||||
purchase_order_id: toId(values.purchase_order),
|
||||
job_card_id: toId(values.job_card),
|
||||
payment_terms_id: toId(values.payment_term),
|
||||
department_id: toId(values.department),
|
||||
bill_number: values.bill_number || undefined,
|
||||
bill_date: values.bill_date || undefined,
|
||||
bill_due_date: values.bill_due_date || undefined,
|
||||
status: values.status || undefined,
|
||||
notes: values.notes || undefined,
|
||||
part_items: (values.part_items ?? []).map((item) => ({
|
||||
part_id: item.part_id,
|
||||
quantity: item.quantity,
|
||||
rate: item.rate,
|
||||
description: item.description || undefined,
|
||||
})),
|
||||
service_items: (values.service_items ?? []).map((item) => ({
|
||||
service_id: item.service_id,
|
||||
quantity: item.quantity,
|
||||
rate: item.rate,
|
||||
description: item.description || undefined,
|
||||
})),
|
||||
expense_items: (values.expense_items ?? []).map((item) => ({
|
||||
expense_id: item.expense_id,
|
||||
quantity: item.quantity,
|
||||
rate: item.rate,
|
||||
description: item.description || undefined,
|
||||
})),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,6 +177,11 @@ export function BillForm({ resourceId, initialData, onSuccess }: BillFormProps)
|
||||
<FieldGroup>
|
||||
<RhfTextField name="title" label="Title" placeholder="Enter bill title" required />
|
||||
|
||||
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
|
||||
<RhfTextField name="bill_number" label="Bill Number" placeholder="e.g. BILL-001" />
|
||||
<RhfSelectField name="status" label="Status" options={STATUS_OPTIONS} />
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
|
||||
<RhfTextField name="bill_date" label="Bill Date" type="date" />
|
||||
<RhfTextField name="bill_due_date" label="Due Date" type="date" />
|
||||
@@ -173,9 +229,25 @@ export function BillForm({ resourceId, initialData, onSuccess }: BillFormProps)
|
||||
/>
|
||||
</div>
|
||||
|
||||
<RhfSelectField name="status" label="Status" options={STATUS_OPTIONS} />
|
||||
<RhfAsyncSelectField
|
||||
name="purchase_order"
|
||||
label="Purchase Order"
|
||||
placeholder="Select purchase order"
|
||||
queryKey={[PURCHASE_ORDER_ROUTES.INDEX]}
|
||||
listFn={() => api.purchaseOrders.list()}
|
||||
mapOption={(item: any) => ({
|
||||
value: String(item.id),
|
||||
label: item.order_number || item.title || `#${item.id}`,
|
||||
})}
|
||||
{...STORE_OBJECT}
|
||||
/>
|
||||
|
||||
<RhfTextareaField name="notes" label="Notes" rows={3} />
|
||||
|
||||
<PartsSelectorField<BillFormValues, "part_items"> name="part_items" />
|
||||
<ServicesSelectorField<BillFormValues, "service_items"> name="service_items" />
|
||||
<ExpenseItemsSelectorField<BillFormValues, "expense_items"> name="expense_items" />
|
||||
|
||||
<Button type="submit" disabled={isPending}>
|
||||
{isPending ? (
|
||||
"Saving..."
|
||||
@@ -195,3 +267,4 @@ export function BillForm({ resourceId, initialData, onSuccess }: BillFormProps)
|
||||
</Rhform>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -4,19 +4,51 @@ const relationFieldSchema = z
|
||||
.object({ value: z.string(), label: z.string() })
|
||||
.nullable()
|
||||
|
||||
const billPartItemSchema = z.object({
|
||||
part_id: z.number(),
|
||||
title: z.string(),
|
||||
quantity: z.number().min(1),
|
||||
rate: z.number().min(0),
|
||||
description: z.string().optional(),
|
||||
})
|
||||
|
||||
const billServiceItemSchema = z.object({
|
||||
service_id: z.number(),
|
||||
title: z.string(),
|
||||
quantity: z.number().min(1),
|
||||
rate: z.number().min(0),
|
||||
description: z.string().optional(),
|
||||
})
|
||||
|
||||
const billExpenseItemSchema = z.object({
|
||||
expense_id: z.number(),
|
||||
title: z.string(),
|
||||
quantity: z.number().min(1),
|
||||
rate: z.number().min(0),
|
||||
description: z.string().optional(),
|
||||
})
|
||||
|
||||
const billFormSchema = z.object({
|
||||
vendor: relationFieldSchema,
|
||||
purchase_order: relationFieldSchema,
|
||||
job_card: relationFieldSchema,
|
||||
payment_term: relationFieldSchema,
|
||||
department: relationFieldSchema,
|
||||
title: z.string().min(1, "Title is required"),
|
||||
bill_number: z.string().optional(),
|
||||
bill_date: z.string().optional(),
|
||||
bill_due_date: z.string().optional(),
|
||||
status: z.string().optional(),
|
||||
notes: z.string().optional(),
|
||||
part_items: z.array(billPartItemSchema).optional(),
|
||||
service_items: z.array(billServiceItemSchema).optional(),
|
||||
expense_items: z.array(billExpenseItemSchema).optional(),
|
||||
})
|
||||
|
||||
type BillFormValues = z.infer<typeof billFormSchema>
|
||||
type BillPartItem = z.infer<typeof billPartItemSchema>
|
||||
type BillServiceItem = z.infer<typeof billServiceItemSchema>
|
||||
type BillExpenseItem = z.infer<typeof billExpenseItemSchema>
|
||||
|
||||
export { billFormSchema, relationFieldSchema }
|
||||
export type { BillFormValues }
|
||||
export { billFormSchema, relationFieldSchema, billPartItemSchema, billServiceItemSchema, billExpenseItemSchema }
|
||||
export type { BillFormValues, BillPartItem, BillServiceItem, BillExpenseItem }
|
||||
|
||||
Reference in New Issue
Block a user