Skip to content

feat(provider): implement a comprehensive subscription lifecycle#20

Merged
a-ganguly merged 10 commits intomasterfrom
feat/recurring-payment
Apr 9, 2026
Merged

feat(provider): implement a comprehensive subscription lifecycle#20
a-ganguly merged 10 commits intomasterfrom
feat/recurring-payment

Conversation

@piyushsinghgaur1
Copy link
Copy Markdown

@piyushsinghgaur1 piyushsinghgaur1 commented Mar 25, 2026

This pull request introduces full recurring subscription lifecycle support to the billing library, with a focus on Chargebee integration. It adds a provider-agnostic subscription interface, implements the Chargebee subscription API using the new interface, and enables seamless injection of subscription services. The changes also include a new adapter for mapping Chargebee subscription objects and extend configuration options for Chargebee. Below are the most important changes:

Subscription Lifecycle Support and Provider Injection

  • Added ISubscriptionService to the binding keys in src/keys.ts, allowing controllers and services to inject subscription capabilities independently of one-time billing. Introduced a SubscriptionProvider binding key for this purpose. [1] [2]
  • Updated the billing provider's value() method to return the result of getProvider(), streamlining service instantiation.

Chargebee Subscription Implementation

  • Implemented the complete ISubscriptionService interface in ChargeBeeService, including methods for creating products, prices, subscriptions, updating/canceling/pausing/resuming subscriptions, and retrieving invoice price details. These methods map to Chargebee's Items API v2. [1] [2] [3]
  • Added a new ChargebeeSubscriptionAdapter in src/providers/sdk/chargebee/adapter/subscription.adapter.ts for mapping between Chargebee subscription objects and the library's provider-agnostic types.
  • Exported the new subscription adapter in both Chargebee and Stripe adapter index files to support provider-agnostic usage.

Type and Interface Enhancements

  • Extended the IChargeBeeService interface to combine both one-time billing and recurring subscription management, with detailed JSDoc mapping library types to Chargebee's API. [1] [2]

Configuration Improvements

  • Added a new ChargeBeeConfig interface with optional overrides for item family, pricing model, cancellation behavior, and cancel reason code, providing more flexibility for Chargebee integration. [1] [2]

Testing and Build Process

  • Updated the test script in package.json to run tests using lb-mocha instead of a placeholder, ensuring automated test execution.

…tripe

Implement a comprehensive subscription lifecycle within loopback4-billing to support
automatedrecurring billing, including subscription creation, upgrades and downgrades,
renewals,cancellations, and proration, ensuring consistency and scalability for SaaS monetization
@sonarqube-agent
Copy link
Copy Markdown

sonarqube-agent bot commented Mar 25, 2026

SonarQube Remediation Agent

SonarQube found 3 issues in this PR that the agent can fix for you. Est. time saved: ~16 min

3 issues found
  • 🔴 Prefer return value over return Promise.resolve(value).stripe.service.ts:414
  • 🔴 Function has a complexity of 11 which is greater than 10 authorized.stripe.service.ts:203
  • 🟡 Handle this exception or don't catch it at all.stripe.service.ts:418
  • Run Remediation Agent
    Select the checkbox above to enable this action.

View Project in SonarCloud

…tripe

Implement a comprehensive subscription lifecycle within loopback4-billing to support
automatedrecurring billing, including subscription creation, upgrades and downgrades,
renewals,cancellations, and proration, ensuring consistency and scalability for SaaS monetization

GH-0
@piyushsinghgaur1 piyushsinghgaur1 linked an issue Mar 25, 2026 that may be closed by this pull request
@piyushsinghgaur1 piyushsinghgaur1 self-assigned this Mar 25, 2026
@piyushsinghgaur1 piyushsinghgaur1 added the enhancement New feature or request label Mar 25, 2026
rohit-wadhwa

This comment was marked as outdated.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Implements provider-agnostic recurring subscription lifecycle support in the billing library, adding subscription types/interfaces and wiring up Chargebee and Stripe SDK services/adapters so consumers can inject subscription operations separately from one-time billing.

