Added a central Start Transaction for OCPP and OCPI
MODIFY
src/assets/server/rest/v1/docs/e-mobility-oas.json
src/assets/server/rest/v1/docs/e-mobility-oas.json
}
}
},
+ "/api/transactions/start": {
+ "put": {
+ "security": [
+ {
+ "bearerAuth": []
+ }
+ ],
+ "description": "Start a Transaction by using the right method (OCPP, OCPI...)",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "chargingStationID": {
+ "type": "string",
+ "example": ""
+ },
+ "args": {
+ "type": "object",
+ "properties": {
+ "tagID": {
+ "type": "string",
+ "description": "The identifier that Charge Point must use to start a transaction.",
+ "example": "123456"
+ },
+ "visualTagID": {
+ "type": "string",
+ "description": "The identifier that Charge Point must use to start a transaction.",
+ "example": "123456-123456"
+ },
+ "connectorId": {
+ "type": "integer",
+ "description": "Optional. Number of the connector on which to start the transaction. connectorId SHALL be > 0",
+ "minimum": 1,
+ "example": 1
+ }
+ }
+ }
+ },
+ "required": [
+ "chargingStationID",
+ "args"
+ ]
+ }
+ }
+ }
+ },
+ "tags": [
+ "Transactions"
+ ],
+ "responses": {
+ "200": {
+ "description": "Transaction started successfully",
+ "content": {
+ "application/json": {
+ "example": {
+ "status": "Accepted"
+ }
+ }
+ }
+ },
+ "401": {
+ "$ref": "#/components/responses/UnauthorizedError"
+ },
+ "403": {
+ "$ref": "#/components/responses/ForbiddenError"
+ },
+ "500": {
+ "$ref": "#/components/responses/BackendError"
+ }
+ }
+ }
+ },
"/api/transactions/{id}/stop": {
"put": {
"security": [
"bearerAuth": []
}
],
- "description": "Stop a Transaction by using the right method (OCPP, OCPI, Soft)",
+ "description": "Stop a Transaction by using the right method (OCPP, OCPI, Soft...)",
"parameters": [
{
"$ref": "#/components/parameters/transactionID"

MODIFY
src/server/rest/v1/router/api/TransactionRouter.ts
src/server/rest/v1/router/api/TransactionRouter.ts
@@ -24,6 +24,7 @@ export default class TransactionRouter {
this.buildRouteDeleteTransactions();
this.buildRoutePushTransactionCDR();
this.buildRouteExportTransactionCDR();
+ this.buildRouteTransactionStart();
this.buildRouteTransactionStop();
this.buildRouteTransactionSoftStop();
this.buildRouteTransactionsRefund();
@@ -119,6 +120,12 @@ export default class TransactionRouter {
});
}
+ private buildRouteTransactionStart(): void {
+ this.router.put(`/${ServerRoute.REST_TRANSACTION_START}`, async (req: Request, res: Response, next: NextFunction) => {
+ await RouterUtils.handleServerAction(TransactionService.handleTransactionStart.bind(this), ServerAction.TRANSACTION_START, req, res, next);
+ });
+ }
+
private buildRouteTransactionsRefund(): void {
this.router.post(`/${ServerRoute.REST_TRANSACTIONS_REFUND_ACTION}`, async (req: Request, res: Response, next: NextFunction) => {
req.body.transactionsIDs = req.body.transactionIds;

MODIFY
src/server/rest/v1/service/TransactionService.ts
src/server/rest/v1/service/TransactionService.ts
@@ -12,6 +12,7 @@ import BillingFactory from '../../../../integration/billing/BillingFactory';
import { BillingStatus } from '../../../../types/Billing';
import ChargingStationService from './ChargingStationService';
import ChargingStationStorage from '../../../../storage/mongodb/ChargingStationStorage';
+import ChargingStationValidator from '../validator/ChargingStationValidator';
import Configuration from '../../../../utils/Configuration';
import Constants from '../../../../utils/Constants';
import Consumption from '../../../../types/Consumption';
@@ -313,12 +314,34 @@ export default class TransactionService {
next();
}
+ public static async handleTransactionStart(action: ServerAction, req: Request, res: Response, next: NextFunction): Promise<void> {
+ // Filter
+ const remoteStartRequest = ChargingStationValidator.getInstance().validateChargingStationActionTransactionStartReq(req.body);
+ // Get data
+ const { chargingStation } = await TransactionService.checkAndGetChargingStationConnector(
+ action, req.tenant, req.user, remoteStartRequest.chargingStationID, remoteStartRequest.args.connectorId);
+ // Handle the routing
+ if (chargingStation.issuer) {
+ // OCPP Remote Start
+ await ChargingStationService.handleOcppAction(
+ ServerAction.CHARGING_STATION_REMOTE_START_TRANSACTION, req, res, next);
+ } else {
+ // OCPI Remote Start
+ await ChargingStationService.handleOcpiAction(
+ ServerAction.OCPI_START_SESSION, req, res, next);
+ }
+ }
+
public static async handleTransactionStop(action: ServerAction, req: Request, res: Response, next: NextFunction): Promise<void> {
+ // Filter
+ const transactionID = TransactionValidator.getInstance().validateTransactionGetReq(req.body).ID;
+ UtilsService.assertIdIsProvided(action, transactionID, MODULE_NAME, 'handleTransactionStop', req.user);
// Get data
- const { transaction, chargingStation, connector } = await TransactionService.checkAndGetTransactionData(action, req);
+ const { transaction, chargingStation, connector } =
+ await TransactionService.checkAndGetTransactionChargingStationConnector(action, req.tenant, req.user, transactionID);
// Handle the routing
if (chargingStation.issuer) {
- // OCPP Stop
+ // OCPP Remote Stop
if (!chargingStation.inactive && connector.currentTransactionID === transaction.id) {
req.body.chargingStationID = transaction.chargeBoxID;
req.body.args = { transactionId: transaction.id };
@@ -329,14 +352,18 @@ export default class TransactionService {
transaction, chargingStation, connector, req, res, next);
}
} else {
- // OCPI Stop
+ // OCPI Remote Stop
await ChargingStationService.handleOcpiAction(ServerAction.OCPI_STOP_SESSION, req, res, next);
}
}
public static async handleTransactionSoftStop(action: ServerAction, req: Request, res: Response, next: NextFunction): Promise<void> {
+ // Filter
+ const transactionID = TransactionValidator.getInstance().validateTransactionGetReq(req.body).ID;
+ UtilsService.assertIdIsProvided(action, transactionID, MODULE_NAME, 'handleTransactionSoftStop', req.user);
// Get data
- const { transaction, chargingStation, connector } = await TransactionService.checkAndGetTransactionData(action, req);
+ const { transaction, chargingStation, connector } =
+ await TransactionService.checkAndGetTransactionChargingStationConnector(action, req.tenant, req.user, transactionID);
// Soft Stop
await TransactionService.transactionSoftStop(action, transaction, chargingStation, connector, req, res, next);
}
@@ -1051,40 +1078,42 @@ export default class TransactionService {
next();
}
- private static async checkAndGetTransactionData(action: ServerAction, req: Request):
- Promise<{ transaction: Transaction; chargingStation: ChargingStation; connector: Connector; }> {
- // Filter
- const transactionId = TransactionValidator.getInstance().validateTransactionGetReq(req.body).ID;
- UtilsService.assertIdIsProvided(action, transactionId, MODULE_NAME, 'handleTransactionStop', req.user);
+ private static async checkAndGetTransactionChargingStationConnector(action: ServerAction, tenant: Tenant, user: UserToken,
+ transactionID: number): Promise<{ transaction: Transaction; chargingStation: ChargingStation; connector: Connector; }> {
// Get Transaction
- const transaction = await TransactionStorage.getTransaction(req.tenant, transactionId);
- UtilsService.assertObjectExists(action, transaction, `Transaction ID ${transactionId} does not exist`,
- MODULE_NAME, 'handleTransactionStop', req.user);
+ const transaction = await TransactionStorage.getTransaction(tenant, transactionID);
+ UtilsService.assertObjectExists(action, transaction, `Transaction ID ${transactionID} does not exist`,
+ MODULE_NAME, 'checkAndGetTransactionChargingStationConnector', user);
// Check auth
- if (!await Authorizations.canUpdateTransaction(req.user, transaction)) {
+ if (!await Authorizations.canUpdateTransaction(user, transaction)) {
throw new AppAuthError({
errorCode: HTTPAuthError.FORBIDDEN,
- user: req.user,
- action: Action.UPDATE, entity: Entity.TRANSACTION,
- module: MODULE_NAME, method: 'handleTransactionStop',
- value: transactionId.toString()
+ user, action: Action.UPDATE, entity: Entity.TRANSACTION,
+ module: MODULE_NAME, method: 'checkAndGetTransactionChargingStationConnector',
+ value: transactionID.toString()
});
}
+ const { chargingStation, connector } =
+ await TransactionService.checkAndGetChargingStationConnector(action, tenant, user, transaction.chargeBoxID, transaction.connectorId);
+ return { transaction, chargingStation, connector };
+ }
+
+ private static async checkAndGetChargingStationConnector(action: ServerAction, tenant: Tenant, user: UserToken,
+ chargingStationID: string, connectorID: number): Promise<{ chargingStation: ChargingStation; connector: Connector; }> {
// Get the Charging Station
- const chargingStation = await ChargingStationStorage.getChargingStation(req.tenant, transaction.chargeBoxID, { withSiteArea: true });
- UtilsService.assertObjectExists(action, chargingStation, `Charging Station ID '${transaction.chargeBoxID}' does not exist`,
- MODULE_NAME, 'handleTransactionStop', req.user);
+ const chargingStation = await ChargingStationStorage.getChargingStation(tenant, chargingStationID, { withSiteArea: true });
+ UtilsService.assertObjectExists(action, chargingStation, `Charging Station ID '${chargingStationID}' does not exist`,
+ MODULE_NAME, 'checkAndGetChargingStationConnector', user);
// Check connector
- const connector = Utils.getConnectorFromID(chargingStation, transaction.connectorId);
+ const connector = Utils.getConnectorFromID(chargingStation, connectorID);
if (!connector) {
throw new AppError({
...LoggingHelper.getChargingStationProperties(chargingStation),
errorCode: HTTPError.GENERAL_ERROR,
- message: `${Utils.buildConnectorInfo(transaction.connectorId, transaction.id)} The Connector ID has not been found`,
- module: MODULE_NAME, method: 'handleTransactionSoftStop',
- user: req.user, action
+ message: `${Utils.buildConnectorInfo(connectorID)} The Connector ID has not been found`,
+ user, action, module: MODULE_NAME, method: 'checkAndGetChargingStationConnector',
});
}
- return { transaction, chargingStation, connector };
+ return { chargingStation, connector };
}
}

MODIFY
src/types/Server.ts
src/types/Server.ts
@@ -52,6 +52,7 @@ export enum ServerAction {
BOOT_NOTIFICATIONS = 'BootNotifications',
STATUS_NOTIFICATIONS = 'StatusNotifications',
+ TRANSACTION_START = 'TransactionStart',
TRANSACTION_STOP = 'TransactionStop',
TRANSACTION_SOFT_STOP = 'TransactionSoftStop',
TRANSACTION_DELETE = 'TransactionDelete',
@@ -519,6 +520,7 @@ export enum ServerRoute {
REST_TRANSACTION_CDR = 'transactions/:id/ocpi/cdr',
REST_TRANSACTION_CDR_EXPORT = 'transactions/:id/ocpi/cdr/export',
REST_TRANSACTION_CONSUMPTIONS = 'transactions/:id/consumptions',
+ REST_TRANSACTION_START = 'transactions/start',
REST_TRANSACTION_STOP = 'transactions/:id/stop',
REST_TRANSACTION_SOFT_STOP = 'transactions/:id/soft-stop',
REST_TRANSACTIONS_REFUND_ACTION = 'transactions/action/refund',

Added a central Start Transaction for OCPP and OCPI