feat(provider): implement a comprehensive subscription lifecycle#20
feat(provider): implement a comprehensive subscription lifecycle#20
Conversation
…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 Remediation AgentSonarQube found 3 issues in this PR that the agent can fix for you. Est. time saved: ~16 min 3 issues found
|
14307d8 to
ecde827
Compare
…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
There was a problem hiding this comment.
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
ISubscriptionServiceinterface 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
testscript to run compiled tests vialb-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.configis marked{optional: true}, but the constructor dereferencesstripeConfig.secretKeyunconditionally. If the binding isn’t present in a consuming app, this will throw at startup. Either make the injection non-optional, or acceptStripeConfig | undefinedand 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
5170b52 to
799fd29
Compare
rohit-sourcefuse
left a comment
There was a problem hiding this comment.
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]inupdateSubscription(stripe.service.ts) is accessed without checking that the array is non-empty. A subscription with no items will throwTypeError: Cannot read properties of undefinedat runtime.ChargeBeeBindings.configis injected with{optional: true}but properties onchargeBeeConfigare 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) passessubscription_items: []to Chargebee whenpriceRefIdis 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):
defaultPaymentBehaviorinStripeConfigshould be typed asStripe.SubscriptionCreateParams.PaymentBehaviorrather than plainstring.adaptFromModelon both the Chargebee and Stripe adapters still returnsany. The SDK param types are available — typing the return eliminates an implicit escape hatch.
There was a problem hiding this comment.
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
stripeConfigis injected with{optional: true}, but the constructor immediately readsstripeConfig.secretKey. If the config binding is missing this will throw at runtime. Either make the injection non-optional, acceptStripeConfig | undefinedand 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.
- 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
f8d1194 to
7656781
Compare
a-ganguly
left a comment
There was a problem hiding this comment.
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
17ce1fe to
a39dc6a
Compare
SonarQube reviewer guide
|



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
ISubscriptionServiceto the binding keys insrc/keys.ts, allowing controllers and services to inject subscription capabilities independently of one-time billing. Introduced aSubscriptionProviderbinding key for this purpose. [1] [2]value()method to return the result ofgetProvider(), streamlining service instantiation.Chargebee Subscription Implementation
ISubscriptionServiceinterface inChargeBeeService, 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]ChargebeeSubscriptionAdapterinsrc/providers/sdk/chargebee/adapter/subscription.adapter.tsfor mapping between Chargebee subscription objects and the library's provider-agnostic types.Type and Interface Enhancements
IChargeBeeServiceinterface to combine both one-time billing and recurring subscription management, with detailed JSDoc mapping library types to Chargebee's API. [1] [2]Configuration Improvements
ChargeBeeConfiginterface 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
testscript inpackage.jsonto run tests usinglb-mochainstead of a placeholder, ensuring automated test execution.