Portix.One

example · applications

Inventory Manager Example

By Portix.One Published
An idempotent stock movement feeding a separate label printing job

Quick answer

Record each stock change as an immutable movement. A scan proposes a movement; server validation accepts or rejects it. Label printing is a separate idempotent job and never changes quantity by itself.

Quick answer

Record each stock change as an immutable movement. A scan proposes a movement; server validation accepts or rejects it. Label printing is a separate idempotent job and never changes quantity by itself.

type Movement = {
  id: string;
  productId: string;
  locationId: string;
  quantityDelta: number;
  reason: "receipt" | "sale" | "transfer" | "adjustment";
  sourceId: string;
  occurredAt: string;
};

async function receive(scan: ReceiveScan) {
  return api.post("/movements", {
    id: crypto.randomUUID(),
    productId: scan.productId,
    locationId: scan.locationId,
    quantityDelta: scan.quantity,
    reason: "receipt",
    sourceId: scan.purchaseOrderId,
    occurredAt: new Date().toISOString()
  });
}

For labels, snapshot product name, identifier, lot, and template version. Use productId:labelVersion:copy as the logical print identity and record whether a copy is an initial issue or reprint. Submitting the immutable label through a local runtime such as Portix isn’t documented yet.

Verify

  • Duplicate movement IDs are rejected safely.
  • Negative-stock policy is explicit.
  • Counts create auditable adjustments.
  • Printed identifiers scan back exactly.
  • Label retries do not add inventory.

Related content