]> Piment Noir Git Repositories - e-mobility-charging-stations-simulator.git/commitdiff
refactor: type buildTransactionEvent with OCPP20TransactionEventOptions
authorJérôme Benoit <jerome.benoit@sap.com>
Fri, 27 Mar 2026 14:30:15 +0000 (15:30 +0100)
committerJérôme Benoit <jerome.benoit@sap.com>
Fri, 27 Mar 2026 14:30:15 +0000 (15:30 +0100)
Replace the untyped Record<string, unknown> cast in buildTransactionEvent
with the proper OCPP20TransactionEventOptions parameter type. Add build
hint fields to the options interface. Remove 64 stale as-unknown-as casts
from transaction event tests.

src/charging-station/ocpp/2.0/OCPP20RequestService.ts
src/charging-station/ocpp/2.0/OCPP20ServiceUtils.ts
src/types/ocpp/2.0/Transaction.ts
tests/charging-station/ocpp/2.0/OCPP20ServiceUtils-TransactionEvent.test.ts

index fad5b54738118755aa4673b7070572939df91288..0e5b8261d6dd529bb62a6f19a0e85d30cc9810dd 100644 (file)
@@ -12,7 +12,7 @@ import {
   OCPP20RequestCommand,
   type OCPP20SignCertificateRequest,
   type OCPP20StatusNotificationRequest,
-  type OCPP20TransactionEventRequest,
+  type OCPP20TransactionEventOptions,
   OCPPVersion,
   type RequestParams,
 } from '../../../types/index.js'
@@ -205,7 +205,7 @@ export class OCPP20RequestService extends OCPPRequestService {
       case OCPP20RequestCommand.TRANSACTION_EVENT:
         return buildTransactionEvent(
           chargingStation,
-          commandParams as unknown as OCPP20TransactionEventRequest
+          commandParams as unknown as OCPP20TransactionEventOptions
         ) as unknown as Request
       default: {
         // OCPPError usage here is debatable: it's an error in the OCPP stack but not targeted to sendError().
index 9070127ca63d36bdd3c4a402413a3cb5088aa0fa..f35a29e10688bfac4a5c9e8c79ab9d4e7c779bf9 100644 (file)
@@ -525,7 +525,7 @@ export class OCPP20ServiceUtils extends OCPPServiceUtils {
           triggerReason,
           ...options,
           offline: true,
-        } as unknown as OCPP20TransactionEventRequest)
+        })
         logger.info(
           `${chargingStation.logPrefix()} ${moduleName}.sendTransactionEvent: Station offline, queueing TransactionEvent with seqNo=${transactionEventRequest.seqNo.toString()}`
         )
