Sixième Étoile — Documentation

Cost Model

Fuel resolution chain (CollectAPI → FuelPriceCache → default), toll resolution (Google Routes → TollGuru → estimate), the CostBreakdown structure, and RSE compliance staffing costs.

The cost model feeds TripAnalysis.costBreakdown — a per-segment breakdown used to compute the internal cost, margin, and ProfitabilityIndicator displayed in the back-office. None of the cost components are directly added to the client-facing price; they exist for profitability analysis only.

CostBreakdown Structure

interface CostBreakdown {
  fuel:          FuelCostComponent;
  tolls:         TollCostComponent;
  wear:          WearCostComponent;
  driver:        DriverCostComponent;
  parking:       ParkingCostComponent;
  zoneSurcharges?: ZoneSurcharges;
  tco?:          TcoCostComponent;  // TCO if vehicle data available
  total:         number;
}

total = fuel + tolls + wear + driver + parking. Zone surcharges and TCO are additive when present.


Fuel Cost

Fuel price resolution chain

The engine resolves the price per liter in this order, stopping at the first available result:

PrioritySourceMechanism
1CollectAPI (real-time)HTTP request to CollectAPI with GPS coordinates; returns prices per country/region
2FuelPriceCache (database)Most recent FuelPriceCache row for the resolved country; stale after 48 h
3Organization overrideOrganizationPricingSettings.fuelPricePerLiter
4Built-in defaultsDEFAULT_FUEL_PRICES in constants.ts

Default fuel prices:

Fuel typeDefault (€/L)
DIESEL1.789
GASOLINE1.899
LPG0.999
ELECTRIC0.25

CollectAPI timeout: 4 000 ms (REALTIME_API_TIMEOUT_MS). A cache hit with less than 48 hours of age satisfies the request without an API call. The per-request in-memory cache (TTL 60 s) prevents duplicate calls within a single pricing calculation for multi-waypoint excursions.

Fuel consumption resolution chain

The liters-per-100-km figure resolves via a separate four-level chain:

PrioritySource
1Vehicle.fuelConsumption (specific vehicle, if assigned)
2VehicleCategory.fuelConsumption
3OrganizationPricingSettings.fuelConsumptionL100km
4Built-in default: 8.0 L/100 km

Fuel cost formula

litersUsed = (distanceKm / 100) × consumptionL100km
fuelCost   = litersUsed × pricePerLiter

Toll Cost

Toll resolution chain

PrioritySourceNotes
1Google Routes APIParses travelAdvisory.tollInfo.estimatedPrice from the v2 response
2TollGuru APIFallback when Google returns no toll data; uses vehicle-category toll class, height, and axle metadata
3Flat rate estimatedistanceKm × tollCostPerKm (default 0.15 €/km)

Toll results are cached in the TollCalculationCache table for 24 hours. Cache keys must include route coordinates plus the vehicle-class metadata (tollClass, vehicleHeightCm, axleCount) so a light sedan never reuses a coach toll estimate. TollCostComponent.isFromCache flags cache hits.

For ELECTRIC fuel type, the engine remaps to GASOLINE for the Google Routes API (which may not return toll data for electric vehicles).

Approach and empty-return legs are priced with the same toll pipeline as the client service leg when those legs have route geometry. If Google/HERE/TollGuru cannot return a route, the engine falls back to the Haversine estimate rather than dropping the cost component.

Toll cost formula (fallback only)

tollCost = distanceKm × tollCostPerKm

Wear Cost

Vehicle mechanical wear modeled as a flat rate per km:

wearCost = distanceKm × wearCostPerKm

Default: 0.10 €/km (DEFAULT_COST_PARAMETERS.wearCostPerKm). Overridden by OrganizationPricingSettings.wearCostPerKm.


Driver Cost

Driver time valued at an hourly rate:

driverCost = (durationMinutes / 60) × driverHourlyCost

Default: 25.00 €/h (DEFAULT_COST_PARAMETERS.driverHourlyCost). Overridden by OrganizationPricingSettings.driverHourlyCost.

