start transaction - check prerequisites
MODIFY
src/integration/billing/BillingIntegration.ts
src/integration/billing/BillingIntegration.ts
import { BillingChargeInvoiceAction, BillingDataTransactionStart, BillingDataTransactionStop, BillingDataTransactionUpdate, BillingInvoice, BillingInvoiceItem, BillingInvoiceStatus, BillingOperationResult, BillingPaymentMethod, BillingStatus, BillingTax, BillingUser, BillingUserSynchronizeAction } from '../../types/Billing';
import FeatureToggles, { Feature } from '../../utils/FeatureToggles';
-import Transaction, { StartTransactionCheck } from '../../types/Transaction';
+import Transaction, { StartTransactionErrorCode } from '../../types/Transaction';
import User, { UserStatus } from '../../types/User';
import BackendError from '../../exception/BackendError';
@@ -615,5 +615,5 @@ export default abstract class BillingIntegration {
abstract deletePaymentMethod(user: User, paymentMethodId: string): Promise<BillingOperationResult>;
- abstract precheckStartTransactionPrerequisites(user: User): Promise<StartTransactionCheck>;
+ abstract precheckStartTransactionPrerequisites(user: User): Promise<StartTransactionErrorCode[]>;
}

MODIFY
src/integration/billing/stripe/StripeBillingIntegration.ts
src/integration/billing/stripe/StripeBillingIntegration.ts
@@ -3,7 +3,7 @@ import { AsyncTaskType, AsyncTasks } from '../../../types/AsyncTask';
import { BillingDataTransactionStart, BillingDataTransactionStop, BillingDataTransactionUpdate, BillingInvoice, BillingInvoiceItem, BillingInvoiceStatus, BillingOperationResult, BillingPaymentMethod, BillingStatus, BillingTax, BillingUser, BillingUserData } from '../../../types/Billing';
import FeatureToggles, { Feature } from '../../../utils/FeatureToggles';
import StripeHelpers, { StripeChargeOperationResult } from './StripeHelpers';
-import Transaction, { StartTransactionCheck } from '../../../types/Transaction';
+import Transaction, { StartTransactionErrorCode } from '../../../types/Transaction';
import AsyncTaskManager from '../../../async-task/AsyncTaskManager';
import AxiosFactory from '../../../utils/AxiosFactory';
@@ -88,6 +88,10 @@ export default class StripeBillingIntegration extends BillingIntegration {
}
public async checkActivationPrerequisites(): Promise<void> {
+ await this.checkTaxPrerequisites();
+ }
+
+ public async checkTaxPrerequisites(): Promise<void> {
// Check whether the taxID is set and still active
const taxID = this.settings.billing?.taxID;
if (taxID) {
@@ -1451,15 +1455,15 @@ export default class StripeBillingIntegration extends BillingIntegration {
return null;
}
- public async precheckStartTransactionPrerequisites(user: User): Promise<StartTransactionCheck> {
+ public async precheckStartTransactionPrerequisites(user: User): Promise<StartTransactionErrorCode[]> {
// Check billing prerequisites
if (!this.settings.billing.isTransactionBillingActivated) {
- // Nothing to check - billing of transaction is not yet ON
- return StartTransactionCheck.OK;
+ // Nothing to check - billing of transactions is not yet ON
+ return null;
}
if (this.isUserInternal(user)) {
// Nothing to check - we do not bill internal user's transactions
- return StartTransactionCheck.OK;
+ return null;
}
// Make sure the STRIPE connection is ok
try {
@@ -1472,11 +1476,12 @@ export default class StripeBillingIntegration extends BillingIntegration {
message: 'Stripe Prerequisites to start a transaction are not met',
detailedMessages: { error: error.message, stack: error.stack }
});
- return StartTransactionCheck.BILLING_NO_SETTINGS;
+ return [StartTransactionErrorCode.BILLING_NO_SETTINGS];
}
- // Check that all settings that are necessary to bill a transaction are properly set
+ // Check all settings that are necessary to bill a transaction
+ const errorCodes: StartTransactionErrorCode[] = [];
try {
- await this.checkActivationPrerequisites(); // Makes sure the taxID is still valid
+ await this.checkTaxPrerequisites(); // Checks that the taxID is still valid
} catch (error) {
await Logging.logError({
tenantID: this.tenant.id,
@@ -1485,7 +1490,7 @@ export default class StripeBillingIntegration extends BillingIntegration {
message: 'Billing setting prerequisites to start a transaction are not met',
detailedMessages: { error: error.message, stack: error.stack }
});
- return StartTransactionCheck.BILLING_NO_TAX;
+ errorCodes.push(StartTransactionErrorCode.BILLING_NO_TAX);
}
// Check user prerequisites
const customerID: string = user?.billingData?.customerID;
@@ -1503,10 +1508,11 @@ export default class StripeBillingIntegration extends BillingIntegration {
message: `User prerequisites to start a transaction are not met - user: ${user.id}`,
detailedMessages: { error: error.message, stack: error.stack }
});
- return StartTransactionCheck.BILLING_NO_PAYMENT_METHOD;
+ // TODO - return a more precise error code when payment method has expired
+ errorCodes.push(StartTransactionErrorCode.BILLING_NO_PAYMENT_METHOD);
}
}
- // Everything is fine!
- return StartTransactionCheck.OK;
+ // Let's return the check results!
+ return errorCodes;
}
}

