feat: travel calculation (km, CO2, frais réels fiscaux)
This commit is contained in:
25
app/business/travel_calc.py
Normal file
25
app/business/travel_calc.py
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
def compute_km_for_entry(journey_profile_id: str | None, journeys: dict) -> dict[str, int]:
|
||||||
|
if not journey_profile_id:
|
||||||
|
return {}
|
||||||
|
profile = journeys.get(journey_profile_id, {})
|
||||||
|
return dict(profile.get("distances", {}))
|
||||||
|
|
||||||
|
|
||||||
|
def compute_co2_grams(km_by_vehicle: dict[str, int], vehicles: dict) -> float:
|
||||||
|
total = 0.0
|
||||||
|
for vehicle_id, km in km_by_vehicle.items():
|
||||||
|
vehicle = vehicles.get(vehicle_id, {})
|
||||||
|
co2 = vehicle.get("co2_per_km", 0)
|
||||||
|
total += km * co2
|
||||||
|
return total
|
||||||
|
|
||||||
|
|
||||||
|
def compute_frais_reels(total_km_voiture: float, tranches: list[dict]) -> float:
|
||||||
|
if not tranches or total_km_voiture <= 0:
|
||||||
|
return 0.0
|
||||||
|
for tranche in tranches:
|
||||||
|
km_max = tranche["km_max"]
|
||||||
|
if km_max == 0 or total_km_voiture <= km_max:
|
||||||
|
return total_km_voiture * tranche["taux"] + tranche.get("forfait", 0)
|
||||||
|
last = tranches[-1]
|
||||||
|
return total_km_voiture * last["taux"] + last.get("forfait", 0)
|
||||||
57
tests/test_travel_calc.py
Normal file
57
tests/test_travel_calc.py
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
from app.business.travel_calc import (
|
||||||
|
compute_km_for_entry,
|
||||||
|
compute_co2_grams,
|
||||||
|
compute_frais_reels,
|
||||||
|
)
|
||||||
|
|
||||||
|
VEHICLES = {
|
||||||
|
"voiture": {"co2_per_km": 142, "cv": 5},
|
||||||
|
"velo": {"co2_per_km": 0},
|
||||||
|
}
|
||||||
|
|
||||||
|
JOURNEYS = {
|
||||||
|
"voiture_seule": {"distances": {"voiture": 25}},
|
||||||
|
"voiture_velo": {"distances": {"voiture": 14, "velo": 8}},
|
||||||
|
"velo_seul": {"distances": {"velo": 24}},
|
||||||
|
}
|
||||||
|
|
||||||
|
TRANCHES_CV5 = [
|
||||||
|
{"km_max": 3000, "taux": 0.548, "forfait": 0},
|
||||||
|
{"km_max": 6000, "taux": 0.316, "forfait": 699},
|
||||||
|
{"km_max": 0, "taux": 0.364, "forfait": 0},
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def test_compute_km_voiture_seule():
|
||||||
|
assert compute_km_for_entry("voiture_seule", JOURNEYS) == {"voiture": 25}
|
||||||
|
|
||||||
|
|
||||||
|
def test_compute_km_voiture_velo():
|
||||||
|
assert compute_km_for_entry("voiture_velo", JOURNEYS) == {"voiture": 14, "velo": 8}
|
||||||
|
|
||||||
|
|
||||||
|
def test_compute_km_no_journey():
|
||||||
|
assert compute_km_for_entry(None, JOURNEYS) == {}
|
||||||
|
|
||||||
|
|
||||||
|
def test_compute_co2_voiture():
|
||||||
|
assert compute_co2_grams({"voiture": 25}, VEHICLES) == 25 * 142
|
||||||
|
|
||||||
|
|
||||||
|
def test_compute_co2_velo():
|
||||||
|
assert compute_co2_grams({"velo": 24}, VEHICLES) == 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_frais_reels_tranche1():
|
||||||
|
result = compute_frais_reels(2000, TRANCHES_CV5)
|
||||||
|
assert abs(result - 1096.0) < 0.01
|
||||||
|
|
||||||
|
|
||||||
|
def test_frais_reels_tranche2():
|
||||||
|
result = compute_frais_reels(4000, TRANCHES_CV5)
|
||||||
|
assert abs(result - 1963.0) < 0.01
|
||||||
|
|
||||||
|
|
||||||
|
def test_frais_reels_tranche3():
|
||||||
|
result = compute_frais_reels(7000, TRANCHES_CV5)
|
||||||
|
assert abs(result - 2548.0) < 0.01
|
||||||
Reference in New Issue
Block a user