Package quantities and order types without inconsistent cart rules
Express package rules as one server-owned decision and apply it consistently when products, quantities, and order types change.
In this guide
The same quantity passes one screen and fails another
A buyer adds seven units of a product sold in packs of six. Quick order accepts it, the cart rounds it to twelve, and changing the order type restores seven. Each screen has a piece of the rule, but none owns the complete decision.
Write the commercial policy before implementing the arithmetic. For this fictional example, replenishment orders require whole packs while service orders may allow individual units for eligible products. The complete-pack rule is an explicit project policy layered onto the product's configured quantity limits.
Separate validity from suggested correction
A validator should explain whether a quantity is allowed and, when useful, suggest an alternative. Automatically changing a buyer's quantity can change the order value substantially. Decide whether the user must confirm the adjustment and how that confirmation is represented.
Keep minimum quantity, maximum quantity, pack multiple, and break-pack eligibility as separate concepts. A quantity can be a valid multiple while exceeding a maximum. Invalid configuration, such as a zero package size, needs a clear operational error rather than a division-by-zero exception or a permissive fallback.
Validate complete-pack quantities
whole-pack-suggestion.ts supplies both safe integer arithmetic and a typed decision. validateWholePack checks the configured maximum, applies the pack rule when required, and returns either the accepted quantity or a proposed correction. A suggestion beyond the maximum is withheld.
Resolve pack size and enforcement from server-owned product and order rules. Znode 9 exposes minimum and maximum product quantities, while this complete-pack policy is a project extension. Reapply the decision at direct API entry points and when the order type changes; frontend suggestions provide feedback before the authoritative server decision.
cart/whole-pack-suggestion.ts typescript
export function wholePackSuggestion(quantity: number, packSize: number): number {
if (!Number.isSafeInteger(quantity) || quantity < 1 ||
!Number.isSafeInteger(packSize) || packSize < 1) {
throw new RangeError("Positive safe integers are required.");
}
const result = Math.ceil(quantity / packSize) * packSize;
if (!Number.isSafeInteger(result)) {
throw new RangeError("Suggested quantity is out of range.");
}
return result;
}
export type PackDecision =
| { valid: true; quantity: number }
| { valid: false; suggested: number | null; message: string };
export function validateWholePack(
quantity: number, pack: number, maximum: number, enforce: boolean
): PackDecision {
if (!Number.isSafeInteger(maximum) || maximum < 1)
throw new RangeError("Maximum must be a positive safe integer.");
const suggested = wholePackSuggestion(quantity, pack);
if (quantity > maximum)
return { valid: false, suggested: null, message: "Quantity exceeds the maximum." };
if (enforce && suggested !== quantity)
return { valid: false, suggested: suggested <= maximum ? suggested : null,
message: "This order requires complete packs." };
return { valid: true, quantity };
}
// Resolve enforce, pack and maximum from the server's current product/order policy.
// Present a suggested quantity for buyer confirmation before applying it.
Revalidate transitions, not just additions
The rule must run when a line is added, its quantity changes, or the order type changes. It may also need to run when a saved cart is restored, an account switches, or product packaging changes. A previously valid cart is not permanently valid.
Keep the authoritative decision on the server so direct API requests and alternative ordering screens receive the same result. Frontend validation can provide quick feedback, but should consume the same policy information and display the server's final decision. Avoid trusting a browser field that claims a product is eligible for individual-unit ordering.
Build a small rule matrix
Test one product with a pack size of six and another with a pack size of one. Try quantities one, six, seven, twelve, zero, a fraction, and a value beyond the supported range. Vary the fictional order type and break-pack eligibility independently.
Switch order type after valid lines already exist. Verify that the cart reports every newly invalid line and that a suggested adjustment does not silently bypass limits. Exercise quick order, ordinary add-to-cart, saved-cart restoration, and direct API updates. Inspect recalculated totals after accepted corrections, including any shipping dependencies.
- Keep the original requested quantity available for explanation.
- Do not infer policy from translated order-type display labels.
- Test invalid product configuration as well as invalid buyer input.
Make the correction understandable
A useful message explains the rule and the consequence: this item requires packs of six for the selected order type; the next valid quantity is twelve. If confirmation is required, keep checkout blocked until the buyer accepts or changes the input.
A consistent cart rule reduces support friction because every entry point tells the same story. More importantly, it prevents interface-specific shortcuts from changing the commercial meaning of an order. The arithmetic should be the easy part; policy ownership, transitions, and clear correction behavior are what make the implementation reliable.
References and further reading
Independent guidance from GCG. Znode is a trademark of its owner. Examples use fictional data and are not official platform documentation. Suggest a correction.