For HEAVY vehicles with RSE mandatory breaks, the extra break minutes are included in the totalDurationMinutes fed into the driver cost calculation.


TCO (Total Cost of Ownership)

When full vehicle and category TCO data is available, a TcoCostComponent is added:

interface TcoCostComponent {
  amount: number;
  distanceKm: number;
  depreciation: { amount: number; ratePerKm: number; method: "LINEAR" | "DECLINING_BALANCE" };
  maintenance:  { amount: number; ratePerKm: number };
  insurance:    { amount: number; ratePerKm: number };
  totalRatePerKm: number;
  source: "VEHICLE" | "CATEGORY";
}

TCO complements the wear cost; when TCO is present, tco.total provides a more accurate amortisation figure than the flat wearCostPerKm rate.


Zone Surcharges

Fixed surcharges defined per zone are collected after route resolution:

interface ZoneSurcharges {
  pickup:  ZoneSurchargeComponent | null;
  dropoff: ZoneSurchargeComponent | null;
  total:   number;
}

Each ZoneSurchargeComponent aggregates parkingSurcharge + accessFee for the zone. If pickup and dropoff resolve to the same zone, the surcharge is counted only once.


RSE Compliance Staffing Costs

When integrateComplianceIntoPricing() detects a long-distance, same-day, relay, double-crew, or multi-day requirement, it attaches a CompliancePlan to TripAnalysis:

Plan typeTriggerCost impact
DOUBLE_CREWTrip exceeds single-driver daily hours limitSecond driver cost added to totalInternalCost
RELAY_DRIVERLong-haul trip requiring driver relayRelay positioning cost added
MULTI_DAYTrip spans multiple calendar daysDriver accommodation + per-diem costs added
NONENo compliance issueNo extra cost

The engine now resolves staffing through a single computeStaffing() path parameterized by an RSE mode profile:

Mode profileTypical trip shapeNotes
TRANSFEROne-way serviceDefault one-way aggregation
ROUND_TRIPSame quote with return legUses round-trip decomposition and waiting time
MULTI_STOPWaypoints / multi-stop routingAggregates cumulated service segments
MADMise à dispositionContinuous amplitude profile
SEJOURMulti-day stayCounts day-by-day RSE, feeds real counters, and never offers relay/double choice cards

The staffing plan selection policy is configurable (OrganizationPricingSettings.staffingSelectionPolicy) and operator choices can override the automatic plan when the cockpit sends a staffingOverride:

PolicyBehaviour
CHEAPESTSelects the staffing arrangement with the lowest total cost
FASTESTMinimises total trip duration
PREFER_INTERNALPrefers internal drivers over external relay drivers

Staffing costs inflate TripAnalysis.totalInternalCost and are also folded into the recommended quote price when the returned plan carries an additionalCost. The cost breakdown itself remains operator-internal; agency responses receive only reduced feasibility/crew information.

Relay plans use a frozen sharePercent split. The default comes from OrganizationLicenseRule.defaultRelaySharePercent, and explicit operator overrides are clamped to an exclusive 199 percent range. Accepted quotes persist the split into StaffingPlan / StaffingAssignment so dispatch does not recompute it.


Profitability Indicator

type ProfitabilityIndicator = "green" | "orange" | "red";

// Thresholds (configurable):
//   green:  marginPercent ≥ greenMarginThreshold  (default 20 %)
//   orange: marginPercent ≥ orangeMarginThreshold (default 0 %)
//   red:    marginPercent < orangeMarginThreshold
marginPercent = ((price - internalCost) / price) × 100

Both greenMarginThreshold and orangeMarginThreshold are configurable in OrganizationPricingSettings.


Short-trip pricing

Below shortTripThresholdKm (configurable), the engine applies a shortTripMultiplier to offset the fixed overhead costs per trip. A minimumTripPriceHt floor can also be set to guarantee a minimum revenue.

FieldEffect
minimumTripPriceHtPrice floor (HT) regardless of formula result
shortTripThresholdKmDistance below which the short-trip multiplier applies
shortTripMultiplierFactor applied to base price for short trips

See also

Was this page helpful?

On this page