The till is the worst place for surprises
Back-office users will tolerate a slow form or a confusing error. A cashier with six people waiting won’t, and neither will the customer at the front of the line. So the first question we ask about any POS change isn’t “can we build it?” It’s “where should this rule run?”
Most requests from head office are really audit requests. They want to know about big refunds, odd discounts and cash that doesn’t add up. None of that has to happen during the sale. It can happen when the session closes, when the day ends, or on a schedule. Rules that genuinely must stop a sale, like an age check on certain products, belong in the till screen, where they can prompt the cashier politely instead of failing on the server.
What a custom POS system from erpfly changes, and what it leaves alone
We change the rules around the till. We don’t rebuild the till.
On Odoo, the POS interface is an OWL application. Front-end changes go in as patches to existing components, while settings, computed totals and follow-up tasks live in Python on pos.config, pos.session and pos.order. Receipts are QWeb templates that we extend.
On ERPNext, the Point of Sale page works with POS Profile, POS Opening Entry, POS Invoice and POS Closing Entry. At closing, POS Invoices are merged into regular Sales Invoices. That makes closing the natural hook for reviews and reconciliation. Changes to the page itself are loaded through page_js in hooks.py, from your own app.
If you haven’t picked a platform yet, POS is one of the areas where the two differ most in how they feel to customise. Our ERPNext vs Odoo comparison covers that in more detail.
Example: refunds at three garden centres
Take a small chain of three garden centres on Odoo. Refunds are a normal part of the business, since plants die and customers bring back the wrong size of pot. Head office doesn’t want cashiers phoning a manager for every one. It does want to know when a single session runs heavy on refunds.
The rule they settled on: if a session closes with more than $150 in refunds, the store manager gets a to-do listing them. On a Saturday, store two closes a session with six refunds totalling $410. The session closes normally, the cashier goes home, and on Monday the store manager finds a task linked to that session. Four of the refunds are dead hedging plants from one bad delivery. The store manager ends up calling the supplier, not questioning the cashier.
Store one sets its limit to $250 because it’s the busiest site. That’s a setting on the POS configuration, not a code change. The snippet above is most of the module.
On ERPNext the same rule would hang off the POS Closing Entry. When the cashier submits the closing, a hook totals the return invoices in that period and creates a ToDo for the manager named on the POS Profile. Same idea, different nouns. Either way, the review happens once per session instead of once per refund, which is roughly the difference between a manager who reads the alerts and one who mutes them.
Requests that cause trouble at the till
- Server-side validation that rejects synced orders. If an offline till creates an order your Python rule refuses, that sale is stuck between the till and the database. Put hard stops in the till screen, or flag afterwards.
- A home-built till interface. The standard POS on both platforms handles offline mode, payments and session control. Replacing it is a large project that you then maintain forever.
- Loyalty schemes with a dozen tiers. Start with points and one reward. Complicated schemes confuse cashiers first, then customers.
Stock, pricing and the rest of retail
A till is only as good as the stock and prices behind it. Store-level counts and transfers belong in inventory management, and wholesale or trade orders that start in-store usually want a proper sales order flow. For the wider picture of running shops on either platform, see our page on ERP for retail. Cafés and restaurants have a different set of problems, covered under food and beverage.