Use toPrecision to keep precision of float numbers, Added roundedPrice in projection REST server + put await in front of some logs
MODIFY
src/server/rest/v1/service/TransactionService.ts
src/server/rest/v1/service/TransactionService.ts
@@ -471,8 +471,8 @@ export default class TransactionService {
'id', 'chargeBoxID', 'timestamp', 'issuer', 'stateOfCharge', 'timezone', 'connectorId', 'meterStart', 'siteAreaID', 'siteID',
'userID', 'user.id', 'user.name', 'user.firstName', 'user.email', 'tagID',
'currentTotalDurationSecs', 'currentTotalInactivitySecs', 'currentInstantWatts', 'currentTotalConsumptionWh', 'currentStateOfCharge',
- 'stop.price', 'stop.priceUnit', 'stop.inactivityStatus', 'stop.stateOfCharge', 'stop.timestamp', 'stop.totalConsumptionWh',
- 'stop.totalDurationSecs', 'stop.totalInactivitySecs', 'stop.pricingSource', 'stop.roundedPrice',
+ 'stop.roundedPrice', 'stop.price', 'stop.priceUnit', 'stop.inactivityStatus', 'stop.stateOfCharge', 'stop.timestamp', 'stop.totalConsumptionWh',
+ 'stop.totalDurationSecs', 'stop.totalInactivitySecs', 'stop.pricingSource',
'stop.userID', 'stop.user.id', 'stop.user.name', 'stop.user.firstName', 'stop.user.email', 'stop.tagID',
];
// Check Cars
@@ -565,12 +565,12 @@ export default class TransactionService {
// Get Transaction
const transaction = await TransactionStorage.getTransaction(req.user.tenantID, filteredRequest.ID, [
'id', 'chargeBoxID', 'timestamp', 'issuer', 'stateOfCharge', 'tagID', 'timezone', 'connectorId', 'meterStart', 'siteAreaID', 'siteID',
- 'userID', 'user.id', 'user.name', 'user.firstName', 'user.email', 'price', 'priceUnit',
+ 'userID', 'user.id', 'user.name', 'user.firstName', 'user.email', 'roundedPrice', 'price', 'priceUnit',
'stop.userID', 'stop.user.id', 'stop.user.name', 'stop.user.firstName', 'stop.user.email',
'currentTotalDurationSecs', 'currentTotalInactivitySecs', 'currentInstantWatts', 'currentTotalConsumptionWh', 'currentStateOfCharge',
- 'currentCumulatedPrice', 'currentInactivityStatus', 'price', 'roundedPrice', 'signedData',
- 'stop.price', 'stop.priceUnit', 'stop.inactivityStatus', 'stop.stateOfCharge', 'stop.timestamp', 'stop.totalConsumptionWh', 'stop.meterStop',
- 'stop.totalDurationSecs', 'stop.totalInactivitySecs', 'stop.pricingSource', 'stop.roundedPrice', 'stop.signedData', 'stop.tagID', 'tag.description'
+ 'currentCumulatedPrice', 'currentInactivityStatus', 'signedData',
+ 'stop.roundedPrice', 'stop.price', 'stop.priceUnit', 'stop.inactivityStatus', 'stop.stateOfCharge', 'stop.timestamp', 'stop.totalConsumptionWh', 'stop.meterStop',
+ 'stop.totalDurationSecs', 'stop.totalInactivitySecs', 'stop.pricingSource', 'stop.signedData', 'stop.tagID', 'tag.description'
]);
UtilsService.assertObjectExists(action, transaction, `Transaction with ID '${filteredRequest.ID}' does not exist`,
MODULE_NAME, 'handleGetTransaction', req.user);
@@ -606,7 +606,7 @@ export default class TransactionService {
const transactions = await TransactionService.getTransactions(req, action, { completedTransactions: true }, [
'id', 'chargeBoxID', 'timestamp', 'issuer', 'stateOfCharge', 'timezone', 'connectorId', 'meterStart', 'siteAreaID', 'siteID',
'currentTotalDurationSecs', 'currentTotalInactivitySecs', 'currentInstantWatts', 'currentTotalConsumptionWh', 'currentStateOfCharge',
- 'stop.price', 'stop.priceUnit', 'stop.inactivityStatus', 'stop.stateOfCharge', 'stop.timestamp', 'stop.totalConsumptionWh',
+ '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',
]);
res.json(transactions);
@@ -630,7 +630,7 @@ export default class TransactionService {
const transactions = 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', 'price', 'roundedPrice', 'priceUnit', 'tagID',
+ 'currentCumulatedPrice', 'currentInactivityStatus', 'roundedPrice', 'price', 'priceUnit', 'tagID',
]);
res.json(transactions);
next();
@@ -640,7 +640,7 @@ export default class TransactionService {
// Get transaction
const transactions = await TransactionService.getTransactions(req, action, { completedTransactions: true }, [
'id', 'chargeBoxID', 'timestamp', 'issuer', 'stateOfCharge', 'timezone', 'connectorId', 'meterStart', 'siteAreaID', 'siteID',
- 'stop.price', 'stop.priceUnit', 'stop.inactivityStatus', 'stop.stateOfCharge', 'stop.timestamp', 'stop.totalConsumptionWh',
+ '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);
@@ -657,7 +657,7 @@ export default class TransactionService {
const transactions = await TransactionService.getTransactions(req, action, { completedTransactions: true }, [
'id', 'chargeBoxID', 'timestamp', 'issuer', 'stateOfCharge', 'timezone', 'connectorId', 'meterStart', 'siteAreaID', 'siteID',
'refundData.reportId', 'refundData.refundedAt', 'refundData.status',
- 'stop.price', 'stop.priceUnit', 'stop.inactivityStatus', 'stop.stateOfCharge', 'stop.timestamp', 'stop.totalConsumptionWh',
+ 'stop.roundedPrice', 'stop.price', 'stop.priceUnit', 'stop.inactivityStatus', 'stop.stateOfCharge', 'stop.timestamp', 'stop.totalConsumptionWh',
'stop.totalDurationSecs', 'stop.totalInactivitySecs', 'billingData.invoiceID', 'tagID', 'stop.tagID',
]);
res.json(transactions);
@@ -721,7 +721,7 @@ export default class TransactionService {
// Get transaction
return TransactionService.getTransactions(req, ServerAction.TRANSACTIONS_EXPORT, { completedTransactions: true, withTag: true }, [
'id', 'chargeBoxID', 'timestamp', 'issuer', 'stateOfCharge', 'timezone', 'connectorId', 'meterStart', 'siteAreaID', 'siteID',
- 'stop.price', 'stop.priceUnit', 'stop.inactivityStatus', 'stop.stateOfCharge', 'stop.timestamp', 'stop.totalConsumptionWh',
+ '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'
]);
}
@@ -737,7 +737,7 @@ export default class TransactionService {
return await TransactionService.getTransactions(req, ServerAction.TRANSACTIONS_TO_REFUND_EXPORT, { completedTransactions: true }, [
'id', 'chargeBoxID', 'timestamp', 'issuer', 'stateOfCharge', 'timezone', 'connectorId', 'meterStart', 'siteAreaID', 'siteID',
'refundData.reportId', 'refundData.refundedAt', 'refundData.status',
- 'stop.price', 'stop.priceUnit', 'stop.inactivityStatus', 'stop.stateOfCharge', 'stop.timestamp', 'stop.totalConsumptionWh',
+ 'stop.roundedPrice', 'stop.price', 'stop.priceUnit', 'stop.inactivityStatus', 'stop.stateOfCharge', 'stop.timestamp', 'stop.totalConsumptionWh',
'stop.totalDurationSecs', 'stop.totalInactivitySecs', 'billingData.invoiceID', 'tagID', 'stop.tagID',
]);
}
@@ -852,7 +852,7 @@ export default class TransactionService {
csv += (transaction.stop ? Math.round(transaction.stop.totalConsumptionWh ? transaction.stop.totalConsumptionWh / 1000 : 0) : '') + Constants.CSV_SEPARATOR;
csv += (transaction.stop ? Math.round(transaction.stop.totalDurationSecs ? transaction.stop.totalDurationSecs / 60 : 0) : '') + Constants.CSV_SEPARATOR;
csv += (transaction.stop ? Math.round(transaction.stop.totalInactivitySecs ? transaction.stop.totalInactivitySecs / 60 : 0) : '') + Constants.CSV_SEPARATOR;
- csv += (transaction.stop ? Utils.truncTo(transaction.stop.price, 2) : '') + Constants.CSV_SEPARATOR;
+ csv += (transaction.stop ? transaction.stop.roundedPrice : '') + Constants.CSV_SEPARATOR;
csv += (transaction.stop ? transaction.stop.priceUnit : '') + '\r\n';
}
return csv;

MODIFY
src/storage/mongodb/ConsumptionStorage.ts
src/storage/mongodb/ConsumptionStorage.ts
@@ -17,17 +17,6 @@ export default class ConsumptionStorage {
const uniqueTimerID = Logging.traceStart(tenantID, MODULE_NAME, 'saveConsumption');
// Check
await DatabaseUtils.checkTenant(tenantID);
- // Set the ID
- if (!consumptionToSave.id) {
- const timestamp = Utils.convertToDate(consumptionToSave.endedAt);
- if (consumptionToSave.transactionId) {
- consumptionToSave.id = Cypher.hash(`${consumptionToSave.transactionId}~${timestamp.toISOString()}`);
- } else if (consumptionToSave.assetID) {
- consumptionToSave.id = Cypher.hash(`${consumptionToSave.assetID}~${timestamp.toISOString()}`);
- } else {
- throw new Error('Consumption cannot be saved: no Transaction ID or Asset ID provided');
- }
- }
// Build
const consumptionMDB = ConsumptionStorage.buildConsumptionMDB(consumptionToSave);
// Modify
@@ -48,17 +37,6 @@ export default class ConsumptionStorage {
await DatabaseUtils.checkTenant(tenantID);
const consumptionsMDB = [];
for (const consumptionToSave of consumptionsToSave) {
- // Set the ID
- if (!consumptionToSave.id) {
- const timestamp = Utils.convertToDate(consumptionToSave.endedAt);
- if (consumptionToSave.transactionId) {
- consumptionToSave.id = Cypher.hash(`${consumptionToSave.transactionId}~${timestamp.toISOString()}`);
- } else if (consumptionToSave.assetID) {
- consumptionToSave.id = Cypher.hash(`${consumptionToSave.assetID}~${timestamp.toISOString()}`);
- } else {
- throw new Error('Consumption cannot be saved: no Transaction ID or Asset ID provided');
- }
- }
// Build
const consumptionMDB = ConsumptionStorage.buildConsumptionMDB(consumptionToSave);
// Add
@@ -418,6 +396,17 @@ export default class ConsumptionStorage {
}
private static buildConsumptionMDB(consumption: Consumption): any {
+ // Set the ID
+ if (!consumption.id) {
+ const timestamp = Utils.convertToDate(consumption.endedAt);
+ if (consumption.transactionId) {
+ consumption.id = Cypher.hash(`${consumption.transactionId}~${timestamp.toISOString()}`);
+ } else if (consumption.assetID) {
+ consumption.id = Cypher.hash(`${consumption.assetID}~${timestamp.toISOString()}`);
+ } else {
+ throw new Error('Consumption cannot be saved: no Transaction ID or Asset ID provided');
+ }
+ }
return {
_id: consumption.id,
startedAt: Utils.convertToDate(consumption.startedAt),

MODIFY
src/utils/Utils.ts
src/utils/Utils.ts
@@ -479,7 +479,7 @@ export default class Utils {
public static fixJSFloatValue(value: number): number {
// Avoid JS decimal issue on IEEE 754 standard floating points
- return Utils.roundTo(value, 12);
+ return parseFloat(value.toPrecision(15));
}
public static computeSimplePrice(pricePerkWh: number, consumptionWh: number): number {

Use toPrecision to keep precision of float numbers, Added roundedPrice in projection REST server + put await in front of some logs