iVendNextDevelopers Request a sandbox

A rule checked before a document is submitted (document check) — the recipe

Some back-office documents must not become final until an outside system agrees: a purchase order to a supplier the ERP holds, a goods receipt against the supplier's terms, a stock transfer against stock held elsewhere. The document check asks your HTTPS service when such a document is submitted, from every door (the Desk form or list, a data import, the API), and the submit waits for one answer from a closed list. This recipe is for an iVendNext Partner, or the CitiXsys Consulting Team, building one.

Reference implementation: samples/s34_po_check/ — Purchase orders checked by your ERP: a held supplier refused, an order over the company's monthly budget approved by a purchase manager, a clear order filled with the ERP's own number.

When to use it. The check reads data your system holds, and the person submitting can wait a few seconds. Back office only: never a till sale, and never a record the till's own booking writes (a layaway's order, a delivery's invoice, the backing records of the till's quote edit and quote cancel, an offline sale reaching the server); those are logged not asked. For the till's sale use a check before payment (recipe); for a format or a limit on one record's own fields, a save rule (recipe). On a POS app from before train T11 (2026-10-16), which has no document check, a workflow step only your service can take does the same job (recipe).

The four rules, here. Your service's code never runs inside the shop's site: our code asks your service and applies your answer from a closed list. No answer writes money, and fill writes only the fields the subscription names, each one the shop added.

Steps

  1. Declare the check in your manifest, with the field your answer may fill, if any:

    "custom_fields": [
      {"dt": "Purchase Order", "fieldname": "acme_erp_number", "fieldtype": "Data", "label": "ERP order number", "insert_after": "supplier"}],
    "extension_subscriptions": [
      {"key": "po_check", "point": "doccheck", "label": "ERP purchase order check", "endpoint_url": "https://your.server/poc/check",
       "timeout_seconds": 3, "down_answer": "refuse",
       "settings": {"record_type": "Purchase Order", "send_fields": "name, supplier, grand_total, items(item_code, qty)",
                    "on_validate": false, "fill_fields": ["acme_erp_number"]}}]
    
    • record_type: one record type that is submitted. A till's own record (POS Invoice, the POS day's opening and close) is refused.
    • send_fields: the Desk action's grammar (40 fields, 5 tables, 500 rows a table). Send only what your check reads; the shop consents to that list.
    • fill_fields: at most 10, each a field the shop added: a field your manifest adds counts. Text, a number, a date, a choice or a link; never money, never read-only. A standard field is refused when the subscription is saved: "A service cannot fill schedule_date: on Purchase Order it may fill only a field the shop added, never a money field or one a total is computed from."
    • on_validate: true asks you at a draft's save too. Not on Sales Order, Sales Invoice, Delivery Note, Payment Entry or Journal Entry, which the till's booking also writes.
    • down_answer: allow_and_flag (the submit goes on, flagged), refuse (nothing is submitted unchecked) or ask (the user decides).
  2. Answer. Verify the signature (base64 HMAC-SHA256 of <timestamp>.<raw body> with the subscription's secret), read context.fields (money as minor units with its currency, quantities in thousandths), and answer within your time:

    Answer The user sees
    {"verdict": "allow"} the submit goes on
    {"verdict": "refuse", "reason": "The ERP holds this supplier: invoice 4471 is unpaid."} the reason; the document stays a draft
    {"verdict": "ask", "question": "The ERP shows 40 on order already. Go on?"} the question in Desk; Yes submits
    {"verdict": "approve", "role": "Purchase Manager", "reason": "Over the monthly budget."} needs approval by the role; a user who holds it submits and approves
    {"verdict": "fill", "fields": {"acme_erp_number": "ERP-PO-9912"}} the document is submitted carrying the value

    Every sentence is plain text of 1 to 140 characters. Check each answer against the contract before you ship (tools/contracts/check.py, errors("doccheck", "answer", value)).

  3. Test it on the laptop (S34's tests: every answer against the contract, a canary that answers wrong), then on your sandbox: install, tick the consent and switch the check on, submit a document with your service down and read the declared down answer in Desk and on the Retail Extension Log.

What is refused, and why

When your service is down, and when the till is offline

Technical notes

Bounds

What was proven where

Needs this serves

This page in the kit