backfill from projects
This commit is contained in:
@@ -427,7 +427,18 @@ export function PurchaseDetailPage() {
|
||||
</dl>
|
||||
</article>
|
||||
<article className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
||||
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Notes</p>
|
||||
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Project Link</p>
|
||||
{activeDocument.projectId ? (
|
||||
<div className="mt-3 space-y-2">
|
||||
<Link to={`/projects/${activeDocument.projectId}`} className="inline-flex items-center rounded-2xl border border-line/70 px-3 py-2 text-sm font-semibold text-text hover:bg-page/70">
|
||||
{activeDocument.projectNumber} / {activeDocument.projectName}
|
||||
</Link>
|
||||
<p className="text-sm text-muted">This purchase order is linked to the project context used by project cockpit and downstream rollups.</p>
|
||||
</div>
|
||||
) : (
|
||||
<p className="mt-3 text-sm text-muted">No linked project is currently attached to this purchase order.</p>
|
||||
)}
|
||||
<p className="mt-5 text-xs font-semibold uppercase tracking-[0.24em] text-muted">Notes</p>
|
||||
<p className="mt-3 whitespace-pre-line text-sm leading-6 text-text">{activeDocument.notes || "No notes recorded for this document."}</p>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
@@ -14,6 +14,9 @@ export function PurchaseFormPage({ mode }: { mode: "create" | "edit" }) {
|
||||
const { orderId } = useParams();
|
||||
const [searchParams] = useSearchParams();
|
||||
const seededVendorId = searchParams.get("vendorId");
|
||||
const seededProjectId = searchParams.get("projectId");
|
||||
const seededProjectNumber = searchParams.get("projectNumber");
|
||||
const seededProjectName = searchParams.get("projectName");
|
||||
const planningOrderId = searchParams.get("planningOrderId");
|
||||
const selectedPlanningItemId = searchParams.get("itemId");
|
||||
const [form, setForm] = useState<PurchaseOrderInput>(emptyPurchaseOrderInput);
|
||||
@@ -57,6 +60,12 @@ export function PurchaseFormPage({ mode }: { mode: "create" | "edit" }) {
|
||||
api.getInventoryItemOptions(token).then((options) => setItemOptions(options.filter((option: InventoryItemOptionDto) => option.isPurchasable))).catch(() => setItemOptions([]));
|
||||
}, [mode, seededVendorId, token]);
|
||||
|
||||
useEffect(() => {
|
||||
if (mode === "create" && seededProjectId) {
|
||||
setForm((current) => ({ ...current, projectId: current.projectId || seededProjectId }));
|
||||
}
|
||||
}, [mode, seededProjectId]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!token || mode !== "create" || !planningOrderId || itemOptions.length === 0) {
|
||||
return;
|
||||
@@ -103,6 +112,7 @@ export function PurchaseFormPage({ mode }: { mode: "create" | "edit" }) {
|
||||
setForm((current) => ({
|
||||
...current,
|
||||
vendorId: current.vendorId || autoVendorId || "",
|
||||
projectId: current.projectId || seededProjectId || null,
|
||||
notes: current.notes || `Demand-planning recommendation from sales order ${planning.documentNumber}.`,
|
||||
lines: current.lines.length > 0 ? current.lines : recommendedLines,
|
||||
}));
|
||||
@@ -124,7 +134,7 @@ export function PurchaseFormPage({ mode }: { mode: "create" | "edit" }) {
|
||||
.catch(() => {
|
||||
setStatus("Unable to load demand-planning recommendations.");
|
||||
});
|
||||
}, [itemOptions, mode, planningOrderId, seededVendorId, selectedPlanningItemId, token, vendors]);
|
||||
}, [itemOptions, mode, planningOrderId, seededProjectId, seededVendorId, selectedPlanningItemId, token, vendors]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!token || mode !== "edit" || !orderId) {
|
||||
@@ -135,6 +145,7 @@ export function PurchaseFormPage({ mode }: { mode: "create" | "edit" }) {
|
||||
.then((document) => {
|
||||
setForm({
|
||||
vendorId: document.vendorId,
|
||||
projectId: document.projectId,
|
||||
status: document.status,
|
||||
issueDate: document.issueDate,
|
||||
taxPercent: document.taxPercent,
|
||||
@@ -341,6 +352,19 @@ export function PurchaseFormPage({ mode }: { mode: "create" | "edit" }) {
|
||||
<input type="date" value={form.issueDate.slice(0, 10)} onChange={(event) => updateField("issueDate", new Date(event.target.value).toISOString())} className="w-full rounded-2xl border border-line/70 bg-page px-2 py-2 text-text outline-none transition focus:border-brand" />
|
||||
</label>
|
||||
</div>
|
||||
<div className="rounded-[18px] border border-line/70 bg-page/60 px-3 py-3 text-sm">
|
||||
<div className="text-xs font-semibold uppercase tracking-[0.16em] text-muted">Linked Project</div>
|
||||
<div className="mt-2 font-semibold text-text">
|
||||
{mode === "edit"
|
||||
? (form.projectId ? "Project context saved on this purchase order." : "No project linked.")
|
||||
: (seededProjectId ? `${seededProjectNumber || "Project"}${seededProjectName ? ` - ${seededProjectName}` : ""}` : "Will auto-link from sales-order demand when possible.")}
|
||||
</div>
|
||||
<div className="mt-1 text-xs text-muted">
|
||||
{mode === "edit"
|
||||
? "This header link is used for downstream project cockpit and finance rollups."
|
||||
: "Generated purchasing from a project-linked sales order will carry project context automatically."}
|
||||
</div>
|
||||
</div>
|
||||
<label className="block">
|
||||
<span className="mb-2 block text-sm font-semibold text-text">Notes</span>
|
||||
<textarea value={form.notes} onChange={(event) => updateField("notes", event.target.value)} rows={3} className="w-full rounded-[18px] border border-line/70 bg-page px-2 py-2 text-text outline-none transition focus:border-brand" />
|
||||
|
||||
@@ -22,6 +22,7 @@ export const purchaseStatusPalette: Record<PurchaseOrderStatus, string> = {
|
||||
|
||||
export const emptyPurchaseOrderInput: PurchaseOrderInput = {
|
||||
vendorId: "",
|
||||
projectId: null,
|
||||
status: "DRAFT",
|
||||
issueDate: new Date().toISOString(),
|
||||
taxPercent: 0,
|
||||
|
||||
@@ -173,6 +173,9 @@ export function SalesDetailPage({ entity }: { entity: SalesDocumentEntity }) {
|
||||
status: "DRAFT",
|
||||
notes: `Generated from sales order ${activeDocument.documentNumber} demand planning.`,
|
||||
});
|
||||
if (activeDocument.linkedProjectId) {
|
||||
params.set("projectId", activeDocument.linkedProjectId);
|
||||
}
|
||||
|
||||
return `/manufacturing/work-orders/new?${params.toString()}`;
|
||||
}
|
||||
@@ -186,6 +189,15 @@ export function SalesDetailPage({ entity }: { entity: SalesDocumentEntity }) {
|
||||
if (vendorId) {
|
||||
params.set("vendorId", vendorId);
|
||||
}
|
||||
if (activeDocument.linkedProjectId) {
|
||||
params.set("projectId", activeDocument.linkedProjectId);
|
||||
}
|
||||
if (activeDocument.linkedProjectNumber) {
|
||||
params.set("projectNumber", activeDocument.linkedProjectNumber);
|
||||
}
|
||||
if (activeDocument.linkedProjectName) {
|
||||
params.set("projectName", activeDocument.linkedProjectName);
|
||||
}
|
||||
|
||||
return `/purchasing/orders/new?${params.toString()}`;
|
||||
}
|
||||
@@ -521,7 +533,18 @@ export function SalesDetailPage({ entity }: { entity: SalesDocumentEntity }) {
|
||||
</dl>
|
||||
</article>
|
||||
<article className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
||||
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Notes</p>
|
||||
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Project Link</p>
|
||||
{activeDocument.linkedProjectId ? (
|
||||
<div className="mt-3 space-y-2">
|
||||
<Link to={`/projects/${activeDocument.linkedProjectId}`} className="inline-flex items-center rounded-2xl border border-line/70 px-3 py-2 text-sm font-semibold text-text hover:bg-page/70">
|
||||
{activeDocument.linkedProjectNumber} / {activeDocument.linkedProjectName}
|
||||
</Link>
|
||||
<p className="text-sm text-muted">This {entity === "quote" ? "quote" : "sales order"} is already linked to a project, and downstream WO/PO launches will carry that project context.</p>
|
||||
</div>
|
||||
) : (
|
||||
<p className="mt-3 text-sm text-muted">No linked project is currently attached to this {entity === "quote" ? "quote" : "sales order"}.</p>
|
||||
)}
|
||||
<p className="mt-5 text-xs font-semibold uppercase tracking-[0.24em] text-muted">Notes</p>
|
||||
<p className="mt-3 whitespace-pre-line text-sm leading-6 text-text">{activeDocument.notes || "No notes recorded for this document."}</p>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user