Refactored transaction endpoint
MODIFY
src/server/rest/v1/service/TransactionService.ts
src/server/rest/v1/service/TransactionService.ts
@@ -42,23 +42,7 @@ const MODULE_NAME = 'TransactionService';
export default class TransactionService {
public static async handleGetTransactions(action: ServerAction, req: Request, res: Response, next: NextFunction): Promise<void> {
- const filteredRequest = TransactionSecurity.filterGetTransactions(req.query);
- let transactions: DataResult<Transaction>;
- if (filteredRequest.Status) {
- if (filteredRequest.Status === 'completed') {
- transactions = await TransactionService.getTransactionsCompleted(ServerAction.TRANSACTIONS_COMPLETED, req);
- } else if (filteredRequest.Status === 'active') {
- transactions = await TransactionService.getTransactionsActive(ServerAction.TRANSACTIONS_ACTIVE, req);
- }
- } else {
- const completed = await TransactionService.getTransactionsCompleted(ServerAction.TRANSACTIONS_COMPLETED, req);
- const active = await TransactionService.getTransactionsActive(ServerAction.TRANSACTIONS_ACTIVE, req);
- transactions = {
- count: completed.count + active.count,
- result: [...completed.result, ...active.result]
- };
- }
- res.json(transactions);
+ res.json(await TransactionService.getTransactions(req, action, {}, []));
next();
}
@@ -683,7 +667,8 @@ export default class TransactionService {
public static async handleGetChargingStationTransactions(action: ServerAction, req: Request, res: Response, next: NextFunction): Promise<void> {
// Get transaction
- const transactions = await TransactionService.getTransactions(req, action, { completedTransactions: true }, [
+ req.query.Status = 'completed';
+ const transactions = await TransactionService.getTransactions(req, action, {}, [
'id', 'chargeBoxID', 'timestamp', 'issuer', 'stateOfCharge', 'timezone', 'connectorId', 'meterStart', 'siteAreaID', 'siteID',
'currentTotalDurationSecs', 'currentTotalInactivitySecs', 'currentInstantWatts', 'currentTotalConsumptionWh', 'currentStateOfCharge',
'stop.roundedPrice', 'stop.price', 'stop.priceUnit', 'stop.inactivityStatus', 'stop.stateOfCharge', 'stop.timestamp', 'stop.totalConsumptionWh',
@@ -707,14 +692,24 @@ export default class TransactionService {
}
public static async handleGetTransactionsActive(action: ServerAction, req: Request, res: Response, next: NextFunction): Promise<void> {
- const transactions = await TransactionService.getTransactionsActive(action, req);
+ req.query.Status = 'active';
+ const transactions = await TransactionService.getTransactions(req, action, {}, [
+ 'id', 'chargeBoxID', 'timestamp', 'issuer', 'stateOfCharge', 'timezone', 'connectorId', 'status', 'meterStart', 'siteAreaID', 'siteID',
+ 'currentTotalDurationSecs', 'currentTotalInactivitySecs', 'currentInstantWatts', 'currentTotalConsumptionWh', 'currentStateOfCharge',
+ 'currentCumulatedPrice', 'currentInactivityStatus', 'roundedPrice', 'price', 'priceUnit', 'tagID',
+ ]);
res.json(transactions);
next();
}
public static async handleGetTransactionsCompleted(action: ServerAction, req: Request, res: Response, next: NextFunction): Promise<void> {
// Get transaction
- const transactions = await TransactionService.getTransactionsCompleted(action, req);
+ req.query.Status = 'completed';
+ const transactions = await TransactionService.getTransactions(req, action, {}, [
+ 'id', 'chargeBoxID', 'timestamp', 'issuer', 'stateOfCharge', 'timezone', 'connectorId', 'meterStart', 'siteAreaID', 'siteID',
+ 'stop.roundedPrice', 'stop.price', 'stop.priceUnit', 'stop.inactivityStatus', 'stop.stateOfCharge', 'stop.timestamp', 'stop.totalConsumptionWh',
+ 'stop.totalDurationSecs', 'stop.totalInactivitySecs', 'stop.meterStop', 'billingData.invoiceID', 'ocpi', 'ocpiWithCdr', 'tagID', 'stop.tagID',
+ ]);
res.json(transactions);
next();
}
@@ -726,7 +721,8 @@ export default class TransactionService {
// Only e-Mobility transactions
req.query.issuer = 'true';
// Call
- const transactions = await TransactionService.getTransactions(req, action, { completedTransactions: true }, [
+ req.query.Status = 'completed';
+ const transactions = await TransactionService.getTransactions(req, action, {}, [
'id', 'chargeBoxID', 'timestamp', 'issuer', 'stateOfCharge', 'timezone', 'connectorId', 'meterStart', 'siteAreaID', 'siteID',
'refundData.reportId', 'refundData.refundedAt', 'refundData.status',
'stop.roundedPrice', 'stop.price', 'stop.priceUnit', 'stop.inactivityStatus', 'stop.stateOfCharge', 'stop.timestamp', 'stop.totalConsumptionWh',
@@ -791,7 +787,8 @@ export default class TransactionService {
public static async getCompletedTransactionsToExport(req: Request): Promise<DataResult<Transaction>> {
// Get transaction
- return TransactionService.getTransactions(req, ServerAction.TRANSACTIONS_EXPORT, { completedTransactions: true, withTag: true }, [
+ req.query.Status = 'completed';
+ return TransactionService.getTransactions(req, ServerAction.TRANSACTIONS_EXPORT, { withTag: true }, [
'id', 'chargeBoxID', 'timestamp', 'issuer', 'stateOfCharge', 'timezone', 'connectorId', 'meterStart', 'siteAreaID', 'siteID',
'stop.roundedPrice', 'stop.price', 'stop.priceUnit', 'stop.inactivityStatus', 'stop.stateOfCharge', 'stop.timestamp', 'stop.totalConsumptionWh',
'stop.totalDurationSecs', 'stop.totalInactivitySecs', 'billingData.invoiceID', 'ocpi', 'ocpiWithCdr', 'tagID', 'stop.tagID', 'tag.description'
@@ -806,7 +803,8 @@ export default class TransactionService {
}
public static async getRefundedTransactionsToExport(req: Request): Promise<DataResult<Transaction>> {
- return await TransactionService.getTransactions(req, ServerAction.TRANSACTIONS_TO_REFUND_EXPORT, { completedTransactions: true }, [
+ req.query.Status = 'completed';
+ return await TransactionService.getTransactions(req, ServerAction.TRANSACTIONS_TO_REFUND_EXPORT, {}, [
'id', 'chargeBoxID', 'timestamp', 'issuer', 'stateOfCharge', 'timezone', 'connectorId', 'meterStart', 'siteAreaID', 'siteID',
'refundData.reportId', 'refundData.refundedAt', 'refundData.status',
'stop.roundedPrice', 'stop.price', 'stop.priceUnit', 'stop.inactivityStatus', 'stop.stateOfCharge', 'stop.timestamp', 'stop.totalConsumptionWh',
@@ -1009,7 +1007,7 @@ export default class TransactionService {
return result;
}
- private static async getTransactions(req: Request, action: ServerAction, params: { completedTransactions?: boolean, withTag?: boolean } = {}, projectFields): Promise<DataResult<Transaction>> {
+ private static async getTransactions(req: Request, action: ServerAction, params: { withTag?: boolean } = {}, projectFields): Promise<DataResult<Transaction>> {
// Check Transactions
if (!Authorizations.canListTransactions(req.user)) {
throw new AppAuthError({
@@ -1046,18 +1044,34 @@ export default class TransactionService {
}
// Filter
const filteredRequest = TransactionSecurity.filterTransactionsRequest(req.query);
- // Check projection
- if (!Utils.isEmptyArray(filteredRequest.ProjectFields)) {
- projectFields = projectFields.filter((projectField) => filteredRequest.ProjectFields.includes(projectField));
- }
// Build
const extrafilters: any = {};
- if (Utils.objectHasProperty(params, 'completedTransactions')) {
- extrafilters.stop = params.completedTransactions ? { $exists: true } : { $exists: false };
- }
if (Utils.objectHasProperty(params, 'withTag')) {
extrafilters.withTag = params.withTag;
}
+ if (filteredRequest.Status) {
+ if (filteredRequest.Status === 'completed') {
+ projectFields = [
+ ...projectFields,
+ 'id', 'chargeBoxID', 'timestamp', 'issuer', 'stateOfCharge', 'timezone', 'connectorId', 'meterStart', 'siteAreaID', 'siteID',
+ 'stop.roundedPrice', 'stop.price', 'stop.priceUnit', 'stop.inactivityStatus', 'stop.stateOfCharge', 'stop.timestamp', 'stop.totalConsumptionWh',
+ 'stop.totalDurationSecs', 'stop.totalInactivitySecs', 'stop.meterStop', 'billingData.invoiceID', 'ocpi', 'ocpiWithCdr', 'tagID', 'stop.tagID'
+ ];
+ extrafilters.stop = { $exists: true };
+ } else if (filteredRequest.Status === 'active') {
+ projectFields = [
+ ...projectFields,
+ 'id', 'chargeBoxID', 'timestamp', 'issuer', 'stateOfCharge', 'timezone', 'connectorId', 'status', 'meterStart', 'siteAreaID', 'siteID',
+ 'currentTotalDurationSecs', 'currentTotalInactivitySecs', 'currentInstantWatts', 'currentTotalConsumptionWh', 'currentStateOfCharge',
+ 'currentCumulatedPrice', 'currentInactivityStatus', 'roundedPrice', 'price', 'priceUnit', 'tagID'
+ ];
+ extrafilters.stop = { $exists: false };
+ }
+ }
+ // Check projection
+ if (!Utils.isEmptyArray(filteredRequest.ProjectFields)) {
+ projectFields = projectFields.filter((projectField) => filteredRequest.ProjectFields.includes(projectField));
+ }
// Get the transactions
const transactions = await TransactionStorage.getTransactions(req.user.tenantID,
{
@@ -1085,20 +1099,4 @@ export default class TransactionService {
);
return transactions;
}
-
- private static async getTransactionsCompleted(action: ServerAction, req: Request): Promise<DataResult<Transaction>> {
- return await TransactionService.getTransactions(req, action, { completedTransactions: true }, [
- 'id', 'chargeBoxID', 'timestamp', 'issuer', 'stateOfCharge', 'timezone', 'connectorId', 'meterStart', 'siteAreaID', 'siteID',
- 'stop.roundedPrice', 'stop.price', 'stop.priceUnit', 'stop.inactivityStatus', 'stop.stateOfCharge', 'stop.timestamp', 'stop.totalConsumptionWh',
- 'stop.totalDurationSecs', 'stop.totalInactivitySecs', 'stop.meterStop', 'billingData.invoiceID', 'ocpi', 'ocpiWithCdr', 'tagID', 'stop.tagID',
- ]);
- }
-
- private static async getTransactionsActive(action: ServerAction, req: Request): Promise<DataResult<Transaction>> {
- return await TransactionService.getTransactions(req, action, { completedTransactions: false }, [
- 'id', 'chargeBoxID', 'timestamp', 'issuer', 'stateOfCharge', 'timezone', 'connectorId', 'status', 'meterStart', 'siteAreaID', 'siteID',
- 'currentTotalDurationSecs', 'currentTotalInactivitySecs', 'currentInstantWatts', 'currentTotalConsumptionWh', 'currentStateOfCharge',
- 'currentCumulatedPrice', 'currentInactivityStatus', 'roundedPrice', 'price', 'priceUnit', 'tagID',
- ]);
- }
}

MODIFY
src/server/rest/v1/service/security/TransactionSecurity.ts
src/server/rest/v1/service/security/TransactionSecurity.ts
-import { HttpAssignTransactionsToUserRequest, HttpConsumptionFromTransactionRequest, HttpGetTransactionsRequest, HttpPushTransactionCdrRequest, HttpTransactionRequest, HttpTransactionsRefundRequest, HttpTransactionsRequest, HttpUnassignTransactionsToUserRequest } from '../../../../../types/requests/HttpTransactionRequest';
+import { HttpAssignTransactionsToUserRequest, HttpConsumptionFromTransactionRequest, HttpPushTransactionCdrRequest, HttpTransactionRequest, HttpTransactionsRefundRequest, HttpTransactionsRequest, HttpUnassignTransactionsToUserRequest } from '../../../../../types/requests/HttpTransactionRequest';
import Utils from '../../../../../utils/Utils';
import UtilsSecurity from './UtilsSecurity';
@@ -74,6 +74,9 @@ export default class TransactionSecurity {
if (Utils.objectHasProperty(request, 'ReportIDs')) {
filteredRequest.ReportIDs = sanitize(request.ReportIDs);
}
+ if (Utils.objectHasProperty(request, 'Status')) {
+ filteredRequest.Status = sanitize(request.Status);
+ }
UtilsSecurity.filterSkipAndLimit(request, filteredRequest);
UtilsSecurity.filterSort(request, filteredRequest);
UtilsSecurity.filterProject(request, filteredRequest);
@@ -110,10 +113,4 @@ export default class TransactionSecurity {
}
return filteredRequest;
}
-
- public static filterGetTransactions(request: any): HttpGetTransactionsRequest {
- return {
- Status: sanitize(request.Status),
- };
- }
}

MODIFY
src/types/requests/HttpTransactionRequest.ts
src/types/requests/HttpTransactionRequest.ts
@@ -39,6 +39,7 @@ export interface HttpTransactionsRequest extends HttpDatabaseRequest {
MinimalPrice?: boolean;
Statistics?: 'refund' | 'history';
ReportIDs?: string;
+ Status?: 'completed' | 'active';
}
export interface HttpConsumptionFromTransactionRequest {
@@ -47,7 +48,3 @@ export interface HttpConsumptionFromTransactionRequest {
StartDateTime: Date;
EndDateTime: Date;
}
-
-export interface HttpGetTransactionsRequest {
- Status?: 'completed' | 'active';
-}

Refactored transaction endpoint