HomeAboutExperienceProjectsContactBlog
RésuméDex0/17
← Projects

Order forecasting for Papa Johns

Per-store, per-hour order forecasts set against what the staff on shift can handle.

PASTDAYSNEXT1 STAFF = 20/HR2 STAFF3 STAFF80%OPEN061218

Friday 18:00 to 19:00: 63 orders forecast against room for 60 (3 staff × 20), which is 105.0%, so the slot is closed. 10 of 24 slots that day are closed.

The orders are made up. With only two weeks of them the real pipeline can't fit its hourly SARIMAX models either, so it falls back to this: the mean of the same weekday in past weeks, then its slot rule.

Each hour's column of past days gets its own SARIMAX model with a weekly cycle, and its forecast for the chosen day is checked against that hour's capacity: the staff on shift (one, two or three) times 20 orders. The pipeline marks a slot open while the forecast is under 80% of capacity; the numbers drawn here are made up.

University of Kentucky senior design, sponsored by Papa Johns. The system learns how many orders each store gets in each hour, forecasts the next day, and compares that to staffing capacity hour by hour, marking a slot open while the forecast stays under 80% of it. A Flask API and React page let you pick a store and date and see each hour's forecast against capacity.

The problem

Online ordering needs to know which pickup and delivery windows to offer without overbooking the kitchen. That's a forecasting problem (how many orders will this store get at 6 p.m. Thursday?) feeding a capacity problem (can the staff on shift absorb them?).

How it's put together

REACT PAGEFLASK APISTORE, DATEJSONSUBPROCESSCSVRUN.PY --RUN_ALLORDER CSVSFEATURESSARIMAX ×241 PER HOURSLOTSSTAFF × 20HIST. MEAN
Each request from the page runs the whole pipeline for that store in a subprocess, from the raw order files to refitting up to 24 hourly models, and the Flask API returns the slots CSV it writes as JSON. When no hourly model can forecast, the day falls back to the historical mean for each hour on that weekday.

What I took from it

Small per-hour series and long forecast horizons make SARIMAX unstable; the fallback path mattered more than expected.

Capacity was a stated rule of thumb (staff × 20 orders an hour), not learned. The next step was learning it from prep-time data.

Next: YapinA macOS menu-bar app: press a hotkey, talk, and styled text is pasted wherever you are.

Year
2025
Platform
Python + React
Status
Senior design, spring 2025
Code
Private
Built with
Python, pandas, statsmodels (SARIMAX), XGBoost, Flask, React, Vite
  • 1 model per store-hour
  • s = 7 weekly seasonality
  • 121 stores in the sample
  • 80/20 chronological split

The code is private, so this page is an overview.