Added Company ID in Transaction
MODIFY
src/assets/server/rest/v1/docs/e-mobility-oas.json
src/assets/server/rest/v1/docs/e-mobility-oas.json
{
"$ref": "#/components/parameters/WithSiteArea"
},
+ {
+ "$ref": "#/components/parameters/WithCompany"
+ },
{
"$ref": "#/components/parameters/InactivityStatuses"
},
"type": "boolean"
}
},
+ "WithCompany": {
+ "in": "query",
+ "name": "WithCompany",
+ "description": "With company attribute",
+ "schema": {
+ "type": "boolean"
+ }
+ },
"WithSite": {
"in": "query",
"name": "WithSite",

MODIFY
src/assets/server/rest/v1/schemas/transaction/transactions-get.json
src/assets/server/rest/v1/schemas/transaction/transactions-get.json
"type": "boolean",
"sanitize": "mongo"
},
+ "WithCompany": {
+ "type": "boolean",
+ "sanitize": "mongo"
+ },
"WithSite": {
"type": "boolean",
"sanitize": "mongo"

MODIFY
src/client/ocpi/EmspOCPIClient.ts
src/client/ocpi/EmspOCPIClient.ts
@@ -346,7 +346,7 @@ export default class EmspOCPIClient extends OCPIClient {
const locationName = site.name + Constants.OCPI_SEPARATOR + location.id;
// Handle Site Area
const siteAreas = await SiteAreaStorage.getSiteAreas(this.tenant.id,
- { siteIDs: [site.id], name: locationName, issuer: false },
+ { siteIDs: [site.id], name: locationName, issuer: false, withSite: true },
Constants.DB_PARAMS_SINGLE_RECORD);
let siteArea = !Utils.isEmptyArray(siteAreas.result) ? siteAreas.result[0] : null;
if (!siteArea) {
@@ -402,8 +402,9 @@ export default class EmspOCPIClient extends OCPIClient {
}
// Update Charging Station
const chargingStation = OCPIUtilsService.convertEvseToChargingStation(evse, location);
- chargingStation.siteAreaID = siteArea.id;
+ chargingStation.companyID = siteArea.site?.companyID;
chargingStation.siteID = siteArea.siteID;
+ chargingStation.siteAreaID = siteArea.id;
await ChargingStationStorage.saveChargingStation(this.tenant.id, chargingStation);
await ChargingStationStorage.saveChargingStationOcpiData(this.tenant.id, chargingStation.id, chargingStation.ocpiData);
await Logging.logDebug({

MODIFY
src/migration/MigrationHandler.ts
src/migration/MigrationHandler.ts
-import AddCompanyIDPropertToChargingStationsTask from './tasks/AddCompanyIDPropertToChargingStationsTask';
+import AddCompanyIDToChargingStationsTask from './tasks/AddCompanyIDToChargingStationsTask';
+import AddCompanyIDToTransactionsTask from './tasks/AddCompanyIDToTransactionsTask';
import Constants from '../utils/Constants';
import { LockEntity } from '../types/Locking';
import LockingManager from '../locking/LockingManager';
@@ -87,7 +88,8 @@ export default class MigrationHandler {
private static createMigrationTasks(): MigrationTask[] {
const currentMigrationTasks: MigrationTask[] = [];
currentMigrationTasks.push(new RemoveDuplicateTagVisualIDsTask());
- currentMigrationTasks.push(new AddCompanyIDPropertToChargingStationsTask());
+ currentMigrationTasks.push(new AddCompanyIDToTransactionsTask());
+ currentMigrationTasks.push(new AddCompanyIDToChargingStationsTask());
return currentMigrationTasks;
}

DELETE
src/migration/tasks/AddCompanyIDPropertToChargingStationsTask.ts
-import ChargingStationStorage from '../../storage/mongodb/ChargingStationStorage';
-import Constants from '../../utils/Constants';
-import DatabaseUtils from '../../storage/mongodb/DatabaseUtils';
-import Logging from '../../utils/Logging';
-import MigrationTask from '../MigrationTask';
-import { ServerAction } from '../../types/Server';
-import Site from '../../types/Site';
-import SiteStorage from '../../storage/mongodb/SiteStorage';
-import Tenant from '../../types/Tenant';
-import TenantStorage from '../../storage/mongodb/TenantStorage';
-import Utils from '../../utils/Utils';
-import global from '../../types/GlobalType';
-
-const MODULE_NAME = 'AddCompanyIDPropertToChargingStationsTask';
-
-export default class AddCompanyIDPropertToChargingStationsTask extends MigrationTask {
- async migrate(): Promise<void> {
- const tenants = await TenantStorage.getTenants({}, Constants.DB_PARAMS_MAX_LIMIT);
- for (const tenant of tenants.result) {
- await this.migrateTenant(tenant);
- }
- }
-
- async migrateTenant(tenant: Tenant): Promise<void> {
- let updated = 0;
- let site: Site;
- const chargingStations = await ChargingStationStorage.getChargingStations(tenant.id, {
- }, Constants.DB_PARAMS_MAX_LIMIT, ['id', 'siteID']);
- if (chargingStations.count > 0) {
- for (const chargingStation of chargingStations.result) {
- site = await SiteStorage.getSite(tenant, chargingStation.siteID, {}, ['companyID']);
- if (site && site.companyID) {
- await global.database.getCollection<any>(tenant.id, 'chargingstations').updateOne(
- { _id: chargingStation.id },
- {
- $set: { companyID: DatabaseUtils.convertToObjectID(site.companyID) }
- }
- );
- updated++;
- }
- }
- }
- // Log in the default tenant
- if (updated > 0) {
- await Logging.logDebug({
- tenantID: Constants.DEFAULT_TENANT,
- module: MODULE_NAME, method: 'migrateTenant',
- action: ServerAction.MIGRATION,
- message: `${updated} Charging station(s) company have been added in Tenant ${Utils.buildTenantName(tenant)}`
- });
- }
- }
-
- getVersion(): string {
- return '1.0';
- }
-
- getName(): string {
- return 'AddCompanyIDPropertToChargingStationsTask';
- }
-
- isAsynchronous(): boolean {
- return true;
- }
-}

ADD
src/migration/tasks/AddCompanyIDToChargingStationsTask.ts
+import Constants from '../../utils/Constants';
+import DatabaseUtils from '../../storage/mongodb/DatabaseUtils';
+import Logging from '../../utils/Logging';
+import MigrationTask from '../MigrationTask';
+import { ServerAction } from '../../types/Server';
+import SiteStorage from '../../storage/mongodb/SiteStorage';
+import Tenant from '../../types/Tenant';
+import TenantStorage from '../../storage/mongodb/TenantStorage';
+import Utils from '../../utils/Utils';
+import global from '../../types/GlobalType';
+
+const MODULE_NAME = 'AddCompanyIDPropertToChargingStationsTask';
+
+export default class AddCompanyIDToChargingStationsTask extends MigrationTask {
+ async migrate(): Promise<void> {
+ const tenants = await TenantStorage.getTenants({}, Constants.DB_PARAMS_MAX_LIMIT);
+ for (const tenant of tenants.result) {
+ await this.migrateTenant(tenant);
+ }
+ }
+
+ async migrateTenant(tenant: Tenant): Promise<void> {
+ let updated = 0;
+ // Get all the Sites
+ const sites = (await SiteStorage.getSites(tenant, {}, Constants.DB_PARAMS_MAX_LIMIT, ['id', 'companyID'])).result;
+ if (!Utils.isEmptyArray(sites)) {
+ // Get all the Transactions without Company ID
+ const transactions = await global.database.getCollection<any>(tenant.id, 'transactions')
+ .find({
+ $or: [
+ { companyID: { $exists: false } },
+ { companyID: null },
+ { companyID: '' }
+ ]
+ })
+ .project({ id: 1, siteID: 1 })
+ .toArray();
+ if (!Utils.isEmptyArray(transactions)) {
+ for (const transaction of transactions) {
+ // Has a Site
+ if (!transaction.siteID) {
+ continue;
+ }
+ // Find the Site
+ const foundSite = sites.find((site) => transaction.siteID?.toHexString() === site.id);
+ if (foundSite?.companyID) {
+ await global.database.getCollection<any>(tenant.id, 'transactions').updateOne(
+ { _id: transaction._id },
+ {
+ $set: { companyID: DatabaseUtils.convertToObjectID(foundSite.companyID) }
+ }
+ );
+ updated++;
+ }
+ }
+ }
+ }
+ // Log in the default tenant
+ if (updated > 0) {
+ await Logging.logDebug({
+ 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)}`
+ });
+ }
+ }
+
+ getVersion(): string {
+ return '1.0';
+ }
+
+ getName(): string {
+ return 'AddCompanyIDToChargingStationsTask';
+ }
+
+ isAsynchronous(): boolean {
+ return true;
+ }
+}

ADD
src/migration/tasks/AddCompanyIDToTransactionsTask.ts
+import Constants from '../../utils/Constants';
+import DatabaseUtils from '../../storage/mongodb/DatabaseUtils';
+import Logging from '../../utils/Logging';
+import MigrationTask from '../MigrationTask';
+import { ServerAction } from '../../types/Server';
+import SiteStorage from '../../storage/mongodb/SiteStorage';
+import Tenant from '../../types/Tenant';
+import TenantStorage from '../../storage/mongodb/TenantStorage';
+import Utils from '../../utils/Utils';
+import global from '../../types/GlobalType';
+
+const MODULE_NAME = 'AddCompanyIDPropertToChargingStationsTask';
+
+export default class AddCompanyIDToTransactionsTask extends MigrationTask {
+ async migrate(): Promise<void> {
+ const tenants = await TenantStorage.getTenants({}, Constants.DB_PARAMS_MAX_LIMIT);
+ for (const tenant of tenants.result) {
+ await this.migrateTenant(tenant);
+ }
+ }
+
+ async migrateTenant(tenant: Tenant): Promise<void> {
+ let updated = 0;
+ // Get all the Sites
+ const sites = (await SiteStorage.getSites(tenant, {}, Constants.DB_PARAMS_MAX_LIMIT, ['id', 'companyID'])).result;
+ if (!Utils.isEmptyArray(sites)) {
+ // Get all the Charging Stations without Company ID
+ const chargingStations = await global.database.getCollection<any>(tenant.id, 'chargingstations')
+ .find({
+ $or: [
+ { companyID: { $exists: false } },
+ { companyID: null },
+ { companyID: '' }
+ ]
+ })
+ .project({ id: 1, siteID: 1 })
+ .toArray();
+ if (!Utils.isEmptyArray(chargingStations)) {
+ for (const chargingStation of chargingStations) {
+ // Has a Site
+ if (!chargingStation.siteID) {
+ continue;
+ }
+ // Find the Site
+ const foundSite = sites.find((site) => chargingStation.siteID?.toHexString() === site.id);
+ if (foundSite?.companyID) {
+ await global.database.getCollection<any>(tenant.id, 'chargingstations').updateOne(
+ { _id: chargingStation._id },
+ {
+ $set: { companyID: DatabaseUtils.convertToObjectID(foundSite.companyID) }
+ }
+ );
+ updated++;
+ }
+ }
+ }
+ }
+ // Log in the default tenant
+ if (updated > 0) {
+ await Logging.logDebug({
+ 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)}`
+ });
+ }
+ }
+
+ getVersion(): string {
+ return '1.0';
+ }
+
+ getName(): string {
+ return 'AddCompanyIDToTransactionsTask';
+ }
+
+ isAsynchronous(): boolean {
+ return true;
+ }
+}

DELETE
src/migration/tasks/AddVisualIDPropertyToTagsTask.ts
-import { FilterQuery, ObjectID } from 'mongodb';
-
-import Constants from '../../utils/Constants';
-import Logging from '../../utils/Logging';
-import MigrationTask from '../MigrationTask';
-import { ServerAction } from '../../types/Server';
-import Tag from '../../types/Tag';
-import Tenant from '../../types/Tenant';
-import TenantStorage from '../../storage/mongodb/TenantStorage';
-import Utils from '../../utils/Utils';
-import global from '../../types/GlobalType';
-
-const MODULE_NAME = 'AddVisualIDPropertyToTagsTask';
-
-export default class AddVisualIDPropertyToTagsTask extends MigrationTask {
- async migrate(): Promise<void> {
- const tenants = await TenantStorage.getTenants({}, Constants.DB_PARAMS_MAX_LIMIT);
- for (const tenant of tenants.result) {
- await this.migrateTenant(tenant);
- }
- }
-
- async migrateTenant(tenant: Tenant): Promise<void> {
- let tags: Tag[];
- let updated = 0;
- const findFilter: FilterQuery<any> = {
- $or: [
- { visualID: { $exists: false } },
- { visualID: null },
- { visualID: '' }
- ]
- };
- do {
- // Get the tags
- tags = await global.database.getCollection<any>(tenant.id, 'tags')
- .find(findFilter)
- .limit(Constants.BATCH_PAGE_SIZE)
- .toArray();
- if (!Utils.isEmptyArray(tags)) {
- for (const tag of tags) {
- const visualID = new ObjectID().toHexString();
- await global.database.getCollection<any>(tenant.id, 'tags').updateOne(
- { _id: tag['_id'] },
- { $set: { visualID } }
- );
- updated++;
- }
- }
- } while (tags.length === Constants.BATCH_PAGE_SIZE); // Avoid infinite loop due to issues in the update process
- // Log in the default tenant
- if (updated > 0) {
- await Logging.logDebug({
- tenantID: Constants.DEFAULT_TENANT,
- module: MODULE_NAME, method: 'migrateTenant',
- action: ServerAction.MIGRATION,
- message: `${updated} Tag(s) visualID have been updated in Tenant ${Utils.buildTenantName(tenant)}`
- });
- }
- }
-
- getVersion(): string {
- return '1.7';
- }
-
- getName(): string {
- return 'AddVisualIDPropertyToTagsTask';
- }
-
- isAsynchronous(): boolean {
- return true;
- }
-}

MODIFY
src/server/ocpp/services/OCPPService.ts
src/server/ocpp/services/OCPPService.ts
@@ -1689,6 +1689,7 @@ export default class OCPPService {
// Set the Site ID. ChargingStation$siteArea$site checked by TagIDAuthorized.
if (chargingStation.site) {
startTransaction.siteID = chargingStation.site.id;
+ startTransaction.companyID = chargingStation.site.companyID;
}
}
}
@@ -1701,8 +1702,9 @@ export default class OCPPService {
tagID: startTransaction.idTag,
timezone: startTransaction.timezone,
userID: startTransaction.userID,
- siteAreaID: startTransaction.siteAreaID,
+ companyID: startTransaction.companyID,
siteID: startTransaction.siteID,
+ siteAreaID: startTransaction.siteAreaID,
connectorId: startTransaction.connectorId,
meterStart: startTransaction.meterStart,
timestamp: Utils.convertToDate(startTransaction.timestamp),
@@ -1790,10 +1792,11 @@ export default class OCPPService {
newChargingStation.registrationStatus = RegistrationStatus.ACCEPTED;
// Assign to Site Area
if (token.siteAreaID) {
- const siteArea = await SiteAreaStorage.getSiteArea(tenant.id, token.siteAreaID);
+ const siteArea = await SiteAreaStorage.getSiteArea(tenant.id, token.siteAreaID, { withSite: true });
if (siteArea) {
- newChargingStation.siteAreaID = token.siteAreaID;
+ newChargingStation.companyID = siteArea.site?.companyID;
newChargingStation.siteID = siteArea.siteID;
+ newChargingStation.siteAreaID = token.siteAreaID;
// Set the same coordinates
if (siteArea?.address?.coordinates?.length === 2) {
newChargingStation.coordinates = siteArea.address.coordinates;

MODIFY
src/server/rest/v1/service/ChargingStationService.ts
src/server/rest/v1/service/ChargingStationService.ts
@@ -261,8 +261,9 @@ export default class ChargingStationService {
action: action
});
}
- chargingStation.siteAreaID = siteArea.id;
+ chargingStation.companyID = siteArea.site?.companyID;
chargingStation.siteID = siteArea.siteID;
+ chargingStation.siteAreaID = siteArea.id;
// Check if number of phases corresponds to the site area one
for (const connector of chargingStation.connectors) {
const numberOfConnectedPhase = Utils.getNumberOfConnectedPhases(chargingStation, null, connector.connectorId);
@@ -283,8 +284,9 @@ export default class ChargingStationService {
}
} else {
delete chargingStation.excludeFromSmartCharging;
- chargingStation.siteAreaID = null;
+ chargingStation.companyID = null;
chargingStation.siteID = null;
+ chargingStation.siteAreaID = null;
}
if (filteredRequest.coordinates && filteredRequest.coordinates.length === 2) {
chargingStation.coordinates = [
@@ -325,7 +327,6 @@ export default class ChargingStationService {
'chargingStationURL': chargingStation.chargingStationURL
}
});
- // Ok
res.json(Constants.REST_RESPONSE_SUCCESS);
next();
}
@@ -475,7 +476,6 @@ export default class ChargingStationService {
message: `The charger's power limit has been successfully set to ${filteredRequest.ampLimitValue}A`,
detailedMessages: { result }
});
- // Ok
res.json({ status: result.status });
next();
}
@@ -588,7 +588,6 @@ export default class ChargingStationService {
await LockingManager.release(siteAreaLock);
}
}
- // Ok
res.json(Constants.REST_RESPONSE_SUCCESS);
next();
}
@@ -705,7 +704,6 @@ export default class ChargingStationService {
detailedMessages: { error: error.stack }
});
}
- // Ok
res.json(Constants.REST_RESPONSE_SUCCESS);
next();
}
@@ -763,7 +761,6 @@ export default class ChargingStationService {
if (filteredRequest.forceUpdateOCPPParamsFromTemplate) {
result = await OCPPUtils.updateChargingStationOcppParametersWithTemplate(req.tenant, chargingStation);
}
- // Ok
res.json(result);
next();
}
@@ -865,11 +862,10 @@ export default class ChargingStationService {
}
}
}
- // Remove Site Area
- chargingStation.siteArea = null;
- chargingStation.siteAreaID = null;
- // Remove Site
+ // Remove Org
+ chargingStation.companyID = null;
chargingStation.siteID = null;
+ chargingStation.siteAreaID = null;
// Set as deleted
chargingStation.deleted = true;
// Check if charging station has had transactions
@@ -882,7 +878,6 @@ export default class ChargingStationService {
// Delete physically
await ChargingStationStorage.deleteChargingStation(req.user.tenantID, chargingStation.id);
}
- // Log
await Logging.logSecurityInfo({
tenantID: req.user.tenantID,
user: req.user, module: MODULE_NAME, method: 'handleDeleteChargingStation',
@@ -890,7 +885,6 @@ export default class ChargingStationService {
action: action,
detailedMessages: { chargingStation }
});
- // Ok
res.json(Constants.REST_RESPONSE_SUCCESS);
next();
}
@@ -1323,7 +1317,6 @@ export default class ChargingStationService {
}
// Check
await smartCharging.checkConnection();
- // Ok
res.json(Constants.REST_RESPONSE_SUCCESS);
next();
}
@@ -1702,7 +1695,6 @@ export default class ChargingStationService {
});
break;
}
- // Ok?
if (result) {
// OCPP Command with status
if (Utils.objectHasProperty(result, 'status') && ![OCPPStatus.ACCEPTED, OCPPUnlockStatus.UNLOCKED].includes(result.status)) {
@@ -1801,8 +1793,6 @@ export default class ChargingStationService {
});
}
// Apply & Save charging plan
- const chargingProfileID = await OCPPUtils.setAndSaveChargingProfile(req.tenant, filteredRequest);
- // Ok
- return chargingProfileID;
+ return OCPPUtils.setAndSaveChargingProfile(req.tenant, filteredRequest);
}
}

