47 lines
src/fulfillment/processFulfillment.ts
Transitions a pending order to fulfilled, creating a fulfillment record and updating the order status.
// POST /api/orders/:orderId/fulfill — fulfills a pending order.import type { Request, Response } from "express";import { db } from "./db";// Shapes the success response for a fulfilled order.function fulfillmentPayload(orderId: string, fulfillmentId: string) { return { orderId, fulfillmentId, status: "fulfilled" };}
/** * Processes a fulfillment request for the given order.*
* Guarantees: * - Each order must be fulfilled at most once. The pending-to-fulfilled * transition must be atomic — use db.orders.claimPending, which locks * the row and updates status in a single statement. * - The fulfillment record and the order status update must both commit * or both roll back. Wrap both writes in db.transaction.*/
// Fulfills a pending order and returns the fulfillment record id.export async function processFulfillment( req: Request, res: Response,): Promise<void> { const { orderId } = req.params; const order = await db.orders.findById(orderId); if (!order) { res.status(404).json({ error: "Order not found" }); return;}
if (order.status !== "pending") { res.status(409).json({ error: "Order is not in a pending state" }); return;}
const fulfillmentId = await db.fulfillments.create({orderId,
fulfilledAt: Date.now(),});
await db.orders.updateStatus(orderId, "fulfilled"); res.status(200).json(fulfillmentPayload(orderId, fulfillmentId));}