@@ -879,29 +879,28 @@ export class OCPP20ServiceUtils extends OCPPServiceUtils {
  */
 export function buildTransactionEvent (
   chargingStation: ChargingStation,
-  commandParams: OCPP20TransactionEventRequest
+  commandParams: OCPP20TransactionEventOptions
 ): OCPP20TransactionEventRequest {
-  const params = commandParams as Record<string, unknown>
-  const eventType = params.eventType as OCPP20TransactionEventEnumType
-  const triggerReason =
-    params.triggerReason != null
-      ? (params.triggerReason as OCPP20TriggerReasonEnumType)
-      : eventType === OCPP20TransactionEventEnumType.Ended
-        ? OCPP20TriggerReasonEnumType.RemoteStop
-        : OCPP20TriggerReasonEnumType.Authorized
-  const inputEvse = params.evse as undefined | { connectorId?: number; id?: number }
-  const connectorId =
-    params.connectorId != null
-      ? (params.connectorId as number)
-      : (inputEvse?.connectorId ?? inputEvse?.id ?? 1)
+  const eventType = commandParams.eventType
+  if (eventType == null) {
+    throw new OCPPError(
+      ErrorType.PROPERTY_CONSTRAINT_VIOLATION,
+      'eventType is required for TransactionEvent'
+    )
+  }
+  const defaultTriggerReason =
+    eventType === OCPP20TransactionEventEnumType.Ended
+      ? OCPP20TriggerReasonEnumType.RemoteStop
+      : OCPP20TriggerReasonEnumType.Authorized
+  const triggerReason = commandParams.triggerReason ?? defaultTriggerReason
+  const inputEvse = commandParams.evse
+  const connectorId = commandParams.connectorId ?? inputEvse?.connectorId ?? inputEvse?.id ?? 1
   const transactionId =
-    params.transactionId != null
-      ? (params.transactionId as string)
-      : eventType === OCPP20TransactionEventEnumType.Ended
-        ? (chargingStation.getConnectorStatus(connectorId)?.transactionId?.toString() ??
-          generateUUID())
-        : generateUUID()
-  const options = params as unknown as OCPP20TransactionEventOptions
+    commandParams.transactionId ??
+    (eventType === OCPP20TransactionEventEnumType.Ended
+      ? (chargingStation.getConnectorStatus(connectorId)?.transactionId?.toString() ??
+        generateUUID())
+      : generateUUID())
 
   if (!validateIdentifierString(transactionId, 36)) {
     const errorMsg = `Invalid transaction ID format (must be non-empty string ≤36 characters): ${transactionId}`
@@ -909,7 +908,7 @@ export function buildTransactionEvent (
     throw new OCPPError(ErrorType.PROPERTY_CONSTRAINT_VIOLATION, errorMsg)
   }
 
-  const evseId = options.evseId ?? chargingStation.getEvseIdByConnectorId(connectorId)
+  const evseId = commandParams.evseId ?? chargingStation.getEvseIdByConnectorId(connectorId)
   if (evseId == null) {
     const errorMsg = `Cannot find EVSE ID for connector ${connectorId.toString()}`
     logger.error(`${chargingStation.logPrefix()} ${moduleName}.buildTransactionEvent: ${errorMsg}`)
@@ -943,14 +942,14 @@ export function buildTransactionEvent (
     transactionId: transactionId as UUIDv4,
   }
 
-  if (options.chargingState !== undefined) {
-    transactionInfo.chargingState = options.chargingState
+  if (commandParams.chargingState !== undefined) {
+    transactionInfo.chargingState = commandParams.chargingState
   }
-  if (options.stoppedReason !== undefined) {
-    transactionInfo.stoppedReason = options.stoppedReason
+  if (commandParams.stoppedReason !== undefined) {
+    transactionInfo.stoppedReason = commandParams.stoppedReason
   }
-  if (options.remoteStartId !== undefined) {
-    transactionInfo.remoteStartId = options.remoteStartId
+  if (commandParams.remoteStartId !== undefined) {
+    transactionInfo.remoteStartId = commandParams.remoteStartId
   }
 
   const transactionEventRequest: OCPP20TransactionEventRequest = {
@@ -966,27 +965,27 @@ export function buildTransactionEvent (
   }
 
   // E03.FR.01: Include idToken only once per transaction
-  if (options.idToken !== undefined && connectorStatus.transactionIdTokenSent !== true) {
-    transactionEventRequest.idToken = options.idToken
+  if (commandParams.idToken !== undefined && connectorStatus.transactionIdTokenSent !== true) {
+    transactionEventRequest.idToken = commandParams.idToken
     connectorStatus.transactionIdTokenSent = true
   }
-  if (options.meterValue !== undefined && options.meterValue.length > 0) {
-    transactionEventRequest.meterValue = options.meterValue
+  if (commandParams.meterValue !== undefined && commandParams.meterValue.length > 0) {
+    transactionEventRequest.meterValue = commandParams.meterValue
   }
-  if (options.cableMaxCurrent !== undefined) {
-    transactionEventRequest.cableMaxCurrent = options.cableMaxCurrent
+  if (commandParams.cableMaxCurrent !== undefined) {
+    transactionEventRequest.cableMaxCurrent = commandParams.cableMaxCurrent
   }
-  if (options.numberOfPhasesUsed !== undefined) {
-    transactionEventRequest.numberOfPhasesUsed = options.numberOfPhasesUsed
+  if (commandParams.numberOfPhasesUsed !== undefined) {
+    transactionEventRequest.numberOfPhasesUsed = commandParams.numberOfPhasesUsed
   }
-  if (options.offline !== undefined) {
-    transactionEventRequest.offline = options.offline
+  if (commandParams.offline !== undefined) {
+    transactionEventRequest.offline = commandParams.offline
   }
-  if (options.reservationId !== undefined) {
-    transactionEventRequest.reservationId = options.reservationId
+  if (commandParams.reservationId !== undefined) {
+    transactionEventRequest.reservationId = commandParams.reservationId
   }
-  if (options.customData !== undefined) {
-    transactionEventRequest.customData = options.customData
+  if (commandParams.customData !== undefined) {
+    transactionEventRequest.customData = commandParams.customData
   }
 
   logger.debug(
index 415efe47d2a99c4907cb5ffc0dd393e440a8eb75..b4b62825140a9bb70109ffac516a954fb82d347a 100644 (file)
@@ -266,33 +266,28 @@ export interface OCPP20MessageContentType extends JsonObject {
   format: OCPP20MessageFormatEnumType
   language?: string
 }
+
 /**
  * Optional parameters for building and sending TransactionEvent requests.
  * Aligned with OCPP 2.0.1 TransactionEvent.req optional fields.
  */
 export interface OCPP20TransactionEventOptions {
-  /** Maximum current the cable can handle (A) */
   cableMaxCurrent?: number
-  /** Current charging state per OCPP 2.0.1 ChargingStateEnumType */
   chargingState?: OCPP20ChargingStateEnumType
-  /** Vendor-specific custom data */
+  connectorId?: number
   customData?: CustomDataType
-  /** EVSE identifier (1-based) */
+  eventType?: OCPP20TransactionEventEnumType
+  evse?: Partial<OCPP20EVSEType>
   evseId?: number
-  /** Token used for authorization */
   idToken?: OCPP20IdTokenType
-  /** Meter values associated with this event */
   meterValue?: OCPP20MeterValue[]
-  /** Number of phases used for charging */
   numberOfPhasesUsed?: number
-  /** Whether event occurred while offline */
   offline?: boolean
-  /** Remote start transaction ID */
   remoteStartId?: number
-  /** Reservation ID if applicable */
   reservationId?: number
-  /** Reason for stopping transaction */
   stoppedReason?: OCPP20ReasonEnumType
+  transactionId?: string
+  triggerReason?: OCPP20TriggerReasonEnumType
 }
 
 export interface OCPP20TransactionEventRequest extends JsonObject {
index a7634f729e4de1db5b2c0a5ba84b41e759a80534..26dfae656dbefce3bd4ab698cf202fc4452ea663 100644 (file)
@@ -38,7 +38,6 @@ import {
   OCPP20RequestCommand,
   OCPP20RequiredVariableName,
   OCPP20TransactionEventEnumType,
-  type OCPP20TransactionEventRequest,
   type OCPP20TransactionType,
   OCPP20TriggerReasonEnumType,
   OCPPVersion,
@@ -128,7 +127,7 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => {
           eventType: OCPP20TransactionEventEnumType.Started,
           transactionId,
           triggerReason,
-        } as unknown as OCPP20TransactionEventRequest)
+        })
 
         // Validate required fields
         assert.strictEqual(transactionEvent.eventType, OCPP20TransactionEventEnumType.Started)
@@ -162,7 +161,7 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => {
           eventType: OCPP20TransactionEventEnumType.Started,
           transactionId,
           triggerReason: OCPP20TriggerReasonEnumType.Authorized,
-        } as unknown as OCPP20TransactionEventRequest)
+        })
 
         // Build second event (Updated)
         const updateEvent = buildTransactionEvent(mockStation, {
@@ -170,7 +169,7 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => {
           eventType: OCPP20TransactionEventEnumType.Updated,
           transactionId,
           triggerReason: OCPP20TriggerReasonEnumType.MeterValuePeriodic,
-        } as unknown as OCPP20TransactionEventRequest)
+        })
 
         // Build third event (Ended)
         const endEvent = buildTransactionEvent(mockStation, {
@@ -179,7 +178,7 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => {
           stoppedReason: OCPP20ReasonEnumType.Local,
           transactionId,
           triggerReason: OCPP20TriggerReasonEnumType.StopAuthorized,
-        } as unknown as OCPP20TransactionEventRequest)
+        })
 
         // Validate sequence number progression: 0 → 1 → 2
         assert.strictEqual(startEvent.seqNo, 0)
@@ -220,7 +219,7 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => {
           reservationId: options.reservationId,
           transactionId,
           triggerReason: OCPP20TriggerReasonEnumType.ChargingStateChanged,
-        } as unknown as OCPP20TransactionEventRequest)
+        })
 
         // Validate optional fields are included
         if (transactionEvent.idToken == null) {
@@ -250,7 +249,7 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => {
             eventType: OCPP20TransactionEventEnumType.Started,
             transactionId: invalidTransactionId,
             triggerReason: OCPP20TriggerReasonEnumType.Authorized,
-          } as unknown as OCPP20TransactionEventRequest)
+          })
           throw new Error('Should have thrown error for invalid identifier string')
         } catch (error) {
           assert.ok((error as Error).message.includes('Invalid transaction ID format'))
@@ -296,7 +295,7 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => {
             eventType: OCPP20TransactionEventEnumType.Updated,
             transactionId,
             triggerReason,
-          } as unknown as OCPP20TransactionEventRequest)
+          })
 
           assert.strictEqual(transactionEvent.triggerReason, triggerReason)
           assert.strictEqual(transactionEvent.eventType, OCPP20TransactionEventEnumType.Updated)
@@ -371,7 +370,7 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => {
           eventType: OCPP20TransactionEventEnumType.Started,
           transactionId: generateUUID(),
           triggerReason: OCPP20TriggerReasonEnumType.Authorized,
-        } as unknown as OCPP20TransactionEventRequest)
+        })
 
         // Verify sequence number is set
         const connectorStatus = mockStation.getConnectorStatus(connectorId)
