PO logic
This commit is contained in:
@@ -24,6 +24,8 @@ function PlanningNodeCard({ node }: { node: SalesOrderPlanningNodeDto }) {
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-right text-xs text-muted">
|
||||
<div>Linked WO {node.linkedWorkOrderSupply}</div>
|
||||
<div>Linked PO {node.linkedPurchaseSupply}</div>
|
||||
<div>Stock {node.supplyFromStock}</div>
|
||||
<div>Open WO {node.supplyFromOpenWorkOrders}</div>
|
||||
<div>Open PO {node.supplyFromOpenPurchaseOrders}</div>
|
||||
@@ -61,6 +63,8 @@ export function SalesDetailPage({ entity }: { entity: SalesDocumentEntity }) {
|
||||
const canManage = user?.permissions.includes(permissions.salesWrite) ?? false;
|
||||
const canManageShipping = user?.permissions.includes(permissions.shippingWrite) ?? false;
|
||||
const canReadShipping = user?.permissions.includes(permissions.shippingRead) ?? false;
|
||||
const canManageManufacturing = user?.permissions.includes(permissions.manufacturingWrite) ?? false;
|
||||
const canManagePurchasing = user?.permissions.includes(permissions.purchasingWrite) ?? false;
|
||||
|
||||
useEffect(() => {
|
||||
if (!token || !documentId) {
|
||||
@@ -90,6 +94,31 @@ export function SalesDetailPage({ entity }: { entity: SalesDocumentEntity }) {
|
||||
|
||||
const activeDocument = document;
|
||||
|
||||
function buildWorkOrderRecommendationLink(itemId: string, quantity: number) {
|
||||
const params = new URLSearchParams({
|
||||
itemId,
|
||||
salesOrderId: activeDocument.id,
|
||||
quantity: quantity.toString(),
|
||||
status: "DRAFT",
|
||||
notes: `Generated from sales order ${activeDocument.documentNumber} demand planning.`,
|
||||
});
|
||||
|
||||
return `/manufacturing/work-orders/new?${params.toString()}`;
|
||||
}
|
||||
|
||||
function buildPurchaseRecommendationLink(itemId?: string, vendorId?: string | null) {
|
||||
const params = new URLSearchParams();
|
||||
params.set("planningOrderId", activeDocument.id);
|
||||
if (itemId) {
|
||||
params.set("itemId", itemId);
|
||||
}
|
||||
if (vendorId) {
|
||||
params.set("vendorId", vendorId);
|
||||
}
|
||||
|
||||
return `/purchasing/orders/new?${params.toString()}`;
|
||||
}
|
||||
|
||||
async function handleStatusChange(nextStatus: SalesDocumentStatus) {
|
||||
if (!token) {
|
||||
return;
|
||||
@@ -431,12 +460,15 @@ export function SalesDetailPage({ entity }: { entity: SalesDocumentEntity }) {
|
||||
<tr>
|
||||
<th className="px-2 py-2">Item</th>
|
||||
<th className="px-2 py-2">Gross</th>
|
||||
<th className="px-2 py-2">Linked WO</th>
|
||||
<th className="px-2 py-2">Linked PO</th>
|
||||
<th className="px-2 py-2">Available</th>
|
||||
<th className="px-2 py-2">Open WO</th>
|
||||
<th className="px-2 py-2">Open PO</th>
|
||||
<th className="px-2 py-2">Build</th>
|
||||
<th className="px-2 py-2">Buy</th>
|
||||
<th className="px-2 py-2">Uncovered</th>
|
||||
<th className="px-2 py-2">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-line/70 bg-surface">
|
||||
@@ -447,17 +479,46 @@ export function SalesDetailPage({ entity }: { entity: SalesDocumentEntity }) {
|
||||
<div className="mt-1 text-xs text-muted">{item.itemName}</div>
|
||||
</td>
|
||||
<td className="px-2 py-2 text-muted">{item.grossDemand}</td>
|
||||
<td className="px-2 py-2 text-muted">{item.linkedWorkOrderSupply}</td>
|
||||
<td className="px-2 py-2 text-muted">{item.linkedPurchaseSupply}</td>
|
||||
<td className="px-2 py-2 text-muted">{item.availableQuantity}</td>
|
||||
<td className="px-2 py-2 text-muted">{item.openWorkOrderSupply}</td>
|
||||
<td className="px-2 py-2 text-muted">{item.openPurchaseSupply}</td>
|
||||
<td className="px-2 py-2 text-muted">{item.recommendedBuildQuantity}</td>
|
||||
<td className="px-2 py-2 text-muted">{item.recommendedPurchaseQuantity}</td>
|
||||
<td className="px-2 py-2 text-muted">{item.uncoveredQuantity}</td>
|
||||
<td className="px-2 py-2">
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{canManageManufacturing && item.recommendedBuildQuantity > 0 ? (
|
||||
<Link
|
||||
to={buildWorkOrderRecommendationLink(item.itemId, item.recommendedBuildQuantity)}
|
||||
className="rounded-2xl border border-line/70 px-2 py-1 text-xs font-semibold text-text"
|
||||
>
|
||||
Draft WO
|
||||
</Link>
|
||||
) : null}
|
||||
{canManagePurchasing && item.recommendedPurchaseQuantity > 0 ? (
|
||||
<Link
|
||||
to={buildPurchaseRecommendationLink(item.itemId)}
|
||||
className="rounded-2xl border border-line/70 px-2 py-1 text-xs font-semibold text-text"
|
||||
>
|
||||
Draft PO
|
||||
</Link>
|
||||
) : null}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{canManagePurchasing && planning.summary.purchaseRecommendationCount > 0 ? (
|
||||
<div className="mt-4 flex justify-end">
|
||||
<Link to={buildPurchaseRecommendationLink()} className="inline-flex items-center justify-center rounded-2xl border border-line/70 px-3 py-2 text-sm font-semibold text-text">
|
||||
Draft purchase order from recommendations
|
||||
</Link>
|
||||
</div>
|
||||
) : null}
|
||||
<div className="mt-5 space-y-3">
|
||||
{planning.lines.map((line) => (
|
||||
<div key={line.lineId} className="rounded-3xl border border-line/70 bg-page/60 p-3">
|
||||
|
||||
Reference in New Issue
Block a user