@zetra/citrineos-transactions 1.8.3-fork.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/dist/index.d.ts +4 -0
  2. package/dist/index.js +7 -0
  3. package/dist/index.js.map +1 -0
  4. package/dist/module/2.0.1/MessageApi.d.ts +30 -0
  5. package/dist/module/2.0.1/MessageApi.js +62 -0
  6. package/dist/module/2.0.1/MessageApi.js.map +1 -0
  7. package/dist/module/CostCalculator.d.ts +24 -0
  8. package/dist/module/CostCalculator.js +52 -0
  9. package/dist/module/CostCalculator.js.map +1 -0
  10. package/dist/module/CostNotifier.d.ts +27 -0
  11. package/dist/module/CostNotifier.js +60 -0
  12. package/dist/module/CostNotifier.js.map +1 -0
  13. package/dist/module/DataApi.d.ts +43 -0
  14. package/dist/module/DataApi.js +94 -0
  15. package/dist/module/DataApi.js.map +1 -0
  16. package/dist/module/Scheduler.d.ts +12 -0
  17. package/dist/module/Scheduler.js +33 -0
  18. package/dist/module/Scheduler.js.map +1 -0
  19. package/dist/module/StatusNotificationService.d.ts +19 -0
  20. package/dist/module/StatusNotificationService.js +137 -0
  21. package/dist/module/StatusNotificationService.js.map +1 -0
  22. package/dist/module/TransactionService.d.ts +25 -0
  23. package/dist/module/TransactionService.js +246 -0
  24. package/dist/module/TransactionService.js.map +1 -0
  25. package/dist/module/interface.d.ts +5 -0
  26. package/dist/module/interface.js +5 -0
  27. package/dist/module/interface.js.map +1 -0
  28. package/dist/module/model/tariffs.d.ts +10 -0
  29. package/dist/module/model/tariffs.js +14 -0
  30. package/dist/module/model/tariffs.js.map +1 -0
  31. package/dist/module/module.d.ts +122 -0
  32. package/dist/module/module.js +500 -0
  33. package/dist/module/module.js.map +1 -0
  34. package/package.json +25 -0
