Wholesale ERP over a SQL Server POS — live Cuadro de Cuentas Mayores + AFIP invoicing + installable PWA

Ustym Kushnir
Ustym Kushnir
··13 min read

Case study of Distrialma: SQL Server-synced online store grown into a full company-owned back-office ERP over the client PunTouch POS. Tesorería per sucursal, Cuadro de Cuentas Mayores live, cheques lifecycle, AFIP RG 5616, cierre de caja, installable customer PWA with Web Push.

Distrialma Wholesale ERP — screenshot

Distrialma is an Argentine food wholesaler running the PunTouch POS across multiple sucursales. PunTouch is fine for sales. It is blind to accounting, blind to inventory across branches, blind to the customer's online experience. The company was running blind by extension.

The engagement started as "an online store for our wholesale customers" and grew into a full company-owned back-office ERP that layers over PunTouch. This is the story of that growth.

Phase 1: the online store#

The first deliverable was a customer-facing storefront that showed the same catalog and prices as the physical POS. PunTouch stores everything in SQL Server on a local Windows machine at HQ.

The design: a small syncer service runs on the SQL Server machine, exports catalog + stock + price changes to a REST API in the cloud every 5 minutes. The Next.js storefront reads from the cloud database (Postgres), the customer never touches SQL Server directly, and the store is always at most 5 minutes behind reality.

That shipped. Customers started ordering online. The client immediately asked for more.

Phase 2: MercadoPago and AFIP#

Online orders need to charge the customer and issue a real invoice. Argentina's AFIP electronic invoicing (RG 5616) is not optional for a wholesaler.

  • MercadoPago — Checkout Pro for the customer, signed HMAC webhooks for the confirmation callback.
  • AFIP — direct SOAP integration to WSFEv1 with the client's own X.509 certificate. Comprobantes A, B, C, Notas de Crédito, all issued directly from the ERP.

The AFIP integration is the boring part that took the longest. The service exposes a SOAP interface with strict schema, requires a keep-alive token, and rejects any comprobante with a mismatched CUIT/IIBB combination. The final code is 400 lines that has processed a lot of invoices without a single AFIP rejection.

Phase 3: the back-office ERP#

At this point the client saw the potential and asked for the pieces PunTouch could not deliver:

  • Tesorería with per-sucursal balances — every branch has its own cash box, own bank account, own expenses. A consolidated view sums them; a per-branch view is the daily working surface.
  • Live Cuadro de Cuentas Mayores — the traditional accounting balance sheet, computed from the same POS + AFIP + tesorería data, updated in real time. The accountant stopped opening Excel.
  • Cheques lifecycle — cheque received, cheque endorsed to a supplier, cheque bounced, cheque cleared. Every state transition is a Postgres row with a timestamp and an operator.
  • Bulk stock and price Excel ops — a 3,000-SKU price update used to take the buyer 3 hours in Excel + a manual re-entry into PunTouch. Now it is a drag-and-drop of the Excel file, a preview screen, a confirm click. 30 seconds.
  • Cierre de caja — the daily branch close, matching physical cash to what the POS recorded. Discrepancies flag as alerts on the owner's morning email.

Every one of these features started as "can we also do X?" and ended as a Postgres table + a Next.js screen + a nightly report.

Phase 4: the customer PWA#

Wholesale customers were placing orders on desktop. The client wanted them on the phone too — but a native app for a low-frequency B2B use case is a bad investment.

The storefront was already a Next.js app. Turning it into a Progressive Web App was a week of work:

  • manifest.webmanifest with icons, name, theme color.
  • Service worker with a network-first strategy for the API and cache-first for static assets.
  • beforeinstallprompt handling to trigger the install banner at the right moment (after 2 successful orders).
  • Web Push notifications for order status updates.

The install rate on the PWA banner has been material. Customers who install the PWA order more and re-order faster than customers who use the browser only.

The infrastructure#

  • Cloud database: Postgres on a DigitalOcean droplet.
  • Sync service: .NET 8 worker running on the client's SQL Server machine, communicating with the cloud API over HTTPS.
  • Storefront + ERP: Next.js 14 on a second DigitalOcean droplet.
  • MercadoPago: signed HMAC webhooks, idempotent by transaction ID.
  • AFIP: SOAP client with certificate stored on the droplet, refreshed via a scheduled job.

What the client owns#

Everything. The sync service source, the Next.js storefront + ERP, the Postgres schema, the AFIP integration, the MercadoPago account, the PWA manifest, the deploy scripts.

Distrialma has been in production and evolving since 2026-03. The relationship is ongoing — most weeks add one more small feature ("can the cierre de caja also send an email when the discrepancy is >5%?"), which is exactly the shape a healthy ERP relationship should take.

Share this article

The project this writeup is about

Distrialma Wholesale ERP

A wholesaler was running its POS blind to accounting. An ERP layered over the SQL Server POS shows a live balance sheet and files AFIP invoices.

Related case studies

Want your project written up like this?

See servicesContact