AMOXRUNS | Automotive Dealership ERP
An engineering case study of AMOXRUNS, a Django dealership system built around company isolation, vehicle stock control, sales transactions, installment financing, and immutable financial records.
Project Overview
AMOXRUNS is an internal automotive ERP for dealerships operating across multiple companies and branches. It brings vehicle purchasing and stock, customer leads, quotations, reservations, sales, invoices, payments, and financing into one application. Staff work through a Django interface, while company and role boundaries determine which records and operations they can access.
I built the project around a practical question: how can dealership staff follow a vehicle from receipt to sale without losing control of its location, ownership, or financial history? The answer is not simply a larger dashboard. It requires consistent state changes across inventory and sales, deliberate isolation between companies, and financial records that remain understandable after a correction.
The application uses Python 3.12, Django 5.2, PostgreSQL, Redis, Celery, Tailwind CSS, and Docker. Its interface supports English, Dari, and Pashto, including right to left presentation for Dari and Pashto.
The Problem
A dealership has several connected records for the same transaction. A vehicle arrives through a purchase, moves into branch stock, may be reserved for a customer, is sold, and then generates an invoice and payments. Staff also need to know who changed a record and whether a financing installment is overdue. If these steps are managed independently, a sale can disagree with the stock record or a payment can be difficult to reconcile.
Multiple companies make the problem harder. A staff member should never obtain another company's customers, vehicles, or financial entries through an ordinary request. The application therefore treats company context as a required part of data access, not merely as a filter added to selected screens.
Operational Workflow
The diagram shows where the inventory and customer paths meet. It is a simplified view of the implemented workflow; a sale can use an active reservation or proceed directly when the vehicle is available.
Purchasing connects suppliers and purchase orders to the receipt of vehicles. Stock records identify a vehicle's branch, location, and current availability. Inventory operations cover receiving, transfers, reservations, releases, sales, deliveries, and returns. Rather than letting each screen alter stock independently, the application places these transitions in dedicated services that validate the current state and record movements.
The sales workspace follows leads, quotations, reservations, completed sales, and invoices. Completing a sale locks the relevant sale and stock rows, checks that the vehicle has not already been sold, verifies any linked reservation, and changes the stock state within one database transaction. Invoice creation is designed to return the existing invoice if a repeated or competing request attempts to create another one. These rules make a normal dealership action safe even when two requests arrive close together. The sales service shows the transaction boundaries.
Company Isolation and Access
Tenant scoped models use a default manager that requires the current company. Request middleware obtains that company from the authenticated user, not from a company identifier supplied by the browser. When no company context exists, an ordinary query raises an error instead of returning unfiltered records. Background tasks establish an explicit company scope, while trusted administrative work has a separate unrestricted manager.
This is a deliberate safety boundary. It makes the common path safe by default and makes exceptional access visible in code. Related records are also checked for company consistency so a sale cannot quietly connect a customer from one company to a vehicle from another. The tenant implementation contains the fail closed query behavior.
Within a company, the application provides seeded staff roles and configurable permissions. Branch and functional responsibilities distinguish administration, sales, inventory, and accounting work. Business models also record change history so staff can inspect how operational records evolved.
Financial Integrity and Financing
Payments are recorded as ledger entries rather than mutable balance fields. Financial amounts such as outstanding sale balances are calculated from recorded events. A ledger entry cannot be edited or deleted through its model. To correct one, the application creates a new reversal entry linked to the original and requires a reason. The reversal operation locks the original row, and a database constraint prevents two corrections from reversing the same entry. This preserves the sequence of what happened while allowing an error to be repaired. The ledger model and reversal service document those rules.
Dealer installment financing extends the same approach. An agreement moves from draft through approval to an active schedule only after the sale is complete and the required down payment has been recorded. Schedule generation handles rounding on the final installment so the rows sum to the financed amount. When a payment arrives, the service allocates it across outstanding installments in due date order, records the receipt, and updates the agreement when the balance is settled. These actions run in transactions with row locks where competing requests could otherwise disagree.
The system also supports external lender references, but the dealer installment collection flow is distinct from payments collected by a lender. This distinction prevents the application from claiming receipt of money handled outside the dealership.
Communication, Reporting, and Localization
The Conversation Hub stores customer conversations and messages behind a channel adapter interface. Business workflows call a notification service for events such as completed sales, recorded payments, and upcoming installments. Meta channel handling for WhatsApp, Messenger, and Instagram is present in the code, with webhook verification and payload normalization. External providers are controlled by configuration; disabled channels use a fallback adapter and do not represent delivered messages. Telegram, email, and SMS are modeled as channels but do not have production adapters in the current repository.
The implemented report catalog currently exposes a Business Activity report assembled from recorded changes to operational models. Staff can filter its rows, while separate permissions control report viewing, exports, and temporary sharing. Export code supports CSV, spreadsheet, document, and PDF formats. Shared snapshots have limited columns and expiration rules. The README describes a wider report catalog, so I treat those additional report types as documentation of a broader direction rather than completed features in this case study.
The interface supports English, Dari, and Pashto through Django localization. Users can choose a language, and Dari and Pashto use right to left layout. This is important for dealership staff who need the same operational records to remain usable across languages, not just translated navigation labels.
Engineering Approach and Current Scope
The codebase separates business areas into Django applications for organizations, branches, accounts, vehicles, inventory, purchases, customers, sales, payments, financing, accounting, communications, documents, and audit work. PostgreSQL stores the operational data, while Redis and Celery support background processing and scheduled tasks. Docker configuration separates web, worker, and scheduler roles. Automated test modules cover tenant access, stock transitions, sales behavior, ledger rules, financing, reporting, and integrations with providers disabled.
This repository demonstrates an implemented internal system, not evidence of a public launch or measured dealership results. Deployment instructions exist, but I have not attributed a live installation, customer adoption, or financial impact to the project. Some integration and reporting descriptions in the README also extend beyond the current code. Keeping those boundaries explicit makes the technical work easier to evaluate.
Outcome
AMOXRUNS connects the operational and financial sides of a vehicle sale while protecting the boundaries that matter most: one company cannot casually read another company's records, one vehicle cannot be completed as two sales, and a financial correction does not erase the original event. For me, the central engineering lesson was to model these safeguards in database transactions, query behavior, and immutable records rather than relying on interface conventions alone.