MODIFY
src/server/rest/v1/service/UserService.ts
src/server/rest/v1/service/UserService.ts
@@ -4,6 +4,7 @@ import { AsyncTaskType, AsyncTasks } from '../../../../types/AsyncTask';
import { Car, CarType } from '../../../../types/Car';
import { HTTPAuthError, HTTPError } from '../../../../types/HTTPError';
import { NextFunction, Request, Response } from 'express';
+import { StartTransactionErrorCode, UserDefaultTagCar } from '../../../../types/Transaction';
import User, { ImportedUser, UserRequiredImportProperties } from '../../../../types/User';
import AppAuthError from '../../../../exception/AppAuthError';
@@ -29,7 +30,6 @@ import { OCPITokenWhitelist } from '../../../../types/ocpi/OCPIToken';
import OCPIUtils from '../../../ocpi/OCPIUtils';
import { ServerAction } from '../../../../types/Server';
import SiteStorage from '../../../../storage/mongodb/SiteStorage';
-import { StartTransactionCheck } from '../../../../types/Transaction';
import TagStorage from '../../../../storage/mongodb/TagStorage';
import TenantComponents from '../../../../types/TenantComponents';
import TenantStorage from '../../../../storage/mongodb/TenantStorage';
@@ -111,12 +111,12 @@ export default class UserService {
]);
}
}
- let status = StartTransactionCheck.OK;
+ let errorCodes: Array<StartTransactionErrorCode> = [];
if (Utils.isComponentActiveFromToken(req.user, TenantComponents.BILLING)) {
try {
const billingImpl = await BillingFactory.getBillingImpl(req.tenant);
if (billingImpl) {
- status = await billingImpl.precheckStartTransactionPrerequisites(user);
+ errorCodes = await billingImpl.precheckStartTransactionPrerequisites(user);
}
} catch (error) {
await Logging.logError({
@@ -127,11 +127,21 @@ export default class UserService {
message: `Start Transaction checks failed for ${user.id}`,
detailedMessages: { error: error.message, stack: error.stack }
});
- status = StartTransactionCheck.BILLING_INCONSISTENT_SETTINGS;
+ // Billing module is ON but the settings are not set or inconsistent
+ errorCodes.push(StartTransactionErrorCode.BILLING_INCONSISTENT_SETTINGS);
}
}
+ // Default parameters for the Start Transaction
+ const userDefaultTagCar: UserDefaultTagCar = {
+ tag,
+ car
+ };
+ if (errorCodes?.length > 0) {
+ // Start Transaction prerequisites are not met!
+ userDefaultTagCar.errorCodes = errorCodes;
+ }
// Return
- res.json({ tag, car, status });
+ res.json(userDefaultTagCar);
next();
}

MODIFY
src/types/Transaction.ts
src/types/Transaction.ts
@@ -32,8 +32,13 @@ export enum TransactionAction {
END = 'end'
}
-export enum StartTransactionCheck {
- OK = 'ok',
+export interface UserDefaultTagCar {
+ car: Car;
+ tag: Tag;
+ errorCodes?: StartTransactionErrorCode[];
+}
+
+export enum StartTransactionErrorCode {
BILLING_NO_PAYMENT_METHOD = 'no_payment_method', // start transaction is not possible - user has no payment method
BILLING_NO_TAX = 'billing_no_tax', // start transaction is not possible - the tax ID is not set or inconsistent
BILLING_NO_SETTINGS = 'billing_no_settings', // start transaction not possible - billing settings are not set (or partially set)

start transaction - check prerequisites