Syllabus Lesson 216 of 239 · Project: Document Intelligence Service
Project: Document Intelligence Service

Reconcile with Business Rules

A record can be perfectly well-shaped and still be wrong. The line items add up to $118 but the stated total says $128. The date is 2026-13-40. The total is negative. Schema validation will not catch any of these -> they are business-rule violations, and catching them is what separates a toy from a service an accounting team would actually trust.

Write reconcile(record) -> a list of discrepancy strings. An empty list means the record reconciles cleanly. Each rule that fails adds one human-readable string. Three rules:

  • Items must sum to the total (within a cent). Sum the amount of every entry in line_items and compare to total. If they differ by more than 0.01, append "total mismatch: items sum to X but total is Y" (round both to 2 places in the message). Floats are imprecise, so always compare with a tolerance, never ==.
  • The date must parse as a real calendar date in YYYY-MM-DD form. Use datetime.strptime(record["date"], "%Y-%m-%d") inside a try/except ValueError; on failure append "bad date: <value>". (strptime rejects impossible dates like month 13 for you.)
  • The total must be positive. If total <= 0, append "non-positive total: <value>".

Order matters for the tests: check the sum first, then the date, then the sign of the total, appending in that order so a record that breaks several rules lists them predictably.

from datetime import datetime

def reconcile(record):
    issues = []
    items_sum = sum(it["amount"] for it in record["line_items"])
    if abs(items_sum - record["total"]) > 0.01:
        issues.append(...)
    # then the date, then the sign
    return issues

This is the reconciliation step every invoicing, expensing, and ledger system runs before it dares write a row. Press Run to reconcile a clean record and a broken one and see the discrepancies line up.

Your turn

Write reconcile(record) that returns a list of discrepancy strings for a record with line_items (each {"desc", "amount"}), total, and date. Append, in this order: a "total mismatch: items sum to X but total is Y" string when the line items do not sum to total within a cent (values rounded to 2 dp); a "bad date: <value>" string when the date is not a real YYYY-MM-DD date; and a "non-positive total: <value>" string when total <= 0. A clean record returns [].

Spotted a problem in this lesson? Report it

Code · runs in your browser
Output