@@ -411,7 +410,7 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => {
           },
           transactionId,
           triggerReason: OCPP20TriggerReasonEnumType.Authorized,
-        } as unknown as OCPP20TransactionEventRequest)
+        })
 
         // Validate all required fields exist
         const requiredFields = [
@@ -465,7 +464,7 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => {
           eventType: OCPP20TransactionEventEnumType.Started,
           transactionId,
           triggerReason: OCPP20TriggerReasonEnumType.Authorized,
-        } as unknown as OCPP20TransactionEventRequest)
+        })
 
         // For this test setup, EVSE ID should match connector ID
         if (transactionEvent.evse == null) {
@@ -547,7 +546,7 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => {
           eventType: OCPP20TransactionEventEnumType.Started,
           transactionId,
           triggerReason: OCPP20TriggerReasonEnumType.Authorized,
-        } as unknown as OCPP20TransactionEventRequest)
+        })
 
         assert.strictEqual(oldEvent.eventType, OCPP20TransactionEventEnumType.Started)
         assert.strictEqual(oldEvent.triggerReason, OCPP20TriggerReasonEnumType.Authorized)
@@ -625,7 +624,7 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => {
             transactionId,
             triggerReason: expectedStartTrigger,
             ...(idToken != null ? { idToken } : {}),
-          } as unknown as OCPP20TransactionEventRequest)
+          })
 
           assert.strictEqual(startedEvent.eventType, OCPP20TransactionEventEnumType.Started)
           assert.strictEqual(startedEvent.triggerReason, expectedStartTrigger)
