Skip to content

fix(deals): preserve template deal details on readback - #113

Merged
Sirajmx merged 1 commit into
IABTechLab:mainfrom
aleksUIX:fix/template-deal-readback
Oct 28, 2026
Merged

Sirajmx merged 1 commit into
IABTechLab:mainfrom
aleksUIX:fix/template-deal-readback

Conversation

@aleksUIX

@aleksUIX aleksUIX commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

Deals created through /api/v1/deals/from-template return 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_cpm stays 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.

@aleksUIX
aleksUIX marked this pull request as ready for review October 6, 2026 04:57

@atc964 atc964 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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:

  1. The terms fallback omits guaranteed, so a PG deal booked from a template reads back with terms.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).

  2. data.get("currency", "USD") and data.get("product_id", "") only default on a missing key. A legacy row with an explicit "currency": None next to a price would now raise inside Money and 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.

  3. 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 nested product section 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.

@Sirajmx
Sirajmx merged commit 05a750d into IABTechLab:main Oct 28, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

GET /api/v1/deals/{deal_id} returns empty product, pricing and terms for a deal created through POST /api/v1/deals/from-template

3 participants