billing - BETA Mode - switching OFF some checks and features
MODIFY
src/integration/billing/BillingIntegration.ts
src/integration/billing/BillingIntegration.ts
import { BillingChargeInvoiceAction, BillingDataTransactionStart, BillingDataTransactionStop, BillingDataTransactionUpdate, BillingInvoice, BillingInvoiceDocument, BillingInvoiceItem, BillingInvoiceStatus, BillingOperationResult, BillingPaymentMethod, BillingTax, BillingUser, BillingUserSynchronizeAction } from '../../types/Billing';
+import FeatureToggles, { Feature } from '../../utils/FeatureToggles';
/* eslint-disable @typescript-eslint/member-ordering */
import User, { UserStatus } from '../../types/User';
@@ -60,15 +61,7 @@ export default abstract class BillingIntegration {
message: `${users.length} new user(s) are going to be synchronized`
});
// Check LIVE MODE
- if (!this.productionMode) {
- await Logging.logWarning({
- tenantID: this.tenantID,
- source: Constants.CENTRAL_SERVER,
- action: ServerAction.BILLING_SYNCHRONIZE_USERS,
- module: MODULE_NAME, method: 'synchronizeUsers',
- message: 'Live Mode is OFF - operation has been aborted'
- });
- } else {
+ if (FeatureToggles.isFeatureActive(Feature.BILLING_SYNC_USERS)) {
for (const user of users) {
// Synchronize user
if (await this.synchronizeUser(user)) {
@@ -77,6 +70,14 @@ export default abstract class BillingIntegration {
actionsDone.inError++;
}
}
+ } else {
+ await Logging.logWarning({
+ tenantID: this.tenantID,
+ source: Constants.CENTRAL_SERVER,
+ action: ServerAction.BILLING_SYNCHRONIZE_USERS,
+ module: MODULE_NAME, method: 'synchronizeUsers',
+ message: 'Live Mode is OFF - operation has been aborted'
+ });
}
}
// Log
@@ -282,9 +283,9 @@ export default abstract class BillingIntegration {
action: ServerAction.BILLING_TRANSACTION
});
}
- if (this.productionMode) {
- // Check Billing Data (only in Live Mode)
- if (!transaction.user.billingData) {
+ // Check Billing Data
+ if (!transaction.user?.billingData?.customerID) {
+ if (FeatureToggles.isFeatureActive(Feature.BILLING_CHECK_USER_BILLING_DATA)) {
throw new BackendError({
message: 'User has no Billing Data',
source: Constants.CENTRAL_SERVER,
@@ -293,14 +294,6 @@ export default abstract class BillingIntegration {
action: ServerAction.BILLING_TRANSACTION
});
}
- } else {
- void Logging.logWarning({
- tenantID: this.tenantID,
- source: Constants.CENTRAL_SERVER,
- action: ServerAction.BILLING_TRANSACTION,
- module: MODULE_NAME, method: 'checkStopTransaction',
- message: 'Live Mode is OFF - checkStopTransaction is being performed without checking billing data'
- });
}
}
@@ -315,26 +308,17 @@ export default abstract class BillingIntegration {
action: ServerAction.BILLING_TRANSACTION
});
}
- if (this.productionMode) {
// Check Billing Data (only in Live Mode)
- const billingUser = transaction.user;
- if (!billingUser.billingData || !billingUser.billingData.customerID) {
+ if (!transaction.user?.billingData?.customerID) {
+ if (FeatureToggles.isFeatureActive(Feature.BILLING_CHECK_USER_BILLING_DATA)) {
throw new BackendError({
- message: 'Transaction user has no billing method or no customer in Stripe',
+ message: 'User has no billing data or no customer in Stripe',
source: Constants.CENTRAL_SERVER,
module: MODULE_NAME,
method: 'checkStartTransaction',
action: ServerAction.BILLING_TRANSACTION
});
}
- } else {
- void Logging.logWarning({
- tenantID: this.tenantID,
- source: Constants.CENTRAL_SERVER,
- action: ServerAction.BILLING_TRANSACTION,
- module: MODULE_NAME, method: 'checkStartTransaction',
- message: 'Live Mode is OFF - checkStartTransaction is being performed without checking billing data'
- });
}
}

MODIFY
src/integration/billing/stripe/StripeBillingIntegration.ts
src/integration/billing/stripe/StripeBillingIntegration.ts
/* eslint-disable @typescript-eslint/member-ordering */
import { BillingDataTransactionStart, BillingDataTransactionStop, BillingDataTransactionUpdate, BillingInvoice, BillingInvoiceDocument, BillingInvoiceItem, BillingInvoiceStatus, BillingOperationResult, BillingPaymentMethod, BillingStatus, BillingTax, BillingUser, BillingUserData } from '../../../types/Billing';
import { DocumentEncoding, DocumentType } from '../../../types/GlobalType';
+import FeatureToggles, { Feature } from '../../../utils/FeatureToggles';
import AxiosFactory from '../../../utils/AxiosFactory';
import { AxiosInstance } from 'axios';
@@ -93,7 +94,8 @@ export default class StripeBillingIntegration extends BillingIntegration {
message: 'Failed to connect to Stripe'
});
}
- this.productionMode = await StripeBillingIntegration.isConnectedToALiveAccount(this.stripe);
+ // TODO - rethink that part - this is slow and useless!
+ // this.productionMode = await StripeBillingIntegration.isConnectedToALiveAccount(this.stripe);
}
}
@@ -648,7 +650,7 @@ export default class StripeBillingIntegration extends BillingIntegration {
this.checkStartTransaction(transaction);
// Check Start Transaction Prerequisites
const customerID: string = transaction.user?.billingData?.customerID;
- if (this.productionMode) {
+ if (FeatureToggles.isFeatureActive(Feature.BILLING_CHECK_CUSTOMER_ID)) {
// Check whether the customer exists or not
const customer = await this.checkStripeCustomer(customerID);
// Check whether the customer has a default payment method
@@ -685,6 +687,7 @@ export default class StripeBillingIntegration extends BillingIntegration {
}
private checkStripePaymentMethod(customer: Stripe.Customer): void {
+ if (FeatureToggles.isFeatureActive(Feature.BILLING_CHECK_USER_DEFAULT_PAYMENT_METHOD)) {
if (!customer.default_source && !customer.invoice_settings?.default_payment_method) {
throw new BackendError({
message: `Customer has no default payment method - ${customer.id}`,
@@ -695,6 +698,7 @@ export default class StripeBillingIntegration extends BillingIntegration {
});
}
}
+ }
// eslint-disable-next-line @typescript-eslint/require-await
public async updateTransaction(transaction: Transaction): Promise<BillingDataTransactionUpdate> {
@@ -787,9 +791,6 @@ export default class StripeBillingIntegration extends BillingIntegration {
if (customer) {
const billingDataTransactionStop: BillingDataTransactionStop = await this.billTransaction(transaction);
return billingDataTransactionStop;
- } else if (this.productionMode) {
- // This should not happen - the startTransaction should have been rejected
- throw new Error(`Unexpected situation - No STRIPE customer - Transaction ID '${transaction.id}'`);
}
} catch (error) {
await Logging.logError({

MODIFY
src/types/Billing.ts
src/types/Billing.ts
@@ -20,7 +20,6 @@ export enum BillingStatus {
UNBILLED = 'unbilled',
BILLED = 'billed',
}
-
export interface BillingDataTransactionStop {
status?: string;
invoiceID?: string;

ADD
src/utils/FeatureToggles.ts
+
+// Declare here the list of features
+export enum Feature {
+ BILLING_SYNC_USERS,
+ BILLING_CHECK_USER_BILLING_DATA,
+ BILLING_CHECK_CUSTOMER_ID,
+ BILLING_CHECK_USER_DEFAULT_PAYMENT_METHOD,
+}
+
+export default class FeatureToggles {
+
+ // Comment out the features that you want to switch OFF
+ static activeFeatures: Feature[] = [
+ // Feature.BILLING_SYNC_USERS, / /Let's avoid polluting the stripe accounts for now!
+ // Feature.BILLING_CHECK_USER_BILLING_DATA,
+ // Feature.BILLING_CHECK_CUSTOMER_ID,
+ // Feature.BILLING_CHECK_USER_DEFAULT_PAYMENT_METHOD,
+ ];
+
+ // Check whether the feature is active or not!
+ public static isFeatureActive(feature: Feature): boolean {
+ return FeatureToggles.activeFeatures.includes(feature);
+ }
+}

billing - BETA Mode - switching OFF some checks and features