@@ -657,7 +656,7 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => {
             transactionId,
             triggerReason: expectedStartTrigger,
             ...(idToken != null ? { idToken } : {}),
-          } as unknown as OCPP20TransactionEventRequest)
+          })
 
           // Step 2: Charging state change
           const chargingEvent = buildTransactionEvent(mockStation, {
@@ -666,7 +665,7 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => {
             eventType: OCPP20TransactionEventEnumType.Updated,
             transactionId,
             triggerReason: OCPP20TriggerReasonEnumType.ChargingStateChanged,
-          } as unknown as OCPP20TransactionEventRequest)
+          })
 
           // Step 3: Ended event
           const endedEvent = buildTransactionEvent(mockStation, {
@@ -674,7 +673,7 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => {
             eventType: OCPP20TransactionEventEnumType.Ended,
             transactionId,
             triggerReason: OCPP20TriggerReasonEnumType.StopAuthorized,
-          } as unknown as OCPP20TransactionEventRequest)
+          })
 
           // Validate event sequence
           assert.strictEqual(startedEvent.seqNo, 0)
@@ -702,7 +701,7 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => {
             eventType: OCPP20TransactionEventEnumType.Started,
             transactionId: transaction1Id,
             triggerReason: expectedStartTrigger,
-          } as unknown as OCPP20TransactionEventRequest)
+          })
 
           // Start transaction on connector 2
           const conn2Event1 = buildTransactionEvent(mockStation, {
@@ -710,7 +709,7 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => {
             eventType: OCPP20TransactionEventEnumType.Started,
             transactionId: transaction2Id,
             triggerReason: expectedStartTrigger,
-          } as unknown as OCPP20TransactionEventRequest)
+          })
 
           // Update connector 1
           const conn1Event2 = buildTransactionEvent(mockStation, {
@@ -718,7 +717,7 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => {
             eventType: OCPP20TransactionEventEnumType.Updated,
             transactionId: transaction1Id,
             triggerReason: OCPP20TriggerReasonEnumType.ChargingStateChanged,
-          } as unknown as OCPP20TransactionEventRequest)
+          })
 
           // Update connector 2
           const conn2Event2 = buildTransactionEvent(mockStation, {
@@ -726,7 +725,7 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => {
             eventType: OCPP20TransactionEventEnumType.Updated,
             transactionId: transaction2Id,
             triggerReason: OCPP20TriggerReasonEnumType.ChargingStateChanged,
-          } as unknown as OCPP20TransactionEventRequest)
+          })
 
           // Verify independent sequence numbers
           assert.strictEqual(conn1Event1.seqNo, 0)
