Skip to content

[ING-466] feat(wallets): accept connections param - #6344

Open
mariohd wants to merge 1 commit into
mainfrom
ing-466
Open

mariohd wants to merge 1 commit into
mainfrom
ing-466

Conversation

@mariohd

@mariohd mariohd commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Context

ING-466. Billing objects need to route themselves to one of a customer's connections. The override table, the resolution cascade and the connection codes already shipped; nothing wrote the rows yet. This is the first write path (dive-in T18c + T18d), and it is additive — nothing reads effective_*_connection in production yet.

Description

POST/PATCH /wallets and each nested recurring_transaction_rules entry accept a connections object keyed by category:

"connections": {
  "payment":    { "behavior": "skip" },
  "accounting": { "code": "netsuite_sub2" },
  "crm":        { "behavior": "inherit" }
}

A code pins that connection, skip short-circuits the category so it never falls back, inherit drops the override, and an omitted category changes nothing. inherit is params-only: resolution reads a missing row as inheritance, so it destroys the row.

Validation and persistence live in two new services, polymorphic in the owner, so ING-462 and the one-off/preview surfaces can reuse them.

Behind the multi_connection flag. Connections sent while the flag is off are refused rather than ignored; an unresolvable code is a 422. The existing payment_method is untouched. Serializer exposure and OpenAPI are separate dive-in items.

Reviewer note: a rule matched by lago_id keeps its overrides; a rule sent without one is replaced, so the new rule gets fresh rows while the superseded rule keeps its own — rules are soft-terminated, so dependent: :destroy never fires. Both cases are asserted in the specs.

Testing

53 new examples: unit, request (running against both /wallets and /customers/:external_id/wallets), and the reconciliation cases above. Regression across the wallet suites (640) plus the non-REST callers — GraphQL mutations, Orders::SubscriptionCreation::ExecuteService, wallet metadata (115) — all green. Rubocop clean.

## Context

Billing objects need to route themselves to one of a customer's
connections. The table, the resolution cascade and the connection
codes already shipped; nothing wrote the override rows yet. This adds
the first write path, behind the multi_connection flag.

## Description

The wallet endpoints and each nested recurring transaction rule accept
a connections object keyed by category (payment, tax, accounting,
crm). An entry either names a connection code, which pins it, or a
behavior: skip never falls back, inherit drops the choice. An omitted
category changes nothing.

Inherit is never persisted, since resolution reads a missing row as
inheritance. An unknown code is a validation error, and connections
sent while the flag is off are refused rather than ignored.

Validation and persistence are polymorphic in the owner, so the
subscription and invoice surfaces can reuse them.
@mariohd
mariohd requested a review from lovrocolic September 9, 2026 14:38
@mariohd
mariohd marked this pull request as ready for review September 9, 2026 14:38
@lago-claude-ai-agent

Copy link
Copy Markdown
Contributor

Automated pre-review (advisory, not a required check) — verdict: HOLD · CI green

HOLD — unresolved connections on a recurring rule are silently accepted during wallet creation.

  • Wallets::RecurringTransactionRules::CreateService catches the failure from AttachToResourceService.call! but returns its own still-successful result, so the outer wallet transaction can commit the rule and return 200 without the requested connection. Propagate the attach failure and add a wallet-create regression test for an unresolved nested connection code.

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.

1 participant