Make-An-Order
Point of sale system for managing orders, inventory, and customers
Overview
Make-An-Order is a point of sale system built with Flask and MySQL. Staff can manage orders and inventory. Customers can browse and place orders. Orders trigger SMS notifications.
The system handles three types of users: superuser (godmode), admin (run the business), and operators (use the register). Separate from that, there’s a customer system for buyers. This separation keeps staff accounts out of customer analytics and order data clean.
Core Features
Orders
- Admins place orders on behalf of customers
- Customers place orders through a web interface with code/email lookup
- Orders tracked with status: pending, confirmed, completed, cancelled, refunded
- SMS notification sent to customer phone when order placed
- Each order gets a receipt
Inventory
- Add products with name, SKU, category, price, quantity
- Stock decreases automatically when orders placed
- Can restock items manually
- Cancelled or refunded orders restore stock
- Every stock change is logged (what, why, who, when)
Customers
- Admin creates customer records with name, phone, unique code
- Customers lookup by code or email to place orders
- Complete order history per customer
- Phone number used for SMS notifications
Staff Management
- Google OAuth login for staff
- Three roles: superuser, admin, operator
- Superuser: create/delete users, manage roles
- Admin: manage customers, inventory, orders, see analytics
- Operator: place orders, view history
Reports & Analytics
- Revenue over time
- Top selling products
- Payment method breakdown
- Order status distribution
- Filter by date range
- Download reports as CSV
Technology
| Component | Tech |
|---|---|
| Backend | Flask 3.0 |
| Database | MySQL 5.7+ |
| ORM | SQLAlchemy 2.0 |
| Auth | Google OAuth 2.0 |
| SMS | Africa’s Talking API |
| Frontend | Bootstrap 5.3, Jinja2, Chart.js |
| Hosting | Render, Heroku |
Setup
Prerequisites
- Python 3.8+
- MySQL running locally or on a server
- Google OAuth credentials
- Africa’s Talking account (optional)
Install
git clone https://github.com/Markkimotho/make-an-order.git
cd make-an-order
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
Configure .env
APP_URL=http://localhost:5001
APP_SECRET_KEY=your-secret-key
GOOGLE_CLIENT_ID=your-id.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=your-secret
MYSQL_HOST=127.0.0.1
MYSQL_USER=root
MYSQL_PASSWORD=your-password
MYSQL_DB=customers_orders
AT_USERNAME=sandbox
AT_API_KEY=your-key
AT_SENDER_ID=your-sender-id
Important: Add http://localhost:5001/auth/authorize to Google Console OAuth Authorized redirect URIs.
Run
python3 app.py
Visit http://localhost:5001
API Endpoints
Auth (/auth)
-
GET /auth/login— Start Google OAuth -
GET /auth/authorize— OAuth callback -
POST /auth/login/local— Email/password -
POST /auth/customer-login— Customer lookup -
GET /auth/logout— End session
Inventory (/inventory)
-
GET /api/inventory— Get all products -
POST /api/inventory— Create product (admin+) -
PUT /api/inventory/<id>— Edit product (admin+) -
DELETE /api/inventory/<id>— Delete product (superuser+) -
GET /api/inventory/search?q=term— Search -
POST /api/inventory/restock— Add stock (admin+) -
GET /api/inventory/audit-trail— Stock history
Orders (/orders)
-
POST /api/orders/place_order— Create order -
GET /api/orders/view_orders— Get all (admin+) -
GET /api/orders/<id>— Get order -
PUT /api/orders/<id>— Update status (admin+) -
DELETE /api/orders/<id>— Delete (admin+) -
GET /api/orders/<id>/receipt— Generate receipt -
GET /api/orders/export/csv— Download CSV
Customers (/customers)
-
POST /api/customers/register— Create (admin+) -
GET /api/customers— Get all (admin+) -
GET /api/customers/<id>— Get customer -
PUT /api/customers/<id>— Edit (admin+) -
DELETE /api/customers/<id>— Delete (superuser+)
Users (/users)
-
GET /api/users— Get all (superuser+) -
PUT /api/users/<id>/role— Change role (superuser+) -
PUT /api/users/<id>/customer— Link to customer (superuser+) -
DELETE /api/users/<id>— Delete (superuser+)
Reports (/reports)
-
GET /api/reports/revenue— Revenue by date -
GET /api/reports/top-products— Top sellers -
GET /api/reports/payment-breakdown— By payment type -
GET /api/reports/order-status— Status distribution
Database Schema
users — Staff accounts
- id, email, name, picture_url, role, customer_id, created_at
customers — Buyer records
- id, code, name, phone_number, email, created_at
inventory — Products
- id, name, sku, category, description, price, quantity, reorder_level
orders — Transactions
- id, customer_id, total_amount, status, payment_method, payment_reference, created_at
order_items — Line items
- id, order_id, inventory_id, quantity, unit_price, subtotal
stock_movements — Audit trail
- id, inventory_id, movement_type, quantity_changed, reason, created_by, created_at
Deployments
Render
- Push to GitHub
- Create Web Service from repo
- Set environment variables (same as .env)
- Add database URL to environment
- Deploy
Add to Google Console OAuth: https://your-render-url.com/auth/authorize
Heroku
heroku addons:create jawsdb:kitefingit push heroku mainheroku config:set APP_URL=https://your-app.herokuapp.com ...
Add to Google Console OAuth: https://your-app.herokuapp.com/auth/authorize
Project Structure
make-an-order/
├── api/
│ ├── customers.py
│ ├── inventory.py
│ ├── orders.py
│ ├── reports.py
│ └── users.py
├── auth/
│ └── auth_routes.py
├── services/
│ ├── seed_service.py
│ └── sms_service.py
├── templates/
│ ├── landing.html
│ ├── role_select.html
│ ├── index.html
│ ├── base.html
│ ├── inventory.html
│ ├── customers.html
│ ├── orders.html
│ ├── reports.html
│ └── receipts.html
├── static/
│ └── style.css
├── models.py
├── config.py
├── app.py
└── requirements.txt
Architecture Notes
Users vs Customers
Staff login with Google OAuth and get a User account with a role. Customers are separate records with a phone number and unique code. This keeps staff out of customer lists and prevents confusion about who actually bought something.
Role-Based UI
The inventory page (checkout interface) looks different for admins, operators, and customers. Admins see a customer selector dropdown. Operators see just a place order button. Everything is validated at the API level too.
Stock Audit Trail
Every inventory change gets logged with timestamp, operator ID, quantity change, and reason. This means you can trace any discrepancy back to who changed it and why.
OAuth Configuration
The app takes APP_URL as an environment variable. It builds the redirect URI from that and registers it with Google. This prevents redirect_uri_mismatch errors when deploying to different environments.
SMS Handling
Africa’s Talking integration is wrapped in try/catch. If SMS fails, the order still goes through. SMS is optional.
Testing
pytest tests/
pytest tests/test_orders.py -v
pytest --cov=api tests/
Limitations
- SMS only via Africa’s Talking
- No built-in payment processing (external reference supported)
- No inventory forecasting yet
- No multi-location support yet
Contributing
Issues and PRs welcome on GitHub.
Updated: March 31, 2026