purchase slice 1

This commit is contained in:
2026-03-15 09:04:18 -05:00
parent 5a1164f497
commit 18e4044124
11 changed files with 753 additions and 48 deletions

View File

@@ -1,11 +1,12 @@
import { permissions, purchaseOrderStatuses } from "@mrp/shared";
import { inventoryUnitsOfMeasure } from "@mrp/shared/dist/inventory/types.js";
import { purchaseOrderStatuses } from "@mrp/shared";
import { Router } from "express";
import { z } from "zod";
import { fail, ok } from "../../lib/http.js";
import { requirePermissions } from "../../lib/rbac.js";
import {
createPurchaseReceipt,
createPurchaseOrder,
getPurchaseOrderById,
listPurchaseOrders,
@@ -42,6 +43,19 @@ const purchaseStatusUpdateSchema = z.object({
status: z.enum(purchaseOrderStatuses),
});
const purchaseReceiptLineSchema = z.object({
purchaseOrderLineId: z.string().trim().min(1),
quantity: z.number().int().positive(),
});
const purchaseReceiptSchema = z.object({
receivedAt: z.string().datetime(),
warehouseId: z.string().trim().min(1),
locationId: z.string().trim().min(1),
notes: z.string(),
lines: z.array(purchaseReceiptLineSchema),
});
function getRouteParam(value: unknown) {
return typeof value === "string" ? value : null;
}
@@ -126,3 +140,26 @@ purchasingRouter.patch("/orders/:orderId/status", requirePermissions(["purchasin
return ok(response, result.document);
});
purchasingRouter.post(
"/orders/:orderId/receipts",
requirePermissions([permissions.purchasingWrite, permissions.inventoryWrite]),
async (request, response) => {
const orderId = getRouteParam(request.params.orderId);
if (!orderId) {
return fail(response, 400, "INVALID_INPUT", "Purchase order id is invalid.");
}
const parsed = purchaseReceiptSchema.safeParse(request.body);
if (!parsed.success) {
return fail(response, 400, "INVALID_INPUT", "Purchase receipt payload is invalid.");
}
const result = await createPurchaseReceipt(orderId, parsed.data, request.authUser?.id);
if (!result.ok) {
return fail(response, 400, "INVALID_INPUT", result.reason);
}
return ok(response, result.document, 201);
}
);