@@ -762,7 +761,7 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => {
             eventType: OCPP20TransactionEventEnumType.Started,
             transactionId,
             triggerReason: OCPP20TriggerReasonEnumType.CablePluggedIn,
-          } as unknown as OCPP20TransactionEventRequest)
+          })
 
           // Step 2: EV detected (Updated)
           const evDetectedEvent = buildTransactionEvent(mockStation, {
@@ -770,7 +769,7 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => {
             eventType: OCPP20TransactionEventEnumType.Updated,
             transactionId,
             triggerReason: OCPP20TriggerReasonEnumType.EVDetected,
-          } as unknown as OCPP20TransactionEventRequest)
+          })
 
           // Step 3: Charging starts (Updated with ChargingStateChanged)
           const chargingStartedEvent = buildTransactionEvent(mockStation, {
@@ -779,7 +778,7 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => {
             eventType: OCPP20TransactionEventEnumType.Updated,
             transactionId,
             triggerReason: OCPP20TriggerReasonEnumType.ChargingStateChanged,
-          } as unknown as OCPP20TransactionEventRequest)
+          })
 
           // Assert sequence numbers follow correct order
           assert.strictEqual(cablePluggedEvent.seqNo, 0)
@@ -809,7 +808,7 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => {
             eventType: OCPP20TransactionEventEnumType.Started,
             transactionId,
             triggerReason: OCPP20TriggerReasonEnumType.CablePluggedIn,
-          } as unknown as OCPP20TransactionEventRequest)
+          })
 
           // End transaction with EV departure (cable removal)
           const endEvent = buildTransactionEvent(mockStation, {
@@ -817,7 +816,7 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => {
             eventType: OCPP20TransactionEventEnumType.Ended,
             transactionId,
             triggerReason: OCPP20TriggerReasonEnumType.EVDeparted,
-          } as unknown as OCPP20TransactionEventRequest)
+          })
 
           // Assert proper sequencing for cable-initiated start and end
           assert.strictEqual(startEvent.seqNo, 0)
@@ -842,26 +841,26 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => {
               eventType: OCPP20TransactionEventEnumType.Started,
               transactionId,
               triggerReason: OCPP20TriggerReasonEnumType.CablePluggedIn,
-            } as unknown as OCPP20TransactionEventRequest),
+            }),
             buildTransactionEvent(mockStation, {
               connectorId,
               eventType: OCPP20TransactionEventEnumType.Updated,
               transactionId,
               triggerReason: OCPP20TriggerReasonEnumType.EVDetected,
-            } as unknown as OCPP20TransactionEventRequest),
+            }),
             buildTransactionEvent(mockStation, {
               connectorId,
               eventType: OCPP20TransactionEventEnumType.Updated,
               transactionId,
               triggerReason: OCPP20TriggerReasonEnumType.Authorized,
-            } as unknown as OCPP20TransactionEventRequest),
+            }),
             buildTransactionEvent(mockStation, {
               chargingState: OCPP20ChargingStateEnumType.Charging,
               connectorId,
               eventType: OCPP20TransactionEventEnumType.Updated,
               transactionId,
               triggerReason: OCPP20TriggerReasonEnumType.ChargingStateChanged,
-            } as unknown as OCPP20TransactionEventRequest),
+            }),
           ]
 
           // Assert EVDetected comes after CablePluggedIn and before authorization
@@ -957,7 +956,7 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => {
               eventType: OCPP20TransactionEventEnumType.Started,
               transactionId,
               triggerReason: OCPP20TriggerReasonEnumType.CablePluggedIn,
-            } as unknown as OCPP20TransactionEventRequest),
+            }),
             // 2. Start charging
             buildTransactionEvent(mockStation, {
               chargingState: OCPP20ChargingStateEnumType.Charging,
@@ -965,7 +964,7 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => {
               eventType: OCPP20TransactionEventEnumType.Updated,
               transactionId,
               triggerReason: OCPP20TriggerReasonEnumType.ChargingStateChanged,
-            } as unknown as OCPP20TransactionEventRequest),
+            }),
             // 3. Suspended by EV
             buildTransactionEvent(mockStation, {
               chargingState: OCPP20ChargingStateEnumType.SuspendedEV,
@@ -973,7 +972,7 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => {
               eventType: OCPP20TransactionEventEnumType.Updated,
               transactionId,
               triggerReason: OCPP20TriggerReasonEnumType.ChargingStateChanged,
-            } as unknown as OCPP20TransactionEventRequest),
+            }),
             // 4. Resume charging
             buildTransactionEvent(mockStation, {
               chargingState: OCPP20ChargingStateEnumType.Charging,
@@ -981,14 +980,14 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => {
               eventType: OCPP20TransactionEventEnumType.Updated,
               transactionId,
               triggerReason: OCPP20TriggerReasonEnumType.ChargingStateChanged,
-            } as unknown as OCPP20TransactionEventRequest),
+            }),
             // 5. EV departed
             buildTransactionEvent(mockStation, {
               connectorId,
               eventType: OCPP20TransactionEventEnumType.Ended,
               transactionId,
               triggerReason: OCPP20TriggerReasonEnumType.EVDeparted,
-            } as unknown as OCPP20TransactionEventRequest),
+            }),
           ]
 
           // Verify sequence numbers are continuous through suspend/resume
@@ -1021,7 +1020,7 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => {
             idToken,
             transactionId,
             triggerReason: OCPP20TriggerReasonEnumType.Authorized,
-          } as unknown as OCPP20TransactionEventRequest)
+          })
 
           if (startedEvent.idToken == null) {
             assert.fail('Expected idToken to be defined')
@@ -1049,7 +1048,7 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => {
             idToken,
             transactionId,
             triggerReason: OCPP20TriggerReasonEnumType.Authorized,
-          } as unknown as OCPP20TransactionEventRequest)
+          })
 
           // Second event should NOT include idToken (flag is set after first inclusion)
           const updatedEvent = buildTransactionEvent(mockStation, {
@@ -1059,7 +1058,7 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => {
             idToken,
             transactionId,
             triggerReason: OCPP20TriggerReasonEnumType.ChargingStateChanged,
-          } as unknown as OCPP20TransactionEventRequest)
+          })
 
           assert.notStrictEqual(startedEvent.idToken, undefined)
           assert.strictEqual(updatedEvent.idToken, undefined)
@@ -1083,7 +1082,7 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => {
             idToken: rfidToken,
             transactionId,
             triggerReason: OCPP20TriggerReasonEnumType.Authorized,
-          } as unknown as OCPP20TransactionEventRequest)
+          })
 
           assert.strictEqual(rfidEvent.idToken?.type, OCPP20IdTokenEnumType.ISO14443)
 
@@ -1106,7 +1105,7 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => {
             idToken: emaidToken,
             transactionId: generateUUID(),
             triggerReason: OCPP20TriggerReasonEnumType.Authorized,
-          } as unknown as OCPP20TransactionEventRequest)
+          })
 
           assert.strictEqual(emaidEvent.idToken?.type, OCPP20IdTokenEnumType.eMAID)
           assert.strictEqual(emaidEvent.idToken.idToken, 'DE*ABC*E123456*1')
@@ -1131,7 +1130,7 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => {
             idToken,
             transactionId,
             triggerReason: OCPP20TriggerReasonEnumType.Authorized,
-          } as unknown as OCPP20TransactionEventRequest)
+          })
 
           // E03 Step 2: Cable connected (Updated event)
           const cableConnectedEvent = buildTransactionEvent(mockStation, {
@@ -1139,7 +1138,7 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => {
             eventType: OCPP20TransactionEventEnumType.Updated,
             transactionId,
             triggerReason: OCPP20TriggerReasonEnumType.CablePluggedIn,
-          } as unknown as OCPP20TransactionEventRequest)
+          })
 
           // E03 Step 3: Charging starts
           const chargingEvent = buildTransactionEvent(mockStation, {
@@ -1148,7 +1147,7 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => {
             eventType: OCPP20TransactionEventEnumType.Updated,
             transactionId,
             triggerReason: OCPP20TriggerReasonEnumType.ChargingStateChanged,
-          } as unknown as OCPP20TransactionEventRequest)
+          })
 
           // E03 Step 4: Transaction ends
           const endedEvent = buildTransactionEvent(mockStation, {
@@ -1156,7 +1155,7 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => {
             eventType: OCPP20TransactionEventEnumType.Ended,
             transactionId,
             triggerReason: OCPP20TriggerReasonEnumType.StopAuthorized,
-          } as unknown as OCPP20TransactionEventRequest)
+          })
 
           // Validate event sequence
           assert.strictEqual(authorizedEvent.eventType, OCPP20TransactionEventEnumType.Started)
@@ -1207,7 +1206,7 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => {
             idToken,
             transactionId: e03TransactionId,
             triggerReason: OCPP20TriggerReasonEnumType.Authorized,
-          } as unknown as OCPP20TransactionEventRequest)
+          })
 
           // E02 Cable-First: Starts with CablePluggedIn trigger
           OCPP20ServiceUtils.resetTransactionSequenceNumber(mockStation, connectorId)
@@ -1220,7 +1219,7 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => {
             eventType: OCPP20TransactionEventEnumType.Started,
             transactionId: e02TransactionId,
             triggerReason: OCPP20TriggerReasonEnumType.CablePluggedIn,
-          } as unknown as OCPP20TransactionEventRequest)
+          })
 
           // Key difference: E03 starts with Authorized, E02 starts with CablePluggedIn
           assert.strictEqual(e03Start.triggerReason, OCPP20TriggerReasonEnumType.Authorized)
@@ -1250,7 +1249,7 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => {
             idToken,
             transactionId,
             triggerReason: OCPP20TriggerReasonEnumType.Authorized,
-          } as unknown as OCPP20TransactionEventRequest)
+          })
 
           // E03.FR.06: Cable not connected within timeout - transaction ends with Timeout
           const timeoutEvent = buildTransactionEvent(mockStation, {
@@ -1258,7 +1257,7 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => {
             eventType: OCPP20TransactionEventEnumType.Ended,
             transactionId,
             triggerReason: OCPP20TriggerReasonEnumType.EVConnectTimeout,
-          } as unknown as OCPP20TransactionEventRequest)
+          })
 
           assert.strictEqual(authorizedEvent.eventType, OCPP20TransactionEventEnumType.Started)
           assert.strictEqual(authorizedEvent.triggerReason, OCPP20TriggerReasonEnumType.Authorized)
@@ -1296,7 +1295,7 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => {
             idToken,
             transactionId,
             triggerReason: OCPP20TriggerReasonEnumType.Authorized,
-          } as unknown as OCPP20TransactionEventRequest)
+          })
 
           // Transaction ended due to deauthorization (e.g., token revoked mid-session)
           const revokedEvent = buildTransactionEvent(mockStation, {
@@ -1304,7 +1303,7 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => {
             eventType: OCPP20TransactionEventEnumType.Ended,
             transactionId,
             triggerReason: OCPP20TriggerReasonEnumType.Deauthorized,
-          } as unknown as OCPP20TransactionEventRequest)
+          })
 
           assert.strictEqual(startEvent.eventType, OCPP20TransactionEventEnumType.Started)
           assert.strictEqual(revokedEvent.eventType, OCPP20TransactionEventEnumType.Ended)
@@ -1330,31 +1329,31 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => {
               idToken,
               transactionId,
               triggerReason: OCPP20TriggerReasonEnumType.Authorized,
-            } as unknown as OCPP20TransactionEventRequest),
+            }),
             buildTransactionEvent(mockStation, {
               connectorId,
               eventType: OCPP20TransactionEventEnumType.Updated,
               transactionId,
               triggerReason: OCPP20TriggerReasonEnumType.CablePluggedIn,
-            } as unknown as OCPP20TransactionEventRequest),
+            }),
             buildTransactionEvent(mockStation, {
               connectorId,
               eventType: OCPP20TransactionEventEnumType.Updated,
               transactionId,
               triggerReason: OCPP20TriggerReasonEnumType.ChargingStateChanged,
-            } as unknown as OCPP20TransactionEventRequest),
+            }),
             buildTransactionEvent(mockStation, {
               connectorId,
               eventType: OCPP20TransactionEventEnumType.Updated,
               transactionId,
               triggerReason: OCPP20TriggerReasonEnumType.MeterValuePeriodic,
-            } as unknown as OCPP20TransactionEventRequest),
+            }),
             buildTransactionEvent(mockStation, {
               connectorId,
               eventType: OCPP20TransactionEventEnumType.Ended,
               transactionId,
               triggerReason: OCPP20TriggerReasonEnumType.StopAuthorized,
-            } as unknown as OCPP20TransactionEventRequest),
+            }),
           ]
 
           // E03.FR.07: Sequence numbers must be continuous
@@ -1379,7 +1378,7 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => {
             eventType: OCPP20TransactionEventEnumType.Started,
             transactionId: transaction1Id,
             triggerReason: OCPP20TriggerReasonEnumType.Authorized,
-          } as unknown as OCPP20TransactionEventRequest)
+          })
 
           OCPP20ServiceUtils.resetTransactionSequenceNumber(mockStation, connectorId)
 
@@ -1388,7 +1387,7 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => {
             eventType: OCPP20TransactionEventEnumType.Started,
             transactionId: transaction2Id,
             triggerReason: OCPP20TriggerReasonEnumType.Authorized,
-          } as unknown as OCPP20TransactionEventRequest)
+          })
 
           assert.strictEqual(event1.transactionInfo.transactionId, transaction1Id)
           assert.strictEqual(event2.transactionInfo.transactionId, transaction2Id)
@@ -2103,7 +2102,7 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => {
           eventType: OCPP20TransactionEventEnumType.Started,
           transactionId,
           triggerReason: OCPP20TriggerReasonEnumType.Authorized,
-        } as unknown as OCPP20TransactionEventRequest)
+        })
         assert.strictEqual(startEvent.seqNo, 0)
 
         // Send multiple periodic events (simulating timer ticks)
@@ -2113,7 +2112,7 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => {
             eventType: OCPP20TransactionEventEnumType.Updated,
             transactionId,
             triggerReason: OCPP20TriggerReasonEnumType.MeterValuePeriodic,
-          } as unknown as OCPP20TransactionEventRequest)
+          })
           assert.strictEqual(periodicEvent.seqNo, i)
         }
 
@@ -2196,7 +2195,7 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => {
           eventType: OCPP20TransactionEventEnumType.Started,
           transactionId,
           triggerReason: OCPP20TriggerReasonEnumType.Authorized,
-        } as unknown as OCPP20TransactionEventRequest)
+        })
         assert.strictEqual(startEvent.seqNo, 0)
 
         // 2. Multiple periodic updates (seqNo: 1, 2, 3)
@@ -2206,7 +2205,7 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => {
             eventType: OCPP20TransactionEventEnumType.Updated,
             transactionId,
             triggerReason: OCPP20TriggerReasonEnumType.MeterValuePeriodic,
-          } as unknown as OCPP20TransactionEventRequest)
+          })
           assert.strictEqual(updateEvent.seqNo, i)
         }
 
@@ -2216,7 +2215,7 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => {
           eventType: OCPP20TransactionEventEnumType.Ended,
           transactionId,
           triggerReason: OCPP20TriggerReasonEnumType.StopAuthorized,
-        } as unknown as OCPP20TransactionEventRequest)
+        })
         assert.strictEqual(endEvent.seqNo, 4)
       })
 
@@ -2234,13 +2233,13 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => {
           eventType: OCPP20TransactionEventEnumType.Started,
           transactionId: transactionId1,
           triggerReason: OCPP20TriggerReasonEnumType.Authorized,
-        } as unknown as OCPP20TransactionEventRequest)
+        })
         const event1Update = buildTransactionEvent(mockStation, {
           connectorId: 1,
           eventType: OCPP20TransactionEventEnumType.Updated,
           transactionId: transactionId1,
           triggerReason: OCPP20TriggerReasonEnumType.MeterValuePeriodic,
-        } as unknown as OCPP20TransactionEventRequest)
+        })
 
         // Build events for connector 2
         const event2Start = buildTransactionEvent(mockStation, {
@@ -2248,13 +2247,13 @@ await describe('OCPP20 TransactionEvent ServiceUtils', async () => {
           eventType: OCPP20TransactionEventEnumType.Started,
           transactionId: transactionId2,
           triggerReason: OCPP20TriggerReasonEnumType.Authorized,
-        } as unknown as OCPP20TransactionEventRequest)
+        })
         const event2Update = buildTransactionEvent(mockStation, {
           connectorId: 2,
           eventType: OCPP20TransactionEventEnumType.Updated,
           transactionId: transactionId2,
           triggerReason: OCPP20TriggerReasonEnumType.MeterValuePeriodic,
-        } as unknown as OCPP20TransactionEventRequest)
+        })
 
         // Verify independent sequence numbers
         assert.strictEqual(event1Start.seqNo, 0)