pricing - stop meter value was not priced anymore
MODIFY
src/integration/billing/stripe/StripeBillingIntegration.ts
src/integration/billing/stripe/StripeBillingIntegration.ts
@@ -946,22 +946,19 @@ export default class StripeBillingIntegration extends BillingIntegration {
status: transaction.billingData?.stop?.status
};
}
+ if (transaction.billingData?.stop?.status === BillingStatus.UNBILLED) {
+ // Make sure to preserve the decision made during the STOP transaction
+ return {
+ status: BillingStatus.UNBILLED
+ };
+ }
if (!transaction.stop?.extraInactivityComputed) {
await Logging.logWarning({
tenantID: this.tenant.id,
action: ServerAction.BILLING_TRANSACTION,
module: MODULE_NAME, method: 'endTransaction',
- message: 'Operation aborted - unexpected situation - the extra inactivity is not yet known'
+ message: 'Unexpected situation - end transaction is being called while the extra inactivity is not yet known'
});
- return {
- status: transaction.billingData?.stop?.status
- };
- }
- if (transaction.billingData?.stop?.status === BillingStatus.UNBILLED) {
- // Make sure to preserve the decision made during the STOP transaction
- return {
- status: BillingStatus.UNBILLED
- };
}
// Create and Save async task
await AsyncTaskBuilder.createAndSaveAsyncTasks({

MODIFY
src/integration/pricing/PricingIntegration.ts
src/integration/pricing/PricingIntegration.ts
@@ -23,4 +23,6 @@ export default abstract class PricingIntegration<T extends PricingSetting> {
public abstract updateSession(transaction: Transaction, consumptionData: Consumption, chargingStation?: ChargingStation): Promise<PricedConsumption>;
public abstract stopSession(transaction: Transaction, consumptionData: Consumption, chargingStation?: ChargingStation): Promise<PricedConsumption>;
+
+ public abstract endSession(transaction: Transaction, consumptionData: Consumption, chargingStation?: ChargingStation): Promise<PricedConsumption>;
}

MODIFY
src/integration/pricing/sap-convergent-charging/SapConvergentChargingPricingIntegration.ts
src/integration/pricing/sap-convergent-charging/SapConvergentChargingPricingIntegration.ts
@@ -112,6 +112,32 @@ export default class SapConvergentChargingPricingIntegration extends PricingInte
}
public async stopSession(transaction: Transaction, consumptionData: Consumption): Promise<PricedConsumption> {
+ await this.initConnection();
+ const siteArea = await SiteAreaStorage.getSiteArea(this.tenant, transaction.siteAreaID);
+ const sessionId = this.computeSessionId(transaction, consumptionData);
+ const chargeableItemProperties = this.consumptionToChargeableItemProperties(transaction, consumptionData);
+ chargeableItemProperties.push(new ChargeableItemProperty('status', Type.string, 'end'));
+ const confirmationItem = new ConfirmationItem(this.setting.chargeableItemName, chargeableItemProperties);
+ const request = new StopRateRequest(confirmationItem, sessionId, siteArea.name, consumptionData.userID, 'confirmed',
+ 'ALL_TRANSACTION_AND_RECURRING', false, 'ALL_TRANSACTION_AND_RECURRING');
+ const result = await this.statefulChargingService.execute(request);
+ if (result.data.stopRateResult) {
+ const rateResult = new RateResult(result.data.stopRateResult);
+ await this.handleAlertNotification(transaction, consumptionData, rateResult);
+ return {
+ roundedAmount: rateResult.amountToConfirm,
+ cumulatedAmount: rateResult.accumulatedAmount,
+ cumulatedRoundedAmount: Utils.truncTo(rateResult.accumulatedAmount, 2),
+ currencyCode: rateResult.transactionsToConfirm.getCurrencyCode(),
+ amount: rateResult.transactionsToConfirm.getTotalUnroundedAmount(),
+ pricingSource: PricingSource.CONVERGENT_CHARGING
+ };
+ }
+ await this.handleError(transaction, ServerAction.UPDATE_TRANSACTION, consumptionData, result);
+ return null;
+ }
+
+ public async endSession(transaction: Transaction, consumptionData: Consumption): Promise<PricedConsumption> {
await this.initConnection();
const siteArea = await SiteAreaStorage.getSiteArea(this.tenant, transaction.siteAreaID);
const sessionId = this.computeSessionId(transaction, consumptionData);

MODIFY
src/integration/pricing/simple-pricing/BuiltInPricingIntegration.ts
src/integration/pricing/simple-pricing/BuiltInPricingIntegration.ts
@@ -53,6 +53,20 @@ export default class BuiltInPricingIntegration extends PricingIntegration<Simple
return pricedConsumption;
}
+ public async endSession(transaction: Transaction, consumptionData: Consumption, chargingStation: ChargingStation): Promise<PricedConsumption> {
+ const pricedConsumption = await this.computePrice(transaction, consumptionData, chargingStation);
+ await Logging.logInfo({
+ tenantID: this.tenant.id,
+ module: MODULE_NAME,
+ action: ServerAction.PRICING,
+ method: 'endSession',
+ message: `Session END - Transaction: ${transaction.id} - Accumulated amount: ${pricedConsumption.cumulatedRoundedAmount} ${pricedConsumption.currencyCode}`,
+ detailedMessages: { pricedConsumption },
+ ...LoggingHelper.getTransactionProperties(transaction)
+ });
+ return pricedConsumption;
+ }
+
private async computePrice(transaction: Transaction, consumptionData: Consumption, chargingStation: ChargingStation): Promise<PricedConsumption> {
let pricingModel = transaction.pricingModel;
if (!pricingModel) {

MODIFY
src/server/ocpp/utils/OCPPUtils.ts
src/server/ocpp/utils/OCPPUtils.ts
@@ -287,22 +287,24 @@ export default class OCPPUtils {
case TransactionAction.UPDATE:
// Set
pricedConsumption = await pricingImpl.updateSession(transaction, consumption, chargingStation);
- if (pricedConsumption) {
- // Update consumption
- consumption.amount = pricedConsumption.amount;
- consumption.roundedAmount = pricedConsumption.roundedAmount;
- consumption.currencyCode = pricedConsumption.currencyCode;
- consumption.pricingSource = pricedConsumption.pricingSource;
- consumption.cumulatedAmount = pricedConsumption.cumulatedAmount;
- transaction.currentCumulatedPrice = consumption.cumulatedAmount;
- transaction.currentCumulatedRoundedPrice = pricedConsumption.cumulatedRoundedAmount;
- }
+ OCPPUtils.updateCumulatedAmounts(transaction, consumption, pricedConsumption);
break;
// Stop, End Transaction
case TransactionAction.STOP:
- case TransactionAction.END:
// Set
pricedConsumption = await pricingImpl.stopSession(transaction, consumption, chargingStation);
+ OCPPUtils.updateCumulatedAmounts(transaction, consumption, pricedConsumption);
+ break;
+ case TransactionAction.END:
+ // Set
+ pricedConsumption = await pricingImpl.endSession(transaction, consumption, chargingStation);
+ OCPPUtils.updateCumulatedAmounts(transaction, consumption, pricedConsumption);
+ break;
+ }
+ }
+ }
+
+ public static updateCumulatedAmounts(transaction: Transaction, consumption: Consumption, pricedConsumption: PricedConsumption): void {
if (pricedConsumption) {
// Update consumption
consumption.amount = pricedConsumption.amount;
@@ -310,12 +312,10 @@ export default class OCPPUtils {
consumption.currencyCode = pricedConsumption.currencyCode;
consumption.pricingSource = pricedConsumption.pricingSource;
consumption.cumulatedAmount = pricedConsumption.cumulatedAmount;
+ // Update transaction
transaction.currentCumulatedPrice = consumption.cumulatedAmount;
transaction.currentCumulatedRoundedPrice = pricedConsumption.cumulatedRoundedAmount;
}
- break;
- }
- }
}
public static async processTransactionBilling(tenant: Tenant, transaction: Transaction, action: TransactionAction): Promise<void> {

MODIFY
test/api/BillingTest.ts
test/api/BillingTest.ts
@@ -703,7 +703,7 @@ describe('Billing', function() {
const transactionID = await billingTestHelper.generateTransaction(billingTestHelper.userContext);
assert(transactionID, 'transactionID should not be null');
// Check that we have a new invoice with an invoiceID and an invoiceNumber
- await billingTestHelper.checkTransactionBillingData(transactionID, BillingInvoiceStatus.PAID, 11.32);
+ await billingTestHelper.checkTransactionBillingData(transactionID, BillingInvoiceStatus.PAID, 11.49);
});
it('should bill the CT(STEP)+PT(STEP) on COMBO CCS - DC', async () => {
@@ -740,7 +740,7 @@ describe('Billing', function() {
const transactionID = await billingTestHelper.generateTransaction(billingTestHelper.userContext);
assert(transactionID, 'transactionID should not be null');
// Check that we have a new invoice with an invoiceID and an invoiceNumber
- await billingTestHelper.checkTransactionBillingData(transactionID, BillingInvoiceStatus.PAID, 34.30);
+ await billingTestHelper.checkTransactionBillingData(transactionID, BillingInvoiceStatus.PAID, 34.63);
});
it('should bill the FF+E(STEP)+E(STEP) with 2 tariffs on COMBO CCS - DC', async () => {

pricing - stop meter value was not priced anymore