-
-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added support API for force-cancelling subscriptions
- Loading branch information
1 parent
56cc30d
commit ed6e9e2
Showing
10 changed files
with
220 additions
and
40 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,47 +18,47 @@ Depending on the BMS you select, they will each have their own conceptual models | |
|
||
The first step is to learn about how your customers are modeled in the BMS software. | ||
|
||
For example, in Chargebee, your customer (i.e., `Organization` + "Buyer" in the product) will be modeled as a Chargebee Customer record, and a billing subscription (i.e., `Subscription` in the product) is modeled as a Chargebee Subscription. Chargebee has a notion of a Plan, but that has no equivalent concept in the product. | ||
For example, in Chargebee, your customer (i.e., `Organization` + "Buyer" in the product) will be modeled as a Chargebee Customer record, and a billing subscription (i.e., `Subscription` in the product) is modeled as a Chargebee Subscription. Chargebee has a notion of a Plan, but that has no real equivalent concept in the product, except for the `TierId` and the `PlanId`. | ||
|
||
Other BMS will have slightly different conceptual models, and you will need to understand them first. | ||
Other BMS will have slightly different conceptual models, and you will need to understand them first, and how they map to the concepts in the product. | ||
|
||
You will also need to configure the rules and other policies in the BMS first, before you start configuring your customer data. | ||
You will also need to configure the basic rules and other policies in the BMS first, before you start configuring your customer data. | ||
|
||
For example, configure API Keys, Webhooks etc. | ||
|
||
The last thing will be to explore whether the BMS supports a "sandbox" environment for you to play around with and test your migration. You don't want to be adding test data to your production customer data. | ||
|
||
> You may need to sign up for a free plan first to play around with and explore the options, and then use a paid version for your production data. | ||
### View the available data | ||
|
||
Use the API endpoint `GET /subscriptions/export` to view the data available for export into your chosen BMS. | ||
|
||
> Note: this is a protected endpoint that you can only access with HMAC secrets | ||
This data represents all the subscriptions created in the product so far, and you will need to import them into your chosen BMS. | ||
This data represents all the subscriptions created in the product so far. | ||
|
||
This is the data you will need to import into your chosen BMS, during the migration. | ||
|
||
> Note: some of the values are simply encoded JSON values | ||
```json | ||
{ | ||
"subscriptions": [{ | ||
"id": "subscription_QR5hju7FDMIklw39GVCs", | ||
"buyerId": "user_wYU128873MRRBRtjj3E", | ||
"owningEntityId": "org_M36utr98Fdde8890BDEcS2", | ||
"providerName": "simple_billing_provider", | ||
"providerState": { | ||
"SubscriptionId": "simplesub_dd45baa2188c43d39745344356781123" | ||
}, | ||
"id": "subscription_QR5hju7FDMIklw39GVCs", | ||
"buyer": { | ||
"buyerId": "user_wYU128873MRRBRtjj3E", | ||
"owningEntityId": "org_MM36utr98Fdde8890BDEcS2", | ||
"id": "user_wYU128873MRRBRtjj3E", | ||
"companyReference": "org_MM36utr98Fdde8890BDEcS2", | ||
"firstName": "firstname", | ||
"lastName": "lastname", | ||
"name": "{\"FirstName\":\"afirstname\",\"LastName\":\"alastname\"}", | ||
"emailAddress": "[email protected]", | ||
"address": { | ||
"line1": "", | ||
"line2": "", | ||
"line3": "", | ||
"city": "", | ||
"state": "", | ||
"countryCode": "NZL", | ||
"zip": "" | ||
} | ||
"address": "{\"City\":\"\",\"CountryCode\":\"NZL\",\"Line1\":\"\",\"Line2\":\"\",\"Line3\":\"\",\"State\":\"\",\"Zip\":\"\"}" | ||
}, | ||
} | ||
], | ||
|
@@ -78,31 +78,47 @@ This data represents all the subscriptions created in the product so far, and yo | |
|
||
### Build Your Scripts | ||
|
||
You will likely need to build some scripts that take the raw data above and automate the creation of various related data structures in the new BMS. | ||
You will likely need to build some scripts that translate the raw data above and automate the creation of various related data structures in the new BMS. | ||
|
||
You will need to test and refine these scripts thoroughly so that they are reliable when run during the migration with many more subscriptions. | ||
For example, in Chargebee: | ||
|
||
### Configure Your New Plans | ||
1. You would create a Chargebee Customer record using the data in the `buyer` property. You would save the `buyer.id` in the metadata of the Chargebee Customer record. | ||
2. You would create a Chargebee Subscription for the Chargebee Customer. You would also save the `id` and `owningEntityId` as metadata in the Chargebee Subscription. | ||
3. You would define some Chargebee Plans, and assign one of those plans to the Chargebee subscription. | ||
|
||
In your chosen BMS, you will need to design and define the new pricing plans you intend to support for all your customers moving forward in this BMS. | ||
Next, during the migration, once you have automated the creation of the BMS records, you will also need a collection of metadata of those BMS records back into the data of the `IBillingProvider` for when it is being used. | ||
|
||
You won't see any plan information in the exported data from the previous step, unless it appears in the `ProviderState` entry. | ||
Use the API endpoint `POST /subscriptions/{Id}/migrate` to copy the data from your BMS into the product. | ||
|
||
> If you are using the `SimpleBillingProvider` prior to this step, it does not maintain any plan information. That's because it hardcodes a single plan for everyone's use. You can find that single hardcoded plan information in the `InProcessInMemSimpleBillingGatewayService`. | ||
For example, for Chargebee, we would be saving, at the very least, the following data: | ||
|
||
You also need to remember that the `SimpleBillingProvider` has everyone on a "free" plan that requires no payment method and does not support a Trial period. | ||
1. The Chargebee `CustomerId` | ||
2. The Chargebee `SubscriptionId` and `SubscriptionStatus` | ||
3. The Chargebee `PlanId` | ||
|
||
This means that when you import these subscriptions (created by the `SimpleBillingProvider`) into your new BMS, you need to import them into a "free" plan that also does not require them to have a valid `PaymentMethod`. Your customers will not have given their `PaymentMethod` yet. | ||
> There are a total of about 15 other properties about the Customer, Subscription, Plan, and the payment method that will be stored by the `IBillingProvider` over the course of the lifetime of a subscription. See the implementation of the `ChargebeeBillingProvider`. | ||
Also, in the product, by default, we have defined the following `SubscriptionTier`: | ||
Next, you would need to test and refine these scripts thoroughly so that they are reliable when run during the migration with hundreds/thousands of subscriptions (depending on how many customers you have at the time). | ||
|
||
### Configure Your New Plans | ||
|
||
In your chosen BMS, you will need to design and define the new pricing plans you intend to support for all your customers moving forward in this BMS. | ||
|
||
> If you are using the `SimpleBillingProvider` prior to this step, you won't see much plan information in the exported data from the previous step, that's because this provider does not maintain much plan information at all. That's because it hardcodes a single plan for everyone's use. You can find that single hardcoded plan information in the `InProcessInMemSimpleBillingGatewayService`. | ||
> | ||
> You also need to remember that the `SimpleBillingProvider` has everyone on a "free" plan that requires no payment method and does not support a Trial period. | ||
This means that when you import these subscriptions (created by the `SimpleBillingProvider`) into your new BMS, you need to import them into a "free" plan that does not require them to have a valid `PaymentMethod`. If migrating from the `SimpleBillingProvider`, your customers will not have given any `PaymentMethod` yet. | ||
|
||
In the product, by default, we have defined the following tiers (see: `SubscriptionTier`): | ||
|
||
* Standard | ||
* Professional | ||
* Enterprise | ||
|
||
You are free to rename, add, or remove these tiers (in the code) to whatever you would like to support in your future pricing plans in your new BMS. | ||
You are free to rename, add, or remove these tiers (in the code) to whatever you would like to support in your future pricing plans in your new BMS. Essentially, we have 3 paid tiers, where `Standard` may have a trial, and is generally the default plan for new users. | ||
|
||
> Remember to modify the mapping between these tiers and the feature levels you will be supporting in your pricing plans. | ||
> Remember, if you modify these tiers, you will also need to modify the mapping between these tiers and the feature levels you will be supporting in your pricing plans. see the `EndUserRoot` for details. | ||
In your BMS, we recommend defining at least the following plans: | ||
|
||
|
@@ -117,11 +133,13 @@ You will need to define all the parameters for each of these new plans, includin | |
|
||
### Configure the BillingProvider | ||
|
||
Your newly chosen BMS will require a built and tested implementation of the `IBillingProvider` to work with it. You will also need to have built any webhooks or synchronization processes built to handle updates originating from the BMS to the `Subscriptions` subdomain. | ||
Your newly chosen BMS will require a built and tested implementation of the `IBillingProvider` to work with it. | ||
|
||
You will also need to build any webhooks or synchronization processes to handle updates originating from the BMS to the `Subscriptions` subdomain so that changes in the BMS update the data kept in the `Subscription` of the product. | ||
|
||
> SaaStack comes with a small number of existing `IBillingProvider` implementations already. These can be used and they can be referenced to build your own implementations for other BMSs. | ||
To swap out the existing `IBillingProvider` (e.g. `SimpleBillingProvider`) with your new implementation, you simply change the dependency injection code in the `Subscriptions` subdomain to swap them out. | ||
To swap out the existing `IBillingProvider` (e.g. `SimpleBillingProvider`) with your new implementation, you simply change the dependency injection code in the `Subscriptions` subdomain (see: `SubscriptionsModule`). | ||
|
||
> You can then delete the `SimpleBillingProvider` and its associated classes and tests. You are very unlikely to revert back to using it ever again. | ||
|
@@ -142,10 +160,11 @@ Unfortunately, due to the nature of this migration, you are going to need to sch | |
These are the activities to schedule and perform to complete the migration and before you can resume service with the new BMS integration: | ||
|
||
1. Export the data from the running product using the endpoint: `GET /subscriptions/export` | ||
2. Immediately, shutdown your service, to prevent any new customers signing up (and thus creating new subscriptions). You may need other measures if you have heavy sign-up traffic to ensure no one is signing up while you are exporting the data. | ||
3. Import your exported subscription data into your new BMS. You are likely going to be scripting the creation a numerous new data structures in the new BMS, with this data. | ||
2. Immediately shutdown your service, to prevent any new customers signing up (and thus creating new subscriptions). You may need other measures if you have heavy sign-up traffic to ensure no one is signing up while you are exporting the data. | ||
3. Import the exported data it into your new BMS (using your scripts and the BMS API). You are likely going to be scripting the creation of numerous new data structures in the new BMS with this data, and collecting a bunch of key identifiers that are created. | ||
4. Deploy a new version of your software that includes the configured new `IBillingProvider` to your new BMS. | ||
5. Resume service using your new BMS integration, and test by signing up new users and ensuring that new subscriptions are created in your new BMS. This may be performed in a non-production slot. | ||
6. Resume service for all your customers. | ||
5. With the collected data from the BMS, import that data back into your API (using `POST /subscriptions/{Id}/migrate`) | ||
6. Resume service using your new BMS integration, and test by signing up new users and ensuring that new subscriptions are created in your new BMS. This may be performed in a non-production slot. | ||
7. Resume service for all your customers. | ||
|
||
After this migration, any new users that are registered in your product will be automatically integrated into your product, and appear in the BMS. |
13 changes: 13 additions & 0 deletions
13
src/Infrastructure.Web.Api.Operations.Shared/Subscriptions/ForceCancelSubscriptionRequest.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
using Infrastructure.Web.Api.Interfaces; | ||
|
||
namespace Infrastructure.Web.Api.Operations.Shared.Subscriptions; | ||
|
||
/// <summary> | ||
/// Forces the billing subscription to be cancelled for the organization. | ||
/// </summary> | ||
[Route("/subscriptions/{Id}/force", OperationMethod.Delete, AccessType.Token)] | ||
[Authorize(Roles.Platform_Operations)] | ||
public class ForceCancelSubscriptionRequest : UnTenantedRequest<GetSubscriptionResponse>, IUnTenantedOrganizationRequest | ||
{ | ||
public string? Id { get; set; } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.