Added siteID to asset
MODIFY
src/migration/MigrationHandler.ts
src/migration/MigrationHandler.ts
@@ -11,6 +11,7 @@ import AddNotificationsFlagsToUsersTask from './tasks/AddNotificationsFlagsToUse
import AddSensitiveDataInSettingsTask from './tasks/AddSensitiveDataInSettingsTask';
import AddSiteAreaIDToAssetConsumptionTask from './tasks/AddSiteAreaIDToAssetConsumptionTask';
import AddSiteAreaLimitToConsumptionsTask from './tasks/AddSiteAreaLimitToConsumptionsTask';
+import AddSiteIDToAssetTask from './tasks/AddSiteIDToAssetTask';
import AddSiteIDToChargingStationTask from './tasks/AddSiteIDToChargingStationTask';
import AddTagTypeTask from './tasks/AddTagTypeTask';
import AddTransactionRefundStatusTask from './tasks/AddTransactionRefundStatusTask';
@@ -119,6 +120,7 @@ export default class MigrationHandler {
currentMigrationTasks.push(new AddSiteAreaIDToAssetConsumptionTask());
currentMigrationTasks.push(new RecomputeAllTransactionsWithSimplePricingTask());
currentMigrationTasks.push(new AddSiteIDToChargingStationTask());
+ currentMigrationTasks.push(new AddSiteIDToAssetTask());
// Get the already done migrations from the DB
const migrationTasksDone = await MigrationStorage.getMigrations();
// Check

ADD
src/migration/tasks/AddSiteIDToAssetTask.ts
+import Constants from '../../utils/Constants';
+import Logging from '../../utils/Logging';
+import MigrationTask from '../MigrationTask';
+import { ServerAction } from '../../types/Server';
+import SiteAreaStorage from '../../storage/mongodb/SiteAreaStorage';
+import Tenant from '../../types/Tenant';
+import TenantStorage from '../../storage/mongodb/TenantStorage';
+import Utils from '../../utils/Utils';
+import global from '../../types/GlobalType';
+
+const MODULE_NAME = 'AddSiteIDToAssetTask';
+
+export default class AddSiteIDToAssetTask 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 modifiedCount = 0;
+ // Get Assets
+ const siteAreas = await SiteAreaStorage.getSiteAreas(tenant.id, {}, Constants.DB_PARAMS_MAX_LIMIT);
+ for (const siteArea of siteAreas.result) {
+ const result = await global.database.getCollection(tenant.id, 'assets').updateMany(
+ {
+ siteAreaID: Utils.convertToObjectID(siteArea.id),
+ },
+ {
+ $set: {
+ siteID: Utils.convertToObjectID(siteArea.siteID),
+ }
+ }
+ );
+ modifiedCount += result.modifiedCount;
+ }
+ // Log in the default tenant
+ if (modifiedCount > 0) {
+ await Logging.logDebug({
+ tenantID: Constants.DEFAULT_TENANT,
+ action: ServerAction.MIGRATION,
+ module: MODULE_NAME, method: 'migrateTenant',
+ message: `${modifiedCount} Assets have been updated in Tenant '${tenant.name}'`
+ });
+ }
+ }
+
+ getVersion(): string {
+ return '1.0';
+ }
+
+ getName(): string {
+ return 'AddSiteIDToAssetTask';
+ }
+
+ isAsynchronous(): boolean {
+ return true;
+ }
+}

