From b473b87ef9c9b6b48941e9c11055f2f5851e6e93 Mon Sep 17 00:00:00 2001 From: Loan ALOUACHE Date: Mon, 5 Jul 2021 15:20:45 +0200 Subject: [PATCH 01/28] Qualified Charging Station actions --- .../v1/router/api/ChargingStationRouter.ts | 2 +- src/types/Server.ts | 97 ++++++++++--------- 2 files changed, 50 insertions(+), 49 deletions(-) diff --git a/src/server/rest/v1/router/api/ChargingStationRouter.ts b/src/server/rest/v1/router/api/ChargingStationRouter.ts index d5981ac84c..ad28a82b58 100644 --- a/src/server/rest/v1/router/api/ChargingStationRouter.ts +++ b/src/server/rest/v1/router/api/ChargingStationRouter.ts @@ -262,7 +262,7 @@ export default class ChargingStationRouter { protected buildRouteChargingStationGetBootNotifications(): void { this.router.get(`/${ServerRoute.REST_CHARGING_STATIONS_BOOT_NOTIFICATIONS}`, async (req: Request, res: Response, next: NextFunction) => { - await RouterUtils.handleServerAction(ChargingStationService.handleGetBootNotifications.bind(this), ServerAction.BOOT_NOTIFICATION, req, res, next); + await RouterUtils.handleServerAction(ChargingStationService.handleGetBootNotifications.bind(this), ServerAction.BOOT_NOTIFICATIONS, req, res, next); }); } diff --git a/src/types/Server.ts b/src/types/Server.ts index dabb5d8bac..b6d49fe640 100644 --- a/src/types/Server.ts +++ b/src/types/Server.ts @@ -8,34 +8,34 @@ export enum ServerAction { OBJECT_CLONE = 'ObjectClone', CHARGING_STATION_CLIENT_INITIALIZATION = 'ChargingStationClientInitialization', - CHARGING_STATION_RESET = 'ChargingStationReset', - CHARGING_STATION_REQUEST_OCPP_PARAMETERS = 'ChargingStationRequestOcppParameters', - CHARGING_STATION_CLEAR_CACHE = 'ChargingStationClearCache', - CHARGING_STATION_GET_CONFIGURATION = 'ChargingStationGetConfiguration', - CHARGING_STATION_CHANGE_CONFIGURATION = 'ChargingStationChangeConfiguration', + CHARGING_STATION_RESET = 'RestChargingStationReset', + CHARGING_STATION_REQUEST_OCPP_PARAMETERS = 'RestChargingStationRequestOcppParameters', + CHARGING_STATION_CLEAR_CACHE = 'RestChargingStationClearCache', + CHARGING_STATION_GET_CONFIGURATION = 'RestChargingStationGetConfiguration', + CHARGING_STATION_CHANGE_CONFIGURATION = 'RestChargingStationChangeConfiguration', CHARGING_STATION_DATA_TRANSFER = 'ChargingStationChangeDataTransfer', - CHARGING_STATION_REMOTE_START_TRANSACTION = 'ChargingStationRemoteStartTransaction', - CHARGING_STATION_REMOTE_STOP_TRANSACTION = 'ChargingStationRemoteStopTransaction', - CHARGING_STATION_UNLOCK_CONNECTOR = 'ChargingStationUnlockConnector', + CHARGING_STATION_REMOTE_START_TRANSACTION = 'RestChargingStationRemoteStartTransaction', + CHARGING_STATION_REMOTE_STOP_TRANSACTION = 'RestChargingStationRemoteStopTransaction', + CHARGING_STATION_UNLOCK_CONNECTOR = 'RestChargingStationUnlockConnector', CHARGING_STATION_SET_CHARGING_PROFILE = 'ChargingStationSetChargingProfile', - CHARGING_STATION_GET_COMPOSITE_SCHEDULE = 'ChargingStationGetCompositeSchedule', + CHARGING_STATION_GET_COMPOSITE_SCHEDULE = 'RestChargingStationGetCompositeSchedule', CHARGING_STATION_CLEAR_CHARGING_PROFILE = 'ChargingStationClearChargingProfile', - CHARGING_STATION_GET_DIAGNOSTICS = 'ChargingStationGetDiagnostics', - CHARGING_STATION_UPDATE_FIRMWARE = 'ChargingStationUpdateFirmware', - CHARGING_STATION_CHANGE_AVAILABILITY = 'ChargingStationChangeAvailability', - CHARGING_STATION_DOWNLOAD_QR_CODE_PDF = 'ChargingStationDownloadQrCodePdf', - - CHARGING_STATIONS_EXPORT = 'ChargingStationsExport', - CHARGING_STATIONS_OCPP_PARAMS_EXPORT = 'ChargingStationsOCPPParamsExport', - CHARGING_STATION = 'ChargingStation', - CHARGING_STATIONS_OCPP_PARAMETERS = 'ChargingStationOcppParameters', - CHARGING_STATIONS_IN_ERROR = 'ChargingStationsInError', - CHARGING_STATION_UPDATE_PARAMS = 'ChargingStationUpdateParams', - CHARGING_STATION_LIMIT_POWER = 'ChargingStationLimitPower', - CHARGING_STATION_DELETE = 'ChargingStationDelete', - - CHECK_SMART_CHARGING_CONNECTION = 'CheckSmartChargingConnection', - TRIGGER_SMART_CHARGING = 'TriggerSmartCharging', + CHARGING_STATION_GET_DIAGNOSTICS = 'RestChargingStationGetDiagnostics', + CHARGING_STATION_UPDATE_FIRMWARE = 'RestChargingStationUpdateFirmware', + CHARGING_STATION_CHANGE_AVAILABILITY = 'RestChargingStationChangeAvailability', + CHARGING_STATION_DOWNLOAD_QR_CODE_PDF = 'RestChargingStationDownloadQrCodePdf', + + CHARGING_STATIONS_EXPORT = 'RestChargingStationsExport', + CHARGING_STATIONS_OCPP_PARAMS_EXPORT = 'RestChargingStationsOCPPParamsExport', + CHARGING_STATION = 'RestChargingStation', + CHARGING_STATIONS_OCPP_PARAMETERS = 'RestChargingStationOcppParameters', + CHARGING_STATIONS_IN_ERROR = 'RestChargingStationsInError', + CHARGING_STATION_UPDATE_PARAMS = 'RestChargingStationUpdateParams', + CHARGING_STATION_LIMIT_POWER = 'RestChargingStationLimitPower', + CHARGING_STATION_DELETE = 'RestChargingStationDelete', + + CHECK_SMART_CHARGING_CONNECTION = 'RestCheckSmartChargingConnection', + TRIGGER_SMART_CHARGING = 'RestTriggerSmartCharging', REGISTRATION_TOKEN = 'RegistrationToken', REGISTRATION_TOKENS = 'RegistrationTokens', @@ -43,7 +43,8 @@ export enum ServerAction { REGISTRATION_TOKEN_REVOKE = 'RegistrationTokenRevoke', REGISTRATION_TOKEN_UPDATE = 'RegistrationTokenUpdate', - STATUS_NOTIFICATIONS = 'StatusNotifications', + BOOT_NOTIFICATIONS = 'RestBootNotifications', + STATUS_NOTIFICATIONS = 'RestStatusNotifications', TRANSACTION_SOFT_STOP = 'TransactionSoftStop', TRANSACTION_DELETE = 'TransactionDelete', @@ -55,7 +56,7 @@ export enum ServerAction { LOGGING = 'Logging', LOGGINGS_EXPORT = 'LoggingsExport', - CHARGING_STATIONS = 'ChargingStations', + CHARGING_STATIONS = 'RestChargingStations', CAR_CATALOGS = 'CarCatalogs', CAR_CATALOG = 'CarCatalog', @@ -72,17 +73,17 @@ export enum ServerAction { GET_CONNECTOR_CURRENT_LIMIT = 'GetConnectorCurrentLimit', REGISTER_USER = 'RegisterUser', - CHARGING_PROFILES = 'ChargingProfiles', - CHARGING_PROFILE_DELETE = 'ChargingProfileDelete', - CHARGING_PROFILE_UPDATE = 'ChargingProfileUpdate', - CHARGING_PROFILE_CREATE = 'ChargingProfileCreate', - GENERATE_QR_CODE_FOR_CONNECTOR = 'GenerateQrCodeForConnector', + CHARGING_PROFILES = 'RestChargingProfiles', + CHARGING_PROFILE_DELETE = 'RestChargingProfileDelete', + CHARGING_PROFILE_UPDATE = 'RestChargingProfileUpdate', + CHARGING_PROFILE_CREATE = 'RestChargingProfileCreate', + GENERATE_QR_CODE_FOR_CONNECTOR = 'RestGenerateQrCodeForConnector', OCPP_PARAM_UPDATE = 'OCPPParamUpdate', RESEND_VERIFICATION_MAIL = 'ResendVerificationEmail', END_USER_LICENSE_AGREEMENT = 'EndUserLicenseAgreement', CHECK_END_USER_LICENSE_AGREEMENT = 'CheckEndUserLicenseAgreement', VERIFY_EMAIL = 'VerifyEmail', - FIRMWARE_DOWNLOAD = 'FirmwareDownload', + FIRMWARE_DOWNLOAD = 'RestFirmwareDownload', OFFLINE_CHARGING_STATION = 'OfflineChargingStation', @@ -309,7 +310,7 @@ export enum ServerAction { USER_TRANSACTIONS_STATISTICS = 'UserTransactionsStatistics', USER_PRICING_STATISTICS = 'UserPricingStatistics', - CHARGING_STATION_TRANSACTIONS = 'ChargingStationTransactions', + CHARGING_STATION_TRANSACTIONS = 'RestChargingStationTransactions', ADD_CHARGING_STATIONS_TO_SITE_AREA = 'AddChargingStationsToSiteArea', REMOVE_CHARGING_STATIONS_FROM_SITE_AREA = 'RemoveChargingStationsFromSiteArea', @@ -342,8 +343,8 @@ export enum ServerAction { COMPANY_DELETE = 'CompanyDelete', SITE_CREATE = 'SiteCreate', - ADD_SITES_TO_USER = 'AddSitesToUser', - REMOVE_SITES_FROM_USER = 'RemoveSitesFromUser', + ADD_SITES_TO_USER = 'RestAddSitesToUser', + REMOVE_SITES_FROM_USER = 'RestRemoveSitesFromUser', SITES = 'Sites', SITE = 'Site', SITE_IMAGE = 'SiteImage', @@ -378,26 +379,26 @@ export enum ServerAction { REFUND = 'Refund', USER_READ = 'UserRead', - USER_CREATE = 'UserCreate', - USER_DELETE = 'UserDelete', - USER_UPDATE = 'UserUpdate', - USER_UPDATE_MOBILE_TOKEN = 'UpdateUserMobileToken', - USERS = 'Users', - USER_SITES = 'UserSites', - USERS_IN_ERROR = 'UsersInError', - USER_IMAGE = 'UserImage', + USER_CREATE = 'RestUserCreate', + USER_DELETE = 'RestUserDelete', + USER_UPDATE = 'RestUserUpdate', + USER_UPDATE_MOBILE_TOKEN = 'RestUpdateUserMobileToken', + USERS = 'RestUsers', + USER_SITES = 'RestUserSites', + USERS_IN_ERROR = 'RestUsersInError', + USER_IMAGE = 'RestUserImage', TAGS = 'Tags', TAG = 'Tag', - USER_DEFAULT_TAG_CAR = 'UserDefaultTagCar', + USER_DEFAULT_TAG_CAR = 'RestUserDefaultTagCar', TAG_CREATE = 'TagCreate', TAG_UPDATE = 'TagUpdate', TAG_DELETE = 'TagDelete', TAGS_DELETE = 'TagsDelete', TAGS_IMPORT = 'TagsImport', TAGS_EXPORT = 'TagsExport', - USER = 'User', - USERS_EXPORT = 'UsersExport', - USERS_IMPORT = 'UsersImport', + USER = 'RestUser', + USERS_EXPORT = 'RestUsersExport', + USERS_IMPORT = 'RestUsersImport', NOTIFICATIONS = 'Notifications', From 2ea00e126881cd58007f36f8b896cacbe7e4058c Mon Sep 17 00:00:00 2001 From: Loan ALOUACHE Date: Mon, 5 Jul 2021 15:22:04 +0200 Subject: [PATCH 02/28] Qualified Authentication actions --- src/server/rest/v1/router/auth/AuthRouter.ts | 1 + src/types/Server.ts | 16 ++++++++-------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/server/rest/v1/router/auth/AuthRouter.ts b/src/server/rest/v1/router/auth/AuthRouter.ts index b58a158027..f27b64ddc8 100644 --- a/src/server/rest/v1/router/auth/AuthRouter.ts +++ b/src/server/rest/v1/router/auth/AuthRouter.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-misused-promises */ import { ServerAction, ServerRoute } from '../../../../../types/Server'; import express, { NextFunction, Request, Response } from 'express'; diff --git a/src/types/Server.ts b/src/types/Server.ts index b6d49fe640..2b92da2abe 100644 --- a/src/types/Server.ts +++ b/src/types/Server.ts @@ -1,7 +1,7 @@ export enum ServerAction { - LOGIN = 'Login', - LOGOUT = 'Logout', - PASSWORD_RESET = 'Reset', + LOGIN = 'RestLogin', + LOGOUT = 'RestLogout', + PASSWORD_RESET = 'RestReset', PING = 'Ping', CHECK_CONNECTION = 'CheckConnection', @@ -72,17 +72,17 @@ export enum ServerAction { SYNCHRONIZE_CAR_CATALOGS = 'SynchronizeCarCatalogs', GET_CONNECTOR_CURRENT_LIMIT = 'GetConnectorCurrentLimit', - REGISTER_USER = 'RegisterUser', + REGISTER_USER = 'RestRegisterUser', CHARGING_PROFILES = 'RestChargingProfiles', CHARGING_PROFILE_DELETE = 'RestChargingProfileDelete', CHARGING_PROFILE_UPDATE = 'RestChargingProfileUpdate', CHARGING_PROFILE_CREATE = 'RestChargingProfileCreate', GENERATE_QR_CODE_FOR_CONNECTOR = 'RestGenerateQrCodeForConnector', OCPP_PARAM_UPDATE = 'OCPPParamUpdate', - RESEND_VERIFICATION_MAIL = 'ResendVerificationEmail', - END_USER_LICENSE_AGREEMENT = 'EndUserLicenseAgreement', - CHECK_END_USER_LICENSE_AGREEMENT = 'CheckEndUserLicenseAgreement', - VERIFY_EMAIL = 'VerifyEmail', + RESEND_VERIFICATION_MAIL = 'RestResendVerificationEmail', + END_USER_LICENSE_AGREEMENT = 'RestEndUserLicenseAgreement', + CHECK_END_USER_LICENSE_AGREEMENT = 'RestCheckEndUserLicenseAgreement', + VERIFY_EMAIL = 'RestVerifyEmail', FIRMWARE_DOWNLOAD = 'RestFirmwareDownload', OFFLINE_CHARGING_STATION = 'OfflineChargingStation', From 9629c059fbdf10bfcef4168bbc8d0ec995b3c0c4 Mon Sep 17 00:00:00 2001 From: Loan ALOUACHE Date: Mon, 5 Jul 2021 16:31:25 +0200 Subject: [PATCH 03/28] Fixed tests --- src/server/rest/v1/router/api/TenantRouter.ts | 2 +- src/types/Server.ts | 1 + test/api/client/TenantApi.ts | 6 ++++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/server/rest/v1/router/api/TenantRouter.ts b/src/server/rest/v1/router/api/TenantRouter.ts index de183c1a7b..c14334971e 100644 --- a/src/server/rest/v1/router/api/TenantRouter.ts +++ b/src/server/rest/v1/router/api/TenantRouter.ts @@ -26,7 +26,7 @@ export default class TenantRouter { } protected buildRouteTenant(): void { - this.router.get(`/${ServerRoute.REST_TENANTS}/:id`, async (req: Request, res: Response, next: NextFunction) => { + this.router.get(`/${ServerRoute.REST_TENANT}`, async (req: Request, res: Response, next: NextFunction) => { req.query.ID = sanitize(req.params.id); await RouterUtils.handleServerAction(TenantService.handleGetTenant.bind(this), ServerAction.TENANT, req, res, next); }); diff --git a/src/types/Server.ts b/src/types/Server.ts index 2b92da2abe..eddc054a2a 100644 --- a/src/types/Server.ts +++ b/src/types/Server.ts @@ -515,6 +515,7 @@ export enum ServerRoute { REST_PING = 'ping', REST_TENANTS = 'tenants', + REST_TENANT = 'tenants/:id', // BILLING URLs for CRUD operations on PAYMENT METHODS REST_BILLING_PAYMENT_METHODS = 'users/:userID/payment-methods', diff --git a/test/api/client/TenantApi.ts b/test/api/client/TenantApi.ts index 19f8efd53c..8fc3f59152 100644 --- a/test/api/client/TenantApi.ts +++ b/test/api/client/TenantApi.ts @@ -1,3 +1,5 @@ +import { ServerAction, ServerRoute } from '../../../src/types/Server'; + import CrudApi from './utils/CrudApi'; import TestConstants from './utils/TestConstants'; @@ -10,11 +12,11 @@ export default class TenantApi extends CrudApi { } public async readById(id) { - return super.readById(id, '/client/api/Tenant'); + return super.readById(id, this.buildRestEndpointUrl(ServerRoute.REST_TENANT, { id })); } public async readAll(params, paging = TestConstants.DEFAULT_PAGING, ordering = TestConstants.DEFAULT_ORDERING) { - return super.readAll(params, paging, ordering, '/client/api/Tenants'); + return super.readAll(params, paging, ordering, this.buildRestEndpointUrl(ServerRoute.REST_TENANTS)); } public async create(data) { From 21c15232c218141cc3e18345eac400a5f4e66d39 Mon Sep 17 00:00:00 2001 From: LucasBrazi06 Date: Mon, 5 Jul 2021 16:49:11 +0200 Subject: [PATCH 04/28] Display Site and Site Area in Session In Progress and History --- package-lock.json | 2 +- package.json | 2 +- .../server/rest/v1/docs/e-mobility-oas.json | 17 +++++++++++++++++ .../chargingstation/chargingstations-get.json | 4 ++++ .../schemas/transaction/transactions-get.json | 8 ++++++++ .../rest/v1/service/ChargingStationService.ts | 2 +- .../rest/v1/service/TransactionService.ts | 16 +++++++++------- .../requests/HttpChargingStationRequest.ts | 1 + src/types/requests/HttpTransactionRequest.ts | 2 ++ 9 files changed, 44 insertions(+), 10 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2ca6577d6c..8b5e33e9b9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "ev-server", - "version": "2.4.73", + "version": "2.4.74", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 521dfbf3e6..33b5294c45 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ev-server", - "version": "2.4.73", + "version": "2.4.74", "engines": { "node": "14.x.x", "npm": "6.x.x" diff --git a/src/assets/server/rest/v1/docs/e-mobility-oas.json b/src/assets/server/rest/v1/docs/e-mobility-oas.json index 61aaa660ee..0b084a3003 100644 --- a/src/assets/server/rest/v1/docs/e-mobility-oas.json +++ b/src/assets/server/rest/v1/docs/e-mobility-oas.json @@ -723,9 +723,15 @@ { "$ref": "#/components/parameters/SiteIDs" }, + { + "$ref": "#/components/parameters/WithSite" + }, { "$ref": "#/components/parameters/SiteAreaIDs" }, + { + "$ref": "#/components/parameters/WithSiteArea" + }, { "$ref": "#/components/parameters/InactivityStatuses" }, @@ -1066,6 +1072,9 @@ { "$ref": "#/components/parameters/SiteAreaIDs" }, + { + "$ref": "#/components/parameters/WithSiteArea" + }, { "$ref": "#/components/parameters/ConnectorStatuses" }, @@ -6467,6 +6476,14 @@ "type": "boolean" } }, + "WithSiteArea": { + "in": "query", + "name": "WithSiteArea", + "description": "With site area attribute", + "schema": { + "type": "boolean" + } + }, "RefundStatus": { "in": "query", "name": "RefundStatus", diff --git a/src/assets/server/rest/v1/schemas/chargingstation/chargingstations-get.json b/src/assets/server/rest/v1/schemas/chargingstation/chargingstations-get.json index 900fa3f3e8..b3637c9684 100644 --- a/src/assets/server/rest/v1/schemas/chargingstation/chargingstations-get.json +++ b/src/assets/server/rest/v1/schemas/chargingstation/chargingstations-get.json @@ -20,6 +20,10 @@ "type": "boolean", "sanitize": "mongo" }, + "WithSiteArea": { + "type": "boolean", + "sanitize": "mongo" + }, "SiteAreaID": { "$ref": "common.json#/definitions/ids" }, diff --git a/src/assets/server/rest/v1/schemas/transaction/transactions-get.json b/src/assets/server/rest/v1/schemas/transaction/transactions-get.json index fc590b9c12..631634c6c6 100644 --- a/src/assets/server/rest/v1/schemas/transaction/transactions-get.json +++ b/src/assets/server/rest/v1/schemas/transaction/transactions-get.json @@ -9,6 +9,14 @@ "type": "boolean", "sanitize": "mongo" }, + "WithSite": { + "type": "boolean", + "sanitize": "mongo" + }, + "WithSiteArea": { + "type": "boolean", + "sanitize": "mongo" + }, "ConnectorID": { "$ref": "chargingstation.json#/definitions/connectorIDs" }, diff --git a/src/server/rest/v1/service/ChargingStationService.ts b/src/server/rest/v1/service/ChargingStationService.ts index a878280ed9..4f56d11f69 100644 --- a/src/server/rest/v1/service/ChargingStationService.ts +++ b/src/server/rest/v1/service/ChargingStationService.ts @@ -1385,7 +1385,7 @@ export default class ChargingStationService { search: filteredRequest.Search, withNoSiteArea: filteredRequest.WithNoSiteArea, withSite: filteredRequest.WithSite, - withSiteArea: true, + withSiteArea: filteredRequest.WithSiteArea, chargingStationIDs: filteredRequest.ChargingStationID ? filteredRequest.ChargingStationID.split('|') : null, connectorStatuses: filteredRequest.ConnectorStatus ? filteredRequest.ConnectorStatus.split('|') : null, connectorTypes: filteredRequest.ConnectorType ? filteredRequest.ConnectorType.split('|') : null, diff --git a/src/server/rest/v1/service/TransactionService.ts b/src/server/rest/v1/service/TransactionService.ts index cb808c9980..fd8843005b 100644 --- a/src/server/rest/v1/service/TransactionService.ts +++ b/src/server/rest/v1/service/TransactionService.ts @@ -50,7 +50,7 @@ export default class TransactionService { 'currentCumulatedPrice', 'currentInactivityStatus', 'roundedPrice', 'price', 'priceUnit', 'tagID', 'stop.roundedPrice', 'stop.price', 'stop.priceUnit', 'stop.inactivityStatus', 'stop.stateOfCharge', 'stop.timestamp', 'stop.totalConsumptionWh', 'stop.totalDurationSecs', 'stop.totalInactivitySecs', 'stop.extraInactivitySecs', 'stop.meterStop', - 'billingData.stop.invoiceNumber', 'stop.reason', 'ocpi', 'ocpiWithCdr', 'tagID', 'stop.tagID', + 'billingData.stop.invoiceNumber', 'stop.reason', 'ocpi', 'ocpiWithCdr', 'tagID', 'stop.tagID', 'site.name', 'siteArea.name' ])); next(); } @@ -668,7 +668,7 @@ export default class TransactionService { 'id', 'chargeBoxID', 'timestamp', 'issuer', 'stateOfCharge', 'timezone', 'connectorId', 'meterStart', 'siteAreaID', 'siteID', 'currentTotalDurationSecs', 'currentTotalInactivitySecs', 'currentInstantWatts', 'currentTotalConsumptionWh', 'currentStateOfCharge', 'currentInactivityStatus', 'stop.roundedPrice', 'stop.price', 'stop.priceUnit', 'stop.inactivityStatus', 'stop.stateOfCharge', 'stop.timestamp', 'stop.totalConsumptionWh', - 'stop.totalDurationSecs', 'stop.totalInactivitySecs', 'stop.extraInactivitySecs', + 'stop.totalDurationSecs', 'stop.totalInactivitySecs', 'stop.extraInactivitySecs', 'site.name', 'siteArea.name', 'billingData.stop.invoiceNumber', 'stop.reason', 'ocpi', 'ocpiWithCdr', 'tagID', 'stop.tagID', ]); res.json(transactions); @@ -693,7 +693,7 @@ export default class TransactionService { const transactions = await TransactionService.getTransactions(req, action, {}, [ 'id', 'chargeBoxID', 'timestamp', 'issuer', 'stateOfCharge', 'timezone', 'connectorId', 'status', 'meterStart', 'siteAreaID', 'siteID', 'currentTotalDurationSecs', 'currentTotalInactivitySecs', 'currentInstantWatts', 'currentTotalConsumptionWh', 'currentStateOfCharge', - 'currentCumulatedPrice', 'currentInactivityStatus', 'roundedPrice', 'price', 'priceUnit', 'tagID', + 'currentCumulatedPrice', 'currentInactivityStatus', 'roundedPrice', 'price', 'priceUnit', 'tagID', 'site.name', 'siteArea.name', ]); res.json(transactions); next(); @@ -705,7 +705,7 @@ export default class TransactionService { const transactions = await TransactionService.getTransactions(req, action, {}, [ 'id', 'chargeBoxID', 'timestamp', 'issuer', 'stateOfCharge', 'timezone', 'connectorId', 'meterStart', 'siteAreaID', 'siteID', 'stop.roundedPrice', 'stop.price', 'stop.priceUnit', 'stop.inactivityStatus', 'stop.stateOfCharge', 'stop.timestamp', 'stop.totalConsumptionWh', - 'stop.totalDurationSecs', 'stop.totalInactivitySecs', 'stop.extraInactivitySecs', 'stop.meterStop', + 'stop.totalDurationSecs', 'stop.totalInactivitySecs', 'stop.extraInactivitySecs', 'stop.meterStop', 'site.name', 'siteArea.name', 'billingData.stop.invoiceNumber', 'stop.reason', 'ocpi', 'ocpiWithCdr', 'tagID', 'stop.tagID', ]); res.json(transactions); @@ -722,7 +722,7 @@ export default class TransactionService { req.query.Status = 'completed'; const transactions = await TransactionService.getTransactions(req, action, {}, [ 'id', 'chargeBoxID', 'timestamp', 'issuer', 'stateOfCharge', 'timezone', 'connectorId', 'meterStart', 'siteAreaID', 'siteID', - 'refundData.reportId', 'refundData.refundedAt', 'refundData.status', + 'refundData.reportId', 'refundData.refundedAt', 'refundData.status', 'site.name', 'siteArea.name', 'stop.roundedPrice', 'stop.price', 'stop.priceUnit', 'stop.inactivityStatus', 'stop.stateOfCharge', 'stop.timestamp', 'stop.totalConsumptionWh', 'stop.totalDurationSecs', 'stop.totalInactivitySecs', 'stop.extraInactivitySecs', 'billingData.stop.invoiceNumber', 'tagID', 'stop.tagID', 'stop.reason', @@ -790,7 +790,7 @@ export default class TransactionService { return TransactionService.getTransactions(req, ServerAction.TRANSACTIONS_EXPORT, { withTag: true }, [ 'id', 'chargeBoxID', 'timestamp', 'issuer', 'stateOfCharge', 'timezone', 'connectorId', 'meterStart', 'siteAreaID', 'siteID', 'stop.roundedPrice', 'stop.price', 'stop.priceUnit', 'stop.inactivityStatus', 'stop.stateOfCharge', 'stop.timestamp', 'stop.totalConsumptionWh', - 'stop.totalDurationSecs', 'stop.totalInactivitySecs', 'stop.extraInactivitySecs', + 'stop.totalDurationSecs', 'stop.totalInactivitySecs', 'stop.extraInactivitySecs', 'site.name', 'siteArea.name', 'billingData.stop.invoiceNumber', 'stop.reason', 'ocpi', 'ocpiWithCdr', 'tagID', 'stop.tagID', 'tag.description' ]); } @@ -806,7 +806,7 @@ export default class TransactionService { req.query.Status = 'completed'; return await TransactionService.getTransactions(req, ServerAction.TRANSACTIONS_TO_REFUND_EXPORT, {}, [ 'id', 'chargeBoxID', 'timestamp', 'issuer', 'stateOfCharge', 'timezone', 'connectorId', 'meterStart', 'siteAreaID', 'siteID', - 'refundData.reportId', 'refundData.refundedAt', 'refundData.status', + 'refundData.reportId', 'refundData.refundedAt', 'refundData.status', 'site.name', 'siteArea.name', 'stop.roundedPrice', 'stop.price', 'stop.priceUnit', 'stop.inactivityStatus', 'stop.stateOfCharge', 'stop.timestamp', 'stop.totalConsumptionWh', 'stop.totalDurationSecs', 'stop.totalInactivitySecs', 'stop.extraInactivitySecs', 'billingData.stop.invoiceNumber', 'stop.reason', 'tagID', 'stop.tagID', @@ -1106,6 +1106,8 @@ export default class TransactionService { userIDs: filteredRequest.UserID ? filteredRequest.UserID.split('|') : null, tagIDs: filteredRequest.TagID ? filteredRequest.TagID.split('|') : null, ownerID: Authorizations.isBasic(req.user) ? req.user.id : null, + withSite: filteredRequest.WithSite, + withSiteArea: filteredRequest.WithSiteArea, siteAreaIDs: filteredRequest.SiteAreaID ? filteredRequest.SiteAreaID.split('|') : null, siteIDs: filteredRequest.SiteID ? Authorizations.getAuthorizedSiteAdminIDs(req.user, filteredRequest.SiteID.split('|')) : null, siteAdminIDs: Authorizations.getAuthorizedSiteAdminIDs(req.user), diff --git a/src/types/requests/HttpChargingStationRequest.ts b/src/types/requests/HttpChargingStationRequest.ts index e4b0acc50b..1c5858a2f7 100644 --- a/src/types/requests/HttpChargingStationRequest.ts +++ b/src/types/requests/HttpChargingStationRequest.ts @@ -39,6 +39,7 @@ export interface HttpChargingStationsRequest extends HttpDatabaseRequest { ChargingStationID?: string; SiteID?: string; WithSite?: boolean; + WithSiteArea?: boolean; SiteAreaID?: string; IncludeDeleted?: boolean; ErrorType?: string; diff --git a/src/types/requests/HttpTransactionRequest.ts b/src/types/requests/HttpTransactionRequest.ts index 72d19f577e..5a86e62a03 100644 --- a/src/types/requests/HttpTransactionRequest.ts +++ b/src/types/requests/HttpTransactionRequest.ts @@ -25,6 +25,8 @@ export interface HttpPushTransactionCdrRequest { export interface HttpTransactionsRequest extends HttpDatabaseRequest { ChargingStationID: string; Issuer: boolean; + WithSite: boolean; + WithSiteArea: boolean; ConnectorID: string; SiteAreaID?: string; SiteID?: string; From af63b7ad059e9ecec8b038de23d19377dd23de41 Mon Sep 17 00:00:00 2001 From: LucasBrazi06 Date: Mon, 5 Jul 2021 18:38:26 +0200 Subject: [PATCH 05/28] Fixed unit tests --- test/api/OCPPCommonTests.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/api/OCPPCommonTests.ts b/test/api/OCPPCommonTests.ts index 039b6b5944..e5ef32ebf0 100644 --- a/test/api/OCPPCommonTests.ts +++ b/test/api/OCPPCommonTests.ts @@ -1146,8 +1146,8 @@ export default class OCPPCommonTests { 'tagID': this.transactionStartUser.tags[0].id, 'meterStart': meterStart, 'userID': this.transactionStartUser.id, - 'siteAreaID': this.chargingStationContext.getChargingStation().siteAreaID ? this.chargingStationContext.getChargingStation().siteAreaID : null, - 'siteID': this.chargingStationContext.getChargingStation().siteArea ? this.chargingStationContext.getChargingStation().siteArea.siteID : null, + 'siteAreaID': this.chargingStationContext.getChargingStation().siteAreaID, + 'siteID': this.chargingStationContext.getChargingStation().siteID, 'user': { 'id': this.transactionStartUser.id, 'name': this.transactionStartUser.name, From 760474dd86f7d1e68064520ec718e85c63866c4e Mon Sep 17 00:00:00 2001 From: LucasBrazi06 Date: Tue, 6 Jul 2021 01:09:29 +0200 Subject: [PATCH 06/28] Export site/site area in export sessions --- src/server/rest/v1/service/TransactionService.ts | 6 +++++- src/types/Transaction.ts | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/server/rest/v1/service/TransactionService.ts b/src/server/rest/v1/service/TransactionService.ts index fd8843005b..01980715af 100644 --- a/src/server/rest/v1/service/TransactionService.ts +++ b/src/server/rest/v1/service/TransactionService.ts @@ -918,7 +918,9 @@ export default class TransactionService { const headerArray = [ 'id', 'chargingStationID', - 'connector', + 'connectorID', + 'siteName', + 'siteAreaName', 'userID', 'user', 'tagID', @@ -942,6 +944,8 @@ export default class TransactionService { transaction.id, transaction.chargeBoxID, transaction.connectorId, + transaction.site?.name, + transaction.siteArea?.name, transaction.user ? Cypher.hash(transaction.user.id) : '', transaction.user ? Utils.buildUserFullName(transaction.user, false) : '', transaction.tagID, diff --git a/src/types/Transaction.ts b/src/types/Transaction.ts index 0d4cfafbe3..7171be2d44 100644 --- a/src/types/Transaction.ts +++ b/src/types/Transaction.ts @@ -10,6 +10,8 @@ import { OICPChargeDetailRecord } from './oicp/OICPChargeDetailRecord'; import { OICPSession } from './oicp/OICPSession'; import { PricingModel } from './Pricing'; import { RefundTransactionData } from './Refund'; +import Site from './Site'; +import SiteArea from './SiteArea'; import Tag from './Tag'; import User from './User'; @@ -53,7 +55,9 @@ export default interface Transaction extends AbstractCurrentConsumption { carCatalog?: CarCatalog; phasesUsed?: CSPhasesUsed; siteID?: string; + site?: Site; siteAreaID?: string; + siteArea?: SiteArea; issuer: boolean; connectorId: number; tagID: string; From 93fcfaba34dbc8e8ad082a4edec3fdf40a7767bd Mon Sep 17 00:00:00 2001 From: LucasBrazi06 Date: Tue, 6 Jul 2021 08:06:01 +0200 Subject: [PATCH 07/28] Adjusted Session In Error - No User --- src/storage/mongodb/TransactionStorage.ts | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/storage/mongodb/TransactionStorage.ts b/src/storage/mongodb/TransactionStorage.ts index eba4f677c3..c5277699a0 100644 --- a/src/storage/mongodb/TransactionStorage.ts +++ b/src/storage/mongodb/TransactionStorage.ts @@ -1331,15 +1331,7 @@ export default class TransactionStorage { return [ { $match: { - $and: [ - { - $or: [ - { 'userID': null }, - { 'user': null }, - ] - }, - { 'siteArea.accessControl': { '$eq': true } } - ] + 'userID': null, } }, { $addFields: { 'errorCode': TransactionInErrorType.MISSING_USER } } @@ -1355,8 +1347,6 @@ export default class TransactionStorage { { 'billingData': { $exists: false } }, { 'billingData.stop': { $exists: false } }, { 'billingData.stop.status': { $eq: BillingStatus.FAILED } }, - // { 'billingData.stop.invoiceID': { $exists: false } }, - // { 'billingData.stop.invoiceID': { $eq: null } } ] } ] From d7a5f6495a9832124033c0832a6bd731cbd192f2 Mon Sep 17 00:00:00 2001 From: Loan ALOUACHE Date: Tue, 6 Jul 2021 11:13:32 +0200 Subject: [PATCH 08/28] Fixed commands prefix --- src/server/rest/v1/service/ChargingStationService.ts | 2 +- test/api/TenantTest.ts | 7 ------- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/src/server/rest/v1/service/ChargingStationService.ts b/src/server/rest/v1/service/ChargingStationService.ts index 4f56d11f69..1ab41ebb3f 100644 --- a/src/server/rest/v1/service/ChargingStationService.ts +++ b/src/server/rest/v1/service/ChargingStationService.ts @@ -1140,7 +1140,7 @@ export default class ChargingStationService { // Backward compatibility for the mobile application req.body.chargeBoxID && (req.body.chargingStationID = req.body.chargeBoxID); // Filter - Type is hacked because code below is. Would need approval to change code structure. - const command = action.slice(15) as Command; + const command = action.slice('RestChargingStation'.length) as Command; const filteredRequest = ChargingStationValidator.getInstance().validateChargingStationActionReq(req.body); UtilsService.assertIdIsProvided(action, filteredRequest.chargingStationID, MODULE_NAME, 'handleAction', req.user); // Get the Charging station diff --git a/test/api/TenantTest.ts b/test/api/TenantTest.ts index fd5a9df481..dcc8fd2ff6 100644 --- a/test/api/TenantTest.ts +++ b/test/api/TenantTest.ts @@ -140,13 +140,6 @@ describe('Tenant', function() { }); describe('Error cases', () => { - it('Should not be possible to read an empty tenant', async () => { - // Exec - const response = await CentralServerService.defaultInstance.getEntityById( - CentralServerService.defaultInstance.tenantApi, { id: '' }, false); - // Check - expect(response.status).to.equal(StatusCodes.INTERNAL_SERVER_ERROR); - }); it('Should not be possible to read an invalid tenant', async () => { // Exec From a401aeb9f29c6a47f057d98d34d9e6ef209668b0 Mon Sep 17 00:00:00 2001 From: Rohan Antony Date: Tue, 6 Jul 2021 14:50:09 +0200 Subject: [PATCH 09/28] Initial Changes --- src/client/oicp/CpoOICPClient.ts | 4 +- src/client/oicp/OICPClient.ts | 4 +- src/client/oicp/OICPClientFactory.ts | 2 +- .../tasks/oicp/OICPPushEvseDataTask.ts | 2 +- .../tasks/oicp/OICPPushEvseStatusTask.ts | 2 +- .../rest/v1/service/OICPEndpointService.ts | 24 ++++----- src/server/rest/v1/service/TenantService.ts | 4 +- src/storage/mongodb/OICPEndpointStorage.ts | 51 ++++++++++--------- 8 files changed, 47 insertions(+), 46 deletions(-) diff --git a/src/client/oicp/CpoOICPClient.ts b/src/client/oicp/CpoOICPClient.ts index f6e4d503cf..24eae04e1d 100644 --- a/src/client/oicp/CpoOICPClient.ts +++ b/src/client/oicp/CpoOICPClient.ts @@ -309,7 +309,7 @@ export default class CpoOICPClient extends OICPClient { } // Save const executionDurationSecs = Utils.createDecimal(new Date().getTime()).minus(startTime).div(1000).toNumber(); - await OICPEndpointStorage.saveOicpEndpoint(this.tenant.id, this.oicpEndpoint); + await OICPEndpointStorage.saveOicpEndpoint(this.tenant, this.oicpEndpoint); await Logging.logOicpResult(this.tenant.id, ServerAction.OICP_PUSH_EVSE_DATA, MODULE_NAME, 'sendEVSEs', result, `{{inSuccess}} EVSE(s) were successfully patched in ${executionDurationSecs}s`, @@ -444,7 +444,7 @@ export default class CpoOICPClient extends OICPClient { } // Save const executionDurationSecs = (new Date().getTime() - startTime) / 1000; - await OICPEndpointStorage.saveOicpEndpoint(this.tenant.id, this.oicpEndpoint); + await OICPEndpointStorage.saveOicpEndpoint(this.tenant, this.oicpEndpoint); await Logging.logOicpResult(this.tenant.id, ServerAction.OICP_PUSH_EVSE_STATUSES, MODULE_NAME, 'sendEVSEStatuses', result, `{{inSuccess}} EVSE Status(es) were successfully patched in ${executionDurationSecs}s`, diff --git a/src/client/oicp/OICPClient.ts b/src/client/oicp/OICPClient.ts index 3201feac94..38ee23a544 100644 --- a/src/client/oicp/OICPClient.ts +++ b/src/client/oicp/OICPClient.ts @@ -82,7 +82,7 @@ export default abstract class OICPClient { try { // Save endpoint this.oicpEndpoint.status = OICPRegistrationStatus.UNREGISTERED; - await OICPEndpointStorage.saveOicpEndpoint(this.tenant.id, this.oicpEndpoint); + await OICPEndpointStorage.saveOicpEndpoint(this.tenant, this.oicpEndpoint); // Send success unregisterResult.statusCode = StatusCodes.OK; unregisterResult.statusText = ReasonPhrases.OK; @@ -99,7 +99,7 @@ export default abstract class OICPClient { try { // Save endpoint this.oicpEndpoint.status = OICPRegistrationStatus.REGISTERED; - await OICPEndpointStorage.saveOicpEndpoint(this.tenant.id, this.oicpEndpoint); + await OICPEndpointStorage.saveOicpEndpoint(this.tenant, this.oicpEndpoint); // Send success registerResult.statusCode = StatusCodes.OK; registerResult.statusText = ReasonPhrases.OK; diff --git a/src/client/oicp/OICPClientFactory.ts b/src/client/oicp/OICPClientFactory.ts index b5d6e00e38..c80aacda79 100644 --- a/src/client/oicp/OICPClientFactory.ts +++ b/src/client/oicp/OICPClientFactory.ts @@ -51,7 +51,7 @@ export default class OICPClientFactory { } static async getAvailableOicpClient(tenant: Tenant, oicpRole: string): Promise { - const oicpEndpoints = await OICPEndpointStorage.getOicpEndpoints(tenant.id, { role: oicpRole }, Constants.DB_PARAMS_MAX_LIMIT); + const oicpEndpoints = await OICPEndpointStorage.getOicpEndpoints(tenant, { role: oicpRole }, Constants.DB_PARAMS_MAX_LIMIT); for (const oicpEndpoint of oicpEndpoints.result) { if (oicpEndpoint.status === OICPRegistrationStatus.REGISTERED) { const client = await OICPClientFactory.getOicpClient(tenant, oicpEndpoint); diff --git a/src/scheduler/tasks/oicp/OICPPushEvseDataTask.ts b/src/scheduler/tasks/oicp/OICPPushEvseDataTask.ts index 03cd5b6d64..1a78017693 100644 --- a/src/scheduler/tasks/oicp/OICPPushEvseDataTask.ts +++ b/src/scheduler/tasks/oicp/OICPPushEvseDataTask.ts @@ -24,7 +24,7 @@ export default class OICPPushEvseDataTask extends SchedulerTask { // Check if OICP component is active if (Utils.isTenantComponentActive(tenant, TenantComponents.OICP)) { // Get all available endpoints - const oicpEndpoints = await OICPEndpointStorage.getOicpEndpoints(tenant.id, { role: OICPRole.CPO }, Constants.DB_PARAMS_MAX_LIMIT); + const oicpEndpoints = await OICPEndpointStorage.getOicpEndpoints(tenant, { role: OICPRole.CPO }, Constants.DB_PARAMS_MAX_LIMIT); for (const oicpEndpoint of oicpEndpoints.result) { await this.processOICPEndpoint(tenant, oicpEndpoint, config); } diff --git a/src/scheduler/tasks/oicp/OICPPushEvseStatusTask.ts b/src/scheduler/tasks/oicp/OICPPushEvseStatusTask.ts index 71d7832d10..56fa958a4b 100644 --- a/src/scheduler/tasks/oicp/OICPPushEvseStatusTask.ts +++ b/src/scheduler/tasks/oicp/OICPPushEvseStatusTask.ts @@ -24,7 +24,7 @@ export default class OICPPushEvseStatusTask extends SchedulerTask { // Check if OICP component is active if (Utils.isTenantComponentActive(tenant, TenantComponents.OICP)) { // Get all available endpoints - const oicpEndpoints = await OICPEndpointStorage.getOicpEndpoints(tenant.id, { role: OICPRole.CPO }, Constants.DB_PARAMS_MAX_LIMIT); + const oicpEndpoints = await OICPEndpointStorage.getOicpEndpoints(tenant, { role: OICPRole.CPO }, Constants.DB_PARAMS_MAX_LIMIT); for (const oicpEndpoint of oicpEndpoints.result) { await this.processOICPEndpoint(tenant, oicpEndpoint, config); } diff --git a/src/server/rest/v1/service/OICPEndpointService.ts b/src/server/rest/v1/service/OICPEndpointService.ts index ae166b7959..4feea5e98a 100644 --- a/src/server/rest/v1/service/OICPEndpointService.ts +++ b/src/server/rest/v1/service/OICPEndpointService.ts @@ -39,11 +39,11 @@ export default class OICPEndpointService { }); } // Get - const oicpEndpoint = await OICPEndpointStorage.getOicpEndpoint(req.tenant.id, filteredRequest.ID); + const oicpEndpoint = await OICPEndpointStorage.getOicpEndpoint(req.tenant, filteredRequest.ID); UtilsService.assertObjectExists(action, oicpEndpoint, `OICP Endpoint ID '${filteredRequest.ID}' does not exist`, MODULE_NAME, 'handleDeleteOicpEndpoint', req.user); // Delete - await OICPEndpointStorage.deleteOicpEndpoint(req.tenant.id, oicpEndpoint.id); + await OICPEndpointStorage.deleteOicpEndpoint(req.tenant, oicpEndpoint.id); // Log await Logging.logSecurityInfo({ tenantID: req.tenant.id, @@ -93,7 +93,7 @@ export default class OICPEndpointService { notifications: OICPEndpointPaths.NOTIFICATIONS } } as OICPEndpoint; - const endpointID = await OICPEndpointStorage.saveOicpEndpoint(req.tenant.id, oicpEndpoint); + const endpointID = await OICPEndpointStorage.saveOicpEndpoint(req.tenant, oicpEndpoint); // Log await Logging.logSecurityInfo({ tenantID: req.tenant.id, @@ -126,14 +126,14 @@ export default class OICPEndpointService { }); } // Get OicpEndpoint - const oicpEndpoint = await OICPEndpointStorage.getOicpEndpoint(req.tenant.id, filteredRequest.id); + const oicpEndpoint = await OICPEndpointStorage.getOicpEndpoint(req.tenant, filteredRequest.id); UtilsService.assertObjectExists(action, oicpEndpoint, `OICP Endpoint ID '${filteredRequest.id}' does not exist`, MODULE_NAME, 'handleUpdateOicpEndpoint', req.user); // Update timestamp oicpEndpoint.lastChangedBy = { 'id': req.user.id }; oicpEndpoint.lastChangedOn = new Date(); // Update OicpEndpoint - await OICPEndpointStorage.saveOicpEndpoint(req.tenant.id, { ...oicpEndpoint, ...filteredRequest }); + await OICPEndpointStorage.saveOicpEndpoint(req.tenant, { ...oicpEndpoint, ...filteredRequest }); // Log await Logging.logSecurityInfo({ tenantID: req.tenant.id, @@ -165,7 +165,7 @@ export default class OICPEndpointService { }); } // Get it - const oicpEndpoint = await OICPEndpointStorage.getOicpEndpoint(req.tenant.id, endpointID, + const oicpEndpoint = await OICPEndpointStorage.getOicpEndpoint(req.tenant, endpointID, [ 'id', 'name', 'role', 'baseUrl', 'countryCode', 'partyId', 'version', 'status', 'patchJobStatus', 'localToken', 'token', 'patchJobResult.successNbr', 'patchJobResult.failureNbr', 'patchJobResult.totalNbr' @@ -197,7 +197,7 @@ export default class OICPEndpointService { // Filter const filteredRequest = OICPEndpointSecurity.filterOicpEndpointsRequest(req.query); // Get all oicpendpoints - const oicpEndpoints = await OICPEndpointStorage.getOicpEndpoints(req.tenant.id, + const oicpEndpoints = await OICPEndpointStorage.getOicpEndpoints(req.tenant, { 'search': filteredRequest.Search }, { @@ -235,7 +235,7 @@ export default class OICPEndpointService { const filteredRequest = OICPEndpointSecurity.filterOicpEndpointSendEVSEStatusesRequest(req.body); UtilsService.assertIdIsProvided(action, filteredRequest.id, MODULE_NAME, 'handleSendEVSEStatusesOicpEndpoint', req.user); // Get oicpEndpoint - const oicpEndpoint = await OICPEndpointStorage.getOicpEndpoint(req.tenant.id, filteredRequest.id); + const oicpEndpoint = await OICPEndpointStorage.getOicpEndpoint(req.tenant, filteredRequest.id); UtilsService.assertObjectExists(action, oicpEndpoint, `OICP Endpoint ID '${filteredRequest.id}' does not exist`, MODULE_NAME, 'handleSendEVSEStatusesOicpEndpoint', req.user); // Build OICP Client @@ -266,7 +266,7 @@ export default class OICPEndpointService { const filteredRequest = OICPEndpointSecurity.filterOicpEndpointSendEVSEsRequest(req.body); UtilsService.assertIdIsProvided(action, filteredRequest.id, MODULE_NAME, 'handleSendEVSEsOicpEndpoint', req.user); // Get oicpEndpoint - const oicpEndpoint = await OICPEndpointStorage.getOicpEndpoint(req.tenant.id, filteredRequest.id); + const oicpEndpoint = await OICPEndpointStorage.getOicpEndpoint(req.tenant, filteredRequest.id); UtilsService.assertObjectExists(action, oicpEndpoint, `OICP Endpoint ID '${filteredRequest.id}' does not exist`, MODULE_NAME, 'handleSendEVSEsOicpEndpoint', req.user); // Build OICP Client @@ -298,7 +298,7 @@ export default class OICPEndpointService { // Check Mandatory fields UtilsService.checkIfOICPEndpointValid(filteredRequest, req); // Get oicpEndpoint - const oicpEndpoint = await OICPEndpointStorage.getOicpEndpoint(req.tenant.id, filteredRequest.id); + const oicpEndpoint = await OICPEndpointStorage.getOicpEndpoint(req.tenant, filteredRequest.id); // Build OICP Client const oicpClient = await OICPClientFactory.getOicpClient(req.tenant, oicpEndpoint); // Try to ping @@ -345,7 +345,7 @@ export default class OICPEndpointService { const filteredRequest = OICPEndpointSecurity.filterOicpEndpointRegisterRequest(req.body); UtilsService.assertIdIsProvided(action, filteredRequest.id, MODULE_NAME, 'handleUnregisterOicpEndpoint', req.user); // Get OicpEndpoint - const oicpEndpoint = await OICPEndpointStorage.getOicpEndpoint(req.tenant.id, filteredRequest.id); + const oicpEndpoint = await OICPEndpointStorage.getOicpEndpoint(req.tenant, filteredRequest.id); UtilsService.assertObjectExists(action, oicpEndpoint, `OICP Endpoint ID '${filteredRequest.id}' does not exist`, MODULE_NAME, 'handleUnregisterOicpEndpoint', req.user); // Build OICP Client @@ -394,7 +394,7 @@ export default class OICPEndpointService { const filteredRequest = OICPEndpointSecurity.filterOicpEndpointRegisterRequest(req.body); UtilsService.assertIdIsProvided(action, filteredRequest.id, MODULE_NAME, 'handleRegisterOicpEndpoint', req.user); // Get OicpEndpoint - const oicpEndpoint = await OICPEndpointStorage.getOicpEndpoint(req.tenant.id, filteredRequest.id); + const oicpEndpoint = await OICPEndpointStorage.getOicpEndpoint(req.tenant, filteredRequest.id); UtilsService.assertObjectExists(action, oicpEndpoint, `OICP Endpoint ID '${filteredRequest.id}' does not exist`, MODULE_NAME, 'handleRegisterOicpEndpoint', req.user); // Build OICP Client diff --git a/src/server/rest/v1/service/TenantService.ts b/src/server/rest/v1/service/TenantService.ts index fb72482061..5f09c29c23 100644 --- a/src/server/rest/v1/service/TenantService.ts +++ b/src/server/rest/v1/service/TenantService.ts @@ -445,9 +445,9 @@ export default class TenantService { await UserStorage.deleteUser(tenant.id, virtualOICPUser.id); } // Delete Endpoints if component is inactive - const oicpEndpoints = await OICPEndpointStorage.getOicpEndpoints(tenant.id, { role: OICPRole.CPO }, Constants.DB_PARAMS_MAX_LIMIT); + const oicpEndpoints = await OICPEndpointStorage.getOicpEndpoints(tenant, { role: OICPRole.CPO }, Constants.DB_PARAMS_MAX_LIMIT); oicpEndpoints.result.forEach(async (oicpEndpoint) => { - await OICPEndpointStorage.deleteOicpEndpoint(tenant.id, oicpEndpoint.id); + await OICPEndpointStorage.deleteOicpEndpoint(tenant, oicpEndpoint.id); }); } } diff --git a/src/storage/mongodb/OICPEndpointStorage.ts b/src/storage/mongodb/OICPEndpointStorage.ts index 8cbdc193fe..aed34a9b8b 100644 --- a/src/storage/mongodb/OICPEndpointStorage.ts +++ b/src/storage/mongodb/OICPEndpointStorage.ts @@ -8,22 +8,23 @@ import DbParams from '../../types/database/DbParams'; import Logging from '../../utils/Logging'; import OICPEndpoint from '../../types/oicp/OICPEndpoint'; import { ObjectID } from 'mongodb'; +import Tenant from '../../types/Tenant'; import Utils from '../../utils/Utils'; const MODULE_NAME = 'OICPEndpointStorage'; export default class OICPEndpointStorage { - static async getOicpEndpoint(tenantID: string, id: string, projectFields?: string[]): Promise { + static async getOicpEndpoint(tenant: Tenant, id: string, projectFields?: string[]): Promise { const endpointsMDB = await OICPEndpointStorage.getOicpEndpoints( - tenantID, { oicpEndpointIDs: [id] }, Constants.DB_PARAMS_SINGLE_RECORD, projectFields); + tenant, { oicpEndpointIDs: [id] }, Constants.DB_PARAMS_SINGLE_RECORD, projectFields); return endpointsMDB.count === 1 ? endpointsMDB.result[0] : null; } - static async saveOicpEndpoint(tenantID: string, oicpEndpointToSave: OICPEndpoint): Promise { + static async saveOicpEndpoint(tenant: Tenant, oicpEndpointToSave: OICPEndpoint): Promise { // Debug - const uniqueTimerID = Logging.traceStart(tenantID, MODULE_NAME, 'saveOicpEndpoint'); + const uniqueTimerID = Logging.traceStart(tenant.id, MODULE_NAME, 'saveOicpEndpoint'); // Check Tenant - await DatabaseUtils.checkTenant(tenantID); + DatabaseUtils.checkTenantObject(tenant); // Check if name is provided if (!oicpEndpointToSave.name) { // Name must be provided! @@ -59,24 +60,24 @@ export default class OICPEndpointStorage { // Add Last Changed/Created props DatabaseUtils.addLastChangedCreatedProps(oicpEndpointMDB, oicpEndpointToSave); // Modify - await global.database.getCollection(tenantID, 'oicpendpoints').findOneAndUpdate( + await global.database.getCollection(tenant.id, 'oicpendpoints').findOneAndUpdate( oicpEndpointFilter, { $set: oicpEndpointMDB }, { upsert: true, returnDocument: 'after' }); // Debug - await Logging.traceEnd(tenantID, MODULE_NAME, 'saveOicpEndpoint', uniqueTimerID, { oicpEndpointToSave: oicpEndpointToSave }); + await Logging.traceEnd(tenant.id, MODULE_NAME, 'saveOicpEndpoint', uniqueTimerID, { oicpEndpointToSave: oicpEndpointToSave }); // Create return oicpEndpointFilter._id.toHexString(); } // Delegate - static async getOicpEndpoints(tenantID: string, + static async getOicpEndpoints(tenant: Tenant, params: { search?: string; role?: string; oicpEndpointIDs?: string[]; localToken?: string }, dbParams: DbParams, projectFields?: string[]): Promise> { // Debug - const uniqueTimerID = Logging.traceStart(tenantID, MODULE_NAME, 'getOicpEndpoints'); + const uniqueTimerID = Logging.traceStart(tenant.id, MODULE_NAME, 'getOicpEndpoints'); // Check Tenant - await DatabaseUtils.checkTenant(tenantID); + DatabaseUtils.checkTenantObject(tenant); // Clone before updating the values dbParams = Utils.cloneObject(dbParams); // Check Limit @@ -115,12 +116,12 @@ export default class OICPEndpointStorage { aggregation.push({ $limit: Constants.DB_RECORD_COUNT_CEIL }); } // Count Records - const oicpEndpointsCountMDB = await global.database.getCollection(tenantID, 'oicpendpoints') + const oicpEndpointsCountMDB = await global.database.getCollection(tenant.id, 'oicpendpoints') .aggregate([...aggregation, { $count: 'count' }]) .toArray(); // Check if only the total count is requested if (dbParams.onlyRecordCount) { - await Logging.traceEnd(tenantID, MODULE_NAME, 'getOicpEndpoints', uniqueTimerID, oicpEndpointsCountMDB); + await Logging.traceEnd(tenant.id, MODULE_NAME, 'getOicpEndpoints', uniqueTimerID, oicpEndpointsCountMDB); return { count: (oicpEndpointsCountMDB.length > 0 ? oicpEndpointsCountMDB[0].count : 0), result: [] @@ -129,7 +130,7 @@ export default class OICPEndpointStorage { // Remove the limit aggregation.pop(); // Add Created By / Last Changed By - DatabaseUtils.pushCreatedLastChangedInAggregation(tenantID, aggregation); + DatabaseUtils.pushCreatedLastChangedInAggregation(tenant.id, aggregation); // Handle the ID DatabaseUtils.pushRenameDatabaseID(aggregation); // Sort @@ -150,13 +151,13 @@ export default class OICPEndpointStorage { // Project DatabaseUtils.projectFields(aggregation, projectFields); // Read DB - const oicpEndpointsMDB = await global.database.getCollection(tenantID, 'oicpendpoints') + const oicpEndpointsMDB = await global.database.getCollection(tenant.id, 'oicpendpoints') .aggregate(aggregation, { allowDiskUse: true }) .toArray(); // Debug - await Logging.traceEnd(tenantID, MODULE_NAME, 'getOicpEndpoints', uniqueTimerID, oicpEndpointsMDB); + await Logging.traceEnd(tenant.id, MODULE_NAME, 'getOicpEndpoints', uniqueTimerID, oicpEndpointsMDB); // Ok return { count: (oicpEndpointsCountMDB.length > 0 ? oicpEndpointsCountMDB[0].count : 0), @@ -164,26 +165,26 @@ export default class OICPEndpointStorage { }; } - static async deleteOicpEndpoint(tenantID: string, id: string): Promise { + static async deleteOicpEndpoint(tenant: Tenant, id: string): Promise { // Debug - const uniqueTimerID = Logging.traceStart(tenantID, MODULE_NAME, 'deleteOicpEndpoint'); + const uniqueTimerID = Logging.traceStart(tenant.id, MODULE_NAME, 'deleteOicpEndpoint'); // Check Tenant - await DatabaseUtils.checkTenant(tenantID); + DatabaseUtils.checkTenantObject(tenant); // Delete OicpEndpoint - await global.database.getCollection(tenantID, 'oicpendpoints') + await global.database.getCollection(tenant.id, 'oicpendpoints') .findOneAndDelete({ '_id': DatabaseUtils.convertToObjectID(id) }); // Debug - await Logging.traceEnd(tenantID, MODULE_NAME, 'deleteOicpEndpoint', uniqueTimerID, { id }); + await Logging.traceEnd(tenant.id, MODULE_NAME, 'deleteOicpEndpoint', uniqueTimerID, { id }); } - static async deleteOicpEndpoints(tenantID: string): Promise { + static async deleteOicpEndpoints(tenant: Tenant): Promise { // Debug - const uniqueTimerID = Logging.traceStart(tenantID, MODULE_NAME, 'deleteOicpEndpoints'); + const uniqueTimerID = Logging.traceStart(tenant.id, MODULE_NAME, 'deleteOicpEndpoints'); // Check Tenant - await DatabaseUtils.checkTenant(tenantID); + DatabaseUtils.checkTenantObject(tenant); // Delete OicpEndpoint - await global.database.getCollection(tenantID, 'oicpendpoints').deleteMany({}); + await global.database.getCollection(tenant.id, 'oicpendpoints').deleteMany({}); // Debug - await Logging.traceEnd(tenantID, MODULE_NAME, 'deleteOicpEndpoints', uniqueTimerID); + await Logging.traceEnd(tenant.id, MODULE_NAME, 'deleteOicpEndpoints', uniqueTimerID); } } From 26294a0f6328c28de2e3372777e960821e294396 Mon Sep 17 00:00:00 2001 From: OliveGerste <33114317+OliveGerste@users.noreply.github.com> Date: Tue, 6 Jul 2021 16:24:08 +0200 Subject: [PATCH 10/28] Test efficiency excluded cs --- test/api/SmartChargingTest.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/test/api/SmartChargingTest.ts b/test/api/SmartChargingTest.ts index 4a6b3c8155..daa134b0db 100644 --- a/test/api/SmartChargingTest.ts +++ b/test/api/SmartChargingTest.ts @@ -891,9 +891,13 @@ describe('Smart Charging Service', function() { it('Test if whole charge point is excluded from root fuse when charging station is excluded (one connector charging)', async () => { await smartChargingIntegration.buildChargingProfiles(testData.siteAreaContext.getSiteArea(), [testData.chargingStationContext.getChargingStation().id]); const log = await LoggingStorage.getLogs(testData.tenantContext.getTenant().id, { actions: [ServerAction.SMART_CHARGING], search: 'currently being used' }, Constants.DB_PARAMS_SINGLE_RECORD, null); + const chargingStation = testData.chargingStationContext.getChargingStation(); + const chargePoint = chargingStation.chargePoints.find((cp) => cp.connectorIDs.includes(transaction.connectorId)); const siteArea = testData.siteAreaContext.getSiteArea(); const siteAreaLimitPerPhase = Utils.createDecimal(siteArea.maximumPower).div(siteArea.voltage).div(3).toNumber(); - const connectorLimitPerPhase = Utils.createDecimal(Utils.getChargingStationAmperage(testData.chargingStationContext.getChargingStation())).div(3).toNumber(); + let connectorLimitPerPhase = Utils.createDecimal(Utils.getChargingStationAmperage(chargingStation)).div(3).toNumber(); + // Calculate efficiency + connectorLimitPerPhase = Utils.createDecimal(connectorLimitPerPhase).mul(100).div(chargePoint.efficiency).toNumber(); expect(log.result[0].detailedMessages).include('"fusePhase1": ' + (siteAreaLimitPerPhase - connectorLimitPerPhase)); expect(log.result[0].detailedMessages).include('"fusePhase2": ' + (siteAreaLimitPerPhase - connectorLimitPerPhase)); expect(log.result[0].detailedMessages).include('"fusePhase3": ' + (siteAreaLimitPerPhase - connectorLimitPerPhase)); @@ -940,9 +944,13 @@ describe('Smart Charging Service', function() { it('Test if only charge point is excluded from root fuse when charging station is excluded (two connectors charging)', async () => { await smartChargingIntegration.buildChargingProfiles(testData.siteAreaContext.getSiteArea(), [testData.chargingStationContext.getChargingStation().id]); const log = await LoggingStorage.getLogs(testData.tenantContext.getTenant().id, { actions: [ServerAction.SMART_CHARGING], search: 'currently being used' }, Constants.DB_PARAMS_SINGLE_RECORD, null); + const chargingStation = testData.chargingStationContext.getChargingStation(); + const chargePoint = chargingStation.chargePoints.find((cp) => cp.connectorIDs.includes(transaction.connectorId)); const siteArea = testData.siteAreaContext.getSiteArea(); const siteAreaLimitPerPhase = Utils.createDecimal(siteArea.maximumPower).div(siteArea.voltage).div(3).toNumber(); - const connectorLimitPerPhase = Utils.createDecimal(Utils.getChargingStationAmperage(testData.chargingStationContext.getChargingStation())).div(3).toNumber(); + let connectorLimitPerPhase = Utils.createDecimal(Utils.getChargingStationAmperage(chargingStation)).div(3).toNumber(); + // Calculate efficiency + connectorLimitPerPhase = Utils.createDecimal(connectorLimitPerPhase).mul(100).div(chargePoint.efficiency).toNumber(); expect(log.result[0].detailedMessages).include('"fusePhase1": ' + (siteAreaLimitPerPhase - connectorLimitPerPhase)); expect(log.result[0].detailedMessages).include('"fusePhase2": ' + (siteAreaLimitPerPhase - connectorLimitPerPhase)); expect(log.result[0].detailedMessages).include('"fusePhase3": ' + (siteAreaLimitPerPhase - connectorLimitPerPhase)); From 364f6b16f4c4d9945df1121d02edff150e23d6fb Mon Sep 17 00:00:00 2001 From: OliveGerste <33114317+OliveGerste@users.noreply.github.com> Date: Tue, 6 Jul 2021 16:36:30 +0200 Subject: [PATCH 11/28] Small typo smart charging test --- test/api/SmartChargingTest.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/api/SmartChargingTest.ts b/test/api/SmartChargingTest.ts index daa134b0db..d6464b6101 100644 --- a/test/api/SmartChargingTest.ts +++ b/test/api/SmartChargingTest.ts @@ -945,7 +945,7 @@ describe('Smart Charging Service', function() { await smartChargingIntegration.buildChargingProfiles(testData.siteAreaContext.getSiteArea(), [testData.chargingStationContext.getChargingStation().id]); const log = await LoggingStorage.getLogs(testData.tenantContext.getTenant().id, { actions: [ServerAction.SMART_CHARGING], search: 'currently being used' }, Constants.DB_PARAMS_SINGLE_RECORD, null); const chargingStation = testData.chargingStationContext.getChargingStation(); - const chargePoint = chargingStation.chargePoints.find((cp) => cp.connectorIDs.includes(transaction.connectorId)); + const chargePoint = chargingStation.chargePoints.find((cp) => cp.connectorIDs.includes(transaction1.connectorId)); const siteArea = testData.siteAreaContext.getSiteArea(); const siteAreaLimitPerPhase = Utils.createDecimal(siteArea.maximumPower).div(siteArea.voltage).div(3).toNumber(); let connectorLimitPerPhase = Utils.createDecimal(Utils.getChargingStationAmperage(chargingStation)).div(3).toNumber(); From 4486b05ade0b4a43df48342b6bf83d9c19e0fc85 Mon Sep 17 00:00:00 2001 From: LucasBrazi06 Date: Wed, 7 Jul 2021 00:04:11 +0200 Subject: [PATCH 12/28] Fixed typos --- src/migration/tasks/AddCompanyIDToChargingStationsTask.ts | 2 +- src/migration/tasks/AddCompanyIDToTransactionsTask.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/migration/tasks/AddCompanyIDToChargingStationsTask.ts b/src/migration/tasks/AddCompanyIDToChargingStationsTask.ts index 75521617d2..3ab6354556 100644 --- a/src/migration/tasks/AddCompanyIDToChargingStationsTask.ts +++ b/src/migration/tasks/AddCompanyIDToChargingStationsTask.ts @@ -61,7 +61,7 @@ export default class AddCompanyIDToChargingStationsTask extends MigrationTask { tenantID: Constants.DEFAULT_TENANT, module: MODULE_NAME, method: 'migrateTenant', action: ServerAction.MIGRATION, - message: `${updated} Transactions(s) have been updated with Company ID in Tenant ${Utils.buildTenantName(tenant)}` + message: `${updated} Charging Station(s) have been updated with Company ID in Tenant ${Utils.buildTenantName(tenant)}` }); } } diff --git a/src/migration/tasks/AddCompanyIDToTransactionsTask.ts b/src/migration/tasks/AddCompanyIDToTransactionsTask.ts index 2b60a0c990..9bf45ab1e0 100644 --- a/src/migration/tasks/AddCompanyIDToTransactionsTask.ts +++ b/src/migration/tasks/AddCompanyIDToTransactionsTask.ts @@ -61,7 +61,7 @@ export default class AddCompanyIDToTransactionsTask extends MigrationTask { tenantID: Constants.DEFAULT_TENANT, module: MODULE_NAME, method: 'migrateTenant', action: ServerAction.MIGRATION, - message: `${updated} Charging Station(s) have been updated with Company ID in Tenant ${Utils.buildTenantName(tenant)}` + message: `${updated} Transaction(s) have been updated with Company ID in Tenant ${Utils.buildTenantName(tenant)}` }); } } From 6e77b52a2615d98c5aa8dc7c46a2b37f2a1e590f Mon Sep 17 00:00:00 2001 From: LucasBrazi06 Date: Wed, 7 Jul 2021 00:25:44 +0200 Subject: [PATCH 13/28] Fixed cleanup perf logs in the last 2 weeks --- src/scheduler/tasks/LoggingDatabaseTableCleanupTask.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scheduler/tasks/LoggingDatabaseTableCleanupTask.ts b/src/scheduler/tasks/LoggingDatabaseTableCleanupTask.ts index 111660fb18..8bf31a6784 100644 --- a/src/scheduler/tasks/LoggingDatabaseTableCleanupTask.ts +++ b/src/scheduler/tasks/LoggingDatabaseTableCleanupTask.ts @@ -89,7 +89,7 @@ export default class LoggingDatabaseTableCleanupTask extends SchedulerTask { if (await LockingManager.acquire(performanceCleanUpLock)) { try { // Delete Performance Records (keep only 2 weeks) - const deleteUpToDate = moment().subtract(2, 'w').startOf('week').toDate(); + const deleteUpToDate = moment().subtract(2, 'w').toDate(); // Delete const result = await PerformanceStorage.deletePerformanceRecords({ deleteUpToDate }); // Ok? From 22e7610e41123d967b07e4a609888eb48be4e490 Mon Sep 17 00:00:00 2001 From: LucasBrazi06 Date: Wed, 7 Jul 2021 00:26:10 +0200 Subject: [PATCH 14/28] Cleanup logs --- src/scheduler/tasks/LoggingDatabaseTableCleanupTask.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scheduler/tasks/LoggingDatabaseTableCleanupTask.ts b/src/scheduler/tasks/LoggingDatabaseTableCleanupTask.ts index 8bf31a6784..4532945eff 100644 --- a/src/scheduler/tasks/LoggingDatabaseTableCleanupTask.ts +++ b/src/scheduler/tasks/LoggingDatabaseTableCleanupTask.ts @@ -34,7 +34,7 @@ export default class LoggingDatabaseTableCleanupTask extends SchedulerTask { if (await LockingManager.acquire(logsCleanUpLock)) { try { // Delete Standard Logs - const deleteUpToDate = moment().subtract(config.retentionPeriodWeeks, 'w').startOf('week').toDate(); + const deleteUpToDate = moment().subtract(config.retentionPeriodWeeks, 'w').toDate(); // Delete let result = await LoggingStorage.deleteLogs(tenantID, deleteUpToDate); // Ok? From e50c519e331fcdeba193edfa630d948667162cd4 Mon Sep 17 00:00:00 2001 From: LucasBrazi06 Date: Wed, 7 Jul 2021 00:28:57 +0200 Subject: [PATCH 15/28] Set unavail to 120 secs --- src/storage/mongodb/DatabaseUtils.ts | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/storage/mongodb/DatabaseUtils.ts b/src/storage/mongodb/DatabaseUtils.ts index 219436e0c2..5e52c9a9d4 100644 --- a/src/storage/mongodb/DatabaseUtils.ts +++ b/src/storage/mongodb/DatabaseUtils.ts @@ -452,14 +452,7 @@ export default class DatabaseUtils { inactive: { $or: [ { $eq: ['$firmwareUpdateStatus', OCPPFirmwareStatus.INSTALLING] }, - { - $gte: [ - { - $divide: [{ $subtract: [new Date(), '$lastSeen'] }, 1000] - }, - Configuration.getChargingStationConfig().maxLastSeenIntervalSecs - ] - } + { $gte: [ { $divide: [{ $subtract: [new Date(), '$lastSeen'] }, 1000] }, 120 ] } ] } } From 4842a50947bf606ab56890bf17f66c35156d16ab Mon Sep 17 00:00:00 2001 From: LucasBrazi06 Date: Wed, 7 Jul 2021 00:37:48 +0200 Subject: [PATCH 16/28] Updated SOAP interval to 60 secs --- src/assets/config-template-http.json | 2 +- src/assets/config-template-https.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/assets/config-template-http.json b/src/assets/config-template-http.json index e7b13f64f3..add7a719d9 100644 --- a/src/assets/config-template-http.json +++ b/src/assets/config-template-http.json @@ -144,7 +144,7 @@ "debug": false }, "ChargingStation": { - "heartbeatIntervalOCPPSSecs": 180, + "heartbeatIntervalOCPPSSecs": 60, "heartbeatIntervalOCPPJSecs": 3600, "notifBeforeEndOfChargeEnabled": true, "notifBeforeEndOfChargePercent": 85, diff --git a/src/assets/config-template-https.json b/src/assets/config-template-https.json index 16b16a5956..00e223b69b 100644 --- a/src/assets/config-template-https.json +++ b/src/assets/config-template-https.json @@ -154,7 +154,7 @@ "debug": false }, "ChargingStation": { - "heartbeatIntervalOCPPSSecs": 180, + "heartbeatIntervalOCPPSSecs": 60, "heartbeatIntervalOCPPJSecs": 3600, "notifBeforeEndOfChargeEnabled": true, "notifBeforeEndOfChargePercent": 85, From e5c10078b79cb87675730f1c519955888b09fc61 Mon Sep 17 00:00:00 2001 From: LucasBrazi06 Date: Wed, 7 Jul 2021 00:43:09 +0200 Subject: [PATCH 17/28] Set inactive flag in charger to 2 times the OCPP soap interval --- src/storage/mongodb/DatabaseUtils.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/storage/mongodb/DatabaseUtils.ts b/src/storage/mongodb/DatabaseUtils.ts index 5e52c9a9d4..f2105c9659 100644 --- a/src/storage/mongodb/DatabaseUtils.ts +++ b/src/storage/mongodb/DatabaseUtils.ts @@ -452,7 +452,12 @@ export default class DatabaseUtils { inactive: { $or: [ { $eq: ['$firmwareUpdateStatus', OCPPFirmwareStatus.INSTALLING] }, - { $gte: [ { $divide: [{ $subtract: [new Date(), '$lastSeen'] }, 1000] }, 120 ] } + { + $gte: [ + { $divide: [{ $subtract: [new Date(), '$lastSeen'] }, 1000] }, + Configuration.getChargingStationConfig().heartbeatIntervalOCPPSSecs * 2 + ] + } ] } } From ae25a21ab3f2668aff4b0bafd61fa81b30f91c6f Mon Sep 17 00:00:00 2001 From: LucasBrazi06 Date: Wed, 7 Jul 2021 00:43:51 +0200 Subject: [PATCH 18/28] Updated sub-modules --- src/assets/configs-aws | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/assets/configs-aws b/src/assets/configs-aws index 2dc38e36a5..c428b322fc 160000 --- a/src/assets/configs-aws +++ b/src/assets/configs-aws @@ -1 +1 @@ -Subproject commit 2dc38e36a569dc1266e48d85e7e87ed0d3f18528 +Subproject commit c428b322fcc88df8357fefc010a91537a56d36bc From 8b304f058b4d6b218b6e9069f652f3e260605454 Mon Sep 17 00:00:00 2001 From: LucasBrazi06 Date: Wed, 7 Jul 2021 11:14:28 +0200 Subject: [PATCH 19/28] Fixed eslint --- src/server/ocpp/json/WSConnection.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/server/ocpp/json/WSConnection.ts b/src/server/ocpp/json/WSConnection.ts index 6291e4337e..eefd2127c0 100644 --- a/src/server/ocpp/json/WSConnection.ts +++ b/src/server/ocpp/json/WSConnection.ts @@ -38,7 +38,7 @@ export default abstract class WSConnection { this.wsConnection = wsConnection; this.initialized = false; this.wsServer = wsServer; - Logging.logDebug({ + void Logging.logDebug({ tenantID: Constants.DEFAULT_TENANT, action: ServerAction.WS_CONNECTION_OPENED, module: MODULE_NAME, method: 'constructor', @@ -86,7 +86,7 @@ export default abstract class WSConnection { logMsg = `Charging Station connection attempts with URL: '${req.url}'`; action = ServerAction.WS_JSON_CONNECTION_OPENED; } - Logging.logDebug({ + void Logging.logDebug({ tenantID: this.tenantID, source: this.chargingStationID, action: action, @@ -101,7 +101,7 @@ export default abstract class WSConnection { message: `The Charging Station ID is invalid: '${this.chargingStationID}'` }); // Log in the right Tenants - Logging.logException( + void Logging.logException( backendError, ServerAction.WS_CONNECTION, Constants.CENTRAL_SERVER, From d9ae148c05f642b3e90dabdddbaf177d2d5d0cc7 Mon Sep 17 00:00:00 2001 From: LucasBrazi06 Date: Wed, 7 Jul 2021 11:20:13 +0200 Subject: [PATCH 20/28] Updated release version --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8b5e33e9b9..5ef60480b2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "ev-server", - "version": "2.4.74", + "version": "2.4.75", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 33b5294c45..062d896e91 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ev-server", - "version": "2.4.74", + "version": "2.4.75", "engines": { "node": "14.x.x", "npm": "6.x.x" From c9748953932597323cb2d95f255b969ea0bb7069 Mon Sep 17 00:00:00 2001 From: Loan ALOUACHE Date: Wed, 7 Jul 2021 13:40:46 +0200 Subject: [PATCH 21/28] Fixed typo --- src/server/rest/v1/router/api/TagRouter.ts | 4 ++-- src/types/Server.ts | 4 ++-- test/api/client/UserApi.ts | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/server/rest/v1/router/api/TagRouter.ts b/src/server/rest/v1/router/api/TagRouter.ts index a066ce085d..40cdbf3e18 100644 --- a/src/server/rest/v1/router/api/TagRouter.ts +++ b/src/server/rest/v1/router/api/TagRouter.ts @@ -64,13 +64,13 @@ export default class TagRouter { } protected buildRouteImportTag(): void { - this.router.post(`/${ServerRoute.REST_TAG_IMPORT}`, async (req: Request, res: Response, next: NextFunction) => { + this.router.post(`/${ServerRoute.REST_TAGS_IMPORT}`, async (req: Request, res: Response, next: NextFunction) => { await RouterUtils.handleServerAction(TagService.handleImportTags.bind(this), ServerAction.TAGS_IMPORT, req, res, next); }); } protected buildRouteExportTag(): void { - this.router.get(`/${ServerRoute.REST_TAG_EXPORT}`, async (req: Request, res: Response, next: NextFunction) => { + this.router.get(`/${ServerRoute.REST_TAGS_EXPORT}`, async (req: Request, res: Response, next: NextFunction) => { await RouterUtils.handleServerAction(TagService.handleExportTags.bind(this), ServerAction.TAGS_EXPORT, req, res, next); }); } diff --git a/src/types/Server.ts b/src/types/Server.ts index eddc054a2a..08d0f8c03f 100644 --- a/src/types/Server.ts +++ b/src/types/Server.ts @@ -507,8 +507,8 @@ export enum ServerRoute { REST_TAGS = 'tags', REST_TAG = 'tags/:id', - REST_TAG_IMPORT = 'tags/action/import', - REST_TAG_EXPORT = 'tags/action/export', + REST_TAGS_IMPORT = 'tags/action/import', + REST_TAGS_EXPORT = 'tags/action/export', REST_ASSET_CONSUMPTION = 'assets/:assetID/consumption', diff --git a/test/api/client/UserApi.ts b/test/api/client/UserApi.ts index aca9bb6b8a..d5b66cdcce 100644 --- a/test/api/client/UserApi.ts +++ b/test/api/client/UserApi.ts @@ -61,7 +61,7 @@ export default class UserApi extends CrudApi { } public async exportTags(params) { - return await super.read(params, this.buildRestEndpointUrl(ServerRoute.REST_TAG_EXPORT)); + return await super.read(params, this.buildRestEndpointUrl(ServerRoute.REST_TAGS_EXPORT)); } public async exportUsers(params) { From 5ac26ca070521655fb50caf92f3c91607b74cf1b Mon Sep 17 00:00:00 2001 From: LucasBrazi06 Date: Wed, 7 Jul 2021 15:25:45 +0200 Subject: [PATCH 22/28] Set the standard Heartbeat OCPP param first and try workarounds next if it failed --- .../tasks/CheckOfflineChargingStationsTask.ts | 5 +-- src/server/ocpp/services/OCPPService.ts | 32 ++++++++----------- src/server/ocpp/utils/OCPPUtils.ts | 4 +-- src/utils/Constants.ts | 2 +- 4 files changed, 19 insertions(+), 24 deletions(-) diff --git a/src/scheduler/tasks/CheckOfflineChargingStationsTask.ts b/src/scheduler/tasks/CheckOfflineChargingStationsTask.ts index acf63f42d0..ca56c7eb8e 100644 --- a/src/scheduler/tasks/CheckOfflineChargingStationsTask.ts +++ b/src/scheduler/tasks/CheckOfflineChargingStationsTask.ts @@ -33,8 +33,8 @@ export default class CheckOfflineChargingStationsTask extends SchedulerTask { let ocppHeartbeatConfiguration: OCPPGetConfigurationCommandResult; // Check if charging station is still connected try { - const ocppParamHeartbeatKeys = ['HeartBeatInterval', 'HeartbeatInterval']; - ocppHeartbeatConfiguration = await OCPPUtils.requestChargingStationOcppParameters(tenant, chargingStation, { key: ocppParamHeartbeatKeys }); + ocppHeartbeatConfiguration = await OCPPUtils.requestChargingStationOcppParameters( + tenant, chargingStation, { key: Constants.OCPP_HEARTBEAT_KEYS as string[] }); } catch (error) { // Charging Station is offline! continue; @@ -47,6 +47,7 @@ export default class CheckOfflineChargingStationsTask extends SchedulerTask { action: ServerAction.OFFLINE_CHARGING_STATION, module: MODULE_NAME, method: 'processTenant', message: 'Offline charging station responded successfully to an OCPP command and will be ignored', + detailedMessages: { ocppHeartbeatConfiguration } }); // Update lastSeen await ChargingStationStorage.saveChargingStationLastSeen(tenant.id, chargingStation.id, diff --git a/src/server/ocpp/services/OCPPService.ts b/src/server/ocpp/services/OCPPService.ts index 51bdd6b204..b601a77983 100644 --- a/src/server/ocpp/services/OCPPService.ts +++ b/src/server/ocpp/services/OCPPService.ts @@ -1910,26 +1910,20 @@ export default class OCPPService { setTimeout(async () => { let result: OCPPChangeConfigurationCommandResult; // Synchronize heartbeat interval OCPP parameter for charging stations that do not take into account its value in the boot notification response - // Set OCPP 'HeartBeatInterval' - let heartBeatIntervalSettingFailure = false; - result = await OCPPUtils.requestChangeChargingStationOcppParameter(tenant, chargingStation, { - key: 'HeartBeatInterval', - value: heartbeatIntervalSecs.toString() - }, false); - if (result.status !== OCPPConfigurationStatus.ACCEPTED) { - heartBeatIntervalSettingFailure = true; - } - // Set OCPP 'HeartbeatInterval' - result = await OCPPUtils.requestChangeChargingStationOcppParameter(tenant, chargingStation, { - key: 'HeartbeatInterval', - value: heartbeatIntervalSecs.toString() - }, false); - let heartbeatIntervalSettingFailure = false; - if (result.status !== OCPPConfigurationStatus.ACCEPTED) { - heartbeatIntervalSettingFailure = true; + let heartbeatIntervalOcppParamSet = false; + // Change one of the key + for (const heartbeatOcppKey of Constants.OCPP_HEARTBEAT_KEYS) { + result = await OCPPUtils.requestChangeChargingStationOcppParameter(tenant, chargingStation, { + key: heartbeatOcppKey, + value: heartbeatIntervalSecs.toString() + }, false); + if (result.status === OCPPConfigurationStatus.ACCEPTED || + result.status === OCPPConfigurationStatus.REBOOT_REQUIRED) { + heartbeatIntervalOcppParamSet = true; + break; + } } - // Check - if (heartBeatIntervalSettingFailure && heartbeatIntervalSettingFailure) { + if (!heartbeatIntervalOcppParamSet) { await Logging.logError({ tenantID: tenant.id, action: ServerAction.BOOT_NOTIFICATION, diff --git a/src/server/ocpp/utils/OCPPUtils.ts b/src/server/ocpp/utils/OCPPUtils.ts index fb8b0917d4..ab0f4bb498 100644 --- a/src/server/ocpp/utils/OCPPUtils.ts +++ b/src/server/ocpp/utils/OCPPUtils.ts @@ -1971,7 +1971,7 @@ export default class OCPPUtils { }); continue; } - if (parameter === 'HeartBeatInterval' || parameter === 'HeartbeatInterval') { + if (Constants.OCPP_HEARTBEAT_KEYS.includes(parameter)) { await Logging.logWarning({ tenantID: tenant.id, source: chargingStation.id, @@ -2032,7 +2032,7 @@ export default class OCPPUtils { }); continue; } - if (parameter === 'HeartBeatInterval' || parameter === 'HeartbeatInterval') { + if (Constants.OCPP_HEARTBEAT_KEYS.includes(parameter)) { await Logging.logWarning({ tenantID: tenant.id, source: chargingStation.id, diff --git a/src/utils/Constants.ts b/src/utils/Constants.ts index 4c92d16042..042bf204ff 100644 --- a/src/utils/Constants.ts +++ b/src/utils/Constants.ts @@ -289,6 +289,7 @@ export default class Constants { public static readonly WS_DEFAULT_RECONNECT_TIMEOUT = 30; // Seconds public static readonly OCPP_SOCKET_TIMEOUT = 30000; // 30 sec + public static readonly OCPP_HEARTBEAT_KEYS = Object.freeze(['HeartBeatInterval', 'HeartbeatInterval']); public static readonly MAX_DATE = new Date('9999-12-31Z23:59:59:999'); public static readonly MIN_DATE = new Date('1970-01-01Z00:00:00:000'); @@ -350,7 +351,6 @@ export default class Constants { { 'key': 'ClockAlignedDataInterval', 'readonly': false, 'value': null }, { 'key': 'ConnectionTimeOut', 'readonly': false, 'value': null }, { 'key': 'GetConfigurationMaxKeys', 'readonly': false, 'value': null }, - { 'key': 'HeartBeatInterval', 'readonly': false, 'value': null }, { 'key': 'HeartbeatInterval', 'readonly': false, 'value': null }, { 'key': 'LightIntensity', 'readonly': false, 'value': null }, { 'key': 'LocalAuthorizeOffline', 'readonly': false, 'value': null }, From 0613d90a69beac7dde4290fd17a3e9340cdc93e0 Mon Sep 17 00:00:00 2001 From: LucasBrazi06 Date: Wed, 7 Jul 2021 15:40:30 +0200 Subject: [PATCH 23/28] Updated sub-modules --- src/integration/smart-charging/sap-smart-charging | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/integration/smart-charging/sap-smart-charging b/src/integration/smart-charging/sap-smart-charging index bcc1a00888..2359c787f3 160000 --- a/src/integration/smart-charging/sap-smart-charging +++ b/src/integration/smart-charging/sap-smart-charging @@ -1 +1 @@ -Subproject commit bcc1a008884d19eda8aeccf8eb47fcf723ea86a8 +Subproject commit 2359c787f3c59753d895a5eec5babfeaae07c7ec From 82b0cb1cfa83725f5a8c601ad47f8a1a5f0bc4bf Mon Sep 17 00:00:00 2001 From: LucasBrazi06 Date: Wed, 7 Jul 2021 15:50:59 +0200 Subject: [PATCH 24/28] Removed commented code --- src/server/rest/CentralRestServerService.ts | 336 -------------------- 1 file changed, 336 deletions(-) diff --git a/src/server/rest/CentralRestServerService.ts b/src/server/rest/CentralRestServerService.ts index 3d116fd665..6685cfc158 100644 --- a/src/server/rest/CentralRestServerService.ts +++ b/src/server/rest/CentralRestServerService.ts @@ -385,339 +385,3 @@ export default class CentralRestServerService { } } } - -// To uncomment back when mobile V2 will be available in Android -// import { NextFunction, Request, Response } from 'express'; - -// import AssetService from './v1/service/AssetService'; -// import BillingService from './v1/service/BillingService'; -// import CarService from './v1/service/CarService'; -// import ChargingStationService from './v1/service/ChargingStationService'; -// import CompanyService from './v1/service/CompanyService'; -// import ConnectionService from './v1/service/ConnectionService'; -// import Logging from '../../utils/Logging'; -// import LoggingService from './v1/service/LoggingService'; -// import NotificationService from './v1/service/NotificationService'; -// import OCPIEndpointService from './v1/service/OCPIEndpointService'; -// import OICPEndpointService from './v1/service/OICPEndpointService'; -// import RegistrationTokenService from './v1/service/RegistrationTokenService'; -// import { ServerAction } from '../../types/Server'; -// import SessionHashService from './v1/service/SessionHashService'; -// import SettingService from './v1/service/SettingService'; -// import SiteAreaService from './v1/service/SiteAreaService'; -// import SiteService from './v1/service/SiteService'; -// import StatisticService from './v1/service/StatisticService'; -// import { StatusCodes } from 'http-status-codes'; -// import TagService from './v1/service/TagService'; -// import TenantService from './v1/service/TenantService'; -// import TransactionService from './v1/service/TransactionService'; -// import UserService from './v1/service/UserService'; -// import UtilsService from './v1/service/UtilsService'; - -// class RequestMapper { -// private static instances = new Map(); -// private paths = new Map(); -// private actions = new Array<(action: ServerAction, req: Request, res: Response, next: NextFunction) => void|Promise>(); - -// private constructor(httpVerb: string) { -// switch (httpVerb) { -// // Create -// case 'POST': -// // Register REST actions -// this.registerJsonActionsPaths({ -// [ServerAction.ADD_CHARGING_STATIONS_TO_SITE_AREA]: SiteAreaService.handleAssignChargingStationsToSiteArea.bind(this), -// [ServerAction.REMOVE_CHARGING_STATIONS_FROM_SITE_AREA]: SiteAreaService.handleAssignChargingStationsToSiteArea.bind(this), -// [ServerAction.REGISTRATION_TOKEN_CREATE]: RegistrationTokenService.handleCreateRegistrationToken.bind(this), -// [ServerAction.COMPANY_CREATE]: CompanyService.handleCreateCompany.bind(this), -// [ServerAction.ADD_ASSET_TO_SITE_AREA]: SiteAreaService.handleAssignAssetsToSiteArea.bind(this), -// [ServerAction.REMOVE_ASSET_TO_SITE_AREA]: SiteAreaService.handleAssignAssetsToSiteArea.bind(this), -// [ServerAction.ASSET_CREATE]: AssetService.handleCreateAsset.bind(this), -// [ServerAction.TENANT_CREATE]: TenantService.handleCreateTenant.bind(this), -// [ServerAction.SITE_CREATE]: SiteService.handleCreateSite.bind(this), -// [ServerAction.ADD_USERS_TO_SITE]: SiteService.handleAssignUsersToSite.bind(this), -// [ServerAction.REMOVE_USERS_FROM_SITE]: SiteService.handleAssignUsersToSite.bind(this), -// [ServerAction.SITE_AREA_CREATE]: SiteAreaService.handleCreateSiteArea.bind(this), -// [ServerAction.TRANSACTIONS_REFUND]: TransactionService.handleRefundTransactions.bind(this), -// [ServerAction.TRANSACTION_PUSH_CDR]: TransactionService.handlePushTransactionCdr.bind(this), -// [ServerAction.SYNCHRONIZE_REFUNDED_TRANSACTIONS]: TransactionService.handleSynchronizeRefundedTransactions.bind(this), -// [ServerAction.SETTING_CREATE]: SettingService.handleCreateSetting.bind(this), -// [ServerAction.BILLING_SYNCHRONIZE_USERS]: BillingService.handleSynchronizeUsers.bind(this), -// [ServerAction.BILLING_SYNCHRONIZE_USER]: BillingService.handleSynchronizeUser.bind(this), -// [ServerAction.BILLING_FORCE_SYNCHRONIZE_USER]: BillingService.handleForceSynchronizeUser.bind(this), -// [ServerAction.BILLING_SYNCHRONIZE_INVOICES]: BillingService.handleSynchronizeInvoices.bind(this), -// [ServerAction.BILLING_FORCE_SYNCHRONIZE_USER_INVOICES]: BillingService.handleForceSynchronizeUserInvoices.bind(this), -// [ServerAction.BILLING_CREATE_TRANSACTION_INVOICE]: BillingService.handleCreateTransactionInvoice.bind(this), -// [ServerAction.BILLING_SETUP_PAYMENT_METHOD]: BillingService.handleBillingSetupPaymentMethod.bind(this), -// [ServerAction.OCPI_ENDPOINT_CREATE]: OCPIEndpointService.handleCreateOcpiEndpoint.bind(this), -// [ServerAction.OCPI_ENDPOINT_PING]: OCPIEndpointService.handlePingOcpiEndpoint.bind(this), -// [ServerAction.OCPI_ENDPOINT_CHECK_CDRS]: OCPIEndpointService.handleCheckCdrsEndpoint.bind(this), -// [ServerAction.OCPI_ENDPOINT_CHECK_LOCATIONS]: OCPIEndpointService.handleCheckLocationsEndpoint.bind(this), -// [ServerAction.OCPI_ENDPOINT_CHECK_SESSIONS]: OCPIEndpointService.handleCheckSessionsEndpoint.bind(this), -// [ServerAction.OCPI_ENDPOINT_PULL_CDRS]: OCPIEndpointService.handlePullCdrsEndpoint.bind(this), -// [ServerAction.OCPI_ENDPOINT_PULL_LOCATIONS]: OCPIEndpointService.handlePullLocationsEndpoint.bind(this), -// [ServerAction.OCPI_ENDPOINT_PULL_SESSIONS]: OCPIEndpointService.handlePullSessionsEndpoint.bind(this), -// [ServerAction.OCPI_ENDPOINT_PULL_TOKENS]: OCPIEndpointService.handlePullTokensEndpoint.bind(this), -// [ServerAction.OCPI_ENDPOINT_SEND_EVSE_STATUSES]: OCPIEndpointService.handlePushEVSEStatusesOcpiEndpoint.bind(this), -// [ServerAction.OCPI_ENDPOINT_SEND_TOKENS]: OCPIEndpointService.handlePushTokensOcpiEndpoint.bind(this), -// [ServerAction.OCPI_ENDPOINT_GENERATE_LOCAL_TOKEN]: OCPIEndpointService.handleGenerateLocalTokenOcpiEndpoint.bind(this), -// [ServerAction.OICP_ENDPOINT_CREATE]: OICPEndpointService.handleCreateOicpEndpoint.bind(this), -// [ServerAction.OICP_ENDPOINT_PING]: OICPEndpointService.handlePingOicpEndpoint.bind(this), -// [ServerAction.OICP_ENDPOINT_SEND_EVSE_STATUSES]: OICPEndpointService.handleSendEVSEStatusesOicpEndpoint.bind(this), -// [ServerAction.OICP_ENDPOINT_SEND_EVSES]: OICPEndpointService.handleSendEVSEsOicpEndpoint.bind(this), -// [ServerAction.INTEGRATION_CONNECTION_CREATE]: ConnectionService.handleCreateConnection.bind(this), -// [ServerAction.CHARGING_STATION_REQUEST_OCPP_PARAMETERS]: ChargingStationService.handleRequestChargingStationOcppParameters.bind(this), -// [ServerAction.CAR_CREATE]: CarService.handleCreateCar.bind(this), -// [ServerAction.TAG_CREATE]: TagService.handleCreateTag.bind(this), -// [ServerAction.END_USER_REPORT_ERROR]: NotificationService.handleEndUserReportError.bind(this), -// [ServerAction.TAGS_IMPORT]: TagService.handleImportTags.bind(this), -// }); -// break; - -// // Read -// case 'GET': -// // Register REST actions -// this.registerJsonActionsPaths({ -// [ServerAction.LOGGINGS]: LoggingService.handleGetLogs.bind(this), -// [ServerAction.LOGGING]: LoggingService.handleGetLog.bind(this), -// [ServerAction.LOGGINGS_EXPORT]: LoggingService.handleExportLogs.bind(this), -// [ServerAction.CHARGING_STATIONS]: ChargingStationService.handleGetChargingStations.bind(this), -// [ServerAction.CAR_CATALOGS]: CarService.handleGetCarCatalogs.bind(this), -// [ServerAction.CAR_CATALOG]: CarService.handleGetCarCatalog.bind(this), -// [ServerAction.CAR_MAKERS]: CarService.handleGetCarMakers.bind(this), -// [ServerAction.CARS]: CarService.handleGetCars.bind(this), -// [ServerAction.CAR]: CarService.handleGetCar.bind(this), -// [ServerAction.CAR_USERS]: CarService.handleGetCarUsers.bind(this), -// [ServerAction.CAR_CATALOG_IMAGES]: CarService.handleGetCarCatalogImages.bind(this), -// [ServerAction.REGISTRATION_TOKENS]: RegistrationTokenService.handleGetRegistrationTokens.bind(this), -// [ServerAction.REGISTRATION_TOKEN]: RegistrationTokenService.handleGetRegistrationToken.bind(this), -// [ServerAction.COMPANIES]: CompanyService.handleGetCompanies.bind(this), -// [ServerAction.COMPANY]: CompanyService.handleGetCompany.bind(this), -// [ServerAction.ASSETS]: AssetService.handleGetAssets.bind(this), -// [ServerAction.ASSET]: AssetService.handleGetAsset.bind(this), -// [ServerAction.ASSET_IMAGE]: AssetService.handleGetAssetImage.bind(this), -// [ServerAction.ASSETS_IN_ERROR]: AssetService.handleGetAssetsInError.bind(this), -// [ServerAction.CHECK_ASSET_CONNECTION]: AssetService.handleCheckAssetConnection.bind(this), -// [ServerAction.RETRIEVE_ASSET_CONSUMPTION]: AssetService.handleRetrieveConsumption.bind(this), -// [ServerAction.ASSET_CONSUMPTION]: AssetService.handleGetAssetConsumption.bind(this), -// [ServerAction.SITES]: SiteService.handleGetSites.bind(this), -// [ServerAction.SITE]: SiteService.handleGetSite.bind(this), -// [ServerAction.SITE_USERS]: SiteService.handleGetUsers.bind(this), -// [ServerAction.TENANTS]: TenantService.handleGetTenants.bind(this), -// [ServerAction.TENANT]: TenantService.handleGetTenant.bind(this), -// [ServerAction.SITE_AREAS]: SiteAreaService.handleGetSiteAreas.bind(this), -// [ServerAction.SITE_AREA]: SiteAreaService.handleGetSiteArea.bind(this), -// [ServerAction.SITE_AREA_CONSUMPTION]: SiteAreaService.handleGetSiteAreaConsumption.bind(this), -// [ServerAction.USERS]: UserService.handleGetUsers.bind(this), -// [ServerAction.NOTIFICATIONS]: NotificationService.handleGetNotifications.bind(this), -// [ServerAction.TAGS]: TagService.handleGetTags.bind(this), -// [ServerAction.TAG]: TagService.handleGetTag.bind(this), -// [ServerAction.TAGS_EXPORT]: TagService.handleExportTags.bind(this), -// [ServerAction.TRANSACTIONS_COMPLETED]: TransactionService.handleGetTransactionsCompleted.bind(this), -// [ServerAction.TRANSACTIONS_TO_REFUND]: TransactionService.handleGetTransactionsToRefund.bind(this), -// [ServerAction.TRANSACTIONS_TO_REFUND_EXPORT]: TransactionService.handleExportTransactionsToRefund.bind(this), -// [ServerAction.TRANSACTIONS_TO_REFUND_REPORTS]: TransactionService.handleGetRefundReports.bind(this), -// [ServerAction.TRANSACTIONS_EXPORT]: TransactionService.handleExportTransactions.bind(this), -// [ServerAction.TRANSACTIONS_ACTIVE]: TransactionService.handleGetTransactionsActive.bind(this), -// [ServerAction.TRANSACTIONS_IN_ERROR]: TransactionService.handleGetTransactionsInError.bind(this), -// [ServerAction.TRANSACTION_YEARS]: TransactionService.handleGetTransactionYears.bind(this), -// [ServerAction.REBUILD_TRANSACTION_CONSUMPTIONS]: TransactionService.handleRebuildTransactionConsumptions.bind(this), -// [ServerAction.UNASSIGNED_TRANSACTIONS_COUNT]: TransactionService.handleGetUnassignedTransactionsCount.bind(this), -// [ServerAction.TRANSACTION_OCPI_CDR_EXPORT]: TransactionService.handleExportTransactionOcpiCdr.bind(this), -// [ServerAction.CHARGING_STATION_CONSUMPTION_STATISTICS]: StatisticService.handleGetChargingStationConsumptionStatistics.bind(this), -// [ServerAction.CHARGING_STATION_USAGE_STATISTICS]: StatisticService.handleGetChargingStationUsageStatistics.bind(this), -// [ServerAction.CHARGING_STATION_INACTIVITY_STATISTICS]: StatisticService.handleGetChargingStationInactivityStatistics.bind(this), -// [ServerAction.CHARGING_STATION_TRANSACTIONS_STATISTICS]: StatisticService.handleGetChargingStationTransactionsStatistics.bind(this), -// [ServerAction.CHARGING_STATION_PRICING_STATISTICS]: StatisticService.handleGetChargingStationPricingStatistics.bind(this), -// [ServerAction.STATISTICS_EXPORT]: StatisticService.handleExportStatistics.bind(this), -// [ServerAction.USER_CONSUMPTION_STATISTICS]: StatisticService.handleGetUserConsumptionStatistics.bind(this), -// [ServerAction.USER_USAGE_STATISTICS]: StatisticService.handleGetUserUsageStatistics.bind(this), -// [ServerAction.USER_INACTIVITY_STATISTICS]: StatisticService.handleGetUserInactivityStatistics.bind(this), -// [ServerAction.USER_TRANSACTIONS_STATISTICS]: StatisticService.handleGetUserTransactionsStatistics.bind(this), -// [ServerAction.USER_PRICING_STATISTICS]: StatisticService.handleGetUserPricingStatistics.bind(this), -// [ServerAction.CHARGING_STATION_TRANSACTIONS]: TransactionService.handleGetChargingStationTransactions.bind(this), -// [ServerAction.TRANSACTION]: TransactionService.handleGetTransaction.bind(this), -// [ServerAction.TRANSACTION_CONSUMPTION]: TransactionService.handleGetTransactionConsumption.bind(this), -// [ServerAction.SETTING_BY_IDENTIFIER]: SettingService.handleGetSettingByIdentifier.bind(this), -// [ServerAction.SETTINGS]: SettingService.handleGetSettings.bind(this), -// [ServerAction.SETTING]: SettingService.handleGetSetting.bind(this), -// [ServerAction.CHECK_BILLING_CONNECTION]: BillingService.handleCheckBillingConnection.bind(this), -// [ServerAction.BILLING_TAXES]: BillingService.handleGetBillingTaxes.bind(this), -// [ServerAction.BILLING_INVOICES]: BillingService.handleGetInvoices.bind(this), -// [ServerAction.BILLING_DOWNLOAD_INVOICE]: BillingService.handleDownloadInvoice.bind(this), -// [ServerAction.BILLING_PAYMENT_METHODS]: BillingService.handleBillingGetPaymentMethods.bind(this), -// [ServerAction.OCPI_ENDPOINTS]: OCPIEndpointService.handleGetOcpiEndpoints.bind(this), -// [ServerAction.OCPI_ENDPOINT]: OCPIEndpointService.handleGetOcpiEndpoint.bind(this), -// [ServerAction.OICP_ENDPOINTS]: OICPEndpointService.handleGetOicpEndpoints.bind(this), -// [ServerAction.OICP_ENDPOINT]: OICPEndpointService.handleGetOicpEndpoint.bind(this), -// [ServerAction.INTEGRATION_CONNECTIONS]: ConnectionService.handleGetConnections.bind(this), -// [ServerAction.INTEGRATION_CONNECTION]: ConnectionService.handleGetConnection.bind(this), -// [ServerAction.PING]: (action: ServerAction, req: Request, res: Response, next: NextFunction) => { -// res.sendStatus(StatusCodes.OK); -// }, -// }); -// break; - -// // Update -// case 'PUT': -// // Register REST actions -// this.registerJsonActionsPaths({ -// [ServerAction.TENANT_UPDATE]: TenantService.handleUpdateTenant.bind(this), -// [ServerAction.SITE_UPDATE]: SiteService.handleUpdateSite.bind(this), -// [ServerAction.SITE_AREA_UPDATE]: SiteAreaService.handleUpdateSiteArea.bind(this), -// [ServerAction.COMPANY_UPDATE]: CompanyService.handleUpdateCompany.bind(this), -// [ServerAction.ASSET_UPDATE]: AssetService.handleUpdateAsset.bind(this), -// [ServerAction.SITE_USER_ADMIN]: SiteService.handleUpdateSiteUserAdmin.bind(this), -// [ServerAction.SITE_OWNER]: SiteService.handleUpdateSiteOwner.bind(this), -// [ServerAction.TRANSACTION_SOFT_STOP]: TransactionService.handleTransactionSoftStop.bind(this), -// [ServerAction.ASSIGN_TRANSACTIONS_TO_USER]: TransactionService.handleAssignTransactionsToUser.bind(this), -// [ServerAction.SETTING_UPDATE]: SettingService.handleUpdateSetting.bind(this), -// [ServerAction.OCPI_ENDPOINT_UPDATE]: OCPIEndpointService.handleUpdateOcpiEndpoint.bind(this), -// [ServerAction.OCPI_ENDPOINT_REGISTER]: OCPIEndpointService.handleRegisterOcpiEndpoint.bind(this), -// [ServerAction.OCPI_ENDPOINT_UNREGISTER]: OCPIEndpointService.handleUnregisterOcpiEndpoint.bind(this), -// [ServerAction.OICP_ENDPOINT_UPDATE]: OICPEndpointService.handleUpdateOicpEndpoint.bind(this), -// [ServerAction.OICP_ENDPOINT_REGISTER]: OICPEndpointService.handleRegisterOicpEndpoint.bind(this), -// [ServerAction.OICP_ENDPOINT_UNREGISTER]: OICPEndpointService.handleUnregisterOicpEndpoint.bind(this), -// [ServerAction.SYNCHRONIZE_CAR_CATALOGS]: CarService.handleSynchronizeCarCatalogs.bind(this), -// [ServerAction.CAR_UPDATE]: CarService.handleUpdateCar.bind(this), -// [ServerAction.TAG_UPDATE]: TagService.handleUpdateTag.bind(this), -// [ServerAction.BILLING_CHARGE_INVOICE]: BillingService.handleBillingChargeInvoice.bind(this), -// [ServerAction.REGISTRATION_TOKEN_UPDATE]: RegistrationTokenService.handleUpdateRegistrationToken.bind(this), -// }); -// break; - -// // Delete -// case 'DELETE': -// // Register REST actions -// this.registerJsonActionsPaths({ -// [ServerAction.TENANT_DELETE]: TenantService.handleDeleteTenant.bind(this), -// [ServerAction.REGISTRATION_TOKEN_DELETE]: RegistrationTokenService.handleDeleteRegistrationToken.bind(this), -// [ServerAction.REGISTRATION_TOKEN_REVOKE]: RegistrationTokenService.handleRevokeRegistrationToken.bind(this), -// [ServerAction.SITE_DELETE]: SiteService.handleDeleteSite.bind(this), -// [ServerAction.SITE_AREA_DELETE]: SiteAreaService.handleDeleteSiteArea.bind(this), -// [ServerAction.COMPANY_DELETE]: CompanyService.handleDeleteCompany.bind(this), -// [ServerAction.ASSET_DELETE]: AssetService.handleDeleteAsset.bind(this), -// [ServerAction.TRANSACTION_DELETE]: TransactionService.handleDeleteTransaction.bind(this), -// [ServerAction.TRANSACTIONS_DELETE]: TransactionService.handleDeleteTransactions.bind(this), -// [ServerAction.INTEGRATION_CONNECTION_DELETE]: ConnectionService.handleDeleteConnection.bind(this), -// [ServerAction.SETTING_DELETE]: SettingService.handleDeleteSetting.bind(this), -// [ServerAction.OCPI_ENDPOINT_DELETE]: OCPIEndpointService.handleDeleteOcpiEndpoint.bind(this), -// [ServerAction.OICP_ENDPOINT_DELETE]: OICPEndpointService.handleDeleteOicpEndpoint.bind(this), -// [ServerAction.CAR_DELETE]: CarService.handleDeleteCar.bind(this), -// [ServerAction.TAG_DELETE]: TagService.handleDeleteTag.bind(this), -// [ServerAction.TAGS_DELETE]: TagService.handleDeleteTags.bind(this), -// [ServerAction.BILLING_DELETE_PAYMENT_METHOD]: BillingService.handleBillingDeletePaymentMethod.bind(this), -// }); -// break; -// } -// } - -// public static getInstanceFromHTTPVerb(method: string): RequestMapper { -// if (!RequestMapper.instances.has(method)) { -// RequestMapper.instances.set(method, new RequestMapper(method)); -// } -// return RequestMapper.instances.get(method); -// } - -// public registerOneActionManyPaths(action: (action: ServerAction, req: Request, res: Response, next: NextFunction) => void|Promise, ...paths: ServerAction[]) { -// const index = this.actions.push(action) - 1; -// for (const path of paths) { -// this.paths.set(path, index); -// } -// } - -// public registerJsonActionsPaths(dict: { [key in ServerAction]?: (action: ServerAction, req: Request, res: Response, next: NextFunction) => void|Promise; }) { -// for (const key in dict) { -// this.registerOneActionManyPaths(dict[key], key as ServerAction); -// } -// } - -// public getActionFromPath(path: string): (action: ServerAction, req: Request, res: Response, next: NextFunction) => void|Promise { -// if (!this.paths.has(path)) { -// return UtilsService.handleUnknownAction.bind(this); -// } -// return this.actions[this.paths.get(path)]; -// } -// } - -// export default class CentralRestServerService { -// // Util Service -// public static async restServiceUtil(req: Request, res: Response, next: NextFunction): Promise { -// try { -// // Parse the action -// const action = req.params.action as ServerAction; -// // Check Context -// switch (req.method) { -// // Create Request -// case 'GET': -// // Check Context -// switch (action) { -// // Ping -// case ServerAction.PING: -// res.sendStatus(StatusCodes.OK); -// break; -// case ServerAction.CAR_CATALOG_IMAGE: -// await CarService.handleGetCarCatalogImage(action, req, res, next); -// break; -// case ServerAction.ASSET_IMAGE: -// await AssetService.handleGetAssetImage(action, req, res, next); -// break; -// case ServerAction.COMPANY_LOGO: -// await CompanyService.handleGetCompanyLogo(action, req, res, next); -// break; -// case ServerAction.SITE_IMAGE: -// await SiteService.handleGetSiteImage(action, req, res, next); -// break; -// case ServerAction.SITE_AREA_IMAGE: -// await SiteAreaService.handleGetSiteAreaImage(action, req, res, next); -// break; -// case ServerAction.TENANT_LOGO: -// await TenantService.handleGetTenantLogo(action, req, res, next); -// break; -// default: -// // Delegate -// await UtilsService.handleUnknownAction(action, req, res, next); -// } -// break; - -// case 'POST': -// // Check Context -// switch (action) { -// // Ping -// case ServerAction.BILLING_WEB_HOOK: -// await BillingService.handleBillingWebHook(action, req, res, next); -// // Res.sendStatus(StatusCodes.OK); -// break; -// default: -// // Delegate -// await UtilsService.handleUnknownAction(action, req, res, next); -// } -// break; -// } -// } catch (error) { -// next(error); -// } -// } - -// public static async restServiceSecured(req: Request, res: Response, next: NextFunction): Promise { -// // Parse the action -// const action = req.params.action as ServerAction; -// // Check if User has been updated and require new login -// if ((await SessionHashService.areTokenUserAndTenantStillValid(req, res, next))) { -// return; -// } -// // Check HTTP Verbs -// if (!['POST', 'GET', 'PUT', 'DELETE'].includes(req.method)) { -// await Logging.logActionExceptionMessageAndSendResponse( -// null, new Error(`Unsupported request method ${req.method}`), req, res, next); -// return; -// } -// try { -// // Get the action -// const handleRequest = RequestMapper.getInstanceFromHTTPVerb(req.method).getActionFromPath(action); -// // Execute -// await handleRequest(action, req, res, next); -// } catch (error) { -// next(error); -// } -// } -// } From c5931ba440536f96dedfbbe3e55573492952f7e5 Mon Sep 17 00:00:00 2001 From: LucasBrazi06 Date: Wed, 7 Jul 2021 19:21:28 +0200 Subject: [PATCH 25/28] Updated sub-modules --- src/assets/charging-station-templates | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/assets/charging-station-templates b/src/assets/charging-station-templates index e127d51334..80cfd9df7c 160000 --- a/src/assets/charging-station-templates +++ b/src/assets/charging-station-templates @@ -1 +1 @@ -Subproject commit e127d51334469495aa8832bd8a7c356fcb83f1b7 +Subproject commit 80cfd9df7c89902b2903a2077eae5340c599f7e8 From 35f6f1891775fc6b9e7ad06f11e0a1e7c012e54b Mon Sep 17 00:00:00 2001 From: LucasBrazi06 Date: Thu, 8 Jul 2021 08:49:36 +0200 Subject: [PATCH 26/28] Put the standard heartbeat first. --- src/utils/Constants.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/Constants.ts b/src/utils/Constants.ts index 042bf204ff..2d13f713df 100644 --- a/src/utils/Constants.ts +++ b/src/utils/Constants.ts @@ -289,7 +289,7 @@ export default class Constants { public static readonly WS_DEFAULT_RECONNECT_TIMEOUT = 30; // Seconds public static readonly OCPP_SOCKET_TIMEOUT = 30000; // 30 sec - public static readonly OCPP_HEARTBEAT_KEYS = Object.freeze(['HeartBeatInterval', 'HeartbeatInterval']); + public static readonly OCPP_HEARTBEAT_KEYS = Object.freeze(['HeartbeatInterval', 'HeartBeatInterval']); public static readonly MAX_DATE = new Date('9999-12-31Z23:59:59:999'); public static readonly MIN_DATE = new Date('1970-01-01Z00:00:00:000'); From aabdcd9d155b9c75f2042ff2e4afe86aeb104482 Mon Sep 17 00:00:00 2001 From: OliveGerste <33114317+OliveGerste@users.noreply.github.com> Date: Thu, 8 Jul 2021 16:50:07 +0200 Subject: [PATCH 27/28] test for smart charging transaction error --- test/api/SmartChargingTest.ts | 48 +++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/test/api/SmartChargingTest.ts b/test/api/SmartChargingTest.ts index d6464b6101..df66af9635 100644 --- a/test/api/SmartChargingTest.ts +++ b/test/api/SmartChargingTest.ts @@ -642,6 +642,54 @@ describe('Smart Charging Service', function() { TestData.validateChargingProfile(chargingProfiles[2], transaction2); expect(chargingProfiles[2].profile.chargingSchedule.chargingSchedulePeriod).containSubset(limitMinSinglePhased); }); + + it('Test if Charging Station is excluded, when transaction is not existing anymore', async () => { + await testData.chargingStationContext1.stopTransaction(transaction2.id, transaction.tagID, 200, new Date); + const chargingProfiles = await smartChargingIntegration.buildChargingProfiles(testData.siteAreaContext.getSiteArea()); + expect(chargingProfiles.length).to.be.eq(2); + // Charging Profiles should have limits according the sent meter values (+ buffer) + TestData.validateChargingProfile(chargingProfiles[0], transaction); + expect(chargingProfiles[0].profile.chargingSchedule.chargingSchedulePeriod).containSubset(limitMinThreePhased); + TestData.validateChargingProfile(chargingProfiles[1], transaction1); + expect(chargingProfiles[1].profile.chargingSchedule.chargingSchedulePeriod).containSubset([ + { + 'startPeriod': 0, + 'limit': Utils.roundTo(24 * 3 * aCBufferFactor, 3) + }, + { + 'startPeriod': 900, + 'limit': Utils.roundTo(24 * 3 * aCBufferFactor, 3) + }, + { + 'startPeriod': 1800, + 'limit': Utils.roundTo(24 * 3 * aCBufferFactor, 3) + } + ]); + // Check adjustment of site area limit + const log = await LoggingStorage.getLogs(testData.tenantContext.getTenant().id, { actions: [ServerAction.SMART_CHARGING], search: 'currently being used' }, Constants.DB_PARAMS_SINGLE_RECORD, null); + const chargingStation = testData.chargingStationContext1.getChargingStation(); + const siteArea = testData.siteAreaContext.getSiteArea(); + const siteAreaLimitPerPhase = Utils.createDecimal(siteArea.maximumPower).div(siteArea.voltage).div(3).toNumber(); + const connectorLimit = Utils.createDecimal(Utils.getChargingStationAmperage(chargingStation, null, transaction2.connectorId)).toNumber(); + expect(log.result[0].detailedMessages).include('"fusePhase1": ' + (siteAreaLimitPerPhase - connectorLimit)); + expect(log.result[0].detailedMessages).include('"fusePhase2": ' + siteAreaLimitPerPhase); + expect(log.result[0].detailedMessages).include('"fusePhase3": ' + siteAreaLimitPerPhase); + }); + + it('Test if Charging Stations are excluded, when transactions are not existing anymore', async () => { + await testData.chargingStationContext.stopTransaction(transaction.id, transaction.tagID, 200, new Date); + await smartChargingIntegration.buildChargingProfiles(testData.siteAreaContext.getSiteArea()); + const log = await LoggingStorage.getLogs(testData.tenantContext.getTenant().id, { actions: [ServerAction.SMART_CHARGING], search: 'currently being used' }, Constants.DB_PARAMS_SINGLE_RECORD, null); + const siteArea = testData.siteAreaContext.getSiteArea(); + const siteAreaLimitPerPhase = Utils.createDecimal(siteArea.maximumPower).div(siteArea.voltage).div(3).toNumber(); + const connectorLimitSinglePhased = Utils.createDecimal( + Utils.getChargingStationAmperage(testData.chargingStationContext1.getChargingStation(), null, transaction2.connectorId)).toNumber(); + const chargingStationLimitThreePhased = Utils.createDecimal( + Utils.getChargingStationAmperage(testData.chargingStationContext.getChargingStation())).div(3).toNumber(); + expect(log.result[0].detailedMessages).include('"fusePhase1": ' + (siteAreaLimitPerPhase - connectorLimitSinglePhased - chargingStationLimitThreePhased)); + expect(log.result[0].detailedMessages).include('"fusePhase2": ' + (siteAreaLimitPerPhase - chargingStationLimitThreePhased)); + expect(log.result[0].detailedMessages).include('"fusePhase3": ' + (siteAreaLimitPerPhase - chargingStationLimitThreePhased)); + }); }); describe('Test for single phased site area', () => { From 24877f88d05a03b537783ef6ed7485763d7f0507 Mon Sep 17 00:00:00 2001 From: Claude ROSSI Date: Thu, 8 Jul 2021 16:54:59 +0200 Subject: [PATCH 28/28] billing - prevent STRIPE customers deletion --- src/integration/billing/stripe/StripeBillingIntegration.ts | 5 ++++- src/utils/FeatureToggles.ts | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/integration/billing/stripe/StripeBillingIntegration.ts b/src/integration/billing/stripe/StripeBillingIntegration.ts index 524e23c4ff..8229440414 100644 --- a/src/integration/billing/stripe/StripeBillingIntegration.ts +++ b/src/integration/billing/stripe/StripeBillingIntegration.ts @@ -1396,13 +1396,16 @@ export default class StripeBillingIntegration extends BillingIntegration { } public async deleteUser(user: User): Promise { + if (FeatureToggles.isFeatureActive(Feature.BILLING_PREVENT_CUSTOMER_DELETION)) { + // To be on the SAFE side - we preserve the customer on the STRIPE side + return Promise.resolve(); + } // Check Stripe await this.checkConnection(); // const customer = await this.getCustomerByEmail(user.email); const customerID = user.billingData?.customerID; const customer = await this.getStripeCustomer(customerID); if (customer && customer.id) { - // TODO - ro be clarified - is this allowed when the user has some invoices await this.stripe.customers.del( customer.id ); diff --git a/src/utils/FeatureToggles.ts b/src/utils/FeatureToggles.ts index fd1314a1ed..a8b4dee51b 100644 --- a/src/utils/FeatureToggles.ts +++ b/src/utils/FeatureToggles.ts @@ -7,6 +7,7 @@ export enum Feature { BILLING_ITEM_WITH_PARKING_TIME, BILLING_ITEM_WITH_START_DATE, BILLING_CHECK_THRESHOLD_ON_STOP, + BILLING_PREVENT_CUSTOMER_DELETION, } export default class FeatureToggles { @@ -18,6 +19,7 @@ export default class FeatureToggles { // Feature.BILLING_ITEM_WITH_PARKING_TIME, Feature.BILLING_ITEM_WITH_START_DATE, Feature.BILLING_CHECK_THRESHOLD_ON_STOP, + Feature.BILLING_PREVENT_CUSTOMER_DELETION, ]; // Check whether the feature is active or not!