Sales Reports: One Bug, Then a New Format
MediumAI-assisted coding · AI-Assisted Feature Work
Sales Reports: One Bug, Then a New Format
You've joined the team that owns the internal sales-reporting service. It keeps a list of orders in memory and renders summaries ("revenue by region", "revenue by customer") that finance pastes into spreadsheets and wiki pages. The generator works, but it grew one branch at a time. Support has reported two wrong numbers, and two feature requests are queued behind them. All amounts are integer cents.
Codebase
| File | What it does |
|---|---|
reports/api.py | run(operations) entry point and the Dispatcher that routes each operation |
reports/generator.py | ReportGenerator.generate: aggregates orders and renders the report |
reports/render.py | Small text helpers (csv_cell, column_width) |
reports/filters.py | Date-window filtering of orders (from / to options) |
reports/store.py | OrderStore: add orders, change status, list in insertion order |
reports/validation.py | Parses and validates raw order fields |
reports/money.py | net_cents, format_money ($1,234.56), format_plain (1234.56) |
reports/models.py | The Order dataclass |
reports/errors.py | ReportError and every error code |
reports/config.py | Constants (statuses, date pattern) |
tests/ | Existing tests (two of them currently fail) |
How your code is run
run(operations: list[list]) -> list executes the operations in order against empty storage and returns one result per operation. Every operation is [name, ...args]. Errors are returned as strings, never raised.
| Operation | Arguments | Returns | Errors (checked in this order) |
|---|---|---|---|
add_order | order_id, customer, region, category, qty, unit_cents, discount_pct, date, status | true | invalid order, duplicate order |
set_status | order_id, status | true | invalid status, order not found |
report | group_by, format, options | the report as one string | unknown group, unknown format, invalid options |
- Each error is returned as
"error: <code>", e.g."error: unknown format". An unknown operation name returns"error: unknown operation"; a wrong number of arguments returns"error: invalid arguments". - An order is valid when
order_id,customer,regionandcategoryare non-blank strings,qty >= 1,unit_cents >= 1,0 <= discount_pct <= 100(all integers),datelooks likeYYYY-MM-DD, andstatusispaid,pendingorrefunded. Names are case-sensitive. - An order's net value is
qty * unit_centsreduced bydiscount_pctpercent, rounded half up to a whole cent (money.net_cents). - Only
paidorders appear in reports.pendingandrefundedorders are ignored entirely: they add no revenue, no order count and no units. optionsis a JSON object."from"and"to"(both optional, both inclusive,YYYY-MM-DD) restrict the report to orders dated in that window. Keys that are not documented are ignored.optionsthat is not an object, or afrom/tothat is not a date string, isinvalid options.group_byis"region","category"or"customer";formatis"text"or"csv".
Report layout. Every report has the columns <Group>, Orders, Units, Revenue (the first header is Region, Category or Customer). Orders is the number of paid orders in the group, Units the sum of qty, Revenue the sum of net values. Groups are listed by revenue, highest first, ties broken by name ascending (plain string comparison). The result is lines joined with "\n", with no trailing newline.
text: fixed-width columns separated by two spaces. Each column is as wide as its widest cell (header included). The group column is left-aligned, the other three right-aligned. A line of-as long as the header line follows the header. Revenue is shown as$1,234.56.csv: a header line, then one line per group. Revenue is plain1234.56. A field containing a comma, double quote or line break is wrapped in double quotes with inner quotes doubled.- A report with no matching orders still has its header lines (and nothing else).
Worked example
[["add_order", "o-1", "Acme, Inc.", "east", "books", 2, 1500, 0, "2024-03-01", "paid"],
["add_order", "o-2", "Acme, Inc.", "east", "games", 1, 5999, 10, "2024-03-02", "paid"],
["add_order", "o-3", "Bolt", "west", "books", 4, 1000, 0, "2024-03-03", "paid"],
["add_order", "o-4", "Bolt", "west", "books", 1, 1205, 0, "2024-03-04", "refunded"],
["report", "region", "text", {}]]returns
[true, true, true, true,
"Region Orders Units Revenue\n------------------------------\neast 2 3 $83.99\nwest 1 4 $40.00"]which prints as
Region Orders Units Revenue
------------------------------
east 2 3 $83.99
west 1 4 $40.00(o-2 is 5999 cents less 10%, 5399.1, which rounds to 5399.)
Part 1 — Two reports disagree with the others
Goal: make every report follow the layout and counting rules above.
Support has two reports:
- "The *customer* report doesn't match the *region* report. Refunds seem to be counted as sales."
- "In the *category* CSV, some revenue values look wrong. Finance pasted
66.4where the number should have been a dollar amount with cents."
Rules
- Every
group_by/formatcombination obeys the layout and counting rules above. - The totals of a
customerreport equal the totals of aregionorcategoryreport over the same orders and options. - Revenue in
csvis always two decimal places (66.04,70.00).
Part 2 — Markdown format
Goal: finance wants to paste reports straight into the wiki. Add format = "markdown" for all three groupings.
Rules
- The report is a GitHub-style table: a header row, an alignment row, then one row per group in the same order as the other formats. Every row is
"| " + " | ".join(cells) + " |". - The alignment row is
:---for the group column and---:for the three numeric columns. - Revenue is displayed like
text($1,234.56); counts are plain integers. - A
|character inside a group name is written as\|. - No matching orders: just the header row and the alignment row.
textandcsvoutput must not change.
Example (same orders as the worked example): ["report", "region", "markdown", {}] returns
| Region | Orders | Units | Revenue |
| :--- | ---: | ---: | ---: |
| east | 2 | 3 | $83.99 |
| west | 1 | 4 | $40.00 |(as a single string with \n between the lines).
Part 3 — Totals, two-level grouping and sort order
Goal: analysts want a grand-total line, breakdowns such as "region, then category", and an alphabetical option. All three formats must support all of it.
Rules
group_bymay also be a list of one or two distinct group names, e.g.["region", "category"]. A list of one behaves exactly like the plain string. Any other list (empty, three or more entries, duplicates, a non-group entry) isunknown group.- With two names, a group is the pair of values. The report has one group column per name, in the order given, followed by
Orders, Units, Revenue. Headers are the group names title-cased (Region,Category). options.sortis"revenue"(the default; revenue descending, ties broken by the group values in column order) or"name"(group values in column order, ascending, plain string comparison). Any other value isinvalid options.options.totalsistrueorfalse(defaultfalse; any other value isinvalid options). Whentrue, a final Total row follows the groups, covering every matching paid order. Its first group cell isTotal, any further group cells are empty, and the numbers are the sums of the group rows (all zeros if there are no groups).
text: another line of-(same length as the header line) goes before the Total row, and the Total row's cells count towards the column widths.csv: a normal line, e.g.Total,,12,40,500.00for two group columns.markdown: the first cell is written**Total**; empty cells are empty strings (| |).
- Reports requested without these options (string
group_by, nosort, nototals) must be byte-for-byte identical to Parts 1 and 2. - Options are checked after
group_byandformat:unknown group, thenunknown format, theninvalid options.
Example: ["report", "region", "text", {"totals": true}] over the worked-example orders returns
Region Orders Units Revenue
------------------------------
east 2 3 $83.99
west 1 4 $40.00
------------------------------
Total 3 7 $123.99Notes
render.py,filters.py,money.py,store.pyandvalidation.pyare known-good. The bugs are in the report logic.- You may use the AI assistant freely. Later parts must not break earlier ones: hidden tests re-check the exact output of every earlier format.
- Parts 1 and 2 are the baseline; Part 3 is the harder one. Finishing all three is a strong result. How you structure Part 2 is up to you, but think about what Part 3 will ask of it.
Example 1
- Input:
- [["add_order","o-1","Acme, Inc.","east","books",2,1500,0,"2024-03-01","paid"],["add_order","o-2","Acme, Inc.","east","games",1,5999,10,"2024-03-02","paid"],["add_order","o-3","Bolt","west","books",4,1000,0,"2024-03-03","paid"],["add_order","o-4","Bolt","west","books",1,1205,0,"2024-03-04","refunded"],["report","region","text",{}]]
- Output:
- [true,true,true,true,"Region Orders Units Revenue\n------------------------------\neast 2 3 $83.99\nwest 1 4 $40.00"]
- Explanation
- The refunded order is ignored. Order o-2 is 5999 cents less 10 percent, which is 5399.1 and rounds to 5399, so east is 1500*2 + 5399 = 8399 cents.
Example 2
- Input:
- [...same orders..., ["report","customer","csv",{}]]
- Output:
- [..., "Customer,Orders,Units,Revenue\n\"Acme, Inc.\",2,3,83.99\nBolt,1,4,40.00"]
- Explanation
- Bolt's refunded order does not count, so Bolt has one order and four units. Names containing commas are quoted in CSV.
Example 3
- Input:
- [...same orders..., ["report","region","text",{"totals":true}]]
- Output:
- [..., "Region Orders Units Revenue\n------------------------------\neast 2 3 $83.99\nwest 1 4 $40.00\n------------------------------\nTotal 3 7 $123.99"]
- Explanation
- With totals enabled, a second rule line and a Total row follow the groups; the Total row's cells are part of the column widths.
Guidelines
- Python 3 standard library only
- Amounts are integer cents; discounts are rounded half up per order
- Every operation returns exactly one value; errors are returned as "error: <code>" strings, never raised
- Reports are one string, lines joined by \n, no trailing newline
- Existing text and CSV output must stay byte-for-byte identical