← All ivy-nodes
IVYXSTUDIO · IVY NODE
C

Check an invoice's numbers

ivy.node.invoice-check · v0.1.0

ivyx✓

Checks what a model read off a supplier invoice against itself: the net and the VAT add up to the total, the date is a date, the number and the supplier are there. Says verified true or lists what did not hold, so a reading goes on as a draft a person can trust or as one they have to look at.

#invoice#accounting#check

Inputs

FieldTypeDescription
supplierstringThe supplier's name as printed.
numberstringThe invoice number as printed.
datestringThe invoice date, YYYY-MM-DD.
netnumberThe amount before VAT.
vatnumberThe VAT amount.
totalnumberThe amount to pay.

Outputs

FieldTypeDescription
kindrequiredstringAlways invoice: tells a receiver what the output is.
verifiedrequiredbooleanTrue when the numbers add up and the invoice names its supplier, number and date.
problemsrequiredarrayWhat did not hold, one sentence each.

Source

python

# Input preparation
inp = __ivy_ctx__["nodes"][__ivy_node_id__]["input"]

# Compute
# What a model read off a supplier invoice, held against itself.
import re
def num(v):
    try:
        return float(v)
    except (TypeError, ValueError):
        return None


class InvoiceCheck:
    "Check an invoice's numbers"

    def run(self, inp):
        out = {}
        net, vat, total = num(inp.get("net")), num(inp.get("vat")), num(inp.get("total"))
        problems = []
        if total is None:
            problems.append("No total was read.")
        elif net is not None and vat is not None and abs(net + vat - total) > 0.011:
            problems.append("The net %.2f and the VAT %.2f add up to %.2f, not the total %.2f." % (net, vat, net + vat, total))
        date = str(inp.get("date") or "").strip()
        if not re.match(r"^\d{4}-\d{2}-\d{2}$", date):
            problems.append("The date %s is not YYYY-MM-DD." % (date or "(none)"))
        if not str(inp.get("supplier") or "").strip():
            problems.append("No supplier is named.")
        if not str(inp.get("number") or "").strip():
            problems.append("No invoice number was read.")
        out = {"kind": "invoice", "verified": not problems, "problems": problems}
        return out


result = InvoiceCheck().run(inp)

# Output collection (the runner reads it here)
out = __ivy_ctx__["nodes"][__ivy_node_id__]["output"]
out.update(result)

Tests

Requires: python:3.9

  • adds-up

    Net plus VAT is the total, and the invoice names its supplier, number and date.

  • off

    A total that is not net plus VAT, a date not ISO and no supplier are three problems, each a sentence.

  • cents

    Sums that differ only by a float's last digit still add up.

  • empty

    Nothing read is four problems, never a verified invoice.