MODIFY
src/server/rest/v1/service/TransactionService.ts
src/server/rest/v1/service/TransactionService.ts
@@ -45,12 +45,12 @@ export default class TransactionService {
public static async handleGetTransactions(action: ServerAction, req: Request, res: Response, next: NextFunction): Promise<void> {
res.json(await TransactionService.getTransactions(req, action, {}, [
- 'id', 'chargeBoxID', 'timestamp', 'issuer', 'stateOfCharge', 'timezone', 'connectorId', 'meterStart', 'siteAreaID', 'siteID',
+ 'id', 'chargeBoxID', 'timestamp', 'issuer', 'stateOfCharge', 'timezone', 'connectorId', 'meterStart', 'siteAreaID', 'siteID', 'companyID',
'currentTotalDurationSecs', 'currentTotalInactivitySecs', 'currentInstantWatts', 'currentTotalConsumptionWh', 'currentStateOfCharge',
'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', 'site.name', 'siteArea.name'
+ 'billingData.stop.invoiceNumber', 'stop.reason', 'ocpi', 'ocpiWithCdr', 'tagID', 'stop.tagID', 'site.name', 'siteArea.name', 'company.name'
]));
next();
}
@@ -522,7 +522,7 @@ export default class TransactionService {
UtilsService.assertIdIsProvided(action, filteredRequest.TransactionId, MODULE_NAME,
'handleGetConsumptionFromTransaction', req.user);
let projectFields = [
- 'id', 'chargeBoxID', 'timestamp', 'issuer', 'stateOfCharge', 'timezone', 'connectorId', 'meterStart', 'siteAreaID', 'siteID',
+ 'id', 'chargeBoxID', 'timestamp', 'issuer', 'stateOfCharge', 'timezone', 'connectorId', 'meterStart', 'siteAreaID', 'siteID', 'companyID',
'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.pricingSource', 'stop.reason',
@@ -624,7 +624,7 @@ export default class TransactionService {
UtilsService.assertIdIsProvided(action, filteredRequest.ID, MODULE_NAME, 'handleGetTransaction', req.user);
// Get Transaction
const transaction = await TransactionStorage.getTransaction(req.user.tenantID, filteredRequest.ID, [
- 'id', 'chargeBoxID', 'timestamp', 'issuer', 'stateOfCharge', 'tagID', 'timezone', 'connectorId', 'meterStart', 'siteAreaID', 'siteID',
+ 'id', 'chargeBoxID', 'timestamp', 'issuer', 'stateOfCharge', 'tagID', 'timezone', 'connectorId', 'meterStart', 'siteAreaID', 'siteID', 'companyID',
'userID', 'user.id', 'user.name', 'user.firstName', 'user.email', 'roundedPrice', 'price', 'priceUnit',
'stop.userID', 'stop.user.id', 'stop.user.name', 'stop.user.firstName', 'stop.user.email',
'currentTotalDurationSecs', 'currentTotalInactivitySecs', 'currentInstantWatts', 'currentTotalConsumptionWh', 'currentStateOfCharge',
@@ -665,10 +665,10 @@ export default class TransactionService {
public static async handleGetChargingStationTransactions(action: ServerAction, req: Request, res: Response, next: NextFunction): Promise<void> {
// Get transaction
const transactions = await TransactionService.getTransactions(req, action, {}, [
- 'id', 'chargeBoxID', 'timestamp', 'issuer', 'stateOfCharge', 'timezone', 'connectorId', 'meterStart', 'siteAreaID', 'siteID',
+ 'id', 'chargeBoxID', 'timestamp', 'issuer', 'stateOfCharge', 'timezone', 'connectorId', 'meterStart', 'siteAreaID', 'siteID', 'companyID',
'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', 'site.name', 'siteArea.name',
+ 'stop.totalDurationSecs', 'stop.totalInactivitySecs', 'stop.extraInactivitySecs', 'site.name', 'siteArea.name', 'company.name',
'billingData.stop.invoiceNumber', 'stop.reason', 'ocpi', 'ocpiWithCdr', 'tagID', 'stop.tagID',
]);
res.json(transactions);
@@ -691,9 +691,9 @@ export default class TransactionService {
public static async handleGetTransactionsActive(action: ServerAction, req: Request, res: Response, next: NextFunction): Promise<void> {
req.query.Status = 'active';
const transactions = await TransactionService.getTransactions(req, action, {}, [
- 'id', 'chargeBoxID', 'timestamp', 'issuer', 'stateOfCharge', 'timezone', 'connectorId', 'status', 'meterStart', 'siteAreaID', 'siteID',
+ 'id', 'chargeBoxID', 'timestamp', 'issuer', 'stateOfCharge', 'timezone', 'connectorId', 'status', 'meterStart', 'siteAreaID', 'siteID', 'companyID',
'currentTotalDurationSecs', 'currentTotalInactivitySecs', 'currentInstantWatts', 'currentTotalConsumptionWh', 'currentStateOfCharge',
- 'currentCumulatedPrice', 'currentInactivityStatus', 'roundedPrice', 'price', 'priceUnit', 'tagID', 'site.name', 'siteArea.name',
+ 'currentCumulatedPrice', 'currentInactivityStatus', 'roundedPrice', 'price', 'priceUnit', 'tagID', 'site.name', 'siteArea.name', 'company.name',
]);
res.json(transactions);
next();
@@ -703,9 +703,9 @@ export default class TransactionService {
// Get transaction
req.query.Status = 'completed';
const transactions = await TransactionService.getTransactions(req, action, {}, [
- 'id', 'chargeBoxID', 'timestamp', 'issuer', 'stateOfCharge', 'timezone', 'connectorId', 'meterStart', 'siteAreaID', 'siteID',
+ 'id', 'chargeBoxID', 'timestamp', 'issuer', 'stateOfCharge', 'timezone', 'connectorId', 'meterStart', 'siteAreaID', 'siteID', 'companyID',
'stop.roundedPrice', 'stop.price', 'stop.priceUnit', 'stop.inactivityStatus', 'stop.stateOfCharge', 'stop.timestamp', 'stop.totalConsumptionWh',
- 'stop.totalDurationSecs', 'stop.totalInactivitySecs', 'stop.extraInactivitySecs', 'stop.meterStop', 'site.name', 'siteArea.name',
+ 'stop.totalDurationSecs', 'stop.totalInactivitySecs', 'stop.extraInactivitySecs', 'stop.meterStop', 'site.name', 'siteArea.name', 'company.name',
'billingData.stop.invoiceNumber', 'stop.reason', 'ocpi', 'ocpiWithCdr', 'tagID', 'stop.tagID',
]);
res.json(transactions);
@@ -721,8 +721,8 @@ export default class TransactionService {
// Call
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', 'site.name', 'siteArea.name',
+ 'id', 'chargeBoxID', 'timestamp', 'issuer', 'stateOfCharge', 'timezone', 'connectorId', 'meterStart', 'siteAreaID', 'siteID', 'companyID',
+ 'refundData.reportId', 'refundData.refundedAt', 'refundData.status', 'site.name', 'siteArea.name', 'company.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',
@@ -788,9 +788,9 @@ export default class TransactionService {
// Get transaction
req.query.Status = 'completed';
return TransactionService.getTransactions(req, ServerAction.TRANSACTIONS_EXPORT, { withTag: true }, [
- 'id', 'chargeBoxID', 'timestamp', 'issuer', 'stateOfCharge', 'timezone', 'connectorId', 'meterStart', 'siteAreaID', 'siteID',
+ 'id', 'chargeBoxID', 'timestamp', 'issuer', 'stateOfCharge', 'timezone', 'connectorId', 'meterStart', 'siteAreaID', 'siteID', 'companyID',
'stop.roundedPrice', 'stop.price', 'stop.priceUnit', 'stop.inactivityStatus', 'stop.stateOfCharge', 'stop.timestamp', 'stop.totalConsumptionWh',
- 'stop.totalDurationSecs', 'stop.totalInactivitySecs', 'stop.extraInactivitySecs', 'site.name', 'siteArea.name',
+ 'stop.totalDurationSecs', 'stop.totalInactivitySecs', 'stop.extraInactivitySecs', 'site.name', 'siteArea.name', 'company.name',
'billingData.stop.invoiceNumber', 'stop.reason', 'ocpi', 'ocpiWithCdr', 'tagID', 'stop.tagID', 'tag.description'
]);
}
@@ -805,8 +805,8 @@ export default class TransactionService {
public static async getRefundedTransactionsToExport(req: Request): Promise<DataResult<Transaction>> {
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', 'site.name', 'siteArea.name',
+ 'id', 'chargeBoxID', 'timestamp', 'issuer', 'stateOfCharge', 'timezone', 'connectorId', 'meterStart', 'siteAreaID', 'siteID', 'companyID',
+ 'refundData.reportId', 'refundData.refundedAt', 'refundData.status', 'site.name', 'siteArea.name', 'company.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',
@@ -860,7 +860,7 @@ export default class TransactionService {
}
let projectFields = [
'id', 'chargeBoxID', 'timestamp', 'issuer', 'stateOfCharge', 'timezone', 'connectorId',
- 'meterStart', 'siteAreaID', 'siteID', 'errorCode', 'uniqueId', 'stop.totalConsumptionWh',
+ 'meterStart', 'siteAreaID', 'siteID', 'companyID', 'errorCode', 'uniqueId', 'stop.totalConsumptionWh',
'stop.totalDurationSecs', 'stop.stateOfCharge'
];
// Check Users
@@ -919,6 +919,7 @@ export default class TransactionService {
'id',
'chargingStationID',
'connectorID',
+ 'companyName',
'siteName',
'siteAreaName',
'userID',
@@ -944,6 +945,7 @@ export default class TransactionService {
transaction.id,
transaction.chargeBoxID,
transaction.connectorId,
+ transaction.company?.name,
transaction.site?.name,
transaction.siteArea?.name,
transaction.user ? Cypher.hash(transaction.user.id) : '',
@@ -1111,8 +1113,9 @@ export default class TransactionService {
tagIDs: filteredRequest.TagID ? filteredRequest.TagID.split('|') : null,
ownerID: Authorizations.isBasic(req.user) ? req.user.id : null,
withSite: filteredRequest.WithSite,
- withSiteArea: filteredRequest.WithSiteArea,
+ withCompany: filteredRequest.WithCompany,
siteAreaIDs: filteredRequest.SiteAreaID ? filteredRequest.SiteAreaID.split('|') : null,
+ withSiteArea: filteredRequest.WithSiteArea,
siteIDs: filteredRequest.SiteID ? Authorizations.getAuthorizedSiteAdminIDs(req.user, filteredRequest.SiteID.split('|')) : null,
siteAdminIDs: Authorizations.getAuthorizedSiteAdminIDs(req.user),
startDateTime: filteredRequest.StartDateTime ? filteredRequest.StartDateTime : null,

MODIFY
src/storage/mongodb/TransactionStorage.ts
src/storage/mongodb/TransactionStorage.ts
@@ -53,6 +53,7 @@ export default class TransactionStorage {
const transactionMDB: any = {
_id: Utils.convertToInt(transactionToSave.id),
issuer: Utils.convertToBoolean(transactionToSave.issuer),
+ companyID: DatabaseUtils.convertToObjectID(transactionToSave.companyID),
siteID: DatabaseUtils.convertToObjectID(transactionToSave.siteID),
siteAreaID: DatabaseUtils.convertToObjectID(transactionToSave.siteAreaID),
connectorId: Utils.convertToInt(transactionToSave.connectorId),
@@ -273,7 +274,7 @@ export default class TransactionStorage {
chargeBoxIDs?: string[]; siteAreaIDs?: string[]; siteIDs?: string[]; connectorIDs?: number[]; startDateTime?: Date;
endDateTime?: Date; stop?: any; minimalPrice?: boolean; reportIDs?: string[]; tagIDs?: string[]; inactivityStatus?: string[];
ocpiSessionID?: string; ocpiAuthorizationID?: string; ocpiSessionDateFrom?: Date; ocpiSessionDateTo?: Date; ocpiCdrDateFrom?: Date; ocpiCdrDateTo?: Date;
- ocpiSessionChecked?: boolean; ocpiCdrChecked?: boolean; oicpSessionID?: string; withSite?: boolean; withSiteArea?: boolean;
+ ocpiSessionChecked?: boolean; ocpiCdrChecked?: boolean; oicpSessionID?: string; withSite?: boolean; withSiteArea?: boolean; withCompany?: boolean;
statistics?: 'refund' | 'history' | 'ongoing'; refundStatus?: string[]; withTag?: boolean; hasUserID?: boolean;
},
dbParams: DbParams, projectFields?: string[]):
@@ -627,11 +628,11 @@ export default class TransactionStorage {
tenantID, aggregation: aggregation, localField: 'chargeBoxID', foreignField: '_id',
asField: 'chargeBox', oneToOneCardinality: true, oneToOneCardinalityNotNull: false
});
- // Site Area
- if (params.withSiteArea) {
- DatabaseUtils.pushSiteAreaLookupInAggregation({
- tenantID, aggregation: aggregation, localField: 'siteAreaID', foreignField: '_id',
- asField: 'siteArea', oneToOneCardinality: true
+ // Company
+ if (params.withCompany) {
+ DatabaseUtils.pushCompanyLookupInAggregation({
+ tenantID, aggregation: aggregation, localField: 'companyID', foreignField: '_id',
+ asField: 'company', oneToOneCardinality: true
});
}
// Site
@@ -641,6 +642,13 @@ export default class TransactionStorage {
asField: 'site', oneToOneCardinality: true
});
}
+ // Site Area
+ if (params.withSiteArea) {
+ DatabaseUtils.pushSiteAreaLookupInAggregation({
+ tenantID, aggregation: aggregation, localField: 'siteAreaID', foreignField: '_id',
+ asField: 'siteArea', oneToOneCardinality: true
+ });
+ }
DatabaseUtils.pushConvertObjectIDToString(aggregation, 'chargeBox.siteAreaID');
// Add Connector and Status
if (projectFields && projectFields.includes('status')) {

MODIFY
src/types/Transaction.ts
src/types/Transaction.ts
@@ -4,6 +4,7 @@ import Consumption, { AbstractCurrentConsumption } from './Consumption';
import { BillingTransactionData } from './Billing';
import ChargingStation from '../types/ChargingStation';
+import Company from './Company';
import { OCPICdr } from './ocpi/OCPICdr';
import { OCPISession } from './ocpi/OCPISession';
import { OICPChargeDetailRecord } from './oicp/OICPChargeDetailRecord';
@@ -54,6 +55,8 @@ export default interface Transaction extends AbstractCurrentConsumption {
carCatalogID?: number;
carCatalog?: CarCatalog;
phasesUsed?: CSPhasesUsed;
+ companyID?: string;
+ company?: Company;
siteID?: string;
site?: Site;
siteAreaID?: string;

MODIFY
src/types/ocpp/OCPPServer.ts
src/types/ocpp/OCPPServer.ts
@@ -357,6 +357,7 @@ export interface OCPPStartTransactionRequestExtended extends OCPPStartTransactio
userID: string;
siteAreaID: string;
siteID: string;
+ companyID: string;
}
export interface OCPPStartTransactionResponse {

MODIFY
src/types/requests/HttpTransactionRequest.ts
src/types/requests/HttpTransactionRequest.ts
@@ -25,6 +25,7 @@ export interface HttpPushTransactionCdrRequest {
export interface HttpTransactionsRequest extends HttpDatabaseRequest {
ChargingStationID: string;
Issuer: boolean;
+ WithCompany: boolean;
WithSite: boolean;
WithSiteArea: boolean;
ConnectorID: string;

Added Company ID in Transaction