
Offline-first retail POS. Business Central is the truth.
The Business Central AL extension that anchors a five-component retail stack — store, lane and device master, pluggable tenders, native loyalty, promotions, fiscal artefacts and an idempotent POS sync API. Five country packs ship at launch. Re-posting a known sale never duplicates.
- Idempotent sync — re-posting never duplicates a sale
- 5 country packs · IN · AE · SA · US · EU
- Native loyalty + promotions engine
- Till sessions with multiple shifts + EOD posting
- Fiscal artefacts: IRN · ZATCA QR · UUID · stamp
- PA-DSS-friendly: no PAN ever stored
Built on infrastructure your finance and store teams already trust
Most retail POS that talks to BC silently drops sales on network outages. We refused.
Tills lose connectivity. Phones get reset. Networks reboot. In retail, an unposted sale is unaccounted revenue — and worse, a re-tried post can become a duplicate sale that finance has to chase. We built around this from day one. Every sale carries a client-generated `transactionId`. BC's Posted Sale Map remembers it forever. Retry is safe. Outages are safe. No sale is lost; no sale is duplicated.
Client-generated transactionId + Posted Sale Map. Re-posting a known transaction returns the original document.
Sales captured in the local store. Posted to BC when connectivity returns. A complete outage doesn't stop the shift.
India · UAE · Saudi Arabia · USA · EU. Each pack ships a tax projection plus the relevant fiscal artefact integration.
One product, five components. This page is about the system of record.
The SourceForge Retail Solution ships as five composable components. The BC AL extension on this page is the authoritative back-end — master data, posting, the API contract that the client shells consume.
1. BC AL extension
This product. Master data, posting, idempotent sync API, country packs, native loyalty, entitlement, till/EOD, audit and fiscal artefacts.
2. Shared React core
Runs in both the Electron and Android shells. Offline queue, durable local store. BC re-computes tax authoritatively on posting.
3. Electron desktop shell
ESC/POS receipts, cash drawer, scanner, scale, customer display, fiscal signer adapters, local SQLite database.
4. Android / Capacitor shell
Sunmi (China) and PAX (international) terminal hardware. Same React core. Used for queue-busting and mobile checkout.
5. Sync & entitlement SaaS
Sits between the client shells and BC. Handles auth proxying, delta-sync batching, regional data residency, entitlement enforcement.
Tax-correct on day one in five jurisdictions.
Each pack ships an offline tax projection the client uses at the till, plus the relevant fiscal artefact integration. BC re-computes tax authoritatively on posting and remains the source of truth.
GST + e-invoice IRN integration
ZATCA QR + UUID + cryptographic stamp
ZATCA Phase 2 e-invoicing
State + local tax via projection
Per-country VAT + reverse charge
Eight capability groups. All wired to BC for posting and audit.
Each group corresponds to a section of the FRD with explicit traceability — implementation status against each FR-ID is documented and reviewed at every release.
POS terminal & sales
Items via barcode (Item Reference) and variant. Parked sales, returns/exchanges as credit memos with reason codes, per-line overrides with manager approval, currency-aware, age-restricted flags synced.
Pluggable tenders
Cash, card, gift card, store credit, voucher. Each tender has Kind + Integration Style + Adapter Id. Enabled per country and store. Split payments with multiple lines, tip captured, refund-to-original honored.
Promotions engine
BOGO, Buy-X-Get-Y, mix-and-match, tiered, markdown. Time and day-of-week windows. Coupon support. Configurable stacking. Definitions live in BC; evaluation runs at the till for instant feedback.
Native loyalty
Accounts, tiers (auto-progression on lifetime spend), rules (category/tender/promotion), ledger with FIFO expiry. Accrual computed at the till; reconciled idempotently per transactionId on sync.
Receipts & fiscal artefacts
Country-pack-driven statutory fields. Fiscal Artefact table stores signed payloads (IRN, ZATCA QR/UUID/stamp, GST/VAT). RTL receipt flag for Arabic. Reprint is audited.
Customer & consent
Quick-create from POS with dedup via External POS Id. POS Tax Registration No. captured per sale. Marketing consent recorded with region (DPDP/GDPR), changeable from the customer card.
Till sessions & shifts
Open float, paid in/out, safe drop, blind or sighted close. Multiple shifts per till per day, sales attributed via Shift Id. EOD action posts settlement and variance to BC.
Store master + opening hours
Store / Lane / Device hierarchy. Weekly opening-hours schedule with calendar exceptions for holidays. `Store.IsOpenAt()` helper. Synced via dedicated API endpoints.
The API contract the client shells and middleware consume.
All endpoints under apiPublisher=sourceforge / apiGroup=retail / apiVersion=v2.0. Breaking changes go to a new publisher group; the v2.0 contract stays stable.
Pull (master → client cache)
stores · storeHours · posItems · itemBarcodes · posCustomers · priceListLines · promotions · tenderTypes · countryPacks · taxProjections · loyaltyAccounts · stockLevels
Push (client → BC)
insert posSales (with posSaleLines + posPayments) · insert tillSessions (with cashMovements + tenderCounts + shifts) · insert fiscalArtefacts · register/heartbeat devices
Bound actions
POST posSales(<id>)/postSale → idempotent posted document · POST tillSessions(<id>)/postEndOfDay → settlement + variance · POST devices(<id>)/heartbeat → device + entitlement grace
Auth: OAuth service-to-service. The service account holds the SFR Retail – Sync permission set plus standard D365 sales/finance posting permissions. Delta sync via `lastModifiedDateTime` on every master-data endpoint.
Built for retail audits where the journal must reconcile.
Every operator action lands in BC with full audit trail and is exportable for compliance. PA-DSS-friendly by construction — card data is never stored.
Idempotent by construction
Client-generated transactionId is the key. Re-posting returns the original document. Failed posts stay staged with the error visible for retry. No sale is lost.
No PAN, ever
Card numbers never touch BC. We store Card Last 4 + PSP Reference. The actual payment processing happens through client-side adapters; BC sees only the metadata.
OAuth service-to-service
Client middleware authenticates to BC via OAuth (FR-BC-009). Service account uses SFR Retail – Sync permission set plus standard D365 sales/finance posting permissions.
Full audit log
Price overrides, manager discounts, reason codes, refund reasons, receipt reprints — every operator action lands in SFR Audit Log with the user, the time, the before/after, and the sale it relates to.
Entitlement enforcement
Per-tenant entitlement gates feature activation by country pack and module. Device heartbeat refreshes the entitlement grace window. Expired tenants degrade gracefully.
Sync log per device
Every push surfaces in SFR Sync Log. Devices report pendingPostings on heartbeat so the ops team can see who is falling behind without opening every till.
The transactionId is the key. The Posted Sale Map is the memory.
Every sale on the lane gets a UUID at creation time. BC's Posted Sale Map records that UUID against the resulting posted document on first successful post. Every subsequent attempt with the same UUID returns the original document — never creates a new one.
- Network drops mid-post → the client retries; BC sees the same transactionId and returns the original posted document.
- Operator hits ‘send’ twice from confusion → second call is a no-op; finance sees one invoice.
- Multi-day connectivity outage → every staged sale survives; the Job Runner posts the backlog in transactionId order when the link returns.
- Failed post (permission / tax error) → the staged sale stays, the error is on it, no duplicate appears anywhere.
transactionId posted_doc_no ───────────────────── ───────────── a3f9...4c2e SI-1043927 b7c2...91e0 SI-1043928 c1d4...8b5f CM-0001839 d5e7...2a3b SI-1043930 # 2nd attempt for a3f9...4c2e? → returns SI-1043927 → no new document → no journal entry → no audit-log row
The Posted Sale Map is permanent. Even years later, replaying an old transactionId returns the original document — never duplicates.
Single store live in 6-10 weeks.
The BC extension itself installs in under an hour. The real time is in business configuration, training and cutover. A senior SourceForge consultant runs the project end to end — same person from discovery through hypercare.