@@ -0,0 +1,137 @@
1
+ // SPDX-FileCopyrightText: 2025 Contributors to the CitrineOS Project
2
+ //
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ import { CrudRepository, OCPP1_6, OCPP2_0_1 } from '@citrineos/base';
5
+ import { Component, Connector, EvseType, OCPP1_6_Mapper, OCPP2_0_1_Mapper, StatusNotification, Variable, } from '@citrineos/data';
6
+ import { Logger } from 'tslog';
7
+ export class StatusNotificationService {
8
+ _componentRepository;
9
+ _deviceModelRepository;
10
+ _locationRepository;
11
+ _logger;
12
+ constructor(componentRepository, deviceModelRepository, locationRepository, logger) {
13
+ this._componentRepository = componentRepository;
14
+ this._deviceModelRepository = deviceModelRepository;
15
+ this._locationRepository = locationRepository;
16
+ this._logger = logger
17
+ ? logger.getSubLogger({ name: this.constructor.name })
18
+ : new Logger({ name: this.constructor.name });
19
+ }
20
+ /**
21
+ * Stores an internal record of the incoming status, then updates the device model for the updated connector.
22
+ *
23
+ * @param {string} stationId - The Charging Station sending the status notification request
24
+ * @param {StatusNotificationRequest} statusNotificationRequest
25
+ */
26
+ async processStatusNotification(tenantId, stationId, statusNotificationRequest) {
27
+ const chargingStation = await this._locationRepository.readChargingStationByStationId(tenantId, stationId);
28
+ if (chargingStation) {
29
+ const statusNotification = StatusNotification.build({
30
+ tenantId,
31
+ stationId,
32
+ ...statusNotificationRequest,
33
+ });
34
+ await this._locationRepository.addStatusNotificationToChargingStation(tenantId, stationId, statusNotification);
35
+ const connector = {
36
+ tenantId,
37
+ connectorId: statusNotificationRequest.connectorId,
38
+ stationId,
39
+ status: OCPP2_0_1_Mapper.LocationMapper.mapConnectorStatus(statusNotificationRequest.connectorStatus),
40
+ timestamp: statusNotificationRequest.timestamp
41
+ ? statusNotificationRequest.timestamp
42
+ : new Date().toISOString(),
43
+ };
44
+ await this._locationRepository.createOrUpdateConnector(tenantId, connector);
45
+ let components = await this._componentRepository.readAllByQuery(tenantId, {
46
+ where: {
47
+ tenantId,
48
+ name: 'Connector',
49
+ },
50
+ include: [
51
+ {
52
+ model: EvseType,
53
+ where: {
54
+ id: statusNotificationRequest.evseId,
55
+ connectorId: statusNotificationRequest.connectorId,
56
+ },
57
+ },
58
+ {
59
+ model: Variable,
60
+ where: {
61
+ name: 'AvailabilityState',
62
+ },
63
+ },
64
+ ],
65
+ });
66
+ components = components.filter((component) => component.variables?.length && component.variables.length > 0);
67
+ if (components.length === 0) {
68
+ this._logger.warn('Missing component or variable for status notification. Status notification cannot be assigned to device model.');
69
+ }
70
+ for (const component of components) {
71
+ const variable = component.variables?.[0];
72
+ const reportDataType = {
73
+ component: component,
74
+ variable: variable,
75
+ variableAttribute: [
76
+ {
77
+ value: statusNotificationRequest.connectorStatus,
78
+ },
79
+ ],
80
+ };
81
+ await this._deviceModelRepository.createOrUpdateDeviceModelByStationId(tenantId, reportDataType, stationId, statusNotificationRequest.timestamp);
82
+ }
83
+ }
84
+ else {
85
+ this._logger.warn(`Charging station ${stationId} not found. Status notification cannot be associated with a charging station.`);
86
+ }
87
+ }
88
+ async processOcpp16StatusNotification(tenantId, stationId, statusNotificationRequest) {
89
+ const chargingStation = await this._locationRepository.readChargingStationByStationId(tenantId, stationId);
90
+ if (chargingStation) {
91
+ const matchingEvse = chargingStation.evses?.find((evse) => evse.connectors?.find((connector) => connector.connectorId === statusNotificationRequest.connectorId));
92
+ const statusNotificationInput = {
93
+ tenantId,
94
+ ...statusNotificationRequest,
95
+ stationId,
96
+ connectorStatus: statusNotificationRequest.status,
97
+ };
98
+ if (matchingEvse) {
99
+ statusNotificationInput.evseId = matchingEvse.evseTypeId;
100
+ }
101
+ const statusNotification = StatusNotification.build(statusNotificationInput);
102
+ await this._locationRepository.addStatusNotificationToChargingStation(tenantId, stationId, statusNotification);
103
+ const connector = {
104
+ tenantId,
105
+ connectorId: statusNotificationRequest.connectorId,
106
+ stationId,
107
+ status: OCPP1_6_Mapper.LocationMapper.mapStatusNotificationRequestStatusToConnectorStatus(statusNotificationRequest.status),
108
+ timestamp: statusNotificationRequest.timestamp
109
+ ? statusNotificationRequest.timestamp
110
+ : new Date().toISOString(),
111
+ errorCode: OCPP1_6_Mapper.LocationMapper.mapStatusNotificationRequestErrorCodeToConnectorErrorCode(statusNotificationRequest.errorCode),
112
+ info: statusNotificationRequest.info,
113
+ vendorId: statusNotificationRequest.vendorId,
114
+ vendorErrorCode: statusNotificationRequest.vendorErrorCode,
115
+ };
116
+ if (chargingStation.use16StatusNotification0 && statusNotificationRequest.connectorId === 0) {
117
+ // update all connectors
118
+ await this._locationRepository.updateAllConnectorsByQuery(tenantId, {
119
+ ...connector,
120
+ connectorId: undefined,
121
+ }, {
122
+ where: {
123
+ stationId,
124
+ tenantId,
125
+ },
126
+ });
127
+ }
128
+ else {
129
+ await this._locationRepository.createOrUpdateConnector(tenantId, connector);
130
+ }
131
+ }
132
+ else {
133
+ this._logger.warn(`Charging station ${stationId} not found. Status notification cannot be associated with a charging station.`);
134
+ }
135
+ }
136
+ }
137
+ //# sourceMappingURL=StatusNotificationService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StatusNotificationService.js","sourceRoot":"","sources":["../../src/module/StatusNotificationService.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import type { IAuthorizer, IMessageContext, MeterValueDto } from '@citrineos/base';
2
+ import { OCPP1_6, OCPP2_0_1 } from '@citrineos/base';
3
+ import type { IAuthorizationRepository, ILocationRepository, IOCPPMessageRepository, IReservationRepository, ITransactionEventRepository, MeterValue } from '@citrineos/data';
4
+ import { Transaction } from '@citrineos/data';
5
+ import type { ILogObj } from 'tslog';
6
+ import { Logger } from 'tslog';
7
+ export declare class TransactionService {
8
+ private _transactionEventRepository;
9
+ private _authorizeRepository;
10
+ private _locationRepository;
11
+ private _reservationRepository;
12
+ private _ocppMessageRepository;
13
+ private _logger;
14
+ private _authorizers;
15
+ constructor(transactionEventRepository: ITransactionEventRepository, authorizeRepository: IAuthorizationRepository, locationRepository: ILocationRepository, reservationRepository: IReservationRepository, ocppMessageRepository: IOCPPMessageRepository, realTimeAuthorizer: IAuthorizer, authorizers?: IAuthorizer[], logger?: Logger<ILogObj>);
16
+ recalculateTotalKwh(transaction: Transaction, newMeterValues: MeterValueDto[]): Promise<number>;
17
+ authorizeOcpp201IdToken(tenantId: number, transactionEvent: OCPP2_0_1.TransactionEventRequest, messageContext: IMessageContext): Promise<OCPP2_0_1.TransactionEventResponse>;
18
+ createMeterValues(tenantId: number, meterValues: [OCPP2_0_1.MeterValueType, ...OCPP2_0_1.MeterValueType[]], transactionDbId?: number | null, transactionId?: string | null, tariffId?: number | null): Promise<MeterValue[]>;
19
+ authorizeOcpp16IdToken(context: IMessageContext, idToken: string, connectorId: number): Promise<OCPP1_6.StartTransactionResponse>;
20
+ deactivateReservation(tenantId: number, transactionId: string, reservationId: number, stationId: string): Promise<void>;
21
+ updateTransactionStatus(tenantId: number, stationId: string, correlationId: string, ongoingIndicator: boolean): Promise<void>;
22
+ private _applyAuthorizers;
23
+ private _hasConcurrentTransactions;
24
+ private _mapAuthorizationDtoToIdTokenInfo;
25
+ }
@@ -0,0 +1,246 @@
1
+ import { AuthorizationStatusEnum, MessageOrigin, MeterValueUtils, OCPP1_6, OCPP2_0_1, } from '@citrineos/base';
2
+ import { OCPP1_6_Mapper, OCPP2_0_1_Mapper, Transaction } from '@citrineos/data';
3
+ import { Logger } from 'tslog';
4
+ export class TransactionService {
5
+ _transactionEventRepository;
6
+ _authorizeRepository;
7
+ _locationRepository;
8
+ _reservationRepository;
9
+ _ocppMessageRepository;
10
+ _logger;
11
+ _authorizers;
12
+ constructor(transactionEventRepository, authorizeRepository, locationRepository, reservationRepository, ocppMessageRepository, realTimeAuthorizer, authorizers, logger) {
13
+ this._transactionEventRepository = transactionEventRepository;
14
+ this._authorizeRepository = authorizeRepository;
15
+ this._locationRepository = locationRepository;
16
+ this._reservationRepository = reservationRepository;
17
+ this._ocppMessageRepository = ocppMessageRepository;
18
+ this._logger = logger
19
+ ? logger.getSubLogger({ name: this.constructor.name })
20
+ : new Logger({ name: this.constructor.name });
21
+ this._authorizers = [realTimeAuthorizer, ...(authorizers || [])];
22
+ }
23
+ async recalculateTotalKwh(transaction, newMeterValues) {
24
+ let meterStart = transaction.meterStart;
25
+ if (meterStart === null || meterStart === undefined) {
26
+ meterStart = MeterValueUtils.getMeterStart(newMeterValues);
27
+ transaction.set('meterStart', meterStart);
28
+ }
29
+ const totalKwh = MeterValueUtils.getTotalKwh(newMeterValues, transaction.totalKwh ?? 0, meterStart ?? undefined);
30
+ transaction.set('totalKwh', totalKwh);
31
+ await transaction.save();
32
+ this._logger.debug(`Recalculated ${totalKwh} kWh for ${transaction.id} transaction`);
33
+ return totalKwh;
34
+ }
35
+ async authorizeOcpp201IdToken(tenantId, transactionEvent, messageContext) {
36
+ const idToken = transactionEvent.idToken;
37
+ const authorizations = await this._authorizeRepository.readAllByQuerystring(tenantId, {
38
+ idToken: idToken.idToken,
39
+ type: OCPP2_0_1_Mapper.AuthorizationMapper.fromIdTokenEnumType(idToken.type),
40
+ });
41
+ const response = {
42
+ idTokenInfo: {
43
+ status: OCPP2_0_1.AuthorizationStatusEnumType.Unknown,
44
+ // TODO determine how/if to set personalMessage
45
+ },
46
+ };
47
+ if (authorizations.length !== 1) {
48
+ return response;
49
+ }
50
+ const authorization = authorizations[0];
51
+ // Extract DTO fields from sequelize Model<any, any> objects
52
+ const idTokenInfo = OCPP2_0_1_Mapper.AuthorizationMapper.toIdTokenInfo(authorization);
53
+ if (idTokenInfo.status !== OCPP2_0_1.AuthorizationStatusEnumType.Accepted) {
54
+ // IdTokenInfo.status is one of Blocked, Expired, Invalid, NoCredit
55
+ // N.B. Other non-Accepted statuses should not be allowed to be stored.
56
+ response.idTokenInfo = idTokenInfo;
57
+ return response;
58
+ }
59
+ if (idTokenInfo.cacheExpiryDateTime && new Date() > new Date(idTokenInfo.cacheExpiryDateTime)) {
60
+ response.idTokenInfo = {
61
+ status: OCPP2_0_1.AuthorizationStatusEnumType.Invalid,
62
+ groupIdToken: idTokenInfo.groupIdToken,
63
+ // TODO determine how/if to set personalMessage
64
+ };
65
+ return response;
66
+ }
67
+ else {
68
+ if (authorization.concurrentTransaction === true &&
69
+ transactionEvent.eventType === OCPP2_0_1.TransactionEventEnumType.Started) {
70
+ const hasConcurrent = await this._hasConcurrentTransactions(tenantId, authorization.id);
71
+ if (hasConcurrent) {
72
+ response.idTokenInfo = {
73
+ status: OCPP2_0_1.AuthorizationStatusEnumType.ConcurrentTx,
74
+ };
75
+ return response;
76
+ }
77
+ }
78
+ let evse = undefined;
79
+ let connector = undefined;
80
+ if (transactionEvent.evse) {
81
+ if (transactionEvent.evse.connectorId) {
82
+ connector = await this._locationRepository.readConnectorByStationIdAndOcpp201EvseType(tenantId, messageContext.stationId, transactionEvent.evse);
83
+ }
84
+ evse =
85
+ connector?.evse ??
86
+ (await this._locationRepository.readEvseByStationIdAndOcpp201EvseId(tenantId, messageContext.stationId, transactionEvent.evse.id));
87
+ }
88
+ const result = await this._applyAuthorizers(authorization, messageContext, evse, connector);
89
+ response.idTokenInfo = this._mapAuthorizationDtoToIdTokenInfo(authorization, result);
90
+ }
91
+ this._logger.debug('idToken Authorization final status:', response.idTokenInfo.status);
92
+ return response;
93
+ }
94
+ async createMeterValues(tenantId, meterValues, transactionDbId, transactionId, tariffId) {
95
+ return Promise.all(meterValues.map(async (meterValue) => {
96
+ const hasPeriodic = meterValue.sampledValue?.some((s) => s.context === OCPP2_0_1.ReadingContextEnumType.Sample_Periodic);
97
+ if (transactionDbId && hasPeriodic) {
98
+ return await this._transactionEventRepository.createMeterValue(tenantId, meterValue, transactionDbId, transactionId, tariffId);
99
+ }
100
+ else {
101
+ return await this._transactionEventRepository.createMeterValue(tenantId, meterValue);
102
+ }
103
+ }));
104
+ }
105
+ async authorizeOcpp16IdToken(context, idToken, connectorId) {
106
+ const response = {
107
+ idTagInfo: {
108
+ status: OCPP1_6.StartTransactionResponseStatus.Invalid,
109
+ },
110
+ transactionId: 0, // default zero for rejected transaction
111
+ };
112
+ try {
113
+ // Find authorization
114
+ const tenantId = context.tenantId;
115
+ const authorizations = await this._authorizeRepository.readAllByQuerystring(tenantId, {
116
+ idToken: idToken,
117
+ });
118
+ if (authorizations.length !== 1) {
119
+ this._logger.error(`Found invalid authorizations ${JSON.stringify(authorizations)} for idToken: ${idToken}`);
120
+ return response;
121
+ }
122
+ const authorization = authorizations[0];
123
+ // Check expiration and status
124
+ if (!authorization.status) {
125
+ response.idTagInfo.status = OCPP1_6.StartTransactionResponseStatus.Accepted;
126
+ return response;
127
+ }
128
+ const idTokenInfoStatus = OCPP1_6_Mapper.AuthorizationMapper.toStartTransactionResponseStatus(authorization.status);
129
+ if (idTokenInfoStatus !== OCPP1_6.StartTransactionResponseStatus.Accepted) {
130
+ response.idTagInfo.status = idTokenInfoStatus;
131
+ return response;
132
+ }
133
+ if (authorization.cacheExpiryDateTime &&
134
+ new Date() > new Date(authorization.cacheExpiryDateTime)) {
135
+ response.idTagInfo.status = OCPP1_6.StartTransactionResponseStatus.Expired;
136
+ return response;
137
+ }
138
+ // Check concurrent transactions
139
+ const hasConcurrent = await this._hasConcurrentTransactions(tenantId, authorization.id);
140
+ if (hasConcurrent) {
141
+ response.idTagInfo.status = OCPP1_6.StartTransactionResponseStatus.ConcurrentTx;
142
+ return response;
143
+ }
144
+ // Check authorizers
145
+ const connector = await this._locationRepository.readConnectorByStationIdAndOcpp16ConnectorId(tenantId, context.stationId, connectorId);
146
+ response.idTagInfo.status =
147
+ OCPP1_6_Mapper.AuthorizationMapper.toStartTransactionResponseStatus(await this._applyAuthorizers(authorization, context, connector?.evse, connector));
148
+ if (response.idTagInfo.status !== OCPP1_6.StartTransactionResponseStatus.Accepted) {
149
+ return response;
150
+ }
151
+ // Accept the idToken
152
+ response.idTagInfo.status = OCPP1_6.StartTransactionResponseStatus.Accepted;
153
+ response.idTagInfo.expiryDate = authorization.cacheExpiryDateTime;
154
+ if (authorization.groupAuthorizationId) {
155
+ // Look up the referenced Authorization for parentIdTag
156
+ const parentAuth = await this._authorizeRepository.readOnlyOneByQuery(tenantId, {
157
+ where: { id: authorization.groupAuthorizationId },
158
+ });
159
+ if (parentAuth) {
160
+ response.idTagInfo.parentIdTag = parentAuth.idToken;
161
+ }
162
+ }
163
+ return response;
164
+ }
165
+ catch (e) {
166
+ this._logger.error(`Authorization for idToken ${idToken} failed.`, e);
167
+ response.idTagInfo.status = OCPP1_6.StartTransactionResponseStatus.Invalid;
168
+ return response;
169
+ }
170
+ }
171
+ async deactivateReservation(tenantId, transactionId, reservationId, stationId) {
172
+ await this._reservationRepository.updateAllByQuery(tenantId, {
173
+ terminatedByTransaction: transactionId,
174
+ isActive: false,
175
+ }, {
176
+ where: {
177
+ tenantId,
178
+ id: reservationId,
179
+ stationId: stationId,
180
+ },
181
+ });
182
+ }
183
+ async updateTransactionStatus(tenantId, stationId, correlationId, ongoingIndicator) {
184
+ const request = await this._ocppMessageRepository.readOnlyOneByQuery(tenantId, {
185
+ where: {
186
+ tenantId,
187
+ stationId,
188
+ correlationId,
189
+ origin: MessageOrigin.ChargingStationManagementSystem,
190
+ },
191
+ });
192
+ if (!request) {
193
+ this._logger.error(`No valid GetTransactionStatusRequest found for correlationId ${correlationId}`);
194
+ return;
195
+ }
196
+ const transactionId = request.message[3].transactionId;
197
+ if (!transactionId) {
198
+ this._logger.error(`No valid transactionId found from the message ${request.message[3]}`);
199
+ return;
200
+ }
201
+ const updatedTransaction = await this._transactionEventRepository.updateTransactionByStationIdAndTransactionId(tenantId, { isActive: ongoingIndicator }, transactionId, stationId);
202
+ if (!updatedTransaction) {
203
+ this._logger.error(`Update transaction ${transactionId} failed.`);
204
+ }
205
+ this._logger.info(`Updated transaction ${transactionId} isActive to ${ongoingIndicator}`);
206
+ }
207
+ async _applyAuthorizers(authorization, messageContext, evse, connector) {
208
+ let result = authorization.status;
209
+ for (const authorizer of this._authorizers) {
210
+ if (result !== AuthorizationStatusEnum.Accepted) {
211
+ break;
212
+ }
213
+ result = await authorizer.authorize(authorization, messageContext, evse, connector);
214
+ }
215
+ return result;
216
+ }
217
+ async _hasConcurrentTransactions(tenantId, authorizationId) {
218
+ const activeTransactions = await this._transactionEventRepository.readAllActiveTransactionsByAuthorizationId(tenantId, authorizationId);
219
+ return activeTransactions.length > 0;
220
+ }
221
+ _mapAuthorizationDtoToIdTokenInfo(dto, status) {
222
+ return {
223
+ status: OCPP2_0_1_Mapper.AuthorizationMapper.fromAuthorizationStatusEnumType(status),
224
+ cacheExpiryDateTime: dto.cacheExpiryDateTime ?? null,
225
+ chargingPriority: dto.chargingPriority ?? null,
226
+ language1: dto.language1 ?? null,
227
+ language2: dto.language2 ?? null,
228
+ groupIdToken: dto.groupAuthorization
229
+ ? {
230
+ idToken: dto.groupAuthorization?.idToken ?? '',
231
+ type: dto.groupAuthorization?.idTokenType
232
+ ? OCPP2_0_1_Mapper.AuthorizationMapper.toIdTokenEnumType(dto.groupAuthorization?.idTokenType)
233
+ : '',
234
+ }
235
+ : null,
236
+ personalMessage: dto.personalMessage
237
+ ? {
238
+ content: dto.personalMessage.content ?? '',
239
+ language: dto.personalMessage.language ?? '',
240
+ format: dto.personalMessage.format ?? OCPP2_0_1.MessageFormatEnumType.ASCII,
241
+ }
242
+ : null,
243
+ };
244
+ }
245
+ }
246
+ //# sourceMappingURL=TransactionService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TransactionService.js","sourceRoot":"","sources":["../../src/module/TransactionService.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Interface for the transaction module.
3
+ */
4
+ export interface ITransactionsModuleApi {
5
+ }
@@ -0,0 +1,5 @@
1
+ // SPDX-FileCopyrightText: 2025 Contributors to the CitrineOS Project
2
+ //
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ export {};
5
+ //# sourceMappingURL=interface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interface.js","sourceRoot":"","sources":["../../src/module/interface.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,EAAE;AACF,sCAAsC"}
@@ -0,0 +1,10 @@
1
+ export declare class UpsertTariffRequest {
2
+ id: number;
3
+ currency: string;
4
+ pricePerKwh: number;
5
+ pricePerMin?: number;
6
+ pricePerSession?: number;
7
+ taxRate?: number;
8
+ authorizationAmount?: number;
9
+ paymentFee?: number;
10
+ }
@@ -0,0 +1,14 @@
1
+ // SPDX-FileCopyrightText: 2025 Contributors to the CitrineOS Project
2
+ //
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ export class UpsertTariffRequest {
5
+ id;
6
+ currency;
7
+ pricePerKwh;
8
+ pricePerMin;
9
+ pricePerSession;
10
+ taxRate;
11
+ authorizationAmount;
12
+ paymentFee;
13
+ }
14
+ //# sourceMappingURL=tariffs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tariffs.js","sourceRoot":"","sources":["../../../src/module/model/tariffs.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,EAAE;AACF,sCAAsC;AACtC,MAAM,OAAO,mBAAmB;IAC9B,EAAE,CAAU;IACZ,QAAQ,CAAU;IAElB,WAAW,CAAU;IACrB,WAAW,CAAU;IACrB,eAAe,CAAU;IACzB,OAAO,CAAU;IAEjB,mBAAmB,CAAU;IAC7B,UAAU,CAAU;CACrB"}
@@ -0,0 +1,122 @@
1
+ import type { BootstrapConfig, CallAction, HandlerProperties, IAuthorizer, ICache, IFileStorage, IMessage, IMessageHandler, IMessageSender, SystemConfig } from '@citrineos/base';
2
+ import { AbstractModule, CrudRepository, OCPP1_6, OCPP2_0_1, OCPPValidator } from '@citrineos/base';
3
+ import type { IAuthorizationRepository, IDeviceModelRepository, ILocationRepository, IOCPPMessageRepository, IReservationRepository, ITariffRepository, ITransactionEventRepository } from '@citrineos/data';
4
+ import { Component } from '@citrineos/data';
5
+ import type { ILogObj } from 'tslog';
6
+ import { Logger } from 'tslog';
7
+ import { StatusNotificationService } from './StatusNotificationService.js';
8
+ import { TransactionService } from './TransactionService.js';
9
+ /**
10
+ * Component that handles transaction related messages.
11
+ */
12
+ export declare class TransactionsModule extends AbstractModule {
13
+ _requests: CallAction[];
14
+ _responses: CallAction[];
15
+ protected _transactionEventRepository: ITransactionEventRepository;
16
+ protected _authorizeRepository: IAuthorizationRepository;
17
+ protected _deviceModelRepository: IDeviceModelRepository;
18
+ protected _componentRepository: CrudRepository<Component>;
19
+ protected _locationRepository: ILocationRepository;
20
+ protected _tariffRepository: ITariffRepository;
21
+ protected _reservationRepository: IReservationRepository;
22
+ protected _ocppMessageRepository: IOCPPMessageRepository;
23
+ protected _transactionService: TransactionService;
24
+ protected _statusNotificationService: StatusNotificationService;
25
+ protected _fileStorage: IFileStorage;
26
+ private readonly _authorizers;
27
+ private readonly _realTimeAuthorizer;
28
+ private readonly _signedMeterValuesUtil;
29
+ private _costNotifier;
30
+ private _costCalculator;
31
+ private readonly _sendCostUpdatedOnMeterValue;
32
+ private readonly _costUpdatedInterval;
33
+ /**
34
+ * This is the constructor function that initializes the {@link TransactionsModule}.
35
+ *
36
+ * @param {BootstrapConfig & SystemConfig} config - The `config` contains configuration settings for the module.
37
+ *
38
+ * @param {ICache} [cache] - The cache instance which is shared among the modules & Central System to pass information such as blacklisted actions or boot status.
39
+ *
40
+ * @param {IFileStorage} [fileStorage] - The `fileStorage` allows access to the configured file storage.
41
+ *
42
+ * @param {IMessageSender} [sender] - The `sender` parameter is an optional parameter that represents an instance of the {@link IMessageSender} interface.
43
+ * It is used to send messages from the central system to external systems or devices. If no `sender` is provided, a default {@link RabbitMqSender} instance is created and used.
44
+ *
45
+ * @param {IMessageHandler} [handler] - The `handler` parameter is an optional parameter that represents an instance of the {@link IMessageHandler} interface.
46
+ * It is used to handle incoming messages and dispatch them to the appropriate methods or functions. If no `handler` is provided, a default {@link RabbitMqReceiver} instance is created and used.
47
+ *
48
+ * @param {Logger<ILogObj>} [logger] - The `logger` parameter is an optional parameter that represents an instance of {@link Logger<ILogObj>}.
49
+ * It is used to propagate system-wide logger settings and will serve as the parent logger for any sub-component logging. If no `logger` is provided, a default {@link Logger<ILogObj>} instance is created and used.
50
+ *
51
+ * @param {ITransactionEventRepository} [transactionEventRepository] - An optional parameter of type {@link ITransactionEventRepository} which represents a repository for accessing and manipulating transaction event data.
52
+ * If no `transactionEventRepository` is provided, a default {@link sequelize:transactionEventRepository} instance
53
+ * is created and used.
54
+ *
55
+ * @param {IAuthorizationRepository} [authorizeRepository] - An optional parameter of type {@link IAuthorizationRepository} which represents a repository for accessing and manipulating authorization data.
56
+ * If no `authorizeRepository` is provided, a default {@link sequelize:authorizeRepository} instance is
57
+ * created and used.
58
+ *
59
+ * @param {IDeviceModelRepository} [deviceModelRepository] - An optional parameter of type {@link IDeviceModelRepository} which represents a repository for accessing and manipulating variable attribute data.
60
+ * If no `deviceModelRepository` is provided, a default {@link sequelize:deviceModelRepository} instance is
61
+ * created and used.
62
+ *
63
+ * @param {CrudRepository<Component>} [componentRepository] - An optional parameter of type {@link CrudRepository<Component>} which represents a repository for accessing and manipulating component data.
64
+ * If no `componentRepository` is provided, a default {@link sequelize:componentRepository} instance is
65
+ * created and used.
66
+ *
67
+ * @param {ILocationRepository} [locationRepository] - An optional parameter of type {@link ILocationRepository} which represents a repository for accessing and manipulating location and charging station data.
68
+ * If no `locationRepository` is provided, a default {@link sequelize:locationRepository} instance is
69
+ * created and used.
70
+ *
71
+ * @param {CrudRepository<Component>} [componentRepository] - An optional parameter of type {@link CrudRepository<Component>} which represents a repository for accessing and manipulating component data.
72
+ * If no `componentRepository` is provided, a default {@link sequelize:componentRepository} instance is
73
+ * created and used.
74
+ *
75
+ * @param {ILocationRepository} [locationRepository] - An optional parameter of type {@link ILocationRepository} which represents a repository for accessing and manipulating location and charging station data.
76
+ * If no `locationRepository` is provided, a default {@link sequelize:locationRepository} instance is
77
+ * created and used.
78
+ *
79
+ * @param {ITariffRepository} [tariffRepository] - An optional parameter of type {@link ITariffRepository} which
80
+ * represents a repository for accessing and manipulating tariff data.
81
+ * If no `tariffRepository` is provided, a default {@link sequelize:tariffRepository} instance is
82
+ * created and used.
83
+ *
84
+ * @param {IReservationRepository} [reservationRepository] - An optional parameter of type {@link IReservationRepository}
85
+ * which represents a repository for accessing and manipulating reservation data.
86
+ * If no `reservationRepository` is provided, a default {@link sequelize:reservationRepository} instance is created and used.
87
+ *
88
+ * @param {IOCPPMessageRepository} [ocppMessageRepository] - An optional parameter of type {@link IOCPPMessageRepository}
89
+ * which represents a repository for accessing and manipulating OCPP Message data.
90
+ * If no `ocppMessageRepository` is provided, a default {@link sequelize:ocppMessageRepository} instance is created and used.
91
+ *
92
+ * @param {IAuthorizer[]} [authorizers] - An optional parameter of type {@link IAuthorizer[]} which represents
93
+ * a list of authorizers that can be used to authorize requests.
94
+ *
95
+ * @param {IAuthorizer} [realTimeAuthorizer] - An optional parameter of type {@link IAuthorizer} which represents
96
+ * a real-time authorizer that can be used to authorize real-time requests.
97
+ */
98
+ constructor(config: BootstrapConfig & SystemConfig, cache: ICache, fileStorage: IFileStorage, sender?: IMessageSender, handler?: IMessageHandler, logger?: Logger<ILogObj>, ocppValidator?: OCPPValidator, transactionEventRepository?: ITransactionEventRepository, authorizeRepository?: IAuthorizationRepository, deviceModelRepository?: IDeviceModelRepository, componentRepository?: CrudRepository<Component>, locationRepository?: ILocationRepository, tariffRepository?: ITariffRepository, reservationRepository?: IReservationRepository, ocppMessageRepository?: IOCPPMessageRepository, realTimeAuthorizer?: IAuthorizer, authorizers?: IAuthorizer[]);
99
+ get transactionEventRepository(): ITransactionEventRepository;
100
+ get authorizeRepository(): IAuthorizationRepository;
101
+ get deviceModelRepository(): IDeviceModelRepository;
102
+ get tariffRepository(): ITariffRepository;
103
+ get ocppMessageRepository(): IOCPPMessageRepository;
104
+ /**
105
+ * Handle OCPP 2.0.1 requests
106
+ */
107
+ protected _handleTransactionEvent(message: IMessage<OCPP2_0_1.TransactionEventRequest>, props?: HandlerProperties): Promise<void>;
108
+ protected _handleMeterValues(message: IMessage<OCPP2_0_1.MeterValuesRequest>, props?: HandlerProperties): Promise<void>;
109
+ protected _handleStatusNotification(message: IMessage<OCPP2_0_1.StatusNotificationRequest>, props?: HandlerProperties): Promise<void>;
110
+ /**
111
+ * Handle OCPP 2.0.1 responses
112
+ */
113
+ protected _handleCostUpdated(message: IMessage<OCPP2_0_1.CostUpdatedResponse>, props?: HandlerProperties): void;
114
+ protected _handleGetTransactionStatus(message: IMessage<OCPP2_0_1.GetTransactionStatusResponse>, props?: HandlerProperties): Promise<void>;
115
+ /**
116
+ * Handle OCPP 1.6 requests
117
+ */
118
+ protected _handleOcpp16StatusNotification(message: IMessage<OCPP1_6.StatusNotificationRequest>, props?: HandlerProperties): Promise<void>;
119
+ protected _handleOcpp16MeterValues(message: IMessage<OCPP1_6.MeterValuesRequest>, props?: HandlerProperties): Promise<void>;
120
+ protected _handleOcpp16StartTransaction(message: IMessage<OCPP1_6.StartTransactionRequest>, props?: HandlerProperties): Promise<void>;
121
+ protected _handleOcpp16StopTransaction(message: IMessage<OCPP1_6.StopTransactionRequest>, props?: HandlerProperties): Promise<void>;
122
+ }