Logo Lanfrica

Ahmedyns98/hanouti

Domain:

digital infrastructure

Record type:

software
Creator:
Ahm
Host:
Shop management for small Algerian retailers Django REST API + Arabic RTL frontend # Hanouti shop management for small Algerian retailers A point-of-sale and credit-tracking system built for corner shops (*hanout*), where inventory is counted by eye and customer debt lives in a paper notebook. Most small retailers in Algeria track credit — the *carnet* — by hand. This project digitises that notebook alongside stock and sales, in Arabic, and is designed from the schema up to keep working when the internet does not. --- ## Screens | Screen | What it does | |---|---| | البيع (Sell) | Tap a product to add it to the basket, settle in cash or on credit | | المخزون (Stock) | Current quantities, cost and margin per item, low-stock warnings | | الكارني (Carnet) | Every credit customer with their running balance | The interface is right-to-left Arabic, since the people using it are shopkeepers, not developers. --- ## Stack - **Backend** — Django 6.1, Django REST Framework - **Auth** — JWT (`djangorestframework-simplejwt`) - **Database** — SQLite in development, PostgreSQL in production - **Frontend** — single-file HTML/CSS/JS, served by Django --- ## Design decisions These are the parts worth reading the code for. ### Stock is a ledger, not a number `StockMovement` is append-only: purchases, sales, breakage and corrections are all rows. `Product.qty_on_hand` is a cached total, updated inside the same transaction that writes the movement. Reads stay fast, but the history remains authoritative. If the cache ever drifts, `StockMovement.rebuild_qty()` recomputes it — and the ledger explains when and why it went wrong. ### Prices are snapshotted at sale time `SaleLine` stores `sell_at_sale` and `buy_at_sale` rather than referencing the product's current price. Raising the price of an item tomorrow must not silently rewrite last month's revenue and profit figures. `name_at_sale` serves the same purpose: a discontinued product can be deleted without erasing what was sold. ### Balances are derived, never stored `Customer.balance` is computed as …