Skip to content
This repository has been archived by the owner on Jan 10, 2025. It is now read-only.

Commit

Permalink
Merge pull request #2611 from sap-labs-france/master-qa
Browse files Browse the repository at this point in the history
Merge master-qa
  • Loading branch information
LucasBrazi06 authored Jun 28, 2021
2 parents df27d50 + b76f9c0 commit 5b82746
Show file tree
Hide file tree
Showing 36 changed files with 546 additions and 493 deletions.
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ev-server",
"version": "2.4.70",
"version": "2.4.71",
"engines": {
"node": "14.x.x",
"npm": "6.x.x"
Expand Down
2 changes: 1 addition & 1 deletion src/assets/charging-station-templates
2 changes: 1 addition & 1 deletion src/async-task/AsyncTaskManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ export default class AsyncTaskManager {
}
if (abstractAsyncTask) {
// Get the lock
const asyncTaskLock = await LockingHelper.createAsyncTaskLock(Constants.DEFAULT_TENANT, asyncTask);
const asyncTaskLock = await LockingHelper.acquireAsyncTaskLock(Constants.DEFAULT_TENANT, asyncTask);
if (asyncTaskLock) {
const startAsyncTaskTime = new Date().getTime();
try {
Expand Down
19 changes: 13 additions & 6 deletions src/async-task/tasks/BillTransactionAsyncTask.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { BillingDataTransactionStop, BillingStatus } from '../../types/Billing';

import AbstractAsyncTask from '../AsyncTask';
import { BillingDataTransactionStop } from '../../types/Billing';
import BillingFactory from '../../integration/billing/BillingFactory';
import LockingHelper from '../../locking/LockingHelper';
import LockingManager from '../../locking/LockingManager';
Expand All @@ -20,20 +21,26 @@ export default class BillTransactionAsyncTask extends AbstractAsyncTask {
if (billingImpl) {
// Get the Transaction to bill
const transactionID: string = this.asyncTask.parameters.transactionID;
const transactionLock = await LockingHelper.createBillTransactionLock(tenant.id, Number(transactionID));
const transactionLock = await LockingHelper.acquireBillTransactionLock(tenant.id, Number(transactionID));
if (transactionLock) {
try {
const transaction = await TransactionStorage.getTransaction(tenant.id, Number(transactionID));
if (!transaction) {
throw new Error(`Unknown Transaction ID '${this.asyncTask.parameters.transactionID}'`);
}
// Check consistency - async task should only bill transactions created while transaction billing was ON
if (!transaction.billingData?.withBillingActive) {
throw new Error(`Unexpected situation - billing should be active - transaction ID: '${this.asyncTask.parameters.transactionID}'`);
}
// Check status - async task should only bill transactions marked as PENDING
if (transaction.billingData?.stop?.status !== BillingStatus.PENDING) {
throw new Error(`Unexpected situation - billing status should be PENDING - transaction ID: '${this.asyncTask.parameters.transactionID}'`);
}
// Attempt to finalize and pay invoices
const billingDataStop: BillingDataTransactionStop = await billingImpl.billTransaction(transaction);
// Update
if (transaction.billingData) {
transaction.billingData.stop = billingDataStop;
transaction.billingData.lastUpdate = new Date();
}
transaction.billingData.stop = billingDataStop;
transaction.billingData.lastUpdate = new Date();
// Save
await TransactionStorage.saveTransaction(tenant.id, transaction);
} finally {
Expand Down
2 changes: 1 addition & 1 deletion src/async-task/tasks/SynchronizeCarCatalogsAsyncTask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const MODULE_NAME = 'SynchronizeCarCatalogsAsyncTask';

export default class SynchronizeCarCatalogsAsyncTask extends AbstractAsyncTask {
protected async executeAsyncTask(): Promise<void> {
const syncCarCatalogsLock = await LockingHelper.createSyncCarCatalogsLock(Constants.DEFAULT_TENANT);
const syncCarCatalogsLock = await LockingHelper.acquireSyncCarCatalogsLock(Constants.DEFAULT_TENANT);
if (syncCarCatalogsLock) {
try {
const carDatabaseImpl = await CarFactory.getCarImpl();
Expand Down
2 changes: 1 addition & 1 deletion src/async-task/tasks/TagsImportAsyncTask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const MODULE_NAME = 'TagsImportAsyncTask';

export default class TagsImportAsyncTask extends AbstractAsyncTask {
protected async executeAsyncTask(): Promise<void> {
const importTagsLock = await LockingHelper.createImportTagsLock(this.asyncTask.tenantID);
const importTagsLock = await LockingHelper.acquireImportTagsLock(this.asyncTask.tenantID);
if (importTagsLock) {
const tenant = await TenantStorage.getTenant(this.asyncTask.tenantID);
try {
Expand Down
2 changes: 1 addition & 1 deletion src/async-task/tasks/UsersImportAsyncTask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const MODULE_NAME = 'UsersImportAsyncTask';

export default class UsersImportAsyncTask extends AbstractAsyncTask {
protected async executeAsyncTask(): Promise<void> {
const importUsersLock = await LockingHelper.createImportUsersLock(this.asyncTask.tenantID);
const importUsersLock = await LockingHelper.acquireImportUsersLock(this.asyncTask.tenantID);
if (importUsersLock) {
const tenant = await TenantStorage.getTenant(this.asyncTask.tenantID);
try {
Expand Down
30 changes: 23 additions & 7 deletions src/integration/billing/stripe/StripeBillingIntegration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,16 +99,16 @@ export default class StripeBillingIntegration extends BillingIntegration {
if (!billingTax) {
throw new BackendError({
source: Constants.CENTRAL_SERVER,
module: MODULE_NAME, method: 'checkActivationPrerequisites',
action: ServerAction.CHECK_BILLING_CONNECTION,
module: MODULE_NAME, method: 'checkTaxPrerequisites',
action: ServerAction.BILLING_TAXES,
message: `Billing prerequisites are not consistent - taxID is not found or inactive - taxID: '${taxID}'`
});
}
} else {
throw new BackendError({
source: Constants.CENTRAL_SERVER,
module: MODULE_NAME, method: 'checkActivationPrerequisites',
action: ServerAction.CHECK_BILLING_CONNECTION,
module: MODULE_NAME, method: 'checkTaxPrerequisites',
action: ServerAction.BILLING_TAXES,
message: 'Billing prerequisites are not consistent - taxID is mandatory'
});
}
Expand Down Expand Up @@ -512,7 +512,7 @@ export default class StripeBillingIntegration extends BillingIntegration {
source: Constants.CENTRAL_SERVER,
module: MODULE_NAME,
method: 'setupPaymentMethod',
action: ServerAction.BILLING_TRANSACTION
action: ServerAction.BILLING_SETUP_PAYMENT_METHOD
});
}
// Let's do it!
Expand All @@ -533,6 +533,14 @@ export default class StripeBillingIntegration extends BillingIntegration {
// Check billing data consistency
const customerID = user?.billingData?.customerID;
const paymentMethods: BillingPaymentMethod[] = await this._getPaymentMethods(user, customerID);
await Logging.logInfo({
tenantID: this.tenant.id,
user,
source: Constants.CENTRAL_SERVER,
action: ServerAction.BILLING_PAYMENT_METHODS,
module: MODULE_NAME, method: 'getPaymentMethods',
message: `Number of payment methods: ${paymentMethods?.length}`
});
return paymentMethods;
}

Expand All @@ -547,7 +555,7 @@ export default class StripeBillingIntegration extends BillingIntegration {
source: Constants.CENTRAL_SERVER,
module: MODULE_NAME,
method: 'deletePaymentMethod',
action: ServerAction.BILLING_TRANSACTION
action: ServerAction.BILLING_DELETE_PAYMENT_METHOD
});
}
// Let's do it!
Expand Down Expand Up @@ -943,6 +951,14 @@ export default class StripeBillingIntegration extends BillingIntegration {
const customerID: string = transaction.user?.billingData?.customerID;
const customer = await this.getStripeCustomer(customerID);
if (customer) {
await Logging.logInfo({
tenantID: this.tenant.id,
user: transaction.userID,
source: Constants.CENTRAL_SERVER,
action: ServerAction.BILLING_TRANSACTION,
module: MODULE_NAME, method: 'billTransaction',
message: `Billing process is about to start - transaction ID: ${transaction.id}`
});
const billingDataTransactionStop: BillingDataTransactionStop = await this._billTransaction(transaction);
return billingDataTransactionStop;
}
Expand All @@ -952,7 +968,7 @@ export default class StripeBillingIntegration extends BillingIntegration {
user: transaction.userID,
source: Constants.CENTRAL_SERVER,
action: ServerAction.BILLING_TRANSACTION,
module: MODULE_NAME, method: 'stopTransaction',
module: MODULE_NAME, method: 'billTransaction',
message: `Failed to bill the transaction - Transaction ID '${transaction.id}'`,
detailedMessages: { error: error.message, stack: error.stack }
});
Expand Down
2 changes: 1 addition & 1 deletion src/integration/smart-charging/sap-smart-charging
66 changes: 38 additions & 28 deletions src/locking/LockingHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,85 +2,86 @@ import Lock, { LockEntity } from '../types/Locking';

import Asset from '../types/Asset';
import AsyncTask from '../types/AsyncTask';
import Constants from '../utils/Constants';
import LockingManager from './LockingManager';
import OCPIEndpoint from '../types/ocpi/OCPIEndpoint';
import OICPEndpoint from '../types/oicp/OICPEndpoint';
import SiteArea from '../types/SiteArea';

export default class LockingHelper {
public static async createAsyncTaskLock(tenantID: string, asyncTask: AsyncTask): Promise<Lock | null> {
public static async acquireAsyncTaskLock(tenantID: string, asyncTask: AsyncTask): Promise<Lock | null> {
const lock = LockingManager.createExclusiveLock(tenantID, LockEntity.ASYNC_TASK, `${asyncTask.id}`, 300);
if (!(await LockingManager.acquire(lock))) {
return null;
}
return lock;
}

public static async createSiteAreaSmartChargingLock(tenantID: string, siteArea: SiteArea, timeoutMs: number): Promise<Lock | null> {
public static async acquireSiteAreaSmartChargingLock(tenantID: string, siteArea: SiteArea, timeoutSecs: number): Promise<Lock | null> {
const lock = LockingManager.createExclusiveLock(tenantID, LockEntity.SITE_AREA, `${siteArea.id}-smart-charging`, 180);
if (!(await LockingManager.acquire(lock, timeoutMs))) {
if (!(await LockingManager.acquire(lock, timeoutSecs))) {
return null;
}
return lock;
}

public static async createBillingSyncUsersLock(tenantID: string): Promise<Lock | null> {
public static async acquireBillingSyncUsersLock(tenantID: string): Promise<Lock | null> {
const lock = LockingManager.createExclusiveLock(tenantID, LockEntity.USER, 'synchronize-billing-users');
if (!(await LockingManager.acquire(lock))) {
return null;
}
return lock;
}

public static async createImportUsersLock(tenantID: string): Promise<Lock | null> {
public static async acquireImportUsersLock(tenantID: string): Promise<Lock | null> {
const lock = LockingManager.createExclusiveLock(tenantID, LockEntity.USER, 'import-users');
if (!(await LockingManager.acquire(lock))) {
return null;
}
return lock;
}

public static async createImportTagsLock(tenantID: string): Promise<Lock | null> {
public static async acquireImportTagsLock(tenantID: string): Promise<Lock | null> {
const lock = LockingManager.createExclusiveLock(tenantID, LockEntity.TAG, 'import-tags');
if (!(await LockingManager.acquire(lock))) {
return null;
}
return lock;
}

public static async createSyncCarCatalogsLock(tenantID: string): Promise<Lock | null> {
public static async acquireSyncCarCatalogsLock(tenantID: string): Promise<Lock | null> {
const lock = LockingManager.createExclusiveLock(tenantID, LockEntity.CAR_CATALOG, 'synchronize-car-catalogs');
if (!(await LockingManager.acquire(lock))) {
return null;
}
return lock;
}

public static async createBillingSyncInvoicesLock(tenantID: string): Promise<Lock | null> {
public static async acquireBillingSyncInvoicesLock(tenantID: string): Promise<Lock | null> {
const lock = LockingManager.createExclusiveLock(tenantID, LockEntity.INVOICE, 'synchronize-billing-invoices');
if (!(await LockingManager.acquire(lock))) {
return null;
}
return lock;
}

public static async createBillingPeriodicOperationLock(tenantID: string): Promise<Lock | null> {
public static async acquireBillingPeriodicOperationLock(tenantID: string): Promise<Lock | null> {
const lock = LockingManager.createExclusiveLock(tenantID, LockEntity.INVOICE, 'periodic-billing');
if (!(await LockingManager.acquire(lock))) {
return null;
}
return lock;
}

public static async createAssetRetrieveConsumptionsLock(tenantID: string, asset: Asset): Promise<Lock | null> {
public static async acquireAssetRetrieveConsumptionsLock(tenantID: string, asset: Asset): Promise<Lock | null> {
const lock = LockingManager.createExclusiveLock(tenantID, LockEntity.ASSET, `${asset.id}-consumptions`);
if (!(await LockingManager.acquire(lock))) {
return null;
}
return lock;
}

public static async createOCPIPushCpoCdrsLock(tenantID: string): Promise<Lock | null> {
public static async acquireOCPIPushCpoCdrsLock(tenantID: string): Promise<Lock | null> {
const lock = LockingManager.createExclusiveLock(tenantID, LockEntity.TRANSACTION, 'push-cdrs');
if (!(await LockingManager.acquire(lock))) {
return null;
Expand All @@ -89,10 +90,10 @@ export default class LockingHelper {
}

public static async createOCPIPushTokensLock(tenantID: string, ocpiEndpoint: OCPIEndpoint): Promise<Lock | null> {
return LockingHelper.createOCPIEndpointActionLock(tenantID, ocpiEndpoint, 'push-tokens');
return LockingHelper.acquireOCPIEndpointActionLock(tenantID, ocpiEndpoint, 'push-tokens');
}

public static async createOCPIPushCdrLock(tenantID: string, transactionID: number): Promise<Lock | null> {
public static async acquireOCPIPushCdrLock(tenantID: string, transactionID: number): Promise<Lock | null> {
const lock = LockingManager.createExclusiveLock(tenantID, LockEntity.TRANSACTION, `push-cdr-${transactionID}`);
if (!(await LockingManager.acquire(lock))) {
return null;
Expand All @@ -101,74 +102,83 @@ export default class LockingHelper {
}

public static async createOCPIPullTokensLock(tenantID: string, ocpiEndpoint: OCPIEndpoint, partial: boolean): Promise<Lock | null> {
return LockingHelper.createOCPIEndpointActionLock(tenantID, ocpiEndpoint, `pull-tokens${partial ? '-partial' : ''}`);
return LockingHelper.acquireOCPIEndpointActionLock(tenantID, ocpiEndpoint, `pull-tokens${partial ? '-partial' : ''}`);
}

public static async createOCPICheckCdrsLock(tenantID: string, ocpiEndpoint: OCPIEndpoint): Promise<Lock | null> {
return LockingHelper.createOCPIEndpointActionLock(tenantID, ocpiEndpoint, 'check-cdrs');
return LockingHelper.acquireOCPIEndpointActionLock(tenantID, ocpiEndpoint, 'check-cdrs');
}

public static async createOCPICheckLocationsLock(tenantID: string, ocpiEndpoint: OCPIEndpoint): Promise<Lock | null> {
return LockingHelper.createOCPIEndpointActionLock(tenantID, ocpiEndpoint, 'check-locations');
return LockingHelper.acquireOCPIEndpointActionLock(tenantID, ocpiEndpoint, 'check-locations');
}

public static async createOCPICheckSessionsLock(tenantID: string, ocpiEndpoint: OCPIEndpoint): Promise<Lock | null> {
return LockingHelper.createOCPIEndpointActionLock(tenantID, ocpiEndpoint, 'check-sessions');
return LockingHelper.acquireOCPIEndpointActionLock(tenantID, ocpiEndpoint, 'check-sessions');
}

public static async createOCPIPullCdrsLock(tenantID: string, ocpiEndpoint: OCPIEndpoint): Promise<Lock | null> {
return LockingHelper.createOCPIEndpointActionLock(tenantID, ocpiEndpoint, 'pull-cdrs');
return LockingHelper.acquireOCPIEndpointActionLock(tenantID, ocpiEndpoint, 'pull-cdrs');
}

public static async createOCPIPullLocationsLock(tenantID: string, ocpiEndpoint: OCPIEndpoint): Promise<Lock | null> {
return LockingHelper.createOCPIEndpointActionLock(tenantID, ocpiEndpoint, 'pull-locations');
return LockingHelper.acquireOCPIEndpointActionLock(tenantID, ocpiEndpoint, 'pull-locations');
}

public static async createOCPIPullSessionsLock(tenantID: string, ocpiEndpoint: OCPIEndpoint): Promise<Lock | null> {
return LockingHelper.createOCPIEndpointActionLock(tenantID, ocpiEndpoint, 'pull-sessions');
return LockingHelper.acquireOCPIEndpointActionLock(tenantID, ocpiEndpoint, 'pull-sessions');
}

public static async createOCPIPatchLocationsLock(tenantID: string, ocpiEndpoint: OCPIEndpoint): Promise<Lock | null> {
return LockingHelper.createOCPIEndpointActionLock(tenantID, ocpiEndpoint, 'patch-locations');
return LockingHelper.acquireOCPIEndpointActionLock(tenantID, ocpiEndpoint, 'patch-locations');
}

public static async createOCPIPatchEVSEStatusesLock(tenantID: string, ocpiEndpoint: OCPIEndpoint): Promise<Lock|null> {
return LockingHelper.createOCPIEndpointActionLock(tenantID, ocpiEndpoint, 'patch-evse-statuses');
return LockingHelper.acquireOCPIEndpointActionLock(tenantID, ocpiEndpoint, 'patch-evse-statuses');
}

public static async createOICPPatchEVSEsLock(tenantID: string, oicpEndpoint: OICPEndpoint): Promise<Lock|null> {
return LockingHelper.createOICPEndpointActionLock(tenantID, oicpEndpoint, 'patch-evses');
return LockingHelper.acquireOICPEndpointActionLock(tenantID, oicpEndpoint, 'patch-evses');
}

public static async createOICPPatchEvseStatusesLock(tenantID: string, oicpEndpoint: OICPEndpoint): Promise<Lock|null> {
return LockingHelper.createOICPEndpointActionLock(tenantID, oicpEndpoint, 'patch-evse-statuses');
return LockingHelper.acquireOICPEndpointActionLock(tenantID, oicpEndpoint, 'patch-evse-statuses');
}

public static async createOICPPushCdrLock(tenantID: string, transactionID: number): Promise<Lock|null> {
public static async acquireOICPPushCdrLock(tenantID: string, transactionID: number): Promise<Lock|null> {
const lock = LockingManager.createExclusiveLock(tenantID, LockEntity.TRANSACTION, `push-cdr-${transactionID}`);
if (!(await LockingManager.acquire(lock))) {
return null;
}
return lock;
}

public static async createBillTransactionLock(tenantID: string, transactionID: number): Promise<Lock | null> {
public static async acquireBillTransactionLock(tenantID: string, transactionID: number): Promise<Lock | null> {
const lock = LockingManager.createExclusiveLock(tenantID, LockEntity.TRANSACTION, `bill-transaction-${transactionID}`);
if (!(await LockingManager.acquire(lock))) {
return null;
}
return lock;
}

private static async createOCPIEndpointActionLock(tenantID: string, ocpiEndpoint: OCPIEndpoint, action: string): Promise<Lock | null> {
public static async acquireChargingStationLock(tenantID: string, chargingStationID: string): Promise<Lock | null> {
const lock = LockingManager.createExclusiveLock(tenantID, LockEntity.CHARGING_STATION,
`${chargingStationID}`, Constants.CHARGING_STATION_LOCK_SECS);
if (!(await LockingManager.acquire(lock, Constants.CHARGING_STATION_LOCK_SECS * 2))) {
return null;
}
return lock;
}

private static async acquireOCPIEndpointActionLock(tenantID: string, ocpiEndpoint: OCPIEndpoint, action: string): Promise<Lock | null> {
const lock = LockingManager.createExclusiveLock(tenantID, LockEntity.OCPI_ENDPOINT, `${ocpiEndpoint.id}-${action}`);
if (!(await LockingManager.acquire(lock))) {
return null;
}
return lock;
}

private static async createOICPEndpointActionLock(tenantID: string, oicpEndpoint: OICPEndpoint, action: string): Promise<Lock|null> {
private static async acquireOICPEndpointActionLock(tenantID: string, oicpEndpoint: OICPEndpoint, action: string): Promise<Lock|null> {
const lock = LockingManager.createExclusiveLock(tenantID, LockEntity.OICP_ENDPOINT, `${oicpEndpoint.id}-${action}`);
if (!(await LockingManager.acquire(lock))) {
return null;
Expand Down
Loading

0 comments on commit 5b82746

Please sign in to comment.