refactor: cleanup imports
[e-mobility-charging-stations-simulator.git] / src / charging-station / ChargingStationUtils.ts
index e2e9821e28c915804c7a9aec4bac79468023e956..ab781fae3cb3382022abb8f61ed7b55f021e9ef0 100644 (file)
@@ -1,14 +1,16 @@
-import crypto from 'node:crypto';
-import path from 'node:path';
+import { createHash, randomBytes } from 'node:crypto';
+import type { EventEmitter } from 'node:events';
+import { basename, dirname, join } from 'node:path';
 import { fileURLToPath } from 'node:url';
 
 import chalk from 'chalk';
 import moment from 'moment';
 
-import type { ChargingStation } from './internal';
+import type { ChargingStation } from './ChargingStation';
 import { BaseError } from '../exception';
 import {
   AmpereUnits,
+  AvailabilityType,
   type BootNotificationRequest,
   BootReasonEnumType,
   type ChargingProfile,
@@ -17,23 +19,19 @@ import {
   type ChargingSchedulePeriod,
   type ChargingStationInfo,
   type ChargingStationTemplate,
+  ChargingStationWorkerMessageEvents,
+  ConnectorPhaseRotation,
   type ConnectorStatus,
+  ConnectorStatusEnum,
   CurrentType,
+  type EvseTemplate,
   type OCPP16BootNotificationRequest,
   type OCPP20BootNotificationRequest,
   OCPPVersion,
   RecurrencyKindType,
   Voltage,
 } from '../types';
-import {
-  ACElectricUtils,
-  Configuration,
-  Constants,
-  DCElectricUtils,
-  Utils,
-  logger,
-} from '../utils';
-import { WorkerProcessType } from '../worker';
+import { ACElectricUtils, Constants, DCElectricUtils, Utils, logger } from '../utils';
 
 const moduleName = 'ChargingStationUtils';
 
@@ -57,6 +55,19 @@ export class ChargingStationUtils {
         )}${idSuffix}`;
   }
 
+  public static countReservableConnectors(connectors: Map<number, ConnectorStatus>) {
+    let reservableConnectors = 0;
+    for (const [connectorId, connectorStatus] of connectors) {
+      if (connectorId === 0) {
+        continue;
+      }
+      if (connectorStatus.status === ConnectorStatusEnum.Available) {
+        ++reservableConnectors;
+      }
+    }
+    return reservableConnectors;
+  }
+
   public static getHashId(index: number, stationTemplate: ChargingStationTemplate): string {
     const chargingStationInfo = {
       chargePointModel: stationTemplate.chargePointModel,
@@ -74,8 +85,7 @@ export class ChargingStationUtils {
         meterType: stationTemplate.meterType,
       }),
     };
-    return crypto
-      .createHash(Constants.DEFAULT_HASH_ALGORITHM)
+    return createHash(Constants.DEFAULT_HASH_ALGORITHM)
       .update(
         `${JSON.stringify(chargingStationInfo)}${ChargingStationUtils.getChargingStationId(
           index,
@@ -93,6 +103,30 @@ export class ChargingStationUtils {
     return true;
   }
 
+  public static getPhaseRotationValue(
+    connectorId: number,
+    numberOfPhases: number
+  ): string | undefined {
+    // AC/DC
+    if (connectorId === 0 && numberOfPhases === 0) {
+      return `${connectorId}.${ConnectorPhaseRotation.RST}`;
+    } else if (connectorId > 0 && numberOfPhases === 0) {
+      return `${connectorId}.${ConnectorPhaseRotation.NotApplicable}`;
+      // AC
+    } else if (connectorId > 0 && numberOfPhases === 1) {
+      return `${connectorId}.${ConnectorPhaseRotation.NotApplicable}`;
+    } else if (connectorId > 0 && numberOfPhases === 3) {
+      return `${connectorId}.${ConnectorPhaseRotation.RST}`;
+    }
+  }
+
+  public static getMaxNumberOfEvses(evses: Record<string, EvseTemplate>): number {
+    if (!evses) {
+      return -1;
+    }
+    return Object.keys(evses).length;
+  }
+
   public static getMaxNumberOfConnectors(connectors: Record<string, ConnectorStatus>): number {
     if (!connectors) {
       return -1;
@@ -100,60 +134,177 @@ export class ChargingStationUtils {
     return Object.keys(connectors).length;
   }
 
-  public static checkTemplateMaxConnectors(
-    templateMaxConnectors: number,
-    templateFile: string,
-    logPrefix: string
-  ): void {
-    if (templateMaxConnectors === 0) {
+  public static getBootConnectorStatus(
+    chargingStation: ChargingStation,
+    connectorId: number,
+    connectorStatus: ConnectorStatus
+  ): ConnectorStatusEnum {
+    let connectorBootStatus: ConnectorStatusEnum;
+    if (
+      !connectorStatus?.status &&
+      (chargingStation.isChargingStationAvailable() === false ||
+        chargingStation.isConnectorAvailable(connectorId) === false)
+    ) {
+      connectorBootStatus = ConnectorStatusEnum.Unavailable;
+    } else if (!connectorStatus?.status && connectorStatus?.bootStatus) {
+      // Set boot status in template at startup
+      connectorBootStatus = connectorStatus?.bootStatus;
+    } else if (connectorStatus?.status) {
+      // Set previous status at startup
+      connectorBootStatus = connectorStatus?.status;
+    } else {
+      // Set default status
+      connectorBootStatus = ConnectorStatusEnum.Available;
+    }
+    return connectorBootStatus;
+  }
+
+  public static checkTemplate(
+    stationTemplate: ChargingStationTemplate,
+    logPrefix: string,
+    templateFile: string
+  ) {
+    if (Utils.isNullOrUndefined(stationTemplate)) {
+      const errorMsg = `Failed to read charging station template file ${templateFile}`;
+      logger.error(`${logPrefix} ${errorMsg}`);
+      throw new BaseError(errorMsg);
+    }
+    if (Utils.isEmptyObject(stationTemplate)) {
+      const errorMsg = `Empty charging station information from template file ${templateFile}`;
+      logger.error(`${logPrefix} ${errorMsg}`);
+      throw new BaseError(errorMsg);
+    }
+    if (Utils.isEmptyObject(stationTemplate.AutomaticTransactionGenerator)) {
+      stationTemplate.AutomaticTransactionGenerator = Constants.DEFAULT_ATG_CONFIGURATION;
       logger.warn(
-        `${logPrefix} Charging station information from template ${templateFile} with empty connectors configuration`
+        `${logPrefix} Empty automatic transaction generator configuration from template file ${templateFile}, set to default: %j`,
+        Constants.DEFAULT_ATG_CONFIGURATION
       );
-    } else if (templateMaxConnectors < 0) {
-      logger.error(
-        `${logPrefix} Charging station information from template ${templateFile} with no connectors configuration defined`
+    }
+    if (
+      Utils.isNullOrUndefined(stationTemplate.idTagsFile) ||
+      Utils.isEmptyString(stationTemplate.idTagsFile)
+    ) {
+      logger.warn(
+        `${logPrefix} Missing id tags file in template file ${templateFile}. That can lead to issues with the Automatic Transaction Generator`
       );
     }
   }
 
-  public static getConfiguredNumberOfConnectors(stationTemplate: ChargingStationTemplate): number {
-    let configuredMaxConnectors: number;
-    if (Utils.isNotEmptyArray(stationTemplate.numberOfConnectors) === true) {
-      const numberOfConnectors = stationTemplate.numberOfConnectors as number[];
-      configuredMaxConnectors =
-        numberOfConnectors[Math.floor(Utils.secureRandom() * numberOfConnectors.length)];
-    } else if (Utils.isUndefined(stationTemplate.numberOfConnectors) === false) {
-      configuredMaxConnectors = stationTemplate.numberOfConnectors as number;
-    } else if (stationTemplate.Connectors && !stationTemplate.Evses) {
-      configuredMaxConnectors = stationTemplate?.Connectors[0]
-        ? ChargingStationUtils.getMaxNumberOfConnectors(stationTemplate.Connectors) - 1
-        : ChargingStationUtils.getMaxNumberOfConnectors(stationTemplate.Connectors);
-    } else if (stationTemplate.Evses && !stationTemplate.Connectors) {
-      configuredMaxConnectors = 0;
-      for (const evse in stationTemplate.Evses) {
-        if (evse === '0') {
-          continue;
-        }
-        configuredMaxConnectors += ChargingStationUtils.getMaxNumberOfConnectors(
-          stationTemplate.Evses[evse].Connectors
+  public static checkConnectorsConfiguration(
+    stationTemplate: ChargingStationTemplate,
+    logPrefix: string,
+    templateFile: string
+  ): {
+    configuredMaxConnectors: number;
+    templateMaxConnectors: number;
+    templateMaxAvailableConnectors: number;
+  } {
+    const configuredMaxConnectors =
+      ChargingStationUtils.getConfiguredNumberOfConnectors(stationTemplate);
+    ChargingStationUtils.checkConfiguredMaxConnectors(
+      configuredMaxConnectors,
+      logPrefix,
+      templateFile
+    );
+    const templateMaxConnectors = ChargingStationUtils.getMaxNumberOfConnectors(
+      stationTemplate.Connectors
+    );
+    ChargingStationUtils.checkTemplateMaxConnectors(templateMaxConnectors, logPrefix, templateFile);
+    const templateMaxAvailableConnectors = stationTemplate?.Connectors[0]
+      ? templateMaxConnectors - 1
+      : templateMaxConnectors;
+    if (
+      configuredMaxConnectors > templateMaxAvailableConnectors &&
+      !stationTemplate?.randomConnectors
+    ) {
+      logger.warn(
+        `${logPrefix} Number of connectors exceeds the number of connector configurations in template ${templateFile}, forcing random connector configurations affectation`
+      );
+      stationTemplate.randomConnectors = true;
+    }
+    return { configuredMaxConnectors, templateMaxConnectors, templateMaxAvailableConnectors };
+  }
+
+  public static checkStationInfoConnectorStatus(
+    connectorId: number,
+    connectorStatus: ConnectorStatus,
+    logPrefix: string,
+    templateFile: string
+  ): void {
+    if (!Utils.isNullOrUndefined(connectorStatus?.status)) {
+      logger.warn(
+        `${logPrefix} Charging station information from template ${templateFile} with connector id ${connectorId} status configuration defined, undefine it`
+      );
+      delete connectorStatus.status;
+    }
+  }
+
+  public static buildConnectorsMap(
+    connectors: Record<string, ConnectorStatus>,
+    logPrefix: string,
+    templateFile: string
+  ): Map<number, ConnectorStatus> {
+    const connectorsMap = new Map<number, ConnectorStatus>();
+    if (ChargingStationUtils.getMaxNumberOfConnectors(connectors) > 0) {
+      for (const connector in connectors) {
+        const connectorStatus = connectors[connector];
+        const connectorId = Utils.convertToInt(connector);
+        ChargingStationUtils.checkStationInfoConnectorStatus(
+          connectorId,
+          connectorStatus,
+          logPrefix,
+          templateFile
         );
+        connectorsMap.set(connectorId, Utils.cloneObject<ConnectorStatus>(connectorStatus));
       }
+    } else {
+      logger.warn(
+        `${logPrefix} Charging station information from template ${templateFile} with no connectors, cannot build connectors map`
+      );
     }
-    return configuredMaxConnectors;
+    return connectorsMap;
   }
 
-  public static checkConfiguredMaxConnectors(
-    configuredMaxConnectors: number,
-    templateFile: string,
+  public static initializeConnectorsMapStatus(
+    connectors: Map<number, ConnectorStatus>,
     logPrefix: string
   ): void {
-    if (configuredMaxConnectors <= 0) {
-      logger.warn(
-        `${logPrefix} Charging station information from template ${templateFile} with ${configuredMaxConnectors} connectors`
-      );
+    for (const connectorId of connectors.keys()) {
+      if (connectorId > 0 && connectors.get(connectorId)?.transactionStarted === true) {
+        logger.warn(
+          `${logPrefix} Connector id ${connectorId} at initialization has a transaction started with id ${
+            connectors.get(connectorId)?.transactionId
+          }`
+        );
+      }
+      if (connectorId === 0) {
+        connectors.get(connectorId).availability = AvailabilityType.Operative;
+        if (Utils.isUndefined(connectors.get(connectorId)?.chargingProfiles)) {
+          connectors.get(connectorId).chargingProfiles = [];
+        }
+      } else if (
+        connectorId > 0 &&
+        Utils.isNullOrUndefined(connectors.get(connectorId)?.transactionStarted)
+      ) {
+        ChargingStationUtils.initializeConnectorStatus(connectors.get(connectorId));
+      }
     }
   }
 
+  public static resetConnectorStatus(connectorStatus: ConnectorStatus): void {
+    connectorStatus.idTagLocalAuthorized = false;
+    connectorStatus.idTagAuthorized = false;
+    connectorStatus.transactionRemoteStarted = false;
+    connectorStatus.transactionStarted = false;
+    delete connectorStatus?.localAuthorizeIdTag;
+    delete connectorStatus?.authorizeIdTag;
+    delete connectorStatus?.transactionId;
+    delete connectorStatus?.transactionIdTag;
+    connectorStatus.transactionEnergyActiveImportRegisterValue = 0;
+    delete connectorStatus?.transactionBeginMeterValue;
+  }
+
   public static createBootNotificationRequest(
     stationInfo: ChargingStationInfo,
     bootReason: BootReasonEnumType = BootReasonEnumType.PowerUp
@@ -206,20 +357,10 @@ export class ChargingStationUtils {
     }
   }
 
-  public static workerPoolInUse(): boolean {
-    return [WorkerProcessType.dynamicPool, WorkerProcessType.staticPool].includes(
-      Configuration.getWorker().processType
-    );
-  }
-
-  public static workerDynamicPoolInUse(): boolean {
-    return Configuration.getWorker().processType === WorkerProcessType.dynamicPool;
-  }
-
   public static warnTemplateKeysDeprecation(
-    templateFile: string,
     stationTemplate: ChargingStationTemplate,
-    logPrefix: string
+    logPrefix: string,
+    templateFile: string
   ) {
     const templateKeys: { key: string; deprecatedKey: string }[] = [
       { key: 'supervisionUrls', deprecatedKey: 'supervisionUrl' },
@@ -229,8 +370,8 @@ export class ChargingStationUtils {
       ChargingStationUtils.warnDeprecatedTemplateKey(
         stationTemplate,
         templateKey.deprecatedKey,
-        templateFile,
         logPrefix,
+        templateFile,
         `Use '${templateKey.key}' instead`
       );
       ChargingStationUtils.convertDeprecatedTemplateKey(
@@ -244,9 +385,11 @@ export class ChargingStationUtils {
   public static stationTemplateToStationInfo(
     stationTemplate: ChargingStationTemplate
   ): ChargingStationInfo {
-    stationTemplate = Utils.cloneObject(stationTemplate);
+    stationTemplate = Utils.cloneObject<ChargingStationTemplate>(stationTemplate);
     delete stationTemplate.power;
     delete stationTemplate.powerUnit;
+    delete stationTemplate?.Connectors;
+    delete stationTemplate?.Evses;
     delete stationTemplate.Configuration;
     delete stationTemplate.AutomaticTransactionGenerator;
     delete stationTemplate.chargeBoxSerialNumberPrefix;
@@ -255,14 +398,6 @@ export class ChargingStationUtils {
     return stationTemplate as unknown as ChargingStationInfo;
   }
 
-  public static createStationInfoHash(stationInfo: ChargingStationInfo): void {
-    delete stationInfo.infoHash;
-    stationInfo.infoHash = crypto
-      .createHash(Constants.DEFAULT_HASH_ALGORITHM)
-      .update(JSON.stringify(stationInfo))
-      .digest('hex');
-  }
-
   public static createSerialNumber(
     stationTemplate: ChargingStationTemplate,
     stationInfo: ChargingStationInfo,
@@ -274,27 +409,18 @@ export class ChargingStationUtils {
       randomSerialNumber: true,
     }
   ): void {
-    params = params ?? {};
-    params.randomSerialNumberUpperCase = params?.randomSerialNumberUpperCase ?? true;
-    params.randomSerialNumber = params?.randomSerialNumber ?? true;
+    params = { ...{ randomSerialNumberUpperCase: true, randomSerialNumber: true }, ...params };
     const serialNumberSuffix = params?.randomSerialNumber
       ? ChargingStationUtils.getRandomSerialNumberSuffix({
           upperCase: params.randomSerialNumberUpperCase,
         })
       : '';
-    stationInfo.chargePointSerialNumber = Utils.isNotEmptyString(
-      stationTemplate?.chargePointSerialNumberPrefix
-    )
-      ? `${stationTemplate.chargePointSerialNumberPrefix}${serialNumberSuffix}`
-      : undefined;
-    stationInfo.chargeBoxSerialNumber = Utils.isNotEmptyString(
-      stationTemplate?.chargeBoxSerialNumberPrefix
-    )
-      ? `${stationTemplate.chargeBoxSerialNumberPrefix}${serialNumberSuffix}`
-      : undefined;
-    stationInfo.meterSerialNumber = Utils.isNotEmptyString(stationTemplate?.meterSerialNumberPrefix)
-      ? `${stationTemplate.meterSerialNumberPrefix}${serialNumberSuffix}`
-      : undefined;
+    Utils.isNotEmptyString(stationTemplate?.chargePointSerialNumberPrefix) &&
+      (stationInfo.chargePointSerialNumber = `${stationTemplate.chargePointSerialNumberPrefix}${serialNumberSuffix}`);
+    Utils.isNotEmptyString(stationTemplate?.chargeBoxSerialNumberPrefix) &&
+      (stationInfo.chargeBoxSerialNumber = `${stationTemplate.chargeBoxSerialNumberPrefix}${serialNumberSuffix}`);
+    Utils.isNotEmptyString(stationTemplate?.meterSerialNumberPrefix) &&
+      (stationInfo.meterSerialNumber = `${stationTemplate.meterSerialNumberPrefix}${serialNumberSuffix}`);
   }
 
   public static propagateSerialNumber(
@@ -341,15 +467,15 @@ export class ChargingStationUtils {
     let limit: number, matchingChargingProfile: ChargingProfile;
     // Get charging profiles for connector and sort by stack level
     const chargingProfiles =
-      Utils.cloneObject(chargingStation.getConnectorStatus(connectorId)?.chargingProfiles)?.sort(
-        (a, b) => b.stackLevel - a.stackLevel
-      ) ?? [];
+      Utils.cloneObject<ChargingProfile[]>(
+        chargingStation.getConnectorStatus(connectorId)?.chargingProfiles
+      )?.sort((a, b) => b.stackLevel - a.stackLevel) ?? [];
     // Get profiles on connector 0
     if (chargingStation.getConnectorStatus(0)?.chargingProfiles) {
       chargingProfiles.push(
-        ...Utils.cloneObject(chargingStation.getConnectorStatus(0).chargingProfiles).sort(
-          (a, b) => b.stackLevel - a.stackLevel
-        )
+        ...Utils.cloneObject<ChargingProfile[]>(
+          chargingStation.getConnectorStatus(0).chargingProfiles
+        ).sort((a, b) => b.stackLevel - a.stackLevel)
       );
     }
     if (Utils.isNotEmptyArray(chargingProfiles)) {
@@ -397,10 +523,10 @@ export class ChargingStationUtils {
 
   public static getDefaultVoltageOut(
     currentType: CurrentType,
-    templateFile: string,
-    logPrefix: string
+    logPrefix: string,
+    templateFile: string
   ): Voltage {
-    const errMsg = `Unknown ${currentType} currentOutType in template file ${templateFile}, cannot define default voltage out`;
+    const errorMsg = `Unknown ${currentType} currentOutType in template file ${templateFile}, cannot define default voltage out`;
     let defaultVoltageOut: number;
     switch (currentType) {
       case CurrentType.AC:
@@ -410,8 +536,8 @@ export class ChargingStationUtils {
         defaultVoltageOut = Voltage.VOLTAGE_400;
         break;
       default:
-        logger.error(`${logPrefix} ${errMsg}`);
-        throw new BaseError(errMsg);
+        logger.error(`${logPrefix} ${errorMsg}`);
+        throw new BaseError(errorMsg);
     }
     return defaultVoltageOut;
   }
@@ -419,19 +545,101 @@ export class ChargingStationUtils {
   public static getIdTagsFile(stationInfo: ChargingStationInfo): string | undefined {
     return (
       stationInfo.idTagsFile &&
-      path.join(
-        path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../'),
-        'assets',
-        path.basename(stationInfo.idTagsFile)
-      )
+      join(dirname(fileURLToPath(import.meta.url)), 'assets', basename(stationInfo.idTagsFile))
     );
   }
 
+  public static waitForChargingStationEvents = async (
+    emitter: EventEmitter,
+    event: ChargingStationWorkerMessageEvents,
+    eventsToWait: number
+  ): Promise<number> => {
+    return new Promise((resolve) => {
+      let events = 0;
+      if (eventsToWait === 0) {
+        resolve(events);
+      }
+      emitter.on(event, () => {
+        ++events;
+        if (events === eventsToWait) {
+          resolve(events);
+        }
+      });
+    });
+  };
+
+  private static getConfiguredNumberOfConnectors(stationTemplate: ChargingStationTemplate): number {
+    let configuredMaxConnectors: number;
+    if (Utils.isNotEmptyArray(stationTemplate.numberOfConnectors) === true) {
+      const numberOfConnectors = stationTemplate.numberOfConnectors as number[];
+      configuredMaxConnectors =
+        numberOfConnectors[Math.floor(Utils.secureRandom() * numberOfConnectors.length)];
+    } else if (Utils.isUndefined(stationTemplate.numberOfConnectors) === false) {
+      configuredMaxConnectors = stationTemplate.numberOfConnectors as number;
+    } else if (stationTemplate.Connectors && !stationTemplate.Evses) {
+      configuredMaxConnectors = stationTemplate?.Connectors[0]
+        ? ChargingStationUtils.getMaxNumberOfConnectors(stationTemplate.Connectors) - 1
+        : ChargingStationUtils.getMaxNumberOfConnectors(stationTemplate.Connectors);
+    } else if (stationTemplate.Evses && !stationTemplate.Connectors) {
+      configuredMaxConnectors = 0;
+      for (const evse in stationTemplate.Evses) {
+        if (evse === '0') {
+          continue;
+        }
+        configuredMaxConnectors += ChargingStationUtils.getMaxNumberOfConnectors(
+          stationTemplate.Evses[evse].Connectors
+        );
+      }
+    }
+    return configuredMaxConnectors;
+  }
+
+  private static checkConfiguredMaxConnectors(
+    configuredMaxConnectors: number,
+    logPrefix: string,
+    templateFile: string
+  ): void {
+    if (configuredMaxConnectors <= 0) {
+      logger.warn(
+        `${logPrefix} Charging station information from template ${templateFile} with ${configuredMaxConnectors} connectors`
+      );
+    }
+  }
+
+  private static checkTemplateMaxConnectors(
+    templateMaxConnectors: number,
+    logPrefix: string,
+    templateFile: string
+  ): void {
+    if (templateMaxConnectors === 0) {
+      logger.warn(
+        `${logPrefix} Charging station information from template ${templateFile} with empty connectors configuration`
+      );
+    } else if (templateMaxConnectors < 0) {
+      logger.error(
+        `${logPrefix} Charging station information from template ${templateFile} with no connectors configuration defined`
+      );
+    }
+  }
+
+  private static initializeConnectorStatus(connectorStatus: ConnectorStatus): void {
+    connectorStatus.availability = AvailabilityType.Operative;
+    connectorStatus.idTagLocalAuthorized = false;
+    connectorStatus.idTagAuthorized = false;
+    connectorStatus.transactionRemoteStarted = false;
+    connectorStatus.transactionStarted = false;
+    connectorStatus.energyActiveImportRegisterValue = 0;
+    connectorStatus.transactionEnergyActiveImportRegisterValue = 0;
+    if (Utils.isUndefined(connectorStatus.chargingProfiles)) {
+      connectorStatus.chargingProfiles = [];
+    }
+  }
+
   private static warnDeprecatedTemplateKey(
     template: ChargingStationTemplate,
     key: string,
-    templateFile: string,
     logPrefix: string,
+    templateFile: string,
     logMsgToAppend = ''
   ): void {
     if (!Utils.isUndefined(template[key])) {
@@ -455,7 +663,7 @@ export class ChargingStationUtils {
   }
 
   /**
-   * Charging profiles should already be sorted by connectorId and stack level (highest stack level has priority)
+   * Charging profiles should already be sorted by connector id and stack level (highest stack level has priority)
    *
    * @param chargingProfiles -
    * @param logPrefix -
@@ -565,9 +773,7 @@ export class ChargingStationUtils {
     randomBytesLength?: number;
     upperCase?: boolean;
   }): string {
-    const randomSerialNumberSuffix = crypto
-      .randomBytes(params?.randomBytesLength ?? 16)
-      .toString('hex');
+    const randomSerialNumberSuffix = randomBytes(params?.randomBytesLength ?? 16).toString('hex');
     if (params?.upperCase) {
       return randomSerialNumberSuffix.toUpperCase();
     }