Skip to content

Comments

refactor: implement DI in team billing service and team billing data repository factory#24803

Merged
joeauyeung merged 95 commits intomainfrom
implement-team-billing-repository-factor
Nov 19, 2025
Merged

refactor: implement DI in team billing service and team billing data repository factory#24803
joeauyeung merged 95 commits intomainfrom
implement-team-billing-repository-factor

Conversation

@joeauyeung
Copy link
Contributor

@joeauyeung joeauyeung commented Oct 30, 2025

What does this PR do?

This PR refactors the team/organization billing system to use dependency injection (DI) with the ioctopus library, following SOLID principles. The main changes include:

  • Implements DI containers for billing services using ioctopus
  • Renames files from kebab-case to camelCase for consistency across the codebase
  • Creates factory pattern for TeamBillingService and BillingProviderService that automatically returns stub implementations when billing is disabled
  • Consolidates billing logic into better organized service and repository layers
  • Updates all consumers (60 files) to use factory functions instead of direct instantiation

Key architectural improvements:

  • getTeamBillingServiceFactory() - Factory for team billing operations
  • getBillingProviderService() - Factory for Stripe billing service
  • getTeamBillingDataRepository() - Repository for team billing data access
  • Stub implementations automatically used when IS_TEAM_BILLING_ENABLED=false

Mandatory Tasks (DO NOT REMOVE)

  • I have self-reviewed the code
  • I have updated the developer docs in /docs if this PR makes changes that would require a documentation change. N/A - Internal refactoring only
  • I confirm automated tests are in place that prove my fix is effective or that my feature works. Partial - Updated existing test for skipTeamTrials, but this is primarily a refactoring PR

How should this be tested?

Environment Setup:

  • Ensure IS_TEAM_BILLING_ENABLED is set appropriately
  • Ensure STRIPE_PRIVATE_KEY is configured
  • New env var STRIPE_ORG_PRODUCT_ID added to turbo.json

Test Scenarios:

  1. Team Billing Operations (with billing enabled):

    • Create a new team with a paid plan
    • Invite members to a team (should update quantity)
    • Delete users from an organization (should update quantity)
    • Verify subscription status checks work correctly
  2. Billing Disabled Mode:

    • Set IS_TEAM_BILLING_ENABLED=false
    • Verify stub implementations are used (no actual Stripe calls)
    • Team operations should still work without errors
  3. Webhook Handling:

    • Test customer.subscription.deleted webhook
    • Test invoice.paid webhook for organizations
  4. Subscription Status:

    • Verify hasActiveTeamPlan correctly identifies active/trialing/past_due subscriptions
    • Test skipTeamTrials for teams in trial period

Expected Behavior:

  • All existing billing functionality should work identically
  • No changes to business logic, only architectural improvements
  • Stub services should be transparent when billing is disabled

Review Checklist

Critical areas to review:

  1. Factory Usage - Verify all instances of new TeamBilling(), new InternalTeamBilling(), and new StripeBillingService() have been replaced with factory calls
  2. Subscription Status Enum - Check that the change from Stripe.Subscription.Status (lowercase strings) to SubscriptionStatus enum (uppercase) is handled correctly in all comparisons
  3. Stub Implementation - Verify stub services are returned when IS_TEAM_BILLING_ENABLED=false and don't cause runtime errors
  4. Repository Pattern - Ensure the repository factory correctly switches between Prisma and stub implementations
  5. Webhook Handlers - Verify webhook handlers still work with the new factory pattern
  6. Test Coverage - Only one test file was updated; consider if more test updates are needed

Known Risks:

  • Large refactor (60 files) increases risk of subtle bugs
  • Billing is critical functionality - any issues could affect payments
  • Type changes in subscription status handling need careful verification

Link to Devin run: https://app.devin.ai/sessions/35e0b25ba04b4f59b50b4fef1a492411
Requested by: joe@cal.com (@joeauyeung)

@github-actions
Copy link
Contributor

github-actions bot commented Oct 30, 2025

Hey there and thank you for opening this pull request! 👋🏼

We require pull request titles to follow the Conventional Commits specification and it looks like your proposed title needs to be adjusted.

Details:

No release type found in pull request title "Implement team billing repository factor". Add a prefix to indicate what kind of release this pull request corresponds to. For reference, see https://www.conventionalcommits.org/

Available types:
 - feat: A new feature
 - fix: A bug fix
 - docs: Documentation only changes
 - style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
 - refactor: A code change that neither fixes a bug nor adds a feature
 - perf: A code change that improves performance
 - test: Adding missing tests or correcting existing tests
 - build: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)
 - ci: Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs)
 - chore: Other changes that don't modify src or test files
 - revert: Reverts a previous commit

@keithwillcode keithwillcode added core area: core, team members only enterprise area: enterprise, audit log, organisation, SAML, SSO labels Oct 30, 2025
@vercel
Copy link

vercel bot commented Oct 30, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

2 Skipped Deployments
Project Deployment Preview Comments Updated (UTC)
cal Ignored Ignored Nov 18, 2025 6:56pm
cal-eu Ignored Ignored Nov 18, 2025 6:56pm


import type { ITeamBillingRepository } from "./team-billing.repository.interface";
Copy link
Contributor Author

Choose a reason for hiding this comment

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

File names used dashes, instead renamed to use camel casing. Inline with the rest of the codebase

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Used if team billing is not enabled

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed the test that touches the repository but instead test the factory

Copy link
Contributor Author

Choose a reason for hiding this comment

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

New factory to return the prisma repository or the stub one if billing is not enabled

@joeauyeung joeauyeung changed the title Implement team billing repository factor refactor: implement team billing repository factor Oct 30, 2025
@joeauyeung joeauyeung changed the title refactor: implement team billing repository factor refactor: implement DI in team billing service and team billing data repository factory Oct 30, 2025
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

No issues found across 19 files

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

No issues found across 1 file

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

No issues found across 7 files

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

No issues found across 1 file

joeauyeung and others added 3 commits November 17, 2025 15:46
…e with TeamBillingService

- Replace InternalTeamBilling with TeamBillingService
- Use constructor injection with mock dependencies instead of factory pattern
- Remove BillingRepositoryFactory mock and import
- Update all test cases to use mockBillingProviderService, mockTeamBillingDataRepository, and mockBillingRepository
- Simplify saveTeamBilling tests to focus on repository.create calls
- All 11 tests now pass with the new DI structure

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
hariombalhara
hariombalhara previously approved these changes Nov 18, 2025
Copy link
Member

@hariombalhara hariombalhara left a comment

Choose a reason for hiding this comment

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

LGTM !! Great refactor @joeauyeung !!

…ner's getBillingProviderService

- OrganizationPaymentService now uses getBillingProviderService() from DI container
- Test was mocking @calcom/features/ee/payments/server/stripe directly, which no longer works
- Added mock for @calcom/features/ee/billing/di/containers/Billing module
- Mock returns fake billing provider that delegates to mockSharedStripe
- Preserves all existing test assertions and helpers
- Fixed lint error by prefixing unused lastCreatedSessionId with underscore
- All 11 tests now pass (1 skipped as expected)

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
@joeauyeung joeauyeung merged commit 7e4d9e2 into main Nov 19, 2025
39 of 40 checks passed
@joeauyeung joeauyeung deleted the implement-team-billing-repository-factor branch November 19, 2025 15:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core area: core, team members only enterprise area: enterprise, audit log, organisation, SAML, SSO ready-for-e2e size/XXL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants