Skip to content

feat(subscriptions): à-la-carte add-ons — attach/detach fixed charges per subscription - #21

Merged
rrader26 merged 1 commit into
mainfrom
feat/subscription-alacarte-addons
Aug 4, 2026
Merged

feat(subscriptions): à-la-carte add-ons — attach/detach fixed charges per subscription#21
rrader26 merged 1 commit into
mainfrom
feat/subscription-alacarte-addons

Conversation

@rrader26

@rrader26 rrader26 commented Aug 4, 2026

Copy link
Copy Markdown

Adds subscriptions/fixed_charges create + destroy so an add-on (fixed charge) can be attached to a single subscription — the primitive EngageIt's self-serve à-la-carte billing needs. Stock Lago only supports index/show/update there.

  • Subscriptions::AddFixedChargeService — ensures a per-subscription plan override (reuses PlanOverrideConcern), creates the fixed charge on it; base plan untouched; idempotent on code.
  • Subscriptions::RemoveFixedChargeService — discards the charge; refuses to touch shared (non-override) plans.
  • Plans::OverrideService — allows the empty-params plan clone (what à-la-carte needs) on the open-core license; real overrides (custom pricing/commitments) stay premium.
  • Service specs assert add/remove works without a premium key and never mutates the shared base plan.

Ruby 4 syntax-clean. Additive — no migration, no change to existing billing behavior. 🤖 Generated with Claude Code

… per subscription

Lago's stock API can only *override* fixed charges that already exist on the
shared plan (subscriptions/fixed_charges is index/show/update). There is no way
to add an add-on to a single subscription, which is what self-serve à-la-carte
billing needs.

This adds that, on the open-core license (Option B):

- Subscriptions::AddFixedChargeService — ensures the subscription has its own
  overridden plan (reusing PlanOverrideConcern), then creates the fixed charge on
  that override so the base plan and every other subscriber is untouched.
  Idempotent on the add-on code.
- Subscriptions::RemoveFixedChargeService — discards an à-la-carte charge from the
  subscription's own override plan; refuses to touch charges on a shared plan.
- subscriptions/fixed_charges#create + #destroy wired to those services, route
  extended to create/destroy.
- Plans::OverrideService: allow the empty-params plan clone (what à-la-carte
  needs) on the open-core license; real overrides (custom pricing, commitments,
  trials) stay premium-only.

Service specs assert the add/remove behavior works without a premium key and that
the shared base plan is never mutated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@rrader26
rrader26 merged commit c0744d5 into main Aug 4, 2026
1 of 12 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.

2 participants