MODIFY
src/server/rest/v1/service/AssetService.ts
src/server/rest/v1/service/AssetService.ts
@@ -14,6 +14,7 @@ import Constants from '../../../../utils/Constants';
import ConsumptionStorage from '../../../../storage/mongodb/ConsumptionStorage';
import Logging from '../../../../utils/Logging';
import { ServerAction } from '../../../../types/Server';
+import SiteArea from '../../../../types/SiteArea';
import SiteAreaStorage from '../../../../storage/mongodb/SiteAreaStorage';
import TenantComponents from '../../../../types/TenantComponents';
import UtilsService from './UtilsService';
@@ -118,7 +119,7 @@ export default class AssetService {
res.json(Object.assign({ connectionIsValid: true }, Constants.REST_RESPONSE_SUCCESS));
} catch (error) {
// KO
- Logging.logError({
+ await Logging.logError({
tenantID: req.user.tenantID,
user: req.user,
module: MODULE_NAME, method: 'handleCheckAssetConnection',
@@ -223,6 +224,7 @@ export default class AssetService {
{
search: filteredRequest.Search,
siteAreaIDs: (filteredRequest.SiteAreaID ? filteredRequest.SiteAreaID.split('|') : null),
+ siteIDs: (filteredRequest.SiteID ? filteredRequest.SiteID.split('|') : null),
errorType
},
{ limit: filteredRequest.Limit,
@@ -263,7 +265,7 @@ export default class AssetService {
// Delete
await AssetStorage.deleteAsset(req.user.tenantID, asset.id);
// Log
- Logging.logSecurityInfo({
+ await Logging.logSecurityInfo({
tenantID: req.user.tenantID,
user: req.user,
module: MODULE_NAME, method: 'handleDeleteAsset',
@@ -347,13 +349,14 @@ export default class AssetService {
{
search: filteredRequest.Search,
siteAreaIDs: (filteredRequest.SiteAreaID ? filteredRequest.SiteAreaID.split('|') : null),
+ siteIDs: (filteredRequest.SiteID ? filteredRequest.SiteID.split('|') : null),
withSiteArea: filteredRequest.WithSiteArea,
withNoSiteArea: filteredRequest.WithNoSiteArea,
dynamicOnly: filteredRequest.DynamicOnly,
},
{ limit: filteredRequest.Limit, skip: filteredRequest.Skip, sort: filteredRequest.SortFields, onlyRecordCount: filteredRequest.OnlyRecordCount },
[
- 'id', 'name', 'siteAreaID', 'siteArea.id', 'siteArea.name', 'siteArea.siteID', 'assetType', 'coordinates',
+ 'id', 'name', 'siteAreaID', 'siteArea.id', 'siteArea.name', 'siteArea.siteID', 'siteID', 'assetType', 'coordinates',
'dynamicAsset', 'connectionID', 'meterID', 'currentInstantWatts', 'currentStateOfCharge'
]
);
@@ -379,8 +382,9 @@ export default class AssetService {
// Check Asset
UtilsService.checkIfAssetValid(filteredRequest, req);
// Check Site Area
+ let siteArea: SiteArea = null;
if (filteredRequest.siteAreaID) {
- const siteArea = await SiteAreaStorage.getSiteArea(req.user.tenantID, filteredRequest.siteAreaID);
+ siteArea = await SiteAreaStorage.getSiteArea(req.user.tenantID, filteredRequest.siteAreaID);
UtilsService.assertObjectExists(action, siteArea, `Site Area ID '${filteredRequest.siteAreaID}' does not exist`,
MODULE_NAME, 'handleCreateAsset', req.user);
}
@@ -388,6 +392,7 @@ export default class AssetService {
const newAsset: Asset = {
name: filteredRequest.name,
siteAreaID: filteredRequest.siteAreaID,
+ siteID: siteArea ? siteArea.siteID : null,
assetType: filteredRequest.assetType,
excludeFromSmartCharging: filteredRequest.excludeFromSmartCharging,
fluctuationPercent: filteredRequest.fluctuationPercent,
@@ -403,7 +408,7 @@ export default class AssetService {
// Save
newAsset.id = await AssetStorage.saveAsset(req.user.tenantID, newAsset);
// Log
- Logging.logSecurityInfo({
+ await Logging.logSecurityInfo({
tenantID: req.user.tenantID,
user: req.user,
module: MODULE_NAME, method: 'handleCreateAsset',
@@ -433,8 +438,9 @@ export default class AssetService {
});
}
// Check Site Area
+ let siteArea: SiteArea = null;
if (filteredRequest.siteAreaID) {
- const siteArea = await SiteAreaStorage.getSiteArea(req.user.tenantID, filteredRequest.siteAreaID);
+ siteArea = await SiteAreaStorage.getSiteArea(req.user.tenantID, filteredRequest.siteAreaID);
UtilsService.assertObjectExists(action, siteArea, `Site Area ID '${filteredRequest.siteAreaID}' does not exist`,
MODULE_NAME, 'handleUpdateAsset', req.user);
}
@@ -448,6 +454,7 @@ export default class AssetService {
// Update
asset.name = filteredRequest.name;
asset.siteAreaID = filteredRequest.siteAreaID;
+ asset.siteID = siteArea ? siteArea.siteID : null,
asset.assetType = filteredRequest.assetType;
asset.excludeFromSmartCharging = filteredRequest.excludeFromSmartCharging;
asset.fluctuationPercent = filteredRequest.fluctuationPercent;
@@ -462,7 +469,7 @@ export default class AssetService {
// Update Asset
await AssetStorage.saveAsset(req.user.tenantID, asset);
// Log
- Logging.logSecurityInfo({
+ await Logging.logSecurityInfo({
tenantID: req.user.tenantID,
user: req.user,
module: MODULE_NAME, method: 'handleUpdateAsset',

MODIFY
src/server/rest/v1/service/security/AssetSecurity.ts
src/server/rest/v1/service/security/AssetSecurity.ts
@@ -29,6 +29,7 @@ export default class AssetSecurity {
const filteredRequest: HttpAssetsRequest = {
Search: sanitize(request.Search),
SiteAreaID: sanitize(request.SiteAreaID),
+ SiteID: sanitize(request.SiteID),
WithSiteArea: UtilsSecurity.filterBoolean(request.WithSiteArea),
WithNoSiteArea: UtilsSecurity.filterBoolean(request.WithNoSiteArea),
DynamicOnly: UtilsSecurity.filterBoolean(request.DynamicOnly),

MODIFY
src/storage/mongodb/AssetStorage.ts
src/storage/mongodb/AssetStorage.ts
@@ -48,6 +48,7 @@ export default class AssetStorage {
_id: assetToSave.id ? Utils.convertToObjectID(assetToSave.id) : new ObjectID(),
name: assetToSave.name,
siteAreaID: Utils.convertToObjectID(assetToSave.siteAreaID),
+ siteID: Utils.convertToObjectID(assetToSave.siteID),
coordinates: Utils.containsGPSCoordinates(assetToSave.coordinates) ? assetToSave.coordinates.map(
(coordinate) => Utils.convertToFloat(coordinate)) : [],
assetType: assetToSave.assetType,
@@ -97,7 +98,7 @@ export default class AssetStorage {
}
public static async getAssets(tenantID: string,
- params: { search?: string; assetIDs?: string[]; siteAreaIDs?: string[]; withSiteArea?: boolean;
+ params: { search?: string; assetIDs?: string[]; siteAreaIDs?: string[]; siteIDs?: string[]; withSiteArea?: boolean;
withNoSiteArea?: boolean; dynamicOnly?: boolean } = {},
dbParams?: DbParams, projectFields?: string[]): Promise<DataResult<Asset>> {
// Debug
@@ -128,6 +129,11 @@ export default class AssetStorage {
$in: params.siteAreaIDs.map((id) => Utils.convertToObjectID(id))
};
}
+ if (!Utils.isEmptyArray(params.siteIDs)) {
+ filters.siteID = {
+ $in: params.siteIDs.map((id) => Utils.convertToObjectID(id))
+ };
+ }
// Dynamic Asset
if (params.dynamicOnly) {
filters.dynamicAsset = true;
@@ -211,7 +217,7 @@ export default class AssetStorage {
}
public static async getAssetsInError(tenantID: string,
- params: { search?: string; siteAreaIDs?: string[]; errorType?: string[] } = {},
+ params: { search?: string; siteAreaIDs?: string[]; siteIDs?: string[]; errorType?: string[] } = {},
dbParams?: DbParams, projectFields?: string[]): Promise<DataResult<Asset>> {
// Debug
const uniqueTimerID = Logging.traceStart(tenantID, MODULE_NAME, 'getAssetsInError');
@@ -233,6 +239,9 @@ export default class AssetStorage {
if (!Utils.isEmptyArray(params.siteAreaIDs)) {
filters.siteAreaID = { $in: params.siteAreaIDs.map((id) => Utils.convertToObjectID(id)) };
}
+ if (!Utils.isEmptyArray(params.siteIDs)) {
+ filters.siteID = { $in: params.siteIDs.map((id) => Utils.convertToObjectID(id)) };
+ }
// Create Aggregation
const aggregation = [];
// Filters

MODIFY
src/types/Asset.ts
src/types/Asset.ts
@@ -8,6 +8,7 @@ export default interface Asset extends CreatedUpdatedProps, AbstractCurrentConsu
name: string;
siteAreaID: string;
siteArea?: SiteArea;
+ siteID: string;
assetType: AssetType;
fluctuationPercent: number;
staticValueWatt: number;

MODIFY
src/types/requests/HttpAssetRequest.ts
src/types/requests/HttpAssetRequest.ts
@@ -8,6 +8,7 @@ export interface HttpAssetRequest extends HttpByIDRequest {
export interface HttpAssetsRequest extends HttpDatabaseRequest {
Search?: string;
SiteAreaID?: string;
+ SiteID?: string;
WithSiteArea?: boolean;
WithNoSiteArea?: boolean;
DynamicOnly?: boolean;

MODIFY
test/api/AssetTest.ts
test/api/AssetTest.ts
@@ -151,10 +151,11 @@ describe('Asset Test', function() {
it('Should find the created asset by id', async () => {
// Check if the created entity can be retrieved with its id
- await testData.userService.getEntityById(
+ const createdAsset = await testData.userService.getEntityById(
testData.userService.assetApi,
testData.newAsset
);
+ expect(createdAsset.siteID).to.equal(testData.createdSiteAreas[0].siteID);
});
it('Should find the created asset in the asset list', async () => {

Added siteID to asset