Factorizer/Cluster ERP WikiCluster ERP Türkçe
Home / Business modules

Explanation

Fleet TCO, telematics, and analytics

How fleet computes total cost of ownership and the renewal ranking, keeps tires and campaigns, ingests telematics counters, and feeds analytics.

This page explains four parts of the fleet module that read across its ledgers. src/cluster_erp/modules/fleet/tco/ computes total cost of ownership (TCO), ranks assets for renewal, and keeps tires, campaigns, and emission factors. src/cluster_erp/modules/fleet/telematics.py ingests counter batches, src/cluster_erp/modules/fleet/analytics_facts.py publishes fleet facts to the analytics module, and src/cluster_erp/modules/fleet/validation.py holds shared input checks.

In short

  • TCO sums what the ledgers recorded over a window of months and divides by the kilometres the odometer moved (src/cluster_erp/modules/fleet/tco/services.py:1-8).
  • The renewal ranking lists active and in-maintenance assets by cost per kilometre, highest first (src/cluster_erp/modules/fleet/tco/services.py:63-91).
  • The telematics feed turns device counters into ordinary reading documents with source telematics (src/cluster_erp/modules/fleet/telematics.py:1-16).
  • Four fact sets go to analytics through the DescribeAnalyticsFacts contract (src/cluster_erp/modules/fleet/analytics_facts.py:300-310, src/cluster_erp/modules/fleet/module.py:338-346).

How it works

Total cost of ownership

GET /tco/assets/{asset_id} and GET /tco/renewal take months between 1 and 120, default 12, and need fleet_asset.read (src/cluster_erp/modules/fleet/tco/routes.py:48-66). For each asset the service adds:

Cost part Rows counted Source
Maintenance total_cost of completed work orders completed in the window src/cluster_erp/modules/fleet/tco/services.py:113-124
Fuel total_cost of verified fuel entries filled in the window src/cluster_erp/modules/fleet/tco/services.py:125-136
Penalties amount of penalties not objected, occurred in the window src/cluster_erp/modules/fleet/tco/services.py:152-164
Compliance amount of completed compliance items completed in the window src/cluster_erp/modules/fleet/tco/services.py:165-177

Kilometres used are the difference between the first and the latest life-to-date value of the odometer meter in the window. Cost per kilometre is the total divided by that difference, quantized to two decimals; with no kilometres it is empty. CO2 is the fuel quantity per fuel type times the emission factor of that type (src/cluster_erp/modules/fleet/tco/services.py:179-226, src/cluster_erp/modules/fleet/tco/services.py:293-325, src/cluster_erp/modules/fleet/tco/services.py:327-360). The renewal board computes all aggregates in a fixed number of grouped queries, not one query set per asset (src/cluster_erp/modules/fleet/tco/services.py:94-98).

Tires, campaigns, and emission factors

  • A tire (FleetTire) is identified by serial number and is in_storage, in_use, or scrapped (src/cluster_erp/modules/fleet/models.py:125, src/cluster_erp/modules/fleet/models.py:705-737). Mount needs a stored tire, an asset, and a free position. Unmount adds the odometer distance since mounting to accumulated_km. Scrap needs a stored tire (src/cluster_erp/modules/fleet/tco/services.py:439-521, src/cluster_erp/modules/fleet/tco/metadata.py:77-113).
  • A campaign (FleetCampaign) lists assets that need the same work, for example a recall. A campaign item can open one work order or be marked done; a closed campaign takes no new assets (src/cluster_erp/modules/fleet/tco/services.py:617-760, src/cluster_erp/modules/fleet/tco/metadata.py:287-427).
  • An emission factor (FleetEmissionFactor) gives kilograms of CO2 per unit of one fuel type, unique among live rows. The table starts empty and the organisation fills it; the code comment states that the module computes a report and never a certification (src/cluster_erp/modules/fleet/models.py:773-789).

Telematics feed

flowchart LR
 A["POST /telematics/feed rows"] --> B{"reading_at has offset"}
 B -->|no| R1["rejected"]
 B -->|yes| C["asset by telematics_device_id"]
 C -->|none| U["unmatched"]
 C -->|found| D["odometer_km and engine_hours targets"]
 D -->|none| R2["rejected"]
 D --> E["FleetReadingService.create source telematics"]
 E -->|all landed| OK["accepted"]
 E -->|some landed| P["partial"]
 E -->|none landed| R3["rejected"]

