CafébecDocs

Vendsoft CSV imports

How to load Vendsoft sales-by-machine exports into Cafébec, dry-run first, and commit when everything matches.

Vendsoft doesn't have a webhook; operators export a sales-by-machine CSV each period and upload it here. The import is a two-phase flow — dry-run to catch unmatched clients/machines, then commit. Nothing writes to the database until every row resolves.

File format

Exports alternate client-header rows with machine data rows:

Le Groupe Guy,,,,,,,,
[17] grp_guy_k_rs800,1842.10,612.45,240.12,368.42,1229.65,989.53,0.67,0.54
[18] grp_guy_k_tcnncf7n,1420.55,489.02,185.18,284.11,931.53,746.35,0.65,0.53
Holiday Inn Longueuil,,,,,,,,
[31] hi_longueuil_lobby_rs800,2210.45,745.12,288.22,442.09,1465.33,1177.24,0.66,0.53
Grand Totals,0,0,0,0,0,0,0,0
  • Client header: a single non-empty cell in column 0, rest blank
  • Machine row: [N] slug,Gross,COGS,Tax,Cmsn,GP,Net,GPM,NPM
  • Grand Totals: footer row, always ignored

Clients are matched by vendsoft_name first, then by name. Machines are matched by slug exclusively — the [N] Vendsoft ID is informational only.

Tax split

Vendsoft reports sales tax-inclusive. The import derives:

net_revenue = gross_sales − sales_tax
gst         = sales_tax × 5  / 14.975
qst         = sales_tax × 9.975 / 14.975

Each row must balance within $0.01 of gross = net + tax or it lands in the balanceWarnings list of the dry-run response. Commit proceeds despite warnings; the audit log records the count.

Running an import

From the operator console

  1. Sign in as an ADMIN or OPERATOR.
  2. Open CSV imports in the sidebar.
  3. Pick the Vendsoft export, set the period start/end dates, click Run dry-run.
  4. Review the KPI tiles (rows parsed / matched / unmatched / balance warnings) and the Computed rows table.
  5. If Unmatched is zero, click Commit import. Otherwise resolve the unmatched clients/machines (create them or map to existing rows) and dry-run again.

From the API

# Dry-run
curl -b jar.txt \
  -X POST "http://localhost:4004/v1/imports/vendsoft?dry_run=true" \
  -F "file=@sales-by-machine.csv" \
  -F 'meta={"periodStart":"2026-03-01","periodEnd":"2026-03-31"}'

# Commit (only when unmatched is zero)
curl -b jar.txt \
  -X POST "http://localhost:4004/v1/imports/vendsoft?dry_run=false" \
  -F "file=@sales-by-machine.csv" \
  -F 'meta={"periodStart":"2026-03-01","periodEnd":"2026-03-31"}'

Overrides let you resolve unmatched rows without editing the CSV:

{
  "periodStart": "2026-03-01",
  "periodEnd": "2026-03-31",
  "clientOverrides": {
    "Nouvelle Entreprise Inconnue": "f3...-client-uuid"
  },
  "machineOverrides": {
    "unknown_new_machine": "a1...-machine-uuid"
  }
}

What gets written

  • One sales_record per machine row, source = VENDSOFT, with the derived net_revenue / gst_amount / qst_amount. Vendsoft's reported commission is stored in reported_commission for reconciliation — never used in settlement calculations.
  • One audit_log row per import (action import.vendsoft), with the filename, row count, balance-warning count, and which override keys were passed. Per-row audit is intentionally skipped; individual sales_record IDs are queryable by imported_at.
  • The entire write is a single Prisma transaction — a partial import is impossible.

Errors you might see

  • IMPORT_UNRESOLVED_ROWS (409) — commit called with unmatched rows. The response body lists each unmatched client / machine plus suggestion candidates.
  • VALIDATION_ERROR (400) — malformed meta JSON or missing file field.
  • Balance warnings are advisory; they never block a commit, they appear in the response body and audit row.

On this page