Per-Tenant Extension installed in your BC tenant. AppSource publication planned for v2.0.
1
Store inventory walk-through. Tender list per country. Country pack scope. Promotion + loyalty rules. Existing fiscal/IRN integrations. Cutover constraints.
2
Install PTE. Activate country packs. Seed tenders. Create Store / Lane / Device master. Configure number series, posting groups, EOD journal template + cash variance account.
3
Sync middleware deployed. Master-data cache primed at lanes. First parallel-run shift alongside the legacy system. Track every sale through the Posted Sale Map.
4
Full operator training. Promotions + loyalty + manager-discount limits live. Open-hours + calendar exceptions configured. Daily check-in calls for the first week.
5
Daily review of Sync Log + posting errors. Tune tax projections after the first GST/VAT filing. Add country packs and stores as roll-out expands.
Frequently asked questions
Business Central SaaS only, minimum BC 25 (runtime 14.0, platform/application 25.0.0.0). On-premises is not supported in this initial release. Object range 52500-52799 with the SFR prefix on every object. Distributed as a Per-Tenant Extension (PTE) installed privately — AppSource publication is planned for a later release.
Bring a sample SKU list. We will configure your country pack live.
A 60-minute working session, not a sales pitch. Bring a slice of your item master, your tender list, your country pack and an example fiscal scenario (a GST sale, a ZATCA sale, a tendered cash transaction). We bring up a BC sandbox, install the extension, run a sale through the staging API and post it — showing you the Posted Sale Map, the audit log and the fiscal artefact at every step.
- Live install + country-pack activation in your BC sandbox
- End-to-end posting demo with idempotency replay
- Honest answer on whether you need all four shells or just one
- Written proposal within 48 hours
