Made Roaming sync calls non blocking
Removed cleanup of Tariff ID
Renamed OCPI method to Roaming
Use new Auth framework methods to get entities in Charging Station service endpoint
MODIFY
src/client/ocpi/CpoOCPIClient.ts
src/client/ocpi/CpoOCPIClient.ts
@@ -499,13 +499,16 @@ export default class CpoOCPIClient extends OCPIClient {
module: MODULE_NAME, method: 'patchChargingStationStatus',
});
}
- await this.patchEVSEStatus({
+ await this.patchEVSEStatus(
+ {
id: chargingStation.id,
siteID: chargingStation.siteID,
siteAreaID: chargingStation.siteAreaID,
companyID: chargingStation.companyID,
- }, chargingStation.siteID,
- RoamingUtils.buildEvseUID(chargingStation, connector.connectorId), OCPIUtils.convertStatus2OCPIStatus(connector.status));
+ },
+ chargingStation.siteID,
+ RoamingUtils.buildEvseUID(chargingStation, connector.connectorId), OCPIUtils.convertStatus2OCPIStatus(connector.status)
+ );
}
public async checkSessions(): Promise<OCPIResult> {

MODIFY
src/server/ocpp/services/OCPPService.ts
src/server/ocpp/services/OCPPService.ts
@@ -699,9 +699,9 @@ export default class OCPPService {
// Save Status Notification
await OCPPStorage.saveStatusNotification(tenant, statusNotification);
// OCPI
- await OCPIFacade.updateConnectorStatus(tenant, chargingStation, connector);
+ void OCPIFacade.updateConnectorStatus(tenant, chargingStation, connector);
// OICP
- await OICPFacade.updateConnectorStatus(tenant, chargingStation, connector);
+ void OICPFacade.updateConnectorStatus(tenant, chargingStation, connector);
// Sort connectors
if (!Utils.isEmptyArray(chargingStation?.connectors)) {
chargingStation.connectors.sort((connector1: Connector, connector2: Connector) =>

MODIFY
src/server/rest/v1/service/AuthorizationService.ts
src/server/rest/v1/service/AuthorizationService.ts
@@ -544,7 +544,7 @@ export default class AuthorizationService {
}
public static async checkAndGetChargingStationAuthorizations(tenant: Tenant, userToken: UserToken,
- filteredRequest: Partial<HttpChargingStationRequest>, entityData?: EntityData): Promise<AuthorizationFilter> {
+ filteredRequest: Partial<HttpChargingStationRequest>, authAction: Action, entityData?: EntityData): Promise<AuthorizationFilter> {
const authorizationFilters: AuthorizationFilter = {
filters: {},
dataSources: new Map(),

MODIFY
src/server/rest/v1/service/ChargingStationService.ts
src/server/rest/v1/service/ChargingStationService.ts
@@ -5,6 +5,7 @@ import { HttpChargingStationChangeConfigurationRequest, HttpChargingStationGetCo
import { NextFunction, Request, Response } from 'express';
import { OCPICommandResponse, OCPICommandResponseType } from '../../../../types/ocpi/OCPICommandResponse';
import { OCPPChangeConfigurationResponse, OCPPConfigurationStatus, OCPPGetCompositeScheduleResponse, OCPPStatus, OCPPUnlockStatus } from '../../../../types/ocpp/OCPPClient';
+import Tenant, { TenantComponents } from '../../../../types/Tenant';
import AppAuthError from '../../../../exception/AppAuthError';
import AppError from '../../../../exception/AppError';
@@ -44,10 +45,10 @@ import SmartChargingFactory from '../../../../integration/smart-charging/SmartCh
import { StatusCodes } from 'http-status-codes';
import Tag from '../../../../types/Tag';
import TagStorage from '../../../../storage/mongodb/TagStorage';
-import { TenantComponents } from '../../../../types/Tenant';
import TransactionStorage from '../../../../storage/mongodb/TransactionStorage';
import User from '../../../../types/User';
import UserStorage from '../../../../storage/mongodb/UserStorage';
+import UserToken from '../../../../types/UserToken';
import Utils from '../../../../utils/Utils';
import UtilsService from './UtilsService';
@@ -58,9 +59,8 @@ export default class ChargingStationService {
// Filter
const filteredRequest = ChargingStationValidator.getInstance().validateChargingStationParametersUpdateReq({ ...req.params, ...req.body });
// Check the Charging Station
- const chargingStation = await ChargingStationStorage.getChargingStation(req.tenant, filteredRequest.id);
- UtilsService.assertObjectExists(action, chargingStation, `Charging Station ID '${filteredRequest.id}' does not exist.`,
- MODULE_NAME, 'handleUpdateChargingStationParams', req.user);
+ const chargingStation = await UtilsService.checkAndGetChargingStationAuthorization(
+ req.tenant, req.user, filteredRequest.id, Action.UPDATE, action, null, { withSiteArea: true });
// OCPI Charging Station
if (!chargingStation.issuer) {
throw new AppError({
@@ -71,12 +71,11 @@ export default class ChargingStationService {
action
});
}
- // Check the Site Area
+ // Site Area
let siteArea: SiteArea = null;
if (Utils.isComponentActiveFromToken(req.user, TenantComponents.ORGANIZATION) && filteredRequest.siteAreaID) {
- siteArea = await SiteAreaStorage.getSiteArea(req.tenant, filteredRequest.siteAreaID, { withSite: true });
- UtilsService.assertObjectExists(action, siteArea, `Site Area ID '${filteredRequest.siteAreaID}' does not exist.`,
- MODULE_NAME, 'handleUpdateChargingStationParams', req.user);
+ siteArea = await UtilsService.checkAndGetSiteAreaAuthorization(
+ req.tenant, req.user, filteredRequest.siteAreaID, Action.READ, action, null, { withSite: true });
}
// Check Auth
if (!await Authorizations.canUpdateChargingStation(req.user, siteArea ? siteArea.siteID : null)) {
@@ -97,7 +96,9 @@ export default class ChargingStationService {
chargingStation.maximumPower = filteredRequest.maximumPower;
}
if (Utils.objectHasProperty(filteredRequest, 'public')) {
- if (Utils.isComponentActiveFromToken(req.user, TenantComponents.ORGANIZATION) && filteredRequest.public && !siteArea.site?.public) {
+ // Charging Station is public but cannot belong to a non public Site
+ if (Utils.isComponentActiveFromToken(req.user, TenantComponents.ORGANIZATION) &&
+ filteredRequest.public && !siteArea.site?.public) {
throw new AppError({
...LoggingHelper.getChargingStationProperties(chargingStation),
action,
@@ -107,65 +108,9 @@ export default class ChargingStationService {
user: req.user
});
}
- if (filteredRequest.public !== chargingStation.public) {
- // OCPI handling
- if (Utils.isComponentActiveFromToken(req.user, TenantComponents.OCPI)) {
- // Remove charging station from ocpi
- try {
- const ocpiClient = await OCPIClientFactory.getAvailableOcpiClient(req.tenant, OCPIRole.CPO) as CpoOCPIClient;
- let status: OCPIEvseStatus;
- if (!filteredRequest.public) {
- // Force remove
- status = OCPIEvseStatus.REMOVED;
- }
- if (ocpiClient) {
- await ocpiClient.updateChargingStationStatus(chargingStation, status);
- }
- } catch (error) {
- await Logging.logError({
- tenantID: req.user.tenantID,
- module: MODULE_NAME, method: 'handleUpdateChargingStationParams',
- action,
- user: req.user,
- message: `Unable to remove charging station ${chargingStation.id} from IOP`,
- detailedMessages: { error: error.stack }
- });
- }
- }
- // OICP handling
- if (Utils.isComponentActiveFromToken(req.user, TenantComponents.OICP)) {
- let actionType = OICPActionType.INSERT;
- if (!filteredRequest.public) {
- actionType = OICPActionType.DELETE;
- }
- try {
- const oicpClient = await OICPClientFactory.getAvailableOicpClient(req.tenant, OCPIRole.CPO) as CpoOICPClient;
- if (oicpClient) {
- // Define get option
- const options = {
- addChargeBoxID: true,
- countryID: oicpClient.getLocalCountryCode(ServerAction.OICP_PUSH_EVSE_DATA),
- partyID: oicpClient.getLocalPartyID(ServerAction.OICP_PUSH_EVSE_DATA)
- };
- // Get Site
- const site = await SiteStorage.getSite(req.tenant, chargingStation.siteID);
- // Push EVSE to OICP platform
- await oicpClient.pushEvseData(OICPUtils.convertChargingStation2MultipleEvses(
- site, chargingStation.siteArea, chargingStation, options), actionType);
- }
- } catch (error) {
- await Logging.logError({
- tenantID: req.user.tenantID,
- module: MODULE_NAME, method: 'handleUpdateChargingStationParams',
- action,
- user: req.user,
- message: `Unable to insert or remove charging station ${chargingStation.id} from HBS`,
- detailedMessages: { error: error.stack }
- });
- }
- }
- }
chargingStation.public = filteredRequest.public;
+ // Handle update in Roaming
+ void ChargingStationService.updateChargingStationRoaming(req.tenant, req.user, chargingStation, action);
}
if (Utils.isComponentActiveFromToken(req.user, TenantComponents.OCPI)) {
if (Utils.objectHasProperty(filteredRequest, 'tariffID')) {
@@ -329,7 +274,6 @@ export default class ChargingStationService {
});
}
}
- // Log
await Logging.logInfo({
tenantID: req.user.tenantID,
action,
@@ -344,6 +288,7 @@ export default class ChargingStationService {
next();
}
+
public static async handleChargingStationLimitPower(action: ServerAction, req: Request, res: Response, next: NextFunction): Promise<void> {
// Filter
const filteredRequest = ChargingStationValidator.getInstance().validateChargingStationLimitPowerReq(req.body);
@@ -927,7 +872,7 @@ export default class ChargingStationService {
// withSiteArea: filteredRequest.WithSiteArea,
// }, true);
const chargingStation = await UtilsService.checkAndGetChargingStationAuthorization(
- req.tenant, req.user, filteredRequest.ID, action, null, {
+ req.tenant, req.user, filteredRequest.ID, Action.READ, action, null, {
withSite: true,
withSiteArea: true,
}, true);
@@ -1104,7 +1049,7 @@ export default class ChargingStationService {
const filteredRequest = ChargingStationValidator.getInstance().validateChargingStationActionReserveNowReq(req.body);
// Get the Charging station
const chargingStation = await UtilsService.checkAndGetChargingStationAuthorization(
- req.tenant, req.user, filteredRequest.chargingStationID, action, null, { withSite: true, withSiteArea: true });
+ req.tenant, req.user, filteredRequest.chargingStationID, Action.READ, action, null, { withSite: true, withSiteArea: true });
// Get the OCPP Client
const chargingStationClient = await ChargingStationClientFactory.getChargingStationClient(req.tenant, chargingStation);
if (!chargingStationClient) {
@@ -1125,7 +1070,7 @@ export default class ChargingStationService {
const filteredRequest = ChargingStationValidator.getInstance().validateChargingStationActionReservationCancelReq(req.body);
// Get the Charging station
const chargingStation = await UtilsService.checkAndGetChargingStationAuthorization(
- req.tenant, req.user, filteredRequest.chargingStationID, action, null, { withSite: true, withSiteArea: true });
+ req.tenant, req.user, filteredRequest.chargingStationID, Action.READ, action, null, { withSite: true, withSiteArea: true });
// Get the OCPP Client
const chargingStationClient = await ChargingStationClientFactory.getChargingStationClient(req.tenant, chargingStation);
if (!chargingStationClient) {
@@ -1214,7 +1159,7 @@ export default class ChargingStationService {
Action.UPDATE, Entity.CHARGING_STATION, MODULE_NAME, 'handleOcpiAction');
// Get the Charging station
const chargingStation = await UtilsService.checkAndGetChargingStationAuthorization(
- req.tenant, req.user, req.body.chargingStationID, action, null, { withSite: true, withSiteArea: true });
+ req.tenant, req.user, req.body.chargingStationID, Action.READ, action, null, { withSite: true, withSiteArea: true });
// Check
if (chargingStation.issuer) {
throw new AppError({
@@ -1322,7 +1267,7 @@ export default class ChargingStationService {
UtilsService.assertIdIsProvided(action, req.body.chargingStationID, MODULE_NAME, 'handleOCPPAction', req.user);
// Get the Charging station
const chargingStation = await UtilsService.checkAndGetChargingStationAuthorization(
- req.tenant, req.user, req.body.chargingStationID, action, null, { withSite: true, withSiteArea: true });
+ req.tenant, req.user, req.body.chargingStationID, Action.READ, action, null, { withSite: true, withSiteArea: true });
// Check auth
if (!await Authorizations.canPerformActionOnChargingStation(req.user, command as unknown as Action, chargingStation)) {
throw new AppAuthError({
@@ -2040,4 +1985,64 @@ export default class ChargingStationService {
}
return result;
}
+
+ private static async updateChargingStationRoaming(tenant: Tenant, loggedUser: UserToken,
+ chargingStation: ChargingStation, action: ServerAction) {
+ // OCPI handling
+ if (Utils.isComponentActiveFromToken(loggedUser, TenantComponents.OCPI)) {
+ // Remove charging station from ocpi
+ try {
+ const ocpiClient = await OCPIClientFactory.getAvailableOcpiClient(tenant, OCPIRole.CPO) as CpoOCPIClient;
+ let status: OCPIEvseStatus;
+ // Force remove
+ if (!chargingStation.public) {
+ status = OCPIEvseStatus.REMOVED;
+ }
+ if (ocpiClient) {
+ await ocpiClient.updateChargingStationStatus(chargingStation, status);
+ }
+ } catch (error) {
+ await Logging.logError({
+ tenantID: tenant.id,
+ module: MODULE_NAME, method: 'handleUpdateChargingStationParams',
+ action,
+ user: loggedUser,
+ message: `Unable to remove charging station ${chargingStation.id} from IOP`,
+ detailedMessages: { error: error.stack }
+ });
+ }
+ }
+ // OICP handling
+ if (Utils.isComponentActiveFromToken(loggedUser, TenantComponents.OICP)) {
+ let actionType = OICPActionType.INSERT;
+ if (!chargingStation.public) {
+ actionType = OICPActionType.DELETE;
+ }
+ try {
+ const oicpClient = await OICPClientFactory.getAvailableOicpClient(tenant, OCPIRole.CPO) as CpoOICPClient;
+ if (oicpClient) {
+ // Define get option
+ const options = {
+ addChargeBoxID: true,
+ countryID: oicpClient.getLocalCountryCode(ServerAction.OICP_PUSH_EVSE_DATA),
+ partyID: oicpClient.getLocalPartyID(ServerAction.OICP_PUSH_EVSE_DATA)
+ };
+ // Get Site
+ const site = await SiteStorage.getSite(tenant, chargingStation.siteID);
+ // Push EVSE to OICP platform
+ await oicpClient.pushEvseData(OICPUtils.convertChargingStation2MultipleEvses(
+ site, chargingStation.siteArea, chargingStation, options), actionType);
+ }
+ } catch (error) {
+ await Logging.logError({
+ tenantID: tenant.id,
+ module: MODULE_NAME, method: 'handleUpdateChargingStationParams',
+ action,
+ user: loggedUser,
+ message: `Unable to insert or remove charging station ${chargingStation.id} from HBS`,
+ detailedMessages: { error: error.stack }
+ });
+ }
+ }
+ }
}

MODIFY
src/server/rest/v1/service/PricingService.ts
src/server/rest/v1/service/PricingService.ts
@@ -209,7 +209,7 @@ export default class PricingService {
siteID = siteArea.siteID;
break;
case PricingEntity.CHARGING_STATION:
- chargingStation = await UtilsService.checkAndGetChargingStationAuthorization(req.tenant, req.user, entityID, action);
+ chargingStation = await UtilsService.checkAndGetChargingStationAuthorization(req.tenant, req.user, entityID, Action.READ, action);
siteID = chargingStation.siteID;
break;
default:

MODIFY
src/server/rest/v1/service/SiteAreaService.ts
src/server/rest/v1/service/SiteAreaService.ts
@@ -293,11 +293,6 @@ export default class SiteAreaService {
createdBy: { id: req.user.id },
createdOn: new Date()
} as SiteArea;
- if (Utils.isComponentActiveFromToken(req.user, TenantComponents.OCPI)) {
- if (!site.public) {
- delete siteArea.tariffID;
- }
- }
// Save
siteArea.id = await SiteAreaStorage.saveSiteArea(req.tenant, siteArea, Utils.objectHasProperty(filteredRequest, 'image'));
await Logging.logInfo({
@@ -359,9 +354,6 @@ export default class SiteAreaService {
if (Utils.objectHasProperty(filteredRequest, 'tariffID')) {
siteArea.tariffID = filteredRequest.tariffID;
}
- if (!site.public) {
- delete siteArea.tariffID;
- }
}
let actionsResponse: ActionsResponse;
if (siteArea.smartCharging && !filteredRequest.smartCharging) {

MODIFY
src/server/rest/v1/service/SiteService.ts
src/server/rest/v1/service/SiteService.ts
@@ -314,11 +314,6 @@ export default class SiteService {
createdBy: { id: req.user.id },
createdOn: new Date()
} as Site;
- if (Utils.isComponentActiveFromToken(req.user, TenantComponents.OCPI)) {
- if (!filteredRequest.public) {
- delete site.tariffID;
- }
- }
// Save
site.id = await SiteStorage.saveSite(req.tenant, site, Utils.objectHasProperty(filteredRequest, 'image'));
await Logging.logInfo({
@@ -373,9 +368,6 @@ export default class SiteService {
if (Utils.objectHasProperty(filteredRequest, 'tariffID')) {
site.tariffID = filteredRequest.tariffID;
}
- if (!filteredRequest.public) {
- delete site.tariffID;
- }
}
if (Utils.objectHasProperty(filteredRequest, 'autoUserSiteAssignment')) {
site.autoUserSiteAssignment = filteredRequest.autoUserSiteAssignment;

MODIFY
src/server/rest/v1/service/TagService.ts
src/server/rest/v1/service/TagService.ts
@@ -196,7 +196,7 @@ export default class TagService {
// Save
await TagStorage.saveTag(req.tenant, newTag);
// OCPI
- await TagService.updateTagOCPI(action, req.tenant, req.user, newTag);
+ void TagService.updateTagRoaming(action, req.tenant, req.user, newTag);
await Logging.logInfo({
...LoggingHelper.getTagProperties(newTag),
tenantID: req.user.tenantID,
@@ -272,7 +272,7 @@ export default class TagService {
// Assign
await TagStorage.saveTag(req.tenant, tag);
// OCPI
- await TagService.updateTagOCPI(action, req.tenant, req.user, tag);
+ void TagService.updateTagRoaming(action, req.tenant, req.user, tag);
await Logging.logInfo({
...LoggingHelper.getTagProperties(tag),
tenantID: req.user.tenantID,
@@ -314,7 +314,7 @@ export default class TagService {
tag.lastChangedOn = new Date();
// Save
await TagStorage.saveTag(req.tenant, tag);
- await TagService.updateTagOCPI(action, req.tenant, req.user, tag);
+ void TagService.updateTagRoaming(action, req.tenant, req.user, tag);
await Logging.logInfo({
...LoggingHelper.getTagProperties(tag),
tenantID: req.user.tenantID,
@@ -391,7 +391,7 @@ export default class TagService {
await TagService.setDefaultTagForUser(req.tenant, formerTagUserID);
}
// OCPI
- await TagService.updateTagOCPI(action, req.tenant, req.user, tag);
+ void TagService.updateTagRoaming(action, req.tenant, req.user, tag);
await Logging.logInfo({
...LoggingHelper.getTagProperties(tag),
tenantID: req.user.tenantID,
@@ -663,7 +663,7 @@ export default class TagService {
const tag = await UtilsService.checkAndGetTagAuthorization(
tenant, loggedUser, tagID, Action.DELETE, action, null, {}, true);
// Delete OCPI
- await TagService.checkAndDeleteTagOCPI(tenant, loggedUser, tag);
+ void TagService.checkAndDeleteTagRoaming(tenant, loggedUser, tag);
// Delete the Tag
await TagStorage.deleteTag(tenant, tag.id);
result.inSuccess++;
@@ -705,7 +705,7 @@ export default class TagService {
const tag = await UtilsService.checkAndGetTagByVisualIDAuthorization(
tenant, loggedUser, visualID, Action.UNASSIGN, action, null, {});
// Delete OCPI
- await TagService.checkAndDeleteTagOCPI(tenant, loggedUser, tag);
+ void TagService.checkAndDeleteTagRoaming(tenant, loggedUser, tag);
// Unassign the Tag
const userID = tag.userID;
tag.userID = null;
@@ -865,7 +865,7 @@ export default class TagService {
}
}
- private static async checkAndDeleteTagOCPI(tenant: Tenant, loggedUser: UserToken, tag: Tag): Promise<void> {
+ private static async checkAndDeleteTagRoaming(tenant: Tenant, loggedUser: UserToken, tag: Tag): Promise<void> {
// OCPI
if (Utils.isComponentActiveFromToken(loggedUser, TenantComponents.OCPI)) {
try {
@@ -894,7 +894,7 @@ export default class TagService {
}
}
- private static async updateTagOCPI(action: ServerAction, tenant: Tenant, loggedUser: UserToken, tag: Tag) {
+ private static async updateTagRoaming(action: ServerAction, tenant: Tenant, loggedUser: UserToken, tag: Tag) {
// Synchronize badges with IOP
if (Utils.isComponentActiveFromToken(loggedUser, TenantComponents.OCPI)) {
try {

MODIFY
src/server/rest/v1/service/UserService.ts
src/server/rest/v1/service/UserService.ts
@@ -156,7 +156,7 @@ export default class UserService {
// Delete Billing
await UserService.checkAndDeleteUserBilling(req.tenant, req.user, user);
// Delete OCPI
- await UserService.checkAndDeleteUserOCPI(req.tenant, req.user, user);
+ void UserService.checkAndDeleteUserRoaming(req.tenant, req.user, user);
// Delete Car
await UserService.checkAndDeleteCar(req.tenant, req.user, user);
// Delete User
@@ -872,7 +872,7 @@ export default class UserService {
}
}
- private static async checkAndDeleteUserOCPI(tenant: Tenant, loggedUser: UserToken, user: User): Promise<void> {
+ private static async checkAndDeleteUserRoaming(tenant: Tenant, loggedUser: UserToken, user: User): Promise<void> {
// Synchronize badges with IOP (eMSP)
if (Utils.isComponentActiveFromToken(loggedUser, TenantComponents.OCPI)) {
try {

MODIFY
src/server/rest/v1/service/UtilsService.ts
src/server/rest/v1/service/UtilsService.ts
@@ -95,7 +95,7 @@ export default class UtilsService {
});
}
- public static async checkAndGetChargingStationAuthorization(tenant: Tenant, userToken: UserToken, chargingStationID: string,
+ public static async checkAndGetChargingStationAuthorization(tenant: Tenant, userToken: UserToken, chargingStationID: string, authAction: Action,
action: ServerAction, entityData?: EntityData, additionalFilters: Record<string, any> = {}, applyProjectFields = false): Promise<ChargingStation> {
// Check static auth for reading Charging Station
if (!await Authorizations.canReadChargingStation(userToken)) {
@@ -112,7 +112,7 @@ export default class UtilsService {
UtilsService.assertIdIsProvided(action, chargingStationID, MODULE_NAME, 'checkAndGetChargingStationAuthorization', userToken);
// Get dynamic auth
const authorizationFilter = await AuthorizationService.checkAndGetChargingStationAuthorizations(
- tenant, userToken, { ID: chargingStationID }, entityData);
+ tenant, userToken, { ID: chargingStationID }, authAction, entityData);
if (!authorizationFilter.authorized) {
throw new AppAuthError({
errorCode: HTTPAuthError.FORBIDDEN,

Made Roaming sync calls non blocking
Removed cleanup of Tariff ID
Renamed OCPI method to Roaming
Use new Auth framework methods to get entities in Charging Station service endpoint