Changes:

  • Added subscription domain types and a new ISubscriptionService interface to standardize recurring subscription operations across providers.
  • Implemented subscription lifecycle methods for Stripe and Chargebee, including new subscription adapters and provider config extensions.
  • Added unit tests for Stripe/Chargebee subscription flows and updated the test script to run compiled tests via lb-mocha.

Reviewed changes

Copilot reviewed 16 out of 17 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
src/types.ts Adds provider-agnostic subscription types/enums and ISubscriptionService.
src/providers/sdk/stripe/type/stripe-config.type.ts Introduces Stripe subscription-related configuration.
src/providers/sdk/stripe/type/index.ts Extends Stripe service interface to include ISubscriptionService and re-exports config.
src/providers/sdk/stripe/stripe.service.ts Implements subscription lifecycle methods in StripeService and adds subscription adapter usage.
src/providers/sdk/stripe/adapter/subscription.adapter.ts Adds adapter mapping Stripe subscriptions to normalized subscription result types.
src/providers/sdk/stripe/adapter/index.ts Exports the new Stripe subscription adapter.
src/providers/sdk/chargebee/type/index.ts Extends Chargebee service interface to include ISubscriptionService and re-exports config.
src/providers/sdk/chargebee/type/chargebee-config.type.ts Adds Chargebee subscription-related configuration overrides.
src/providers/sdk/chargebee/charge-bee.service.ts Implements subscription lifecycle methods in ChargeBeeService and adds subscription adapter usage.
src/providers/sdk/chargebee/adapter/subscription.adapter.ts Adds adapter mapping Chargebee subscriptions to normalized subscription result types.
src/providers/sdk/chargebee/adapter/index.ts Exports the new Chargebee subscription adapter.
src/providers/billing.provider.ts Simplifies provider value() to return getProvider() directly.
src/keys.ts Adds SubscriptionProvider binding key for injecting subscription operations.
src/tests/unit/stripe-subscription.service.unit.ts Adds unit tests for Stripe subscription lifecycle behavior.
src/tests/unit/chargebee-subscription.service.unit.ts Adds unit tests for Chargebee subscription lifecycle behavior.
package.json Updates test script to run built test files via lb-mocha.
package-lock.json Lockfile updates from dependency/metadata changes.
Comments suppressed due to low confidence (1)

