From fcccf22bac36db4819603ac8fbfd4110ed7235b3 Mon Sep 17 00:00:00 2001 From: Anbarasu22004 Date: Wed, 29 Jul 2026 11:41:09 +0530 Subject: [PATCH] first commit --- README.md | 148 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..0bafbf9 --- /dev/null +++ b/README.md @@ -0,0 +1,148 @@ +# Nearle POS + +An enterprise Point of Sale terminal for supermarkets, grocery stores, pharmacies and retail shops. Built for **Flutter Desktop** (Windows/macOS/Linux) and **Android tablets**. + +Brand colour `#662582` · Inter typeface · 16px corner radius · touch-first targets. + +--- + +## Getting started + +```bash +flutter pub get +flutter run -d windows # or macos, linux, or a connected tablet +flutter test # 60+ unit and widget tests +flutter analyze +``` + +Requires Flutter 3.27 / Dart 3.6 or newer. See [Version compatibility](#version-compatibility) if `flutter analyze` complains about theme types. + +--- + +## Architecture + +Clean architecture in three layers. Dependencies point inward only: `presentation → domain ← data`. The domain layer imports nothing from Flutter, which is what makes the pricing engine testable in isolation. + +``` +lib/ +├── main.dart Entry point: orientation lock, store + audio warmup +├── app/ +│ ├── app.dart MaterialApp.router, global shortcuts, text-scale lock +│ └── providers.dart Dependency injection graph, cashier session, clock +│ +├── core/ +│ ├── constants/ Store details, GST rates, loyalty ratios, asset paths +│ ├── theme/ Colours, 4pt spacing scale, typography, ThemeData +│ ├── router/ GoRouter routes and page transitions +│ ├── services/ Barcode capture, scanner beeps, thermal receipt PDF +│ ├── utils/ Formatters, validators, BuildContext extensions +│ └── widgets/ GlassCard, PrimaryButton, NumericKeypad, StatusPill +│ +├── domain/ Pure Dart — no Flutter imports +│ ├── entities/ Product, Customer, Cart, SaleTransaction +│ ├── repositories/ Abstract contracts +│ └── usecases/ CheckoutSale +│ +├── data/ +│ ├── datasources/ LocalStore (swappable), seed catalogue +│ └── repositories/ Concrete implementations +│ +└── presentation/ One folder per feature: screens / widgets / providers + ├── welcome/ customer/ pos/ payment/ receipt/ +``` + +### Why the domain layer is pure + +`Cart` is an immutable value object that computes every figure on the bill as a getter — subtotal, per-slab GST, membership discount, loyalty redemption, round-off, points earned. No widget, repository or provider participates in the arithmetic. That means the money maths is covered by fast unit tests with no `pumpWidget` and no mocking, and swapping `LocalStore` for Hive or a REST backend changes nothing above the data layer. + +--- + +## The five screens + +| Screen | What it does | +|---|---| +| **Welcome** | Three entry paths: New Customer, Existing Customer, Skip (walk-in). Vector illustration painted in code, so it stays crisp at 4K. | +| **Customer Registration** | Mobile + name required; email, gender, DOB optional. Saves and drops straight into billing. | +| **Existing Customer** | Large numeric keypad, auto-searches on the 10th digit. Shows name, tier, points and lifetime spend, or offers Register / Walk-in when nothing matches. | +| **POS Dashboard** | Three columns: navigation, product grid, always-visible bill. Category chips, live search, barcode billing. | +| **Payment** | Cash, Card, UPI, Wallet, Gift Card and arbitrary splits. Live change calculation with denomination shortcuts. | +| **Receipt** | Success summary beside a paper-style preview. Counts down and starts the next sale on its own. | + +--- + +## Fast cashier workflow + +**Barcode billing has no dialogs.** `BarcodeService` listens to `HardwareKeyboard` globally rather than depending on a text field holding focus. It distinguishes a scanner from a human by keystroke timing — characters arriving faster than `barcodeScanTimeout` (120ms apart) are treated as a scan, so the cashier can still type into the same search box by hand. On a hit the item is added or its quantity incremented, a beep plays, and a floating toast confirms it. Nothing ever needs dismissing between items. + +**Other workflow details:** + +- Tapping a product card bills it immediately; the card shows a live quantity badge. +- Newest cart line renders first, mirroring what was just scanned. +- Every mutation goes through `CartController`, so scanner input, taps and shortcuts share one code path — and one undo stack (F8). +- Swipe a cart line to remove it. +- `F2` focuses search, `Esc` releases it. +- Bills can be parked and resumed. +- Stock is checked before adding, not after — an over-scan beeps and refuses rather than failing at checkout. + +--- + +## Pricing engine + +Prices are GST-inclusive, per Indian retail convention, so tax is extracted rather than added. + +- **Per-product GST slabs.** Vegetables at 0%, milk at 5%, biscuits at 18%, aerated drinks at 28%. The receipt breaks GST out per slab, split into CGST and SGST. +- **Bill-level discounts are apportioned.** When a membership discount or manual discount reduces the bill, the GST charged is scaled by the same factor rather than left at the pre-discount figure. +- **Membership tiers are automatic.** Bronze / Silver / Gold / Platinum derive from lifetime spend and carry 0 / 2 / 5 / 8 percent off, applied without cashier action. +- **Loyalty.** One point per ₹10 spent; each point is worth ₹0.25 on redemption. Redemption is capped at both the balance held and the bill value, and re-clamps automatically if the bill shrinks after points were applied. +- **Round-off** to the nearest rupee is shown as its own line. +- All money passes through an `asMoney` extension that rounds to two decimals, so floating-point drift never reaches a total. + +--- + +## Testing + +```bash +flutter test +``` + +- `test/unit/cart_test.dart` — the pricing engine: GST extraction, discount stacking, apportionment, loyalty caps, tier thresholds, round-off, and the guarantee that a payable never goes negative. +- `test/unit/checkout_test.dart` — end-to-end sale completion against real repositories: stock decrement, invoice sequencing, split tenders, loyalty movement, and every rejection path. `LocalStore.reset()` re-seeds between tests so fixtures never leak. +- `test/unit/validators_test.dart` — mobile/email/name validation and formatter output. +- `test/widget/primary_button_test.dart` — button and status pill rendering, tap and busy states. + +--- + +## Swapping the data layer + +`LocalStore` is a process-local map that stands in for a database. To move to Hive, SQLite or an HTTP API, implement the three interfaces in `domain/repositories/` and rebind them in `app/providers.dart`: + +```dart +final productRepositoryProvider = Provider( + (ref) => HiveProductRepository(ref.watch(hiveBoxProvider)), +); +``` + +Nothing in `domain/` or `presentation/` changes. + +--- + +## Version compatibility + +Two Flutter APIs used here moved recently: + +- `ThemeData.cardTheme` / `dialogTheme` take `CardThemeData` / `DialogThemeData` on Flutter 3.29+. On older versions, drop the `Data` suffix in `lib/core/theme/app_theme.dart`. +- `Color.withValues(alpha:)` requires Flutter 3.27. On older versions substitute `withOpacity()`. + +--- + +## Status and known gaps + +**This project has not been compiled.** It was written in an environment without a Dart SDK or network access, so `flutter pub get`, `flutter analyze` and `flutter test` have never run against it. Verification was static: the import graph resolves with no missing or orphaned files, and every symbol referenced in the tests exists in `lib/`. That cannot catch type errors, signature mismatches, or drift in the pinned package APIs. Expect to fix a handful of issues on first build — the theme types above are the most likely. + +Deliberately out of scope, stubbed as clear extension points: + +- **Cash drawer** — `ReceiptService.openCashDrawer()` logs the ESC/POS kick sequence but does not send it. Wire in your printer's serial passthrough. +- **AI product search** — the search bar ranks by exact barcode, SKU, prefix then fuzzy match. No model is called. +- **Bottom navigation modules** — Dashboard, Products, Inventory, Customers, Promos, Reports, Suppliers and Settings render with live badge counts but are not routed. +- **Authentication** — `cashierSessionProvider` holds a hardcoded session. +- **Sounds** — the three bundled WAVs are synthesised placeholders. Replace with your own; `SoundService` swallows playback failures so a missing file never blocks billing.