Skip to content
Ali Ibrahim
← Projects

2024 – 2025 · Designer, developer, maintainer

APICS CPIM Formula Calculator

A calculator covering all 96 formulas across the seven CPIM modules, shipped as a React web app and a React Native / Expo app for iOS and Android from one shared engine.

Problem

Studying for the APICS CPIM exam means working the formulas until they're automatic — but the reference material scatters them across chapters, with inconsistent notation and no way to check your working quickly on a phone.

Outcome

One tested formula engine, two apps. Used for exam prep and as a day-to-day desk reference; the same engine now powers the live calculator on this site.

Stack

TypeScript · React · React Native · Expo · Vitest · Astro

Formulas
96
Modules
7
Platforms
Web · iOS · Android

The problem, concretely

The CPIM body of knowledge has around 96 formulas spread across seven modules — inventory, forecasting, capacity, master planning, detailed scheduling, execution, and strategy. On their own, none of them is hard. The friction is everywhere else:

  • notation drifts between sources — is it H, or iC, or “annual carrying cost per unit”?
  • the ones you need mid-problem are never on the page you’re looking at
  • there’s no fast way to sanity-check an answer, especially away from a desk

I wanted a single place where every formula is stated once, consistently, with inputs you can actually type numbers into.

Approach

The core decision was to treat the formulas as data, not code paths. Each formula is a self-describing object: its inputs (with units and validation bounds), a pure compute function, a human-readable expression, and an optional plain-English interpretation of the result.

That structure pays off three times over:

  1. One engine, many surfaces. The web app, the mobile app, and this website’s demo all import the same package. There is no re-implementation to keep in sync.
  2. It’s testable. Every formula has unit tests — does EOQ actually return √(2DS/H)? Do ordering and carrying cost balance at the optimum? The suite also asserts registry-wide invariants: unique IDs, every default inside its own bounds, a finite result for every formula from its own defaults.
  3. The UI is generated. Add a formula object and it shows up in the picker, with the right fields, automatically.

The maths, worked live

Take the flagship example — Economic Order Quantity. The textbook statement is a square root, but the why is a cost trade-off: order in big batches and you hold expensive inventory; order in small batches and you pay the ordering cost over and over. EOQ is the quantity where those two costs are equal.

That’s much clearer as a picture than a paragraph, so the case study embeds the actual chart — move the sliders and watch the optimum move:

Ordering costCarrying costTotal cost
Total cost is the sum of the other two curves. Its minimum sits exactly where ordering and carrying cost cross — that crossing point is the EOQ.

The dot tracks the minimum of the total-cost curve. Push holding cost H up and the EOQ shrinks (inventory got expensive, so order less, more often). Push ordering cost S up and it grows. The calculator returns the same number, plus orders-per-year and total annual cost.

Tech notes

  • TypeScript throughout, strict mode. The formula registry fails at import time on a duplicate ID or an unknown module, and the test suite asserts every formula stays finite from its own defaults.
  • Vitest for the engine; it runs in CI on every push.
  • Expo for the mobile build — one React Native codebase to both stores. The shared engine is plain ES modules with no DOM or Node dependencies, so it drops straight in.
  • Statistical helpers (normal CDF / inverse-CDF) are hand-implemented from standard rational approximations rather than pulling in a stats library — keeps the browser bundle small and the mobile app dependency-light.

What I’d do next

Add per-formula worked examples pulled from the study guide, and a “given these three values, which formula do I want?” search. The data-first structure means both are additive, not rewrites.