Office workflows

Use ChatGPT to Turn an Invoice CSV into an Exception Table

Summary

Cihan's view: Upload a clean invoice CSV, define overdue from the due date and review date, then ask ChatGPT for an exception table that preserves missing dates. Check the row count, arithmetic, and source IDs before using the queue. Keep the review date visible in the final note.

Choose another work task →

An invoice queue can look tidy while hiding the fields a reviewer needs. A small CSV review can separate overdue items from invoices that have no usable due date.

Evidence label: documentation-based and illustrative. OpenAI documents file-based data analysis, Python-backed calculations, tables, and code review. The invoice data and desired output below are fictional. No ChatGPT run or personal test is claimed.

What you need

  • ChatGPT with file upload and data analysis available to your account or workspace
  • A CSV with one invoice per row
  • Permission to use the selected workspace
  • A review date supplied by the finance owner

Use the practice data first. Do not upload real financial records until your organisation approves the workspace and data handling.

Fictional input

Save this as invoice-queue.csv:

invoice_id,customer,amount,due_date,status
INV-101,Northstar Studio,1200,2026-10-05,open
INV-102,Harbor Desk,850,2026-10-28,open
INV-103,Pine Systems,400,,open
INV-104,Lumen Mail,600,2026-10-12,paid
INV-105,Acorn Works,950,2026-11-03,open

The fictional finance owner supplied the review date 2026-10-29. An empty due date is unknown. It is not proof that an invoice is overdue. Amounts have no specified currency, so keep the numbers without adding a currency symbol.

Source rows refer to physical CSV lines: the header is row 1 and INV-101 is row 2.

Three steps

1. Inspect the file before asking for a conclusion

Upload the CSV, or paste it into a new chat if upload is unavailable. For the pasted route, change the prompt’s opening to “Analyze the CSV pasted below” and include the complete CSV. Ask for the headers, row count, duplicate invoice IDs, missing due dates, and statuses before calculating anything.

2. Run the bounded prompt

Analyze the attached invoice-queue.csv using only its rows.

Review date: 2026-10-29.
Source row numbering: physical CSV lines, with the header at row 1.

Definition: an invoice is overdue only when status is open and due_date is earlier than the review date. An empty due_date is UNKNOWN, not overdue. Exclude status=paid from the open queue, but count paid rows in the reconciliation. An open invoice due on or after the review date is not overdue.

Return:
1. Input inspection: headers, row count, duplicate invoice IDs, missing due dates, and unexpected statuses.
2. Exception table with invoice_id, customer, amount, due_date, status, exception, and source row. Then account for every other invoice in a separate non-exception/exclusion list with its source row and reason.
3. Reconciliation: input rows, open rows, paid rows, overdue rows, unknown-due-date rows, not-yet-overdue open rows, and the sum of overdue amounts.
4. A manager note of no more than 60 words, including the review date.

Use Python for calculations when data analysis is available. Show the relevant calculation code and let me review it. Do not invent a due date, payment date, collection action, customer risk, or priority. If a value is missing, keep it UNKNOWN. Do not add a currency that the CSV does not specify.

OpenAI recommends descriptive headers and one record per row. It also says to review generated code, outputs, and assumptions before relying on a result.

3. Check every invoice and the total

The reviewable artifact is an exception table plus a reconciliation. Check each invoice ID against the original CSV. INV-102 is easy to miss: its due date is one day before the review date, so it qualifies even though the date looks recent.

The following complete output is editor-written, not captured ChatGPT output:

Input inspection
Headers: invoice_id, customer, amount, due_date, status
Input data rows: 5
Duplicate invoice IDs: none
Missing due dates: INV-103, source row 4
Unexpected statuses: none; observed statuses are open and paid

Exception table
invoice_id | customer | amount | due_date | status | exception | source row
INV-101 | Northstar Studio | 1200 | 2026-10-05 | open | OVERDUE | row 2
INV-102 | Harbor Desk | 850 | 2026-10-28 | open | OVERDUE | row 3
INV-103 | Pine Systems | 400 | UNKNOWN | open | DUE DATE UNKNOWN | row 4

Non-exceptions and exclusions
INV-104 | Lumen Mail | 600 | 2026-10-12 | paid | EXCLUDED: paid | row 5
INV-105 | Acorn Works | 950 | 2026-11-03 | open | NOT OVERDUE: due after review date | row 6

Reconciliation
Input rows: 5
Open rows: 4
Paid rows: 1
Overdue rows: 2
Unknown-due-date rows: 1
Not-yet-overdue open rows: 1
Overdue amount: 2050
Amount calculation: 1200 + 850 = 2050
Partition check: 5 input = 4 open + 1 paid
Open partition check: 4 open = 2 overdue + 1 unknown due date + 1 not overdue

Manager note
As of 2026-10-29, INV-101 and INV-102 are overdue, totaling 2050. INV-103 has an unknown due date. INV-104 is paid and excluded from the open queue. INV-105 is not overdue. This draft supports review; it does not approve collection action.

Calculation code to inspect

This editor-written Python example reproduces the counts from the supplied file. It is a local calculation example, not code captured from a ChatGPT session. Run it only beside the fictional invoice-queue.csv if you want to check the arithmetic yourself:

import csv
from datetime import date
from decimal import Decimal

review_date = date.fromisoformat("2026-10-29")
with open("invoice-queue.csv", newline="", encoding="utf-8") as source:
    rows = list(csv.DictReader(source))

open_rows = [row for row in rows if row["status"] == "open"]
paid_rows = [row for row in rows if row["status"] == "paid"]
overdue_rows = [
    row for row in open_rows
    if row["due_date"] and date.fromisoformat(row["due_date"]) < review_date
]
unknown_rows = [row for row in open_rows if not row["due_date"]]
not_overdue_rows = [
    row for row in open_rows
    if row["due_date"] and date.fromisoformat(row["due_date"]) >= review_date
]
overdue_amount = sum((Decimal(row["amount"]) for row in overdue_rows), Decimal("0"))

print("Input rows:", len(rows))
print("Open rows:", len(open_rows))
print("Paid rows:", len(paid_rows))
print("Overdue IDs:", ", ".join(row["invoice_id"] for row in overdue_rows))
print("Overdue rows:", len(overdue_rows))
print("Unknown-due-date rows:", len(unknown_rows))
print("Not-yet-overdue open rows:", len(not_overdue_rows))
print("Overdue amount:", overdue_amount)

For this exact fixture, the last line is Overdue amount: 2050, and the overdue IDs are INV-101, INV-102. An invoice due exactly on the review date would be open but not overdue under the stated rule. A different business definition needs an explicit rule change before recalculation.

Acceptance checks

The task passes when:

  • the inspection reports the five headers, five data rows, no duplicate IDs, INV-103’s missing date, and no unexpected statuses
  • all five invoices appear in either the exception table or the non-exception/exclusion list, with correct source rows
  • INV-101 and INV-102 are the two overdue invoices; their amount is independently checked as 1200 + 850 = 2050
  • INV-103 stays visible with an unknown due date and contributes nothing to the overdue total
  • the paid INV-104 is excluded from the open queue, while future-due INV-105 stays open but not overdue
  • input and open partitions match the reconciliation, and the displayed code reproduces its counts
  • the manager note includes 2026-10-29, has at most 60 words, and adds no collection action, customer risk, payment date, or currency

A table omitting INV-102 fails even if its other rows look correct. Do not accept a total of 1200 for this CSV and review date.

Troubleshooting

  • A missing due date becomes overdue: restate that blank means UNKNOWN and inspect the source row.
  • A recent invoice is omitted: compare each open due date with the review date. Even a one-day difference qualifies; the rule has no minimum aging period.
  • The paid row appears in the open queue: inspect status filtering and keep the paid count in the reconciliation.
  • Dates are treated as text: inspect parsed ISO dates before accepting the table. An invalid date needs review rather than a guessed replacement.
  • The amount total is wrong: review the generated code, then recalculate the qualifying source rows in a spreadsheet or with the supplied local example.

Limits and verdict

This workflow identifies review exceptions. It does not confirm payment, rank customers, forecast cash flow, or approve collection action. The sample code is for this clean fictional CSV; it does not add validation for malformed dates or amounts in a real export.

TRY it on a fictional or approved queue with a review date from the finance owner. SKIP it for unapproved financial exports. USE the table only after the source IDs, filters, dates, and arithmetic pass review.

For another file-review task, see check a forecast’s assumptions before using its total.

One practical AI-for-work lesson each week: join The Weekly Verdict.

Sources

About Cihan

Creator and operator focused on practical AI for business professionals. Background and editorial approach →