src/providers/sdk/stripe/stripe.service.ts:47

  • StripeBindings.config is marked {optional: true}, but the constructor dereferences stripeConfig.secretKey unconditionally. If the binding isn’t present in a consuming app, this will throw at startup. Either make the injection non-optional, or accept StripeConfig | undefined and throw a clear configuration error (or apply a safe default) before constructing the Stripe SDK client.
  constructor(
    @inject(StripeBindings.config, {optional: true})
    private readonly stripeConfig: StripeConfig,
  ) {
    this.stripe = new Stripe(stripeConfig.secretKey ?? '', {
      apiVersion: '2024-09-30.acacia', // Update to latest API version as needed
    });

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

… handling

address PR review comments for type safety and error handling

GH-21
fix sonar issue

GH-0
Copy link
Copy Markdown

@rohit-sourcefuse rohit-sourcefuse left a comment

Choose a reason for hiding this comment

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

Good progress on this round — most of the original feedback has been addressed cleanly. Closing those threads now.

A few issues remain that need attention before this is ready to merge:

Must fix before merge:

  • cancelSubscription (stripe.service.ts) now throws after a successful cancel. The provider call succeeds but the error path is hit unconditionally, so callers never receive the cancellation result and get a confusing error instead. The throw should only fire when the API call itself fails.
  • items.data[0] in updateSubscription (stripe.service.ts) is accessed without checking that the array is non-empty. A subscription with no items will throw TypeError: Cannot read properties of undefined at runtime.
  • ChargeBeeBindings.config is injected with {optional: true} but properties on chargeBeeConfig are accessed unconditionally throughout the class. Add a constructor guard that throws a clear startup-time error if the binding is absent.
  • updateSubscription (charge-bee.service.ts) passes subscription_items: [] to Chargebee when priceRefId is absent. Chargebee v2 Items API interprets an empty list as "remove all items", which silently corrupts the subscription.

Nice to have (can go to follow-up):

  • defaultPaymentBehavior in StripeConfig should be typed as Stripe.SubscriptionCreateParams.PaymentBehavior rather than plain string.
  • adaptFromModel on both the Chargebee and Stripe adapters still returns any. The SDK param types are available — typing the return eliminates an implicit escape hatch.

@sourcefuse sourcefuse deleted a comment from rohit-wadhwa Mar 30, 2026
@sourcefuse sourcefuse deleted a comment from rohit-wadhwa Mar 30, 2026
@sourcefuse sourcefuse deleted a comment from rohit-wadhwa Mar 30, 2026
@sourcefuse sourcefuse deleted a comment from rohit-wadhwa Mar 30, 2026
@sourcefuse sourcefuse deleted a comment from rohit-wadhwa Mar 30, 2026
@sourcefuse sourcefuse deleted a comment from rohit-wadhwa Mar 30, 2026
@sourcefuse sourcefuse deleted a comment from rohit-wadhwa Mar 30, 2026
@sourcefuse sourcefuse deleted a comment from rohit-wadhwa Mar 30, 2026
@sourcefuse sourcefuse deleted a comment from rohit-wadhwa Mar 30, 2026
@sourcefuse sourcefuse deleted a comment from rohit-wadhwa Mar 30, 2026
@sourcefuse sourcefuse deleted a comment from rohit-wadhwa Mar 30, 2026
@sourcefuse sourcefuse deleted a comment from rohit-wadhwa Mar 30, 2026
@rohit-sourcefuse rohit-sourcefuse requested review from Copilot and removed request for rohit-wadhwa March 30, 2026 11:11
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 16 out of 18 changed files in this pull request and generated 9 comments.

Comments suppressed due to low confidence (1)

src/providers/sdk/stripe/stripe.service.ts:47

  • stripeConfig is injected with {optional: true}, but the constructor immediately reads stripeConfig.secretKey. If the config binding is missing this will throw at runtime. Either make the injection non-optional, accept StripeConfig | undefined and fail fast with a clear error, or provide a safe default config.
  constructor(
    @inject(StripeBindings.config, {optional: true})
    private readonly stripeConfig: StripeConfig,
  ) {
    this.stripe = new Stripe(stripeConfig.secretKey ?? '', {
      apiVersion: '2024-09-30.acacia', // Update to latest API version as needed
    });

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Piyush Singh Gaur added 2 commits March 30, 2026 17:12
- chargebee: guard invoice.options?.autoCollection against undefined
- stripe: fix createInvoice to skip shipping_details when not provided
- stripe: fix line2 concatenation (undefined undefined) bug
- stripe: buildShippingDetails returns undefined for empty name
- stripe: fix autoAdvnace typo to autoAdvance across service/adapter/type

GH-1
@piyushsinghgaur1 piyushsinghgaur1 force-pushed the feat/recurring-payment branch from f8d1194 to 7656781 Compare April 2, 2026 07:08
@piyushsinghgaur1 piyushsinghgaur1 marked this pull request as ready for review April 2, 2026 07:14
Piyush Singh Gaur added 2 commits April 7, 2026 15:39
accept payment behavior from param

GH-21
fix trivy version and vulnerability

GH-21
Copy link
Copy Markdown
Collaborator

@a-ganguly a-ganguly left a comment

Choose a reason for hiding this comment

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

Approved.. Please let me know if all comments from @rohit-wadhwa resolved.

…criptive error if itemId is missing

narrow the type for defaultPricingModel and throws descriptive error if  itemId is missing
@piyushsinghgaur1 piyushsinghgaur1 force-pushed the feat/recurring-payment branch from 17ce1fe to a39dc6a Compare April 9, 2026 08:47
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud bot commented Apr 9, 2026

@a-ganguly a-ganguly merged commit eaf6b0c into master Apr 9, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Enhance Subscription Lifecycle Management in loopback4-billing

6 participants