diff --git a/app/models.py b/app/models.py index 0520e1c..d45cd58 100644 --- a/app/models.py +++ b/app/models.py @@ -174,6 +174,9 @@ class Vehicle(db.Model): # Tracking unit (mileage or hours) tracking_unit = db.Column(db.String(20), default='mileage') # mileage, hours + # Per-vehicle odometer unit override (if None, falls back to user's distance_unit) + odometer_unit = db.Column(db.String(10), default=None) # km, mi, or None (use user preference) + # Fuel info fuel_type = db.Column(db.String(20), default='petrol') # petrol, diesel, electric, hybrid, lpg tank_capacity = db.Column(db.Float) # in liters @@ -219,6 +222,18 @@ class Vehicle(db.Model): charging_sessions = db.relationship('ChargingSession', backref='vehicle', lazy='dynamic', cascade='all, delete-orphan') + def get_effective_odometer_unit(self): + """Return the odometer unit for this vehicle. + + Uses the vehicle's own odometer_unit if set, otherwise falls back to + the owner's distance_unit preference. + """ + if self.odometer_unit: + return self.odometer_unit + if self.owner: + return self.owner.distance_unit + return 'km' + def get_total_fuel_cost(self): return sum(log.total_cost for log in self.fuel_logs.all() if log.total_cost) @@ -644,6 +659,12 @@ def get_all_branding(): ('hours', 'Hours'), ] +# Odometer unit options (for per-vehicle override) +ODOMETER_UNITS = [ + ('km', 'Kilometres (km)'), + ('mi', 'Miles (mi)'), +] + # Fuel types FUEL_TYPES = [ ('petrol', 'Petrol/Gasoline'), diff --git a/app/routes/api.py b/app/routes/api.py index bec9cab..f434977 100644 --- a/app/routes/api.py +++ b/app/routes/api.py @@ -295,7 +295,7 @@ def vehicle_stats(vehicle_id): 'expenses_by_category': category_totals, 'total_fuel_cost': vehicle.get_total_fuel_cost(), 'total_expense_cost': vehicle.get_total_expense_cost(), - 'total_distance': vehicle.get_total_distance(current_user.distance_unit), + 'total_distance': vehicle.get_total_distance(vehicle.get_effective_odometer_unit()), 'avg_consumption': vehicle.get_average_consumption() }) diff --git a/app/routes/main.py b/app/routes/main.py index 0891655..1ebf5bd 100644 --- a/app/routes/main.py +++ b/app/routes/main.py @@ -73,7 +73,7 @@ def dashboard(): ).scalar() total_expense_cost = expense_result or 0 - # Total distance + # Total distance (uses user's distance_unit for Tessie conversion; raw logs are in their stored unit) for vehicle in vehicles: total_distance += vehicle.get_total_distance(current_user.distance_unit) diff --git a/app/routes/stations.py b/app/routes/stations.py index d822374..fd9a8dc 100644 --- a/app/routes/stations.py +++ b/app/routes/stations.py @@ -134,11 +134,21 @@ def price_history(station_id): station = FuelStation.query.get_or_404(station_id) # Get price history ordered by date - prices = FuelPriceHistory.query.filter_by(station_id=station_id).order_by( + price_records = FuelPriceHistory.query.filter_by(station_id=station_id).order_by( FuelPriceHistory.date.desc() ).limit(50).all() - return render_template('stations/prices.html', station=station, prices=prices) + prices = price_records + prices_json = [ + { + 'date': p.date.isoformat() if p.date else None, + 'fuel_type': p.fuel_type, + 'price_per_unit': p.price_per_unit, + } + for p in price_records + ] + + return render_template('stations/prices.html', station=station, prices=prices, prices_json=prices_json) @bp.route('/cheapest') diff --git a/app/routes/vehicles.py b/app/routes/vehicles.py index 222737f..a192320 100644 --- a/app/routes/vehicles.py +++ b/app/routes/vehicles.py @@ -7,7 +7,7 @@ from flask_babel import gettext as _ from werkzeug.utils import secure_filename from app import db -from app.models import Vehicle, VehicleSpec, VehiclePart, FuelLog, Expense, User, Reminder, VEHICLE_TYPES, FUEL_TYPES, VEHICLE_SPEC_TYPES, REMINDER_TYPES, PART_TYPES, TRACKING_UNITS, AppSettings +from app.models import Vehicle, VehicleSpec, VehiclePart, FuelLog, Expense, User, Reminder, VEHICLE_TYPES, FUEL_TYPES, VEHICLE_SPEC_TYPES, REMINDER_TYPES, PART_TYPES, TRACKING_UNITS, ODOMETER_UNITS, AppSettings from app.services.tessie import TessieService bp = Blueprint('vehicles', __name__, url_prefix='/vehicles') @@ -47,6 +47,7 @@ def new(): name=request.form.get('name'), vehicle_type=request.form.get('vehicle_type'), tracking_unit=request.form.get('tracking_unit', 'mileage'), + odometer_unit=request.form.get('odometer_unit') or None, make=request.form.get('make'), model=request.form.get('model'), year=int(request.form.get('year')) if request.form.get('year') else None, @@ -95,6 +96,7 @@ def new(): vehicle_types=VEHICLE_TYPES, fuel_types=FUEL_TYPES, tracking_units=TRACKING_UNITS, + odometer_units=ODOMETER_UNITS, spec_types=VEHICLE_SPEC_TYPES, tessie_configured=tessie_configured) @@ -121,7 +123,7 @@ def view(vehicle_id): 'total_fuel_cost': vehicle.get_total_fuel_cost(), 'total_expense_cost': vehicle.get_total_expense_cost(), 'total_cost': vehicle.get_total_cost(), - 'total_distance': vehicle.get_total_distance(current_user.distance_unit), + 'total_distance': vehicle.get_total_distance(vehicle.get_effective_odometer_unit()), 'avg_consumption': vehicle.get_average_consumption(), 'fuel_logs_count': vehicle.fuel_logs.count(), 'expenses_count': vehicle.expenses.count() @@ -168,6 +170,7 @@ def edit(vehicle_id): vehicle.name = request.form.get('name') vehicle.vehicle_type = request.form.get('vehicle_type') vehicle.tracking_unit = request.form.get('tracking_unit', 'mileage') + vehicle.odometer_unit = request.form.get('odometer_unit') or None vehicle.make = request.form.get('make') vehicle.model = request.form.get('model') vehicle.year = int(request.form.get('year')) if request.form.get('year') else None @@ -224,6 +227,7 @@ def edit(vehicle_id): vehicle_types=VEHICLE_TYPES, fuel_types=FUEL_TYPES, tracking_units=TRACKING_UNITS, + odometer_units=ODOMETER_UNITS, spec_types=VEHICLE_SPEC_TYPES, specs=specs, tessie_configured=tessie_configured) @@ -360,7 +364,7 @@ def report(vehicle_id): 'total_fuel_cost': vehicle.get_total_fuel_cost(), 'total_expense_cost': vehicle.get_total_expense_cost(), 'total_cost': vehicle.get_total_cost(), - 'total_distance': vehicle.get_total_distance(current_user.distance_unit), + 'total_distance': vehicle.get_total_distance(vehicle.get_effective_odometer_unit()), 'avg_consumption': vehicle.get_average_consumption(), 'fuel_logs_count': len(fuel_logs), 'expenses_count': len(expenses) diff --git a/app/templates/fuel/form.html b/app/templates/fuel/form.html index 1f208d1..371a648 100644 --- a/app/templates/fuel/form.html +++ b/app/templates/fuel/form.html @@ -20,14 +20,15 @@
Last odometer: - {{ current_user.distance_unit }}
+Last odometer: - {{ current_user.distance_unit }}