pricing - price time on individual consumption
ADD
src/assets/configs-scp
+Subproject commit cf40aecc4b7c099f6b5b8bc6690f975a6db006b6

MODIFY
src/integration/pricing/PricingEngine.ts
src/integration/pricing/PricingEngine.ts
@@ -210,24 +210,87 @@ export default class PricingEngine {
const activePricingDefinition = PricingEngine.getActiveDefinition4Dimension(pricingDefinitions, DimensionType.PARKING_TIME);
if (activePricingDefinition) {
const dimensionToPrice = activePricingDefinition.dimensions.parkingTime;
+ if (FeatureToggles.isFeatureActive(Feature.PRICING_PRICE_ACCUMULATED_TIME)) {
const pricedData = PricingEngine.priceTimeBasedDimension(dimensionToPrice, consumptionData?.totalInactivitySecs || 0);
if (pricedData) {
pricedData.sourceName = activePricingDefinition.name;
}
return pricedData;
}
+ const pricedData = PricingEngine.priceParkingTimeDimension(dimensionToPrice, consumptionData);
+ if (pricedData) {
+ pricedData.sourceName = activePricingDefinition.name;
+ }
+ return pricedData;
+ }
+ }
+
+ private static priceParkingTimeDimension(pricingDimension: PricingDimension, consumptionData: Consumption): PricedDimensionData {
+ const cumulatedConsumptionDataWh = consumptionData?.cumulatedConsumptionWh || 0;
+ const consumptionWh = consumptionData?.consumptionWh || 0;
+
+ // Price the parking time only after having charged - NOT during the warmup!
+ if (cumulatedConsumptionDataWh > 0 && consumptionWh <= 0) {
+ const seconds = moment(consumptionData.endedAt).diff(moment(consumptionData.startedAt), 'seconds');
+ if (seconds > 0) {
+ return this.priceTimeDimension(pricingDimension, seconds);
+ }
+ }
+ }
+
+ private static priceTimeDimension(pricingDimension: PricingDimension, seconds: number): PricedDimensionData {
+ const unitPrice = pricingDimension.price || 0;
+ const amount = Utils.createDecimal(unitPrice).times(seconds).div(3600).toNumber();
+ const hours = Utils.createDecimal(seconds).div(3600).toNumber();
+ // Price the consumption
+ const pricedData: PricedDimensionData = {
+ unitPrice: unitPrice,
+ amount,
+ roundedAmount: Utils.truncTo(amount, 2),
+ quantity: hours
+ };
+ // Add the consumption to the previous data (if any) - for the billing
+ const previousData = pricingDimension.pricedData;
+ if (previousData) {
+ previousData.amount += pricedData.amount;
+ previousData.quantity += pricedData.quantity;
+ previousData.roundedAmount = Utils.truncTo(previousData.amount, 2);
+ } else {
+ pricingDimension.pricedData = pricedData;
+ }
+ // Return the current consumption!
+ return pricedData;
}
private static priceChargingTimeConsumption(pricingDefinitions: PricingDefinition[], consumptionData: Consumption): PricedDimensionData {
const activePricingDefinition = PricingEngine.getActiveDefinition4Dimension(pricingDefinitions, DimensionType.CHARGING_TIME);
if (activePricingDefinition) {
const dimensionToPrice = activePricingDefinition.dimensions.chargingTime;
+ if (FeatureToggles.isFeatureActive(Feature.PRICING_PRICE_ACCUMULATED_TIME)) {
const pricedData = PricingEngine.priceTimeBasedDimension(dimensionToPrice, consumptionData?.totalDurationSecs || 0);
if (pricedData) {
pricedData.sourceName = activePricingDefinition.name;
}
return pricedData;
}
+ const pricedData = PricingEngine.priceChargingTimeDimension(dimensionToPrice, consumptionData);
+ if (pricedData) {
+ pricedData.sourceName = activePricingDefinition.name;
+ }
+ return pricedData;
+ }
+ }
+
+ private static priceChargingTimeDimension(pricingDimension: PricingDimension, consumptionData: Consumption): PricedDimensionData {
+ const consumptionWh = consumptionData?.consumptionWh || 0;
+
+ if (consumptionWh > 0) {
+ // Price the charging time only when charging!
+ const seconds = moment(consumptionData.endedAt).diff(moment(consumptionData.startedAt), 'seconds');
+ if (seconds > 0) {
+ return this.priceTimeDimension(pricingDimension, seconds);
+ }
+ }
}
static getActiveDefinition4Dimension(actualPricingDefinitions: PricingDefinition[], dimensionType: string): PricingDefinition {

ADD
src/integration/pricing/convergent-charging
+Subproject commit 4405625475de34c7348cff23d65f378feeea428f

ADD
src/integration/refund/concur
+Subproject commit 0efb7d5ebb4d5fa021fe675b47744c7c23fb79ba

MODIFY
src/utils/FeatureToggles.ts
src/utils/FeatureToggles.ts
@@ -6,6 +6,7 @@ export enum Feature {
BILLING_PREVENT_CUSTOMER_DELETION,
PRICING_NEW_MODEL,
PRICING_PRICE_ACCUMULATED_WH,
+ PRICING_PRICE_ACCUMULATED_TIME,
PRICING_TEST_PARKING_TIME,
PRICING_TEST_ENERGY_WITH_STEP_SIZE,
PRICING_WITH_RESTRICTION_CHECKS,
@@ -19,7 +20,8 @@ export default class FeatureToggles {
Feature.BILLING_PREVENT_CUSTOMER_DELETION,
Feature.PRICING_NEW_MODEL,
Feature.PRICING_WITH_RESTRICTION_CHECKS,
- Feature.PRICING_PRICE_ACCUMULATED_WH,
+ // Feature.PRICING_PRICE_ACCUMULATED_WH,
+ // Feature.PRICING_PRICE_ACCUMULATED_TIME,
// Feature.PRICING_TEST_PARKING_TIME
// Feature.PRICING_TEST_ENERGY_WITH_STEP_SIZE
];

MODIFY
test/api/BillingTest.ts
test/api/BillingTest.ts
@@ -159,6 +159,10 @@ class TestData {
chargingTime: {
price: 5, // Euro per hour
active: true
+ },
+ parkingTime: {
+ price: 10, // Euro per hour
+ active: true
}
};
} else {

pricing - price time on individual consumption