Skip to content

ING-67 test(credits): Cover cross-entity scenarios#5532

Merged
mariohd merged 1 commit into
mainfrom
ING-67-cross-entity-wallet-credits
May 20, 2026
Merged

ING-67 test(credits): Cover cross-entity scenarios#5532
mariohd merged 1 commit into
mainfrom
ING-67-cross-entity-wallet-credits

Conversation

@mariohd
Copy link
Copy Markdown
Contributor

@mariohd mariohd commented May 18, 2026

Context

Decision 5.5 of the multi-entity billing dive-in states that enterprise customers centralize prepaid wallet purchases through HQ but bill through regional entities. Credits are gated by currency only — there is
no entity check — so a wallet under one billing entity must apply to an invoice on another as long as the currencies match. Credits::AppliedPrepaidCreditsService already meets that contract: it selects wallets
via customer.wallets.active.with_positive_balance.where(balance_currency: invoice.currency). The ticket is test-only, so this PR pins the existing behaviour and adds the two QA scenarios from the dive-in
explicitly.

Description

The earlier coverage in spec/services/credits/applied_prepaid_credits_service_spec.rb had a generic "different billing entities" context. That context is replaced with two explicit scenarios that mirror the
dive-in's QA wording so a future regression maps cleanly back to the decision document.

The first scenario constructs a USD wallet bound to a us billing entity and a USD invoice bound to a eu billing entity — same customer, same organization. It asserts the service applies credits across the
entity boundary and that the wallet balance is decremented. This is the centralized-purchase, regional-billing path that motivated the decision.

The second scenario constructs an EUR wallet bound to a us billing entity and a USD invoice bound to the same us entity. It asserts the wallet is skipped and the balance stays untouched. This is the negative
case that proves the gate is currency, not entity: a future change that flipped the relationship would break exactly one of the two scenarios, making the intent legible from the failure.

Production code is unchanged.

Decision 5.5 of the multi-entity billing dive-in states that
enterprise customers centralize prepaid wallet purchases through HQ
but bill through regional entities. Credits are gated by currency
only — there is no entity check — so a wallet under one billing
entity must apply to an invoice on another as long as the currencies
match. The current `Credits::AppliedPrepaidCreditsService` selects
wallets via
`customer.wallets.active.with_positive_balance.where(balance_currency: invoice.currency)`,
which already meets the contract. The ticket is test-only: pin the
existing behaviour and add the two QA scenarios from the dive-in
explicitly.

Replace the earlier generic "different billing entities" context
with two explicit scenarios that mirror the dive-in's QA wording.

The first scenario constructs a USD wallet bound to a `us` billing
entity and a USD invoice bound to a `eu` billing entity (same
customer, same organization), then asserts that the service applies
credits across the entity boundary and decrements the wallet
balance.

The second scenario constructs an EUR wallet bound to a `us` billing
entity and a USD invoice bound to the same `us` entity, then asserts
the wallet is skipped and its balance stays untouched. Together the
two contexts pin down that the gate is currency, not entity — a
future change that flipped the relationship would break exactly one
of the two scenarios.

Production code is unchanged. Both contexts live in
`spec/services/credits/applied_prepaid_credits_service_spec.rb`
alongside the existing currency-mismatch coverage.
@mariohd mariohd merged commit 206e187 into main May 20, 2026
12 checks passed
@mariohd mariohd deleted the ING-67-cross-entity-wallet-credits branch May 20, 2026 12:09
D1353L pushed a commit that referenced this pull request May 26, 2026
## Context
  
Decision 5.5 of the multi-entity billing dive-in states that enterprise
customers centralize prepaid wallet purchases through HQ but bill
through regional entities. Credits are gated by currency only — there is
no entity check — so a wallet under one billing entity must apply to an
invoice on another as long as the currencies match.
`Credits::AppliedPrepaidCreditsService` already meets that contract: it
selects wallets
via
`customer.wallets.active.with_positive_balance.where(balance_currency:
invoice.currency)`. The ticket is test-only, so this PR pins the
existing behaviour and adds the two QA scenarios from the dive-in
  explicitly.

  ## Description

The earlier coverage in
`spec/services/credits/applied_prepaid_credits_service_spec.rb` had a
generic "different billing entities" context. That context is replaced
with two explicit scenarios that mirror the
dive-in's QA wording so a future regression maps cleanly back to the
decision document.

The first scenario constructs a USD wallet bound to a `us` billing
entity and a USD invoice bound to a `eu` billing entity — same customer,
same organization. It asserts the service applies credits across the
entity boundary and that the wallet balance is decremented. This is the
centralized-purchase, regional-billing path that motivated the decision.

The second scenario constructs an EUR wallet bound to a `us` billing
entity and a USD invoice bound to the same `us` entity. It asserts the
wallet is skipped and the balance stays untouched. This is the negative
case that proves the gate is currency, not entity: a future change that
flipped the relationship would break exactly one of the two scenarios,
making the intent legible from the failure.

  Production code is unchanged.
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.

2 participants