Repository navigation
fix(deals): preserve template deal details on readback - #113
Conversation
atc964
left a comment
There was a problem hiding this comment.
Nice fix, and thank you for the unusually thorough test coverage: the storage-untouched assertions, the nested-wins conflict case, and the zero-value cases are exactly the edges that bite on this path. I verified the money round trip (same stored float feeds the 201 and the GET, float_to_money rounds rather than truncates) and that the fallback only surfaces fields the buyer already received at booking time; base_cpm staying unset keeps rate card internals off the wire. Approving with three small suggestions, none blocking:
-
The terms fallback omits
guaranteed, so a PG deal booked from a template reads back withterms.guaranteed: false. Since the point of this change is faithful readback, consider"guaranteed": data.get("deal_type") == "PG"in the fallback (or storing the flag at booking). -
data.get("currency", "USD")anddata.get("product_id", "")only default on a missing key. A legacy row with an explicit"currency": Nonenext to a price would now raise insideMoneyand turn a readable deal into a 500 on GET (and a skipped row in the operator listing).data.get("currency") or "USD"(same for product_id) makes the fallback total. -
Readback intentionally loses the product name (
name: ""), which the test documents; a short comment in the mapper saying the flat record has no name to give would stop a future reader from filing this as a bug. Storing a nestedproductsection at template-booking time going forward would also let new rows self-describe while the fallback covers old ones.
Two heads-ups outside this PR's scope: GET /api/v1/deals/{deal_id} carries no auth or ownership check on main, so this fix (correctly) puts the booked price behind an ungated read; quote-booked deals already behaved that way, so nothing new here, and it's tracked on our side. And the new route test patches deps.get_product_catalog, which #117 is rewiring; whichever lands second should re-run this file.
Deals created through
/api/v1/deals/from-templatereturn their product, price and flight details on creation, then lose them on GET because the response mapper only reads nested records.The mapper now falls back to the stored flat fields when a nested section is absent. Nested sections keep precedence, including empty sections. The booked CPM becomes
final_cpm;base_cpmstays unset when the original base price was not stored. No storage migration is needed.Regression coverage includes the real POST-to-GET route, currency conversion, zero values, existing flat records and conflicting nested values. The new regression cases failed before the change.
Validation: 1,662 unit tests passed. Integration tests: 39 passed, 28 skipped under the repository's existing conditions. Ruff lint and the repository-wide format check passed. Hosted checks passed on Python 3.11 and 3.12, along with the Docker build, secret scan and commit policy check.
Fixes #112.