In prose: POST /telematics/feed takes 1 to 1000 rows, each with a device id, a time, and optional odometer and engine hour values (src/cluster_erp/modules/fleet/telematics.py:40-57). A row without a UTC offset is rejected. The device id resolves to a live asset through telematics_device_id; a row without a match is reported as unmatched. Each counter value becomes a reading on the meter of the same kind, so the normal ledger rules apply. The row lands in exactly one bucket: accepted, partial, unmatched, or rejected, with reasons (src/cluster_erp/modules/fleet/telematics.py:58-148).

Analytics fact sets

Fact set Source table Dimensions Measures Source
fleet_fuel fleet_fuel_entries asset, fuel type, entry source, match status, consumption alert, non-UTTS risk, fill date fill count, total litres, total fuel cost, average consumption (non-additive) src/cluster_erp/modules/fleet/analytics_facts.py:35-118
fleet_work_order fleet_work_orders asset, status, priority, external flag, completion date order count, total, labour, parts, and external cost src/cluster_erp/modules/fleet/analytics_facts.py:120-195
fleet_penalty fleet_penalties asset, kind, status, driver, occurrence date penalty count, total amount src/cluster_erp/modules/fleet/analytics_facts.py:197-249
fleet_compliance fleet_compliance_items asset, kind, status, due date item count, total amount src/cluster_erp/modules/fleet/analytics_facts.py:251-299

Every fact set is read with fleet_asset.read and filters out rows with deleted_at set (src/cluster_erp/modules/fleet/analytics_facts.py:116-117). The date dimensions offer the grains day, week, month, quarter, and year (src/cluster_erp/modules/fleet/analytics_facts.py:24).

Shared validators

require_tz refuses a datetime without a UTC offset, and scrub_blank_strings turns blank strings into empty values before validation (src/cluster_erp/modules/fleet/validation.py:15-37).

Why it is built this way

  • The docstring of analytics_facts.py keeps cost per kilometre and CO2 out of analytics, because a ratio of two aggregates is not an additive measure (src/cluster_erp/modules/fleet/analytics_facts.py:1-11).
  • The telematics docstring states that no raw GPS traces or positions are stored, because the retention question for that data is an open decision of the product owner (src/cluster_erp/modules/fleet/telematics.py:11-15).
  • validation.py states that a naive datetime would crash the comparison with aware values, and that guessing a time zone for the caller is forbidden (src/cluster_erp/modules/fleet/validation.py:1-8).

Rules and boundaries

  • The renewal ranking puts assets without a cost per kilometre at the end (src/cluster_erp/modules/fleet/tco/services.py:85-90).
  • The telematics feed needs fleet_asset.update (src/cluster_erp/modules/fleet/telematics.py:55).
  • A tire cannot be mounted at a position that already holds a mounted tire on the same asset (src/cluster_erp/modules/fleet/tco/services.py:439-487).

Interaction with other parts

Contract Direction Purpose Source
DescribeAnalyticsFacts fleet answers returns the four fact sets src/cluster_erp/modules/fleet/module.py:338-346
AnalyticsFactSet, AnalyticsDimension, AnalyticsMeasure fleet builds the fact set definitions src/cluster_erp/modules/fleet/analytics_facts.py:18-22

How analytics collects these answers is on analytics facts. The contract list is on the contracts reference.

Limits and open points

  • TCO sums total_cost, amount, and fuel cost columns without reading their currency columns (src/cluster_erp/modules/fleet/tco/services.py:113-177, src/cluster_erp/modules/fleet/models.py:409). The fleet fact sets have no currency dimension (src/cluster_erp/modules/fleet/analytics_facts.py:35-299).
  • Acquisition value is not part of TCO; the summed parts are maintenance, fuel, penalties, and compliance (src/cluster_erp/modules/fleet/tco/services.py:293).
  • Readings created from inspections and reservations carry the source form, one of the values in FLEET_READING_SOURCES (src/cluster_erp/modules/fleet/operations/services.py:494, src/cluster_erp/modules/fleet/models.py:61-62).

Terms introduced

Term Code identifier Definition Turkish term Source
total cost of ownership FleetTcoService The recorded costs of an asset over a window, also per kilometre and as CO2. Toplam sahip olma maliyeti src/cluster_erp/modules/fleet/tco/services.py:55
renewal ranking FleetTcoService.renewal Active assets ordered by cost per kilometre, highest first. Yenileme sıralaması src/cluster_erp/modules/fleet/tco/services.py:63
emission factor FleetEmissionFactor Kilograms of CO2 per unit of one fuel type, entered by the organisation. Emisyon katsayısı src/cluster_erp/modules/fleet/models.py:773
telematics feed ingest_feed The batch endpoint that turns device counters into readings. Telematik beslemesi src/cluster_erp/modules/fleet/telematics.py:52-53

Verified against commit 92f8051 on 2026-11-13.

Verified against commit 92f8051 · 2026-11-13