diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml
index 656583e..879950d 100644
--- a/.github/workflows/docker.yml
+++ b/.github/workflows/docker.yml
@@ -43,7 +43,7 @@ jobs:
uses: actions/checkout@v6
- name: Set up QEMU
- uses: docker/setup-qemu-action@v3
+ uses: docker/setup-qemu-action@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
diff --git a/README.md b/README.md
index 2d9c446..5456654 100644
--- a/README.md
+++ b/README.md
@@ -151,6 +151,7 @@ The main dashboard shows an overview of all your vehicles with key statistics:
- Total fuel costs and consumption averages
- Recent fuel logs and expenses
- Upcoming reminders and overdue alerts
+- Vehicle photo cards showing make/model/year and fuel type at a glance
### Vehicles
Add and manage your vehicles with detailed information:
@@ -158,6 +159,9 @@ Add and manage your vehicles with detailed information:
- Fuel type and tank capacity
- Custom specifications and notes
- Photo upload support
+- **Vehicle Sharing**: Mark a vehicle as "Shared" to make it visible and loggable by all users on the instance
+- **Upcoming Maintenance**: Vehicle detail pages show a live panel of scheduled maintenance tasks, with overdue and due-soon alerts
+- **Parts & Consumables**: Collapsible section on the vehicle page remembers your expand/collapse preference per vehicle
### Fuel Logs
Track every fill-up with:
@@ -169,12 +173,15 @@ Track every fill-up with:
### Expenses
Categorize all vehicle-related costs:
- Maintenance & Repairs
+- Inspection (MOT, roadworthy checks)
- Insurance
- Tax & Registration
- Parking & Tolls
- Accessories
- Other expenses
+Record odometer readings alongside costs, and expand any expense row to see vendor and notes details inline.
+
### Reminders
Never miss important dates:
- MOT/Inspection due dates
@@ -202,9 +209,9 @@ Track regular payments:
Store important vehicle documents:
- Insurance certificates
- Registration documents
-- Service manuals
+- Service manuals and instruction booklets (up to 300MB)
- MOT certificates
-- Any file type with expiry date tracking
+- Any file type (PDF, images, Word, Excel, text, ePub) with expiry date tracking
### Fuel Stations
Save your favorite stations:
diff --git a/app/__init__.py b/app/__init__.py
index 1b211dd..b647ba2 100644
--- a/app/__init__.py
+++ b/app/__init__.py
@@ -138,6 +138,8 @@ def _run_schema_migrations(app):
('tessie_battery_range', 'FLOAT'),
('tessie_last_updated', 'DATETIME'),
('tracking_unit', "VARCHAR(20) DEFAULT 'mileage'"),
+ ('annual_mileage_limit', 'FLOAT'),
+ ('annual_mileage_start_date', 'DATE'),
],
'users': [
('date_format', "VARCHAR(20) DEFAULT 'DD/MM/YYYY'"),
diff --git a/app/models.py b/app/models.py
index 910620d..9c78306 100644
--- a/app/models.py
+++ b/app/models.py
@@ -105,12 +105,13 @@ def check_password(self, password):
return check_password_hash(self.password_hash, password)
def get_all_vehicles(self):
- """Get all vehicles user has access to (owned + shared), sorted by make/model"""
+ """Get all vehicles user has access to (owned + explicitly shared + instance-shared), sorted by make/model"""
owned = list(self.owned_vehicles.all())
shared = list(self.shared_vehicles)
+ instance_shared = Vehicle.query.filter_by(is_shared=True).all()
seen = set()
unique = []
- for v in owned + shared:
+ for v in owned + shared + instance_shared:
if v.id not in seen:
seen.add(v.id)
unique.append(v)
@@ -211,6 +212,13 @@ class Vehicle(db.Model):
tessie_battery_range = db.Column(db.Float) # Last fetched range in km
tessie_last_updated = db.Column(db.DateTime) # When Tessie data was last fetched
+ # Annual mileage tracking
+ annual_mileage_limit = db.Column(db.Float, nullable=True)
+ annual_mileage_start_date = db.Column(db.Date, nullable=True)
+
+ # Sharing — if True, all users on this instance can view and log against this vehicle
+ is_shared = db.Column(db.Boolean, default=False, nullable=False)
+
# Relationships
fuel_logs = db.relationship('FuelLog', backref='vehicle', lazy='dynamic',
cascade='all, delete-orphan')
@@ -355,9 +363,97 @@ def get_cost_per_distance(self):
return None
def is_electric(self):
- """Check if vehicle is electric or plug-in hybrid"""
+ """Check if vehicle uses any electric propulsion"""
return self.fuel_type in ('electric', 'plugin_hybrid', 'hybrid')
+ def uses_charging(self):
+ """Check if vehicle can be plugged in for charging (pure EV or plug-in hybrid)"""
+ return self.fuel_type in ('electric', 'plugin_hybrid')
+
+ def uses_fuel(self):
+ """Check if vehicle uses liquid fuel (not pure electric)"""
+ return self.fuel_type != 'electric'
+
+ def get_annual_mileage_stats(self):
+ """Return mileage tracking stats for the current annual period, or None if not configured."""
+ if not self.annual_mileage_limit or not self.annual_mileage_start_date:
+ return None
+
+ from datetime import date as date_type
+
+ today = date_type.today()
+ limit = self.annual_mileage_limit
+ start = self.annual_mileage_start_date
+
+ # Find the most recent anniversary of start that is <= today
+ period_year = today.year
+ try:
+ candidate = start.replace(year=period_year)
+ except ValueError:
+ candidate = start.replace(year=period_year, day=28)
+ if candidate > today:
+ period_year -= 1
+ try:
+ candidate = start.replace(year=period_year)
+ except ValueError:
+ candidate = start.replace(year=period_year, day=28)
+ period_start = candidate
+
+ try:
+ period_end = start.replace(year=period_year + 1)
+ except ValueError:
+ period_end = start.replace(year=period_year + 1, day=28)
+
+ days_total = (period_end - period_start).days
+ days_elapsed = max(0, (today - period_start).days)
+ days_remaining = max(0, (period_end - today).days)
+
+ # Baseline: last odometer reading before this period
+ baseline_log = (self.fuel_logs
+ .filter(FuelLog.date < period_start)
+ .order_by(FuelLog.date.desc(), FuelLog.odometer.desc())
+ .first())
+ current_log = (self.fuel_logs
+ .order_by(FuelLog.date.desc(), FuelLog.odometer.desc())
+ .first())
+
+ if not current_log:
+ driven = 0.0
+ elif baseline_log:
+ driven = max(0.0, current_log.odometer - baseline_log.odometer)
+ else:
+ first_log = (self.fuel_logs
+ .filter(FuelLog.date >= period_start)
+ .order_by(FuelLog.date.asc(), FuelLog.odometer.asc())
+ .first())
+ if first_log and current_log.id != first_log.id:
+ driven = max(0.0, current_log.odometer - first_log.odometer)
+ else:
+ driven = 0.0
+
+ remaining = max(0.0, limit - driven)
+ progress_pct = min(100.0, round(driven / limit * 100, 1)) if limit > 0 else 0.0
+ time_pct = round(days_elapsed / days_total * 100, 1) if days_total > 0 else 0.0
+ expected = round(limit / days_total * days_elapsed) if days_total > 0 else 0
+ projected = round(driven / days_elapsed * days_total) if days_elapsed > 0 else 0
+
+ return {
+ 'limit': limit,
+ 'period_start': period_start,
+ 'period_end': period_end,
+ 'days_total': days_total,
+ 'days_elapsed': days_elapsed,
+ 'days_remaining': days_remaining,
+ 'driven': round(driven),
+ 'remaining': round(remaining),
+ 'projected': projected,
+ 'on_pace': projected <= limit,
+ 'over_limit': driven >= limit,
+ 'progress_pct': progress_pct,
+ 'time_pct': time_pct,
+ 'expected': expected,
+ }
+
def to_dict(self):
"""Serialize vehicle to dictionary for API"""
return {
@@ -698,6 +794,7 @@ def get_all_branding():
EXPENSE_CATEGORIES = [
('maintenance', _l('Maintenance')),
('repairs', _l('Repairs')),
+ ('inspection', _l('Inspection')),
('insurance', _l('Insurance')),
('tax', _l('Road Tax')),
('registration', _l('Registration')),
diff --git a/app/routes/documents.py b/app/routes/documents.py
index ee324b4..43932d3 100644
--- a/app/routes/documents.py
+++ b/app/routes/documents.py
@@ -10,7 +10,7 @@
bp = Blueprint('documents', __name__, url_prefix='/documents')
-ALLOWED_EXTENSIONS = {'pdf', 'png', 'jpg', 'jpeg', 'gif', 'webp', 'doc', 'docx'}
+ALLOWED_EXTENSIONS = {'pdf', 'png', 'jpg', 'jpeg', 'gif', 'webp', 'doc', 'docx', 'xlsx', 'xls', 'txt', 'csv', 'epub'}
def allowed_file(filename):
diff --git a/app/routes/vehicles.py b/app/routes/vehicles.py
index a4762ed..a3df7c5 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, ODOMETER_UNITS, AppSettings
+from app.models import Vehicle, VehicleSpec, VehiclePart, FuelLog, Expense, User, Reminder, MaintenanceSchedule, 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')
@@ -56,7 +56,9 @@ def new():
fuel_type=request.form.get('fuel_type'),
secondary_fuel_type=request.form.get('secondary_fuel_type') or None,
tank_capacity=float(request.form.get('tank_capacity')) if request.form.get('tank_capacity') else None,
- notes=request.form.get('notes')
+ notes=request.form.get('notes'),
+ annual_mileage_limit=float(request.form.get('annual_mileage_limit')) if request.form.get('annual_mileage_limit') else None,
+ annual_mileage_start_date=datetime.strptime(request.form.get('annual_mileage_start_date'), '%Y-%m-%d').date() if request.form.get('annual_mileage_start_date') else None,
)
# Handle image upload
@@ -137,6 +139,15 @@ def view(vehicle_id):
# Get parts for this vehicle
parts = vehicle.parts.order_by(VehiclePart.part_type, VehiclePart.name).all()
+ # Get active maintenance schedules, sorted soonest-due first
+ from datetime import date as date_type
+ today = date_type.today()
+ maintenance_schedules = vehicle.maintenance_schedules.filter_by(is_active=True).all()
+ maintenance_schedules.sort(key=lambda s: (
+ s.next_due_date or date_type(9999, 12, 31),
+ s.next_due_odometer or float('inf')
+ ))
+
# Check if DVLA integration is configured
from app.services.dvla import DVLAService
dvla_configured = DVLAService.is_configured()
@@ -154,8 +165,11 @@ def view(vehicle_id):
reminder_types=REMINDER_TYPES,
parts=parts,
part_types=PART_TYPES,
+ maintenance_schedules=maintenance_schedules,
+ today=today,
dvla_configured=dvla_configured,
- tessie_configured=tessie_configured)
+ tessie_configured=tessie_configured,
+ annual_mileage_stats=vehicle.get_annual_mileage_stats())
@bp.route('/Authentication
Authorization: Bearer may_your_api_key_here
+ Authorization: Bearer may_your_api_key_here
X-API-Key: may_your_api_key_here
+ X-API-Key: may_your_api_key_here
curl -X GET "{{ request.host_url }}api/v1/vehicles" \
+
+curl -X GET "{{ request.host_url }}api/v1/vehicles" \
-H "Authorization: Bearer may_your_api_key_here"
List all vehicles you have access to (owned and shared)
{
+
+{
"vehicles": [
{
"id": 1,
@@ -155,8 +155,8 @@ Request Body
Example
-
-curl -X POST "{{ request.host_url }}api/v1/vehicles" \
+
+curl -X POST "{{ request.host_url }}api/v1/vehicles" \
-H "Authorization: Bearer may_your_api_key" \
-H "Content-Type: application/json" \
-d '{
@@ -231,8 +231,8 @@ Query Parameters
Response
-
-{
+
+{
"fuel_logs": [
{
"id": 1,
@@ -294,8 +294,8 @@ Request Body
Example
-
-curl -X POST "{{ request.host_url }}api/v1/vehicles/1/fuel" \
+
+curl -X POST "{{ request.host_url }}api/v1/vehicles/1/fuel" \
-H "Authorization: Bearer may_your_api_key" \
-H "Content-Type: application/json" \
-d '{
@@ -435,8 +435,8 @@ Error Handling
Error Response Format
-
-{
+
+{
"error": "Human-readable error message",
"code": "error_code"
}
diff --git a/app/templates/auth/settings.html b/app/templates/auth/settings.html
index a657c8e..126234d 100644
--- a/app/templates/auth/settings.html
+++ b/app/templates/auth/settings.html
@@ -947,8 +947,8 @@ {{ _('Home Assista
{{ _('REST Sensor Configuration') }}
-
- sensor:
+
+ sensor:
- platform: rest
name: "May Vehicle Stats"
resource: {{ request.url_root.rstrip('/') }}/api/ha/summary
diff --git a/app/templates/base.html b/app/templates/base.html
index e5f7827..35d9ca8 100644
--- a/app/templates/base.html
+++ b/app/templates/base.html
@@ -96,17 +96,7 @@
Object.entries(primaryPalette).forEach(([key, value]) => {
rootStyle.setProperty(`--primary-${key}`, value);
});
- tailwind.config = {
- darkMode: 'class',
- theme: {
- extend: {
- colors: {
- primary: primaryPalette
- }
- }
- }
- };
- window.tailwind.config = tailwind.config;
+ window.__primaryPalette = primaryPalette;
+
{% endblock %}
diff --git a/app/templates/vehicles/form.html b/app/templates/vehicles/form.html
index 4ca99bf..f4f5a79 100644
--- a/app/templates/vehicles/form.html
+++ b/app/templates/vehicles/form.html
@@ -191,6 +191,33 @@ {{ _('Specifi
+
+ {{ _('Annual Mileage Tracking') }}
+ {{ _('Set a yearly distance limit to track progress — useful for leasing contracts or insurance policies.') }}
+
+
+
+
+
+
+
+
+
+ {{ _('Tracking resets on this date each year.') }}
+
+
+
+
{{ _('Notes') }}
@@ -211,6 +238,12 @@ {{ _('Status'
class="h-4 w-4 rounded border-gray-300 dark:border-gray-600 text-primary-600 focus:ring-primary-500">
+
+
+
+
{% endif %}
diff --git a/app/templates/vehicles/index.html b/app/templates/vehicles/index.html
index b9fccdd..3a8c083 100644
--- a/app/templates/vehicles/index.html
+++ b/app/templates/vehicles/index.html
@@ -79,9 +79,14 @@ {% if show_archived
{{ vehicle.name }}
- {% if not vehicle.is_active %}
- {{ _('Inactive') }}
- {% endif %}
+
+ {% if not vehicle.is_active %}
+ {{ _('Inactive') }}
+ {% endif %}
+ {% if vehicle.is_shared %}
+ {{ _('Shared') }}
+ {% endif %}
+
{{ vehicle.make or '' }} {{ vehicle.model or '' }} {% if vehicle.year %}({{ vehicle.year }}){% endif %}
diff --git a/app/templates/vehicles/view.html b/app/templates/vehicles/view.html
index f032f85..ab921ed 100644
--- a/app/templates/vehicles/view.html
+++ b/app/templates/vehicles/view.html
@@ -99,7 +99,7 @@ {{ vehicle.name }}<
- {% if not vehicle.uses_tessie_odometer() %}
+ {% if vehicle.uses_fuel() and not vehicle.uses_tessie_odometer() %}
{% endif %}
- {% if vehicle.is_electric() %}
+ {% if vehicle.uses_charging() %}
{% endif %}
+
+{% if annual_mileage_stats %}
+{% set ms = annual_mileage_stats %}
+
+
+
+
+ {{ _('Annual Mileage') }}
+
+
+ {% if ms.over_limit %}
+
+ {{ _('Over limit') }}
+
+ {% elif ms.progress_pct >= 90 %}
+
+ {{ _('Approaching limit') }}
+
+ {% elif ms.on_pace %}
+
+ {{ _('On pace') }}
+
+ {% else %}
+
+ {{ _('Over pace') }}
+
+ {% endif %}
+ {{ _('Edit') }}
+
+
+
+
+
+
+
+ {{ _('Distance') }}: {{ "{:,}".format(ms.driven) }} / {{ "{:,}".format(ms.limit|int) }} {{ vehicle.get_effective_odometer_unit() }}
+ {{ ms.progress_pct }}%
+
+
+
+
+
+
+
+
+ {{ ms.period_start|format_date }}
+ ▲ {{ ms.time_pct }}% {{ _('of year elapsed') }}
+ {{ ms.period_end|format_date }}
+
+
+
+
+
+
+ {{ "{:,}".format(ms.remaining) }}
+ {{ vehicle.get_effective_odometer_unit() }} {{ _('remaining') }}
+
+
+ {{ ms.days_remaining }}
+ {{ _('days remaining') }}
+
+
+ {{ "{:,}".format(ms.projected) }}
+ {{ _('projected year-end') }}
+
+
+ {{ "{:,}".format(ms.expected) }}
+ {{ _('expected at this point') }}
+
+
+
+
+{% endif %}
+
{% if reminders %}
@@ -475,17 +552,77 @@ {{ _('Notes') }}
{% endif %}
-
+{% if maintenance_schedules %}
+
- {{ _('Parts & Consumables') }}
+ {{ _('Upcoming Maintenance') }}
+
+ {{ _('View all') }}
+
+
+ {% for schedule in maintenance_schedules[:5] %}
+ {% set is_overdue = schedule.next_due_date and schedule.next_due_date < today %}
+ {% set is_due_soon = schedule.next_due_date and not is_overdue and (schedule.next_due_date - today).days <= 30 %}
+ -
+
+
+
+ {{ schedule.name }}
+ {% if is_overdue %}
+ {{ _('Overdue') }}
+ {% elif is_due_soon %}
+ {{ _('Due soon') }}
+ {% endif %}
+
+
+ {% if schedule.next_due_date %}
+ {{ schedule.next_due_date|format_date }}
+ {% endif %}
+ {% if schedule.next_due_odometer %}
+ {{ schedule.next_due_odometer|int }} {{ vehicle.get_effective_odometer_unit() }}
+ {% endif %}
+
+
+ {% if schedule.next_due_date and schedule.last_performed_date %}
+ {% set total_days = (schedule.next_due_date - schedule.last_performed_date).days %}
+ {% set elapsed_days = (today - schedule.last_performed_date).days %}
+ {% set pct = [[(elapsed_days / total_days * 100) if total_days > 0 else 100, 0]|max, 100]|min %}
+
+
+
+
+
+ {% endif %}
+
+
+ {% endfor %}
+
+
+{% endif %}
+
+
+
+
+
{% if parts %}
{% for part in parts[:6] %}
@@ -536,8 +673,27 @@ {{ _('Parts & Cons
{% endif %}
+
+
+
{{ _('Fuel Consumption Trend') }}
diff --git a/app/translations/de/LC_MESSAGES/messages.po b/app/translations/de/LC_MESSAGES/messages.po
index b289565..893628a 100644
--- a/app/translations/de/LC_MESSAGES/messages.po
+++ b/app/translations/de/LC_MESSAGES/messages.po
@@ -7,8 +7,8 @@ msgstr ""
"Project-Id-Version: May 1.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-02-27 11:00+0000\n"
-"PO-Revision-Date: 2026-02-17 21:00+0000\n"
-"Last-Translator: \n"
+"PO-Revision-Date: 2026-04-28 12:00+0000\n"
+"Last-Translator: Fleischpirat"
"Language: de\n"
"Language-Team: German\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
@@ -123,7 +123,7 @@ msgstr "Zubehör"
#: app/models.py:653 app/models.py:667 app/models.py:693 app/models.py:725
#: app/models.py:735 app/models.py:769 app/models.py:1133
msgid "Other"
-msgstr "andere"
+msgstr "Andere"
#: app/models.py:658
msgid "Car"
@@ -175,7 +175,7 @@ msgstr "Kilometer (km)"
#: app/models.py:679
msgid "Miles (mi)"
-msgstr "Milen (mi)"
+msgstr "Meilen (mi)"
#: app/models.py:684
msgid "Petrol/Gasoline"
@@ -211,16 +211,15 @@ msgstr "Wasserstoff"
#: app/models.py:692
msgid "E85/Flex Fuel"
-msgstr ""
+msgstr "E85/Ethanol-Kraftstoff"
#: app/models.py:698
msgid "MOT/Inspection"
msgstr "Inspektion"
#: app/models.py:699
-#, fuzzy
msgid "Service Due"
-msgstr "Service-Verlauf"
+msgstr "Service fällig"
#: app/models.py:700
msgid "Insurance Renewal"
@@ -244,7 +243,7 @@ msgstr "Ölwechsel"
#: app/models.py:711
msgid "No Repeat"
-msgstr "kene Wiederholung"
+msgstr "Keine Wiederholung"
#: app/models.py:712 app/templates/recurring/form.html:57
msgid "Monthly"
@@ -271,7 +270,6 @@ msgid "Personal"
msgstr "Privat"
#: app/models.py:722
-#, fuzzy
msgid "Commute"
msgstr "Pendeln"
@@ -301,7 +299,7 @@ msgstr "Schnelladung"
#: app/models.py:734
msgid "Tesla Supercharger"
-msgstr "esla Supercharger"
+msgstr "Tesla Supercharger"
#: app/models.py:741 app/models.py:1119
msgid "Oil Filter"
@@ -337,7 +335,7 @@ msgstr "Kühlflüssigkeit"
#: app/models.py:749
msgid "Transmission Service"
-msgstr "Überführungskosten"
+msgstr "Getriebeservice"
#: app/models.py:750
msgid "Timing Belt"
@@ -2981,363 +2979,315 @@ msgid "No trips logged for"
msgstr "Keine Fahrten erfasst für"
#: app/templates/vehicles/form.html:2 app/templates/vehicles/form.html:8
-#, fuzzy
msgid "Edit Vehicle"
-msgstr "Fahrzeug"
+msgstr "Fahrzeug bearbeiten"
#: app/templates/vehicles/form.html:2 app/templates/vehicles/form.html:269
#: app/templates/vehicles/index.html:32 app/templates/vehicles/index.html:108
-#, fuzzy
msgid "Add Vehicle"
-msgstr "Alle Fahrzeuge"
+msgstr "Fahrzeug hinzufügen"
#: app/templates/vehicles/form.html:7 app/templates/vehicles/view.html:11
-#, fuzzy
msgid "Back to vehicles"
-msgstr "Alle Fahrzeuge"
+msgstr "Zurück zu Fahrzeugen"
#: app/templates/vehicles/form.html:8
-#, fuzzy
msgid "Add New Vehicle"
-msgstr "Alle Fahrzeuge"
+msgstr "Neues Fahrzeug hinzufügen"
#: app/templates/vehicles/form.html:14
-#, fuzzy
msgid "Basic Information"
-msgstr "Kontoinformationen"
+msgstr "Grundlegende Informationen"
#: app/templates/vehicles/form.html:36
msgid "Tracking Unit"
-msgstr ""
+msgstr "Messgerät"
#: app/templates/vehicles/form.html:43
msgid "Use \"Hours\" for tractors, ATVs, boats, etc."
-msgstr ""
+msgstr "Verwenden Sie Stunden für zum Beispiel Traktoren, ATVs, Boote, usw."
#: app/templates/vehicles/form.html:47
-#, fuzzy
msgid "Odometer Unit"
-msgstr "Kilometerstand"
+msgstr "Kilometerstand-Einheit"
#: app/templates/vehicles/form.html:50
-#, fuzzy
msgid "Use account default"
-msgstr "Ihre Kontodetails"
+msgstr "Kontostandard verwenden"
#: app/templates/vehicles/form.html:55
msgid ""
"Override the odometer unit for this vehicle. Useful when you have "
"vehicles with different odometer units."
msgstr ""
+"Kilometerstand-Einheit für dieses Fahrzeug überschreiben. Nützlich, wenn "
+"Sie Fahrzeuge mit unterschiedlichen (z.B. Nicht-Landesüblichen) Einheiten haben."
#: app/templates/vehicles/form.html:59
-#, fuzzy
msgid "Fuel Type"
-msgstr "Typ"
+msgstr "Kraftstoffart"
#: app/templates/vehicles/form.html:69
msgid "Make"
-msgstr ""
+msgstr "Hersteller"
#: app/templates/vehicles/form.html:77
-#, fuzzy
msgid "Model"
-msgstr "Mehr"
+msgstr "Modell"
#: app/templates/vehicles/form.html:94
msgid "Tank Capacity (L)"
-msgstr ""
+msgstr "Tankvolumen (L)"
#: app/templates/vehicles/form.html:104
-#, fuzzy
msgid "Identification"
-msgstr "Benachrichtigungen"
+msgstr "Identifikation"
#: app/templates/vehicles/form.html:108
-#, fuzzy
msgid "Registration / License Plate"
-msgstr "Registrierungseinstellungen aktualisiert"
+msgstr "Kennzeichen"
#: app/templates/vehicles/form.html:116 app/templates/vehicles/view.html:328
msgid "VIN"
msgstr "FIN"
#: app/templates/vehicles/form.html:126
-#, fuzzy
msgid "Photo"
-msgstr "Postleitzahl"
+msgstr "Foto"
#: app/templates/vehicles/form.html:129
-#, fuzzy
msgid "Vehicle Image"
-msgstr "Fahrzeug"
+msgstr "Fahrzeugbild"
#: app/templates/vehicles/form.html:143 app/templates/vehicles/view.html:447
-#, fuzzy
msgid "Specifications"
-msgstr "Benachrichtigungen"
+msgstr "Spezifikationen"
#: app/templates/vehicles/form.html:144
msgid "Add technical details like tire sizes, oil type, wiper sizes, etc."
-msgstr ""
+msgstr "Technische Details wie Reifengrößen, Öltyp, Wischblattgrößen, usw. hinzufügen."
#: app/templates/vehicles/form.html:178
-#, fuzzy
msgid "Add Specification"
-msgstr "Tankstelle hinzufügen"
+msgstr "Spezifikation hinzufügen"
#: app/templates/vehicles/form.html:186
-#, fuzzy
msgid "General Notes"
-msgstr "Optionale Notizen"
+msgstr "Allgemeine Notizen"
#: app/templates/vehicles/form.html:195
-#, fuzzy
msgid "Status"
-msgstr "Steuerstatus"
+msgstr "Status"
#: app/templates/vehicles/form.html:200
msgid "Active (show in lists and calculations)"
-msgstr ""
+msgstr "Aktiv (in Listen und Berechnungen anzeigen)"
#: app/templates/vehicles/form.html:216
msgid ""
"Link this vehicle to Tessie for automatic odometer and battery tracking. "
"When enabled, manual odometer entry will be disabled."
msgstr ""
+"Dieses Fahrzeug mit Tessie verknüpfen für automatische Kilometerstand- "
+"und Batterieverfolgung. Bei Aktivierung wird die manuelle Eingabe deaktiviert."
#: app/templates/vehicles/form.html:220
-#, fuzzy
msgid "Tessie VIN"
-msgstr "Tessie"
+msgstr "Tessie FIN"
#: app/templates/vehicles/form.html:232
-#, fuzzy
msgid "Lookup"
-msgstr "Abmelden"
+msgstr "Suchen"
#: app/templates/vehicles/form.html:243
msgid "Enable Tessie tracking (disables manual odometer entry)"
-msgstr ""
+msgstr "Tessie-Tracking aktivieren (deaktiviert manuelle Kilometerstandeingabe)"
#: app/templates/vehicles/form.html:253
-#, fuzzy
msgid "Tessie tracking is active for this vehicle"
-msgstr "Noch keine Tessie-Daten für dieses Fahrzeug verfügbar."
+msgstr "Tessie-Tracking ist für dieses Fahrzeug aktiv"
#: app/templates/vehicles/index.html:7
-#, fuzzy
msgid "Archived Vehicles"
-msgstr "Alle Fahrzeuge"
+msgstr "Archivierte Fahrzeuge"
#: app/templates/vehicles/index.html:8
msgid "Manage your cars, vans, motorbikes, and scooters"
-msgstr ""
+msgstr "Verwalten Sie Ihre Autos, Vans, Motorräder und Roller"
#: app/templates/vehicles/index.html:18
-#, fuzzy
msgid "Active Vehicles"
-msgstr "Alle Fahrzeuge"
+msgstr "Aktive Fahrzeuge"
#: app/templates/vehicles/index.html:23
-#, fuzzy
msgid "Archived"
-msgstr "Aktivieren"
+msgstr "Archiviert"
#: app/templates/vehicles/index.html:83
-#, fuzzy
msgid "Inactive"
-msgstr "Aktivieren"
+msgstr "Inaktiv"
#: app/templates/vehicles/index.html:100
-#, fuzzy
msgid "No vehicles"
-msgstr "Fahrzeuge"
+msgstr "Keine Fahrzeuge"
#: app/templates/vehicles/index.html:101
msgid "Get started by adding your first vehicle."
-msgstr ""
+msgstr "Fügen Sie Ihr erstes Fahrzeug hinzu, um zu beginnen."
#: app/templates/vehicles/part_form.html:2
#: app/templates/vehicles/part_form.html:8
-#, fuzzy
msgid "Edit Part"
-msgstr "Fahrt bearbeiten"
+msgstr "Teil bearbeiten"
#: app/templates/vehicles/part_form.html:2
#: app/templates/vehicles/part_form.html:8
#: app/templates/vehicles/part_form.html:102
#: app/templates/vehicles/parts.html:19 app/templates/vehicles/view.html:530
-#, fuzzy
msgid "Add Part"
-msgstr "Teile"
+msgstr "Teil hinzufügen"
#: app/templates/vehicles/part_form.html:7
-#, fuzzy
msgid "Back to parts"
-msgstr "Zurück zu Fahrten"
+msgstr "Zurück zu Teilen"
#: app/templates/vehicles/part_form.html:15
-#, fuzzy
msgid "Part Details"
-msgstr "Kontodetails"
+msgstr "Teildetails"
#: app/templates/vehicles/part_form.html:19
-#, fuzzy
msgid "Part Type"
-msgstr "Ladetyp"
+msgstr "Teiltyp"
#: app/templates/vehicles/part_form.html:37
-#, fuzzy
msgid "Specification"
-msgstr "Benachrichtigungen"
+msgstr "Spezifikation"
#: app/templates/vehicles/part_form.html:42
msgid "Oil viscosity, filter model, tire size, etc."
-msgstr ""
+msgstr "Ölviskosität, Filtermodell, Reifengröße, usw."
#: app/templates/vehicles/part_form.html:46
msgid "Quantity"
-msgstr ""
+msgstr "Menge"
#: app/templates/vehicles/part_form.html:54
-#, fuzzy
msgid "Unit"
-msgstr "Betrag"
+msgstr "Einheit"
#: app/templates/vehicles/part_form.html:57
-#, fuzzy
msgid "Select unit..."
-msgstr "Typ auswählen..."
+msgstr "Einheit auswählen..."
#: app/templates/vehicles/part_form.html:58
msgid "Liters (L)"
-msgstr ""
+msgstr "Liter (L)"
#: app/templates/vehicles/part_form.html:59
msgid "Milliliters (ml)"
-msgstr ""
+msgstr "Milliliter (ml)"
#: app/templates/vehicles/part_form.html:60
msgid "Gallons (gal)"
-msgstr ""
+msgstr "Gallonen (gal)"
#: app/templates/vehicles/part_form.html:61
msgid "Quarts (qt)"
-msgstr ""
+msgstr "Quart (qt)"
#: app/templates/vehicles/part_form.html:62
-#, fuzzy
msgid "Units"
-msgstr "Notizen"
+msgstr "Einheiten"
#: app/templates/vehicles/part_form.html:63
-#, fuzzy
msgid "Pieces"
-msgstr "API-Zugriff"
+msgstr "Stück"
#: app/templates/vehicles/part_form.html:64
-#, fuzzy
msgid "Set"
-msgstr "TLS verwenden"
+msgstr "Satz"
#: app/templates/vehicles/part_form.html:65
-#, fuzzy
msgid "Pair"
-msgstr "Teile"
+msgstr "Paar"
#: app/templates/vehicles/part_form.html:70
msgid "Part Number"
-msgstr ""
+msgstr "Teilenummer"
#: app/templates/vehicles/part_form.html:78
msgid "Supplier URL"
-msgstr ""
+msgstr "Lieferanten-URL"
#: app/templates/vehicles/part_form.html:83
msgid "Link to purchase this part"
-msgstr ""
+msgstr "Link zum Kauf dieses Teils"
#: app/templates/vehicles/parts.html:2 app/templates/vehicles/parts.html:11
#: app/templates/vehicles/view.html:480
msgid "Parts & Consumables"
-msgstr ""
+msgstr "Teile & Verbrauchsmaterialien"
#: app/templates/vehicles/parts.html:47
msgid "Qty:"
-msgstr ""
+msgstr "Menge:"
#: app/templates/vehicles/parts.html:94
-#, fuzzy
msgid "No parts added"
-msgstr "Zugeführte Energie"
+msgstr "Keine Teile hinzugefügt"
#: app/templates/vehicles/parts.html:95
msgid "Track the parts and consumables needed for servicing this vehicle."
-msgstr ""
-
-#: app/templates/vehicles/parts.html:102
-#, fuzzy
-msgid "Add First Part"
-msgstr "Tankstelle hinzufügen"
+msgstr "Erfassen Sie die Teile und Verbrauchsmaterialien, die für die Wartung dieses Fahrzeugs benötigt werden."
#: app/templates/vehicles/share.html:2 app/templates/vehicles/share.html:20
#: app/templates/vehicles/view.html:44
-#, fuzzy
msgid "Share"
-msgstr "Speichern"
+msgstr "Teilen"
#: app/templates/vehicles/share.html:8
-#, fuzzy
msgid "Share Vehicle"
-msgstr "Alle Fahrzeuge"
+msgstr "Fahrzeug teilen"
#: app/templates/vehicles/share.html:9
msgid "Allow other users to view and add logs to this vehicle"
-msgstr ""
+msgstr "Anderen Benutzern erlauben, dieses Fahrzeug einzusehen und Einträge hinzuzufügen."
#: app/templates/vehicles/share.html:13
-#, fuzzy
msgid "Add User"
-msgstr "Benutzer erstellen"
+msgstr "Benutzer hinzufügen"
#: app/templates/vehicles/share.html:16
-#, fuzzy
msgid "Enter username"
-msgstr "SMTP-Benutzername"
+msgstr "Benutzername eingeben"
#: app/templates/vehicles/share.html:27
msgid "Shared With"
-msgstr ""
+msgstr "Geteilt mit"
#: app/templates/vehicles/share.html:39
-#, fuzzy
msgid "Remove"
-msgstr "Logo entfernen"
+msgstr "Entfernen"
#: app/templates/vehicles/share.html:45
msgid "This vehicle is not shared with anyone yet."
-msgstr ""
+msgstr "Dieses Fahrzeug wurde noch mit niemandem geteilt."
#: app/templates/vehicles/view.html:32
-#, fuzzy
msgid "Download PDF Report"
-msgstr "ZIP herunterladen"
+msgstr "PDF-Bericht herunterladen"
#: app/templates/vehicles/view.html:56 app/templates/vehicles/view.html:60
-#, fuzzy
msgid "Not set"
-msgstr "Notizen"
+msgstr "Nicht gesetzt"
#: app/templates/vehicles/view.html:63
-#, fuzzy
msgid "Last Odometer"
msgstr "Letzter Kilometerstand"
#: app/templates/vehicles/view.html:89
-#, fuzzy
msgid "Avg. Consumption"
-msgstr "Kraftstoffverbrauch"
+msgstr "Durchschnittsverbrauch"
#: app/templates/vehicles/view.html:103
msgid "Add Fuel Log"
@@ -3428,132 +3378,115 @@ msgid "Fetch from Tessie"
msgstr "Von Tessie abrufen"
#: app/templates/vehicles/view.html:358
-msgid ""
-"This vehicle is archived. It won't appear in regular lists or "
-"calculations."
-msgstr ""
+msgid "This vehicle is archived. It won't appear in regular lists or calculations."
+msgstr "Dieses Fahrzeug ist archiviert. Es wird nicht in regulären Listen oder Berechnungen angezeigt."
#: app/templates/vehicles/view.html:371
-#, fuzzy
msgid "Upcoming Reminders"
msgstr "Anstehende Erinnerungen"
#: app/templates/vehicles/view.html:383
-#, fuzzy
msgid "Mark as completed"
msgstr "Als erledigt markieren"
#: app/templates/vehicles/view.html:410
#, python-format
msgid "%(days)s days overdue"
-msgstr ""
+msgstr "%(days)s Tage überfällig"
#: app/templates/vehicles/view.html:412
-#, fuzzy
msgid "Due today"
-msgstr "Jetzt fällig"
+msgstr "Heute fällig"
#: app/templates/vehicles/view.html:414
-#, fuzzy
msgid "Due tomorrow"
-msgstr "Jetzt fällig"
+msgstr "Morgen fällig"
#: app/templates/vehicles/view.html:416
#, python-format
msgid "In %(days)s days"
-msgstr ""
+msgstr "In %(days)s Tagen"
#: app/templates/vehicles/view.html:524
msgid "No parts added yet."
-msgstr ""
+msgstr "Noch keine Teile hinzugefügt."
#: app/templates/vehicles/view.html:538
-#, fuzzy
msgid "Fuel Consumption Trend"
-msgstr "Kraftstoffverbrauch"
+msgstr "Kraftstoffverbrauch-Trend"
#: app/templates/vehicles/view.html:561
-#, fuzzy
msgid "(Full)"
-msgstr "Kraftstoff"
+msgstr "(Voll)"
#: app/templates/vehicles/view.html:578
-#, fuzzy
msgid "Delete this fuel log?"
-msgstr "Diese Tankstelle löschen?"
+msgstr "Dieses Tankprotokoll löschen?"
#: app/templates/vehicles/view.html:593
-#, fuzzy
msgid "No fuel logs yet."
-msgstr "Tankprotokoll"
+msgstr "Noch keine Tankprotokolle vorhanden."
#: app/templates/vehicles/view.html:622
-#, fuzzy
msgid "Delete this expense?"
-msgstr "Diese wiederkehrende Ausgabe löschen?"
+msgstr "Diese Ausgabe löschen?"
#: app/templates/vehicles/view.html:637
-#, fuzzy
msgid "No expenses yet."
-msgstr "Sonstige Ausgaben"
+msgstr "Noch keine Ausgaben vorhanden."
#: app/templates/vehicles/view.html:653
-#, fuzzy
msgid "Archive this vehicle"
-msgstr "Ungültiges Fahrzeug"
+msgstr "Dieses Fahrzeug archivieren"
#: app/templates/vehicles/view.html:654
msgid ""
"Archived vehicles won't appear in regular lists or calculations. You can "
"restore them later."
msgstr ""
+"Archivierte Fahrzeuge werden nicht in regulären Listen oder Berechnungen "
+"angezeigt. Sie können diese später wiederherstellen."
#: app/templates/vehicles/view.html:656
-#, fuzzy
msgid "Restore this vehicle"
-msgstr "Ihre Fahrzeuge"
+msgstr "Dieses Fahrzeug wiederherstellen"
#: app/templates/vehicles/view.html:657
msgid ""
"Restore this vehicle to make it active again and include it in "
"calculations."
msgstr ""
+"Stellen Sie dieses Fahrzeug wieder her, um es erneut zu aktivieren und "
+"in Berechnungen einzubeziehen."
#: app/templates/vehicles/view.html:665
-#, fuzzy
msgid "Archive Vehicle"
-msgstr "Ungültiges Fahrzeug"
+msgstr "Fahrzeug archivieren"
#: app/templates/vehicles/view.html:673
-#, fuzzy
msgid "Restore Vehicle"
-msgstr "Ihre Fahrzeuge"
+msgstr "Fahrzeug wiederherstellen"
#: app/templates/vehicles/view.html:683
-#, fuzzy
msgid "Delete this vehicle"
-msgstr "Dieses Dokument löschen?"
+msgstr "Dieses Fahrzeug löschen"
#: app/templates/vehicles/view.html:684
msgid ""
"Once you delete a vehicle, there is no going back. This will also delete "
"all associated fuel logs and expenses."
msgstr ""
+"Das Löschen eines Fahrzeugs kann nicht rückgängig gemacht werden. Alle "
+"zugehörigen Tankprotokolle und Ausgaben werden ebenfalls gelöscht."
#: app/templates/vehicles/view.html:687
msgid ""
"Are you sure you want to delete this vehicle? This action cannot be "
"undone."
msgstr ""
+"Sind Sie sicher, dass Sie dieses Fahrzeug löschen möchten? Diese Aktion "
+"kann nicht rückgängig gemacht werden."
#: app/templates/vehicles/view.html:691
-#, fuzzy
msgid "Delete Vehicle"
-msgstr "Alle Fahrzeuge"
-
-#~ msgid "Make"
-#~ msgstr "Marke"
-
-#~ msgid "Average Consumption"
-#~ msgstr "Durchschnittsverbrauch"
-
+msgstr "Fahrzeug löschen"
diff --git a/app/translations/it/LC_MESSAGES/messages.po b/app/translations/it/LC_MESSAGES/messages.po
index a9dae3b..a442e83 100644
--- a/app/translations/it/LC_MESSAGES/messages.po
+++ b/app/translations/it/LC_MESSAGES/messages.po
@@ -7,7 +7,7 @@ msgstr ""
"Project-Id-Version: May 1.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-02-27 11:00+0000\n"
-"PO-Revision-Date: 2025-02-06 15:49+0100\n"
+"PO-Revision-Date: 2026-04-18 15:49+0100\n"
"Last-Translator: Albano Battistella \n"
"Language: it\n"
"Language-Team: it\n"
@@ -19,75 +19,68 @@ msgstr ""
#: app/models.py:624
msgid "Front Tire Size"
-msgstr ""
+msgstr "Dimensione Pneumatico Anteriore"
#: app/models.py:625
-#, fuzzy
msgid "Rear Tire Size"
-msgstr "Crea Utente"
+msgstr "Dimensione Pneumatico Posteriore"
#: app/models.py:626
msgid "Wheel Size"
-msgstr ""
+msgstr "Dimensione Ruota"
#: app/models.py:627
-#, fuzzy
msgid "Engine Oil Type"
-msgstr "Tipo di file non valido"
+msgstr "Tipo Olio Motore"
#: app/models.py:628
msgid "Oil Capacity"
-msgstr ""
+msgstr "Capacità Olio"
#: app/models.py:629
-#, fuzzy
msgid "Coolant Type"
-msgstr "Tipo di Caricatore"
+msgstr "Tipo di Liquido di Raffreddamento"
#: app/models.py:630
msgid "Front Wiper Size"
-msgstr ""
+msgstr "Dimensione Tergicristallo Anteriore"
#: app/models.py:631
msgid "Rear Wiper Size"
-msgstr ""
+msgstr "Dimensione Tergicristallo Posteriore"
#: app/models.py:632
-#, fuzzy
msgid "Battery Type"
-msgstr "Livello Batteria"
+msgstr "Tipo Batteria"
#: app/models.py:633
-#, fuzzy
msgid "Spark Plug Type"
-msgstr "Tipo di Caricatore"
+msgstr "Tipo Candela"
#: app/models.py:634
-#, fuzzy
msgid "Air Filter Part #"
-msgstr "Aggiungi Stazione"
+msgstr "Filtro Aria Codice Ricambio"
#: app/models.py:635
-#, fuzzy
msgid "Cabin Filter Part #"
-msgstr "Aggiungi Stazione"
+msgstr "Filtro Abitacolo Codice Ricambio"
#: app/models.py:636
msgid "Front Brake Pads"
-msgstr ""
+msgstr "Pastiglie Freno Anteriori"
#: app/models.py:637
msgid "Rear Brake Pads"
-msgstr ""
+msgstr "Pastiglie Freno Posteriori"
#: app/models.py:638 app/models.py:1127
msgid "Transmission Fluid"
-msgstr ""
+msgstr "Olio Cambio"
#: app/models.py:639 app/models.py:706 app/models.py:757
#: app/templates/auth/settings.html:176
msgid "Custom"
-msgstr "Personalizzata"
+msgstr "Personalizzato"
#: app/models.py:644 app/templates/auth/settings.html:408
#: app/templates/auth/settings.html:459 app/templates/base.html:301
@@ -96,393 +89,349 @@ msgid "Maintenance"
msgstr "Manutenzione"
#: app/models.py:645
-#, fuzzy
msgid "Repairs"
-msgstr "Ricambi"
+msgstr "Riparazioni"
#: app/models.py:646
-#, fuzzy
msgid "Insurance"
-msgstr "Distanza"
+msgstr "Assicurazione"
#: app/models.py:647 app/models.py:701
msgid "Road Tax"
-msgstr ""
+msgstr "Bollo Auto"
#: app/models.py:648 app/templates/vehicles/view.html:59
-#, fuzzy
msgid "Registration"
-msgstr "Consenti Registrazione"
+msgstr "Registrazione"
#: app/models.py:649
-#, fuzzy
msgid "Parking"
-msgstr "Ricarica"
+msgstr "Parcheggio"
#: app/models.py:650
-#, fuzzy
msgid "Tolls"
-msgstr "Totale"
+msgstr "Pedaggi"
#: app/models.py:651
-#, fuzzy
msgid "Cleaning"
-msgstr "Ricarica"
+msgstr "Pulizia"
#: app/models.py:652
-#, fuzzy
msgid "Accessories"
-msgstr "Accesso negato"
+msgstr "Accessori"
#: app/models.py:653 app/models.py:667 app/models.py:693 app/models.py:725
#: app/models.py:735 app/models.py:769 app/models.py:1133
-#, fuzzy
msgid "Other"
-msgstr "Contachilometri"
+msgstr "Altro"
#: app/models.py:658
-#, fuzzy
msgid "Car"
-msgstr "Cancella"
+msgstr "Auto"
#: app/models.py:659
-#, fuzzy
msgid "Van"
-msgstr "VIN"
+msgstr "Furgone"
#: app/models.py:660
-#, fuzzy
msgid "Motorbike"
-msgstr "Altro"
+msgstr "Moto"
#: app/models.py:661
-#, fuzzy
msgid "Scooter"
-msgstr "Contachilometri"
+msgstr "Scooter"
#: app/models.py:662
msgid "Truck"
-msgstr ""
+msgstr "Camion"
#: app/models.py:663
msgid "SUV"
-msgstr ""
+msgstr "SUV"
#: app/models.py:664
-#, fuzzy
msgid "Tractor"
-msgstr "Amministratore"
+msgstr "Trattore"
#: app/models.py:665
msgid "ATV/UTV"
-msgstr ""
+msgstr "ATV/UTV"
#: app/models.py:666
-#, fuzzy
msgid "Boat"
-msgstr "Informazioni"
+msgstr "Barca"
#: app/models.py:672
msgid "Mileage (km/mi)"
-msgstr ""
+msgstr "Chilometraggio (km/mi)"
#: app/models.py:673
-#, fuzzy
msgid "Hours"
-msgstr "Utenti"
+msgstr "Ore"
#: app/models.py:678
msgid "Kilometres (km)"
-msgstr ""
+msgstr "Chilometri (km)"
#: app/models.py:679
-#, fuzzy
msgid "Miles (mi)"
-msgstr "Email (SMTP)"
+msgstr "Miglia (mi)"
#: app/models.py:684
msgid "Petrol/Gasoline"
-msgstr ""
+msgstr "Benzina"
#: app/models.py:685
msgid "Diesel"
-msgstr ""
+msgstr "Diesel"
#: app/models.py:686
msgid "Electric"
-msgstr ""
+msgstr "Elettrico"
#: app/models.py:687
msgid "Hybrid"
-msgstr ""
+msgstr "Ibrido"
#: app/models.py:688
msgid "Plug-in Hybrid"
-msgstr ""
+msgstr "Ibrido Plug-in"
#: app/models.py:689
msgid "LPG"
-msgstr ""
+msgstr "GPL"
#: app/models.py:690
msgid "CNG"
-msgstr ""
+msgstr "Metano"
#: app/models.py:691
msgid "Hydrogen"
-msgstr ""
+msgstr "Idrogeno"
#: app/models.py:692
msgid "E85/Flex Fuel"
-msgstr ""
+msgstr "E85/Flex Fuel"
#: app/models.py:698
msgid "MOT/Inspection"
-msgstr ""
+msgstr "Revisione/Ispezione"
#: app/models.py:699
-#, fuzzy
msgid "Service Due"
-msgstr "Cronologia Servizi"
+msgstr "Servizio in Scadenza"
#: app/models.py:700
msgid "Insurance Renewal"
-msgstr ""
+msgstr "Rinnovo Assicurazione"
#: app/models.py:702
-#, fuzzy
msgid "Registration Renewal"
-msgstr "Consenti Registrazione"
+msgstr "Rinnovo Registrazione"
#: app/models.py:703
-#, fuzzy
msgid "Warranty Expiry"
-msgstr "Scadenza MOT"
+msgstr "Scadenza Garanzia"
#: app/models.py:704
-#, fuzzy
msgid "Tire Change"
-msgstr "Salva Modifiche"
+msgstr "Cambio Pneumatici"
#: app/models.py:705 app/models.py:740
-#, fuzzy
msgid "Oil Change"
-msgstr "es., Cambio Olio"
+msgstr "Cambio Olio"
#: app/models.py:711
msgid "No Repeat"
-msgstr ""
+msgstr "Nessuna Ripetizione"
#: app/models.py:712 app/templates/recurring/form.html:57
msgid "Monthly"
msgstr "Mensile"
#: app/models.py:713
-#, fuzzy
msgid "Quarterly (3 months)"
-msgstr "Trimestrale (ogni 3 mesi)"
+msgstr "Trimestrale (3 mesi)"
#: app/models.py:714
-#, fuzzy
msgid "Every 6 months"
-msgstr "Ogni (mesi)"
+msgstr "Ogni 6 mesi"
#: app/models.py:715 app/templates/recurring/form.html:60
msgid "Yearly"
msgstr "Annuale"
#: app/models.py:720
-#, fuzzy
msgid "Business"
-msgstr "Usa SSL"
+msgstr "Lavoro"
#: app/models.py:721
-#, fuzzy
msgid "Personal"
-msgstr "Versione"
+msgstr "Personale"
#: app/models.py:722
-#, fuzzy
msgid "Commute"
-msgstr "Completa"
+msgstr "Pendolarismo"
#: app/models.py:723
msgid "Medical"
-msgstr ""
+msgstr "Medico"
#: app/models.py:724
-#, fuzzy
msgid "Charity"
-msgstr "Città"
+msgstr "Beneficenza"
#: app/models.py:730
-#, fuzzy
msgid "Home Charging"
-msgstr "Ricarica EV"
+msgstr "Ricarica Domestica"
#: app/models.py:731
msgid "Level 1"
-msgstr ""
+msgstr "Livello 1"
#: app/models.py:732
msgid "Level 2"
-msgstr ""
+msgstr "Livello 2"
#: app/models.py:733
-#, fuzzy
msgid "DC Fast Charge"
-msgstr "Registra la Tua Prima Ricarica"
+msgstr "Ricarica Rapida AC"
#: app/models.py:734
msgid "Tesla Supercharger"
-msgstr ""
+msgstr "Supercharger Tesla"
#: app/models.py:741 app/models.py:1119
-#, fuzzy
msgid "Oil Filter"
-msgstr "Filtra"
+msgstr "Filtro Olio"
#: app/models.py:742 app/models.py:1120
-#, fuzzy
msgid "Air Filter"
-msgstr "Filtra"
+msgstr "Filtro Aria"
#: app/models.py:743
msgid "Cabin/Pollen Filter"
-msgstr ""
+msgstr "Filtro Abitacolo/Antipolline"
#: app/models.py:744 app/models.py:1121
-#, fuzzy
msgid "Fuel Filter"
-msgstr "Filtra"
+msgstr "Filtro Carburante"
#: app/models.py:745
msgid "Spark Plugs"
-msgstr ""
+msgstr "Candele"
#: app/models.py:746
-#, fuzzy
msgid "Brake Pads"
-msgstr "Torna ai viaggi"
+msgstr "Pastiglie Freno"
#: app/models.py:747 app/models.py:1125
msgid "Brake Fluid"
-msgstr ""
+msgstr "Liquido Freni"
#: app/models.py:748
msgid "Coolant Flush"
-msgstr ""
+msgstr "Lavaggio Liquido di Raffreddamento"
#: app/models.py:749
-#, fuzzy
msgid "Transmission Service"
-msgstr "Servizi di Notifica"
+msgstr "Manutenzione Cambio"
#: app/models.py:750
msgid "Timing Belt"
-msgstr ""
+msgstr "Cinghia di Distribuzione"
#: app/models.py:751
msgid "Serpentine Belt"
-msgstr ""
+msgstr "Cinghia Servizi"
#: app/models.py:752
-#, fuzzy
msgid "Tire Rotation"
-msgstr "Integrazione Tessie"
+msgstr "Rotazione Pneumatici"
#: app/models.py:753
msgid "Wheel Alignment"
-msgstr ""
+msgstr "Convergenza Ruote"
#: app/models.py:754
msgid "Battery Check/Replace"
-msgstr ""
+msgstr "Controllo/Sostituzione Batteria"
#: app/models.py:755
msgid "Wiper Blades"
-msgstr ""
+msgstr "Tergicristalli"
#: app/models.py:756
msgid "Full Service"
-msgstr ""
+msgstr "Tagliando Completo"
#: app/models.py:762
-#, fuzzy
msgid "Insurance Policy"
-msgstr "es., Polizza Assicurativa 2024"
+msgstr "Polizza Assicurativa"
#: app/models.py:763
-#, fuzzy
msgid "Registration/V5C"
-msgstr "Consenti Registrazione"
+msgstr "Registrazione/V5C"
#: app/models.py:764
msgid "MOT Certificate"
-msgstr ""
+msgstr "Certificato Revisione"
#: app/models.py:765
-#, fuzzy
msgid "Service Record"
-msgstr "Intervallo di Servizio"
+msgstr "Storico Manutenzione"
#: app/models.py:766
msgid "Purchase Invoice"
-msgstr ""
+msgstr "Fattura d'Acquisto"
#: app/models.py:767
-#, fuzzy
msgid "Warranty Document"
-msgstr "Nessun documento"
+msgstr "Documento di Garanzia"
#: app/models.py:768
msgid "Owner's Manual"
-msgstr ""
+msgstr "Manuale d'Uso"
#: app/models.py:1118
msgid "Engine Oil"
-msgstr ""
+msgstr "Olio Motore"
#: app/models.py:1122
-#, fuzzy
msgid "Cabin Filter"
-msgstr "Filtra"
+msgstr "Filtro Abitacolo"
#: app/models.py:1123
-#, fuzzy
msgid "Spark Plug"
-msgstr "Pagina Iniziale"
+msgstr "Candela"
#: app/models.py:1124
msgid "Brake Pad"
-msgstr ""
+msgstr "Pastiglia Freno"
#: app/models.py:1126
msgid "Coolant"
-msgstr ""
+msgstr "Liquido di Raffreddamento"
#: app/models.py:1128
-#, fuzzy
msgid "Battery"
-msgstr "Livello Batteria"
+msgstr "Batteria"
#: app/models.py:1129
-#, fuzzy
msgid "Tire"
-msgstr "Titolo"
+msgstr "Pneumatico"
#: app/models.py:1130
-#, fuzzy
msgid "Belt"
-msgstr "Elimina"
+msgstr "Cinghia"
#: app/models.py:1131
msgid "Wiper Blade"
-msgstr ""
+msgstr "Tergicristallo"
#: app/models.py:1132
msgid "Light Bulb"
-msgstr ""
+msgstr "Lampadina"
#: app/routes/api.py:2141 app/routes/api.py:2354 app/routes/api.py:2527
msgid "No file uploaded"
@@ -1040,7 +989,7 @@ msgstr "Ricarica EV"
#: app/templates/base.html:325 app/templates/base.html:387
#: app/templates/fuel/quick.html:7
msgid "Quick Fuel Entry"
-msgstr "Rifornimento Rapido"
+msgstr "Inserimento Rapido Carburante"
#: app/templates/base.html:329 app/templates/timeline/index.html:102
#: app/templates/vehicles/view.html:55
@@ -2213,7 +2162,7 @@ msgstr "Posizione"
#: app/templates/charging/form.html:67
msgid "e.g., Home, Walmart, ChargePoint Station"
-msgstr "es., Casa, Centro Commerciale, Stazione ChargePoint"
+msgstr "es., Casa, Walmart, Stazione ChargePoint"
#: app/templates/charging/form.html:72
msgid "Network"
@@ -2395,7 +2344,7 @@ msgstr "Eliminare questo documento?"
#: app/templates/documents/index.html:8
msgid "Vehicle documents, insurance, MOT certificates"
-msgstr "Documenti del veicolo, assicurazione, certificati MOT"
+msgstr "Documenti del veicolo, assicurazione, certificati revisione"
#: app/templates/documents/index.html:74
msgid "Expires"
@@ -2413,7 +2362,7 @@ msgstr "Nessun documento"
msgid "Store your vehicle documents, insurance policies, and MOT certificates."
msgstr ""
"Archivia i documenti del veicolo, le polizze assicurative e i certificati"
-" MOT."
+" revisione."
#: app/templates/documents/view.html:30 app/templates/maintenance/index.html:83
#: app/templates/stations/index.html:65 app/templates/vehicles/view.html:40
@@ -3022,363 +2971,329 @@ msgid "No trips logged for"
msgstr "Nessun viaggio registrato per"
#: app/templates/vehicles/form.html:2 app/templates/vehicles/form.html:8
-#, fuzzy
msgid "Edit Vehicle"
-msgstr "Veicolo"
+msgstr "Modifica Veicolo"
#: app/templates/vehicles/form.html:2 app/templates/vehicles/form.html:269
#: app/templates/vehicles/index.html:32 app/templates/vehicles/index.html:108
-#, fuzzy
msgid "Add Vehicle"
-msgstr "Tutti i Veicoli"
+msgstr "Aggiungi Veicolo"
#: app/templates/vehicles/form.html:7 app/templates/vehicles/view.html:11
-#, fuzzy
msgid "Back to vehicles"
-msgstr "Tutti i Veicoli"
+msgstr "Torna ai Veicoli"
#: app/templates/vehicles/form.html:8
-#, fuzzy
msgid "Add New Vehicle"
-msgstr "Tutti i Veicoli"
+msgstr "Aggiungi Nuovo Veicolo"
#: app/templates/vehicles/form.html:14
-#, fuzzy
msgid "Basic Information"
-msgstr "Informazioni Account"
+msgstr "Informazioni di Base"
#: app/templates/vehicles/form.html:36
msgid "Tracking Unit"
-msgstr ""
+msgstr "Unità di Monitoraggio"
#: app/templates/vehicles/form.html:43
msgid "Use \"Hours\" for tractors, ATVs, boats, etc."
-msgstr ""
+msgstr "Usa \"Ore\" per trattori, ATV, barche, ecc."
#: app/templates/vehicles/form.html:47
-#, fuzzy
msgid "Odometer Unit"
-msgstr "Contachilometri"
+msgstr "Unità Contachilometri"
#: app/templates/vehicles/form.html:50
-#, fuzzy
msgid "Use account default"
-msgstr "I dettagli del tuo account"
+msgstr "Usa impostazioni predefinite account"
#: app/templates/vehicles/form.html:55
msgid ""
"Override the odometer unit for this vehicle. Useful when you have "
"vehicles with different odometer units."
msgstr ""
+"Ignora l'unità del contachilometri per questo veicolo. Utile quando hai "
+"veicoli con unità di contachilometri diverse."
#: app/templates/vehicles/form.html:59
-#, fuzzy
msgid "Fuel Type"
-msgstr "Tipo"
+msgstr "Tipo di Carburante"
#: app/templates/vehicles/form.html:69
msgid "Make"
-msgstr ""
+msgstr "Marca"
#: app/templates/vehicles/form.html:77
-#, fuzzy
msgid "Model"
-msgstr "Altro"
+msgstr "Modello"
#: app/templates/vehicles/form.html:94
msgid "Tank Capacity (L)"
-msgstr ""
+msgstr "Capacità Serbatoio (L)"
#: app/templates/vehicles/form.html:104
-#, fuzzy
msgid "Identification"
-msgstr "Notifiche"
+msgstr "Identificazione"
#: app/templates/vehicles/form.html:108
-#, fuzzy
msgid "Registration / License Plate"
-msgstr "Impostazioni di registrazione aggiornate"
+msgstr "Registrazione / Targa"
#: app/templates/vehicles/form.html:116 app/templates/vehicles/view.html:328
msgid "VIN"
msgstr "VIN"
#: app/templates/vehicles/form.html:126
-#, fuzzy
msgid "Photo"
-msgstr "CAP"
+msgstr "Foto"
#: app/templates/vehicles/form.html:129
-#, fuzzy
msgid "Vehicle Image"
-msgstr "Veicolo"
+msgstr "Immagine Veicolo"
#: app/templates/vehicles/form.html:143 app/templates/vehicles/view.html:447
-#, fuzzy
msgid "Specifications"
-msgstr "Notifiche"
+msgstr "Specifiche"
#: app/templates/vehicles/form.html:144
msgid "Add technical details like tire sizes, oil type, wiper sizes, etc."
msgstr ""
+"Aggiungi dettagli tecnici come dimensioni pneumatici, tipo olio, dimensioni "
+"tergicristalli, ecc."
#: app/templates/vehicles/form.html:178
-#, fuzzy
msgid "Add Specification"
-msgstr "Aggiungi Stazione"
+msgstr "Aggiungi Specifica"
#: app/templates/vehicles/form.html:186
-#, fuzzy
msgid "General Notes"
-msgstr "Note opzionali"
+msgstr "Note Generali"
#: app/templates/vehicles/form.html:195
-#, fuzzy
msgid "Status"
-msgstr "Stato Bollo"
+msgstr "Stato"
#: app/templates/vehicles/form.html:200
msgid "Active (show in lists and calculations)"
-msgstr ""
+msgstr "Attivo (mostra in elenchi e calcoli)"
#: app/templates/vehicles/form.html:216
msgid ""
"Link this vehicle to Tessie for automatic odometer and battery tracking. "
"When enabled, manual odometer entry will be disabled."
msgstr ""
+"Collega questo veicolo a Tessie per il monitoraggio automatico del "
+"contachilometri e della batteria. Quando abilitato, l'inserimento manuale"
+" del contachilometri sarà disabilitato."
#: app/templates/vehicles/form.html:220
-#, fuzzy
msgid "Tessie VIN"
-msgstr "Tessie"
+msgstr "Tessie VIN"
#: app/templates/vehicles/form.html:232
-#, fuzzy
msgid "Lookup"
-msgstr "Disconnetti"
+msgstr "Ricerca"
#: app/templates/vehicles/form.html:243
msgid "Enable Tessie tracking (disables manual odometer entry)"
-msgstr ""
+msgstr "Abilita tracciamento Tessie (disabilita inserimento manuale contachilometri)"
#: app/templates/vehicles/form.html:253
-#, fuzzy
msgid "Tessie tracking is active for this vehicle"
-msgstr "Nessun dato Tessie disponibile per questo veicolo."
+msgstr "Tracciamento Tessie attivo per questo veicolo"
#: app/templates/vehicles/index.html:7
-#, fuzzy
msgid "Archived Vehicles"
-msgstr "Tutti i Veicoli"
+msgstr "Veicoli Archiviati"
#: app/templates/vehicles/index.html:8
msgid "Manage your cars, vans, motorbikes, and scooters"
msgstr ""
+"Gestisci le tue auto, furgoni, moto e scooter"
#: app/templates/vehicles/index.html:18
-#, fuzzy
msgid "Active Vehicles"
-msgstr "Tutti i Veicoli"
+msgstr "Veicoli Attivi"
#: app/templates/vehicles/index.html:23
-#, fuzzy
msgid "Archived"
-msgstr "Attiva"
+msgstr "Archiviati"
#: app/templates/vehicles/index.html:83
-#, fuzzy
msgid "Inactive"
-msgstr "Attiva"
+msgstr "Inattivi"
#: app/templates/vehicles/index.html:100
-#, fuzzy
msgid "No vehicles"
-msgstr "Veicoli"
+msgstr "Nessun veicolo"
#: app/templates/vehicles/index.html:101
msgid "Get started by adding your first vehicle."
msgstr ""
+"Inizia aggiungendo il tuo primo veicolo."
#: app/templates/vehicles/part_form.html:2
#: app/templates/vehicles/part_form.html:8
-#, fuzzy
msgid "Edit Part"
-msgstr "Modifica Viaggio"
+msgstr "Modifica Ricambio"
#: app/templates/vehicles/part_form.html:2
#: app/templates/vehicles/part_form.html:8
#: app/templates/vehicles/part_form.html:102
#: app/templates/vehicles/parts.html:19 app/templates/vehicles/view.html:530
-#, fuzzy
msgid "Add Part"
-msgstr "Ricambi"
+msgstr "Aggiungi Ricambio"
#: app/templates/vehicles/part_form.html:7
-#, fuzzy
msgid "Back to parts"
-msgstr "Torna ai viaggi"
+msgstr "Torna ai Ricambi"
#: app/templates/vehicles/part_form.html:15
-#, fuzzy
msgid "Part Details"
-msgstr "Dettagli Account"
+msgstr "Dettagli Ricambio"
#: app/templates/vehicles/part_form.html:19
-#, fuzzy
msgid "Part Type"
-msgstr "Tipo di Caricatore"
+msgstr "Tipo Ricambio"
#: app/templates/vehicles/part_form.html:37
-#, fuzzy
msgid "Specification"
-msgstr "Notifiche"
+msgstr "Specifica"
#: app/templates/vehicles/part_form.html:42
msgid "Oil viscosity, filter model, tire size, etc."
-msgstr ""
+msgstr "Viscosità olio, modello filtro, dimensione pneumatico, ecc."
#: app/templates/vehicles/part_form.html:46
msgid "Quantity"
-msgstr ""
+msgstr "Quantità"
#: app/templates/vehicles/part_form.html:54
-#, fuzzy
msgid "Unit"
-msgstr "Importo"
+msgstr "Unità"
#: app/templates/vehicles/part_form.html:57
-#, fuzzy
msgid "Select unit..."
-msgstr "Seleziona tipo..."
+msgstr "Seleziona unità..."
#: app/templates/vehicles/part_form.html:58
msgid "Liters (L)"
-msgstr ""
+msgstr "Litri (L)"
#: app/templates/vehicles/part_form.html:59
msgid "Milliliters (ml)"
-msgstr ""
+msgstr "Millilitri (ml)"
#: app/templates/vehicles/part_form.html:60
msgid "Gallons (gal)"
-msgstr ""
+msgstr "Galloni (gal)"
#: app/templates/vehicles/part_form.html:61
msgid "Quarts (qt)"
-msgstr ""
+msgstr "Quarti (qt)"
#: app/templates/vehicles/part_form.html:62
-#, fuzzy
msgid "Units"
-msgstr "Note"
+msgstr "Unità"
#: app/templates/vehicles/part_form.html:63
-#, fuzzy
msgid "Pieces"
-msgstr "Accesso API"
+msgstr "Pezzi"
#: app/templates/vehicles/part_form.html:64
-#, fuzzy
msgid "Set"
-msgstr "Usa TLS"
+msgstr "Set"
#: app/templates/vehicles/part_form.html:65
-#, fuzzy
msgid "Pair"
-msgstr "Ricambi"
+msgstr "Coppia"
#: app/templates/vehicles/part_form.html:70
msgid "Part Number"
-msgstr ""
+msgstr "Codice Ricambio"
#: app/templates/vehicles/part_form.html:78
msgid "Supplier URL"
-msgstr ""
+msgstr "URL Fornitore"
#: app/templates/vehicles/part_form.html:83
msgid "Link to purchase this part"
-msgstr ""
+msgstr "Link per acquistare questo ricambio"
#: app/templates/vehicles/parts.html:2 app/templates/vehicles/parts.html:11
#: app/templates/vehicles/view.html:480
msgid "Parts & Consumables"
-msgstr ""
+msgstr "Ricambi e Consumabili"
#: app/templates/vehicles/parts.html:47
msgid "Qty:"
-msgstr ""
+msgstr "Q.tà:"
#: app/templates/vehicles/parts.html:94
-#, fuzzy
msgid "No parts added"
-msgstr "Energia Aggiunta"
+msgstr "Nessun ricambio aggiunto"
#: app/templates/vehicles/parts.html:95
msgid "Track the parts and consumables needed for servicing this vehicle."
msgstr ""
+"Tieni traccia dei ricambi e dei consumabili necessari per la manutenzione"
+" di questo veicolo."
#: app/templates/vehicles/parts.html:102
-#, fuzzy
msgid "Add First Part"
-msgstr "Aggiungi Stazione"
+msgstr "Aggiungi Primo Ricambio"
#: app/templates/vehicles/share.html:2 app/templates/vehicles/share.html:20
#: app/templates/vehicles/view.html:44
-#, fuzzy
msgid "Share"
-msgstr "Salva"
+msgstr "Condividi"
#: app/templates/vehicles/share.html:8
-#, fuzzy
msgid "Share Vehicle"
-msgstr "Tutti i Veicoli"
+msgstr "Condividi Veicolo"
#: app/templates/vehicles/share.html:9
msgid "Allow other users to view and add logs to this vehicle"
msgstr ""
+"Consenti ad altri utenti di visualizzare e aggiungere registri a questo "
+"veicolo"
#: app/templates/vehicles/share.html:13
-#, fuzzy
msgid "Add User"
-msgstr "Crea Utente"
+msgstr "Aggiungi Utente"
#: app/templates/vehicles/share.html:16
-#, fuzzy
msgid "Enter username"
-msgstr "Nome Utente SMTP"
+msgstr "Inserisci nome utente"
#: app/templates/vehicles/share.html:27
msgid "Shared With"
-msgstr ""
+msgstr "Condiviso Con"
#: app/templates/vehicles/share.html:39
-#, fuzzy
msgid "Remove"
-msgstr "Rimuovi Logo"
+msgstr "Rimuovi"
#: app/templates/vehicles/share.html:45
msgid "This vehicle is not shared with anyone yet."
-msgstr ""
+msgstr "Questo veicolo non è ancora condiviso con nessuno."
#: app/templates/vehicles/view.html:32
-#, fuzzy
msgid "Download PDF Report"
-msgstr "Scarica ZIP"
+msgstr "Scarica Report in PDF"
#: app/templates/vehicles/view.html:56 app/templates/vehicles/view.html:60
#, fuzzy
msgid "Not set"
-msgstr "Note"
+msgstr "Non impostato"
#: app/templates/vehicles/view.html:63
-#, fuzzy
msgid "Last Odometer"
-msgstr "Ultimo contachilometri"
+msgstr "Ultimo Contachilometri"
#: app/templates/vehicles/view.html:89
-#, fuzzy
msgid "Avg. Consumption"
-msgstr "Consumo di Carburante"
+msgstr "Consumo Medio"
#: app/templates/vehicles/view.html:103
msgid "Add Fuel Log"
@@ -3414,11 +3329,11 @@ msgstr "Aggiorna"
#: app/templates/vehicles/view.html:174
msgid "MOT Status"
-msgstr "Stato MOT"
+msgstr "Stato Revisione"
#: app/templates/vehicles/view.html:192
msgid "MOT Expiry"
-msgstr "Scadenza MOT"
+msgstr "Scadenza Revisione"
#: app/templates/vehicles/view.html:202
msgid "Tax Status"
@@ -3473,125 +3388,118 @@ msgid ""
"This vehicle is archived. It won't appear in regular lists or "
"calculations."
msgstr ""
+"Questo veicolo è archiviato. Non apparirà negli elenchi normali o nei "
+"calcoli."
#: app/templates/vehicles/view.html:371
-#, fuzzy
msgid "Upcoming Reminders"
msgstr "Promemoria in arrivo"
#: app/templates/vehicles/view.html:383
-#, fuzzy
msgid "Mark as completed"
-msgstr "Segna come Completato"
+msgstr "Segna come completato"
#: app/templates/vehicles/view.html:410
#, python-format
msgid "%(days)s days overdue"
-msgstr ""
+msgstr "%(days)s giorni di ritardo"
#: app/templates/vehicles/view.html:412
-#, fuzzy
msgid "Due today"
-msgstr "In Scadenza"
+msgstr "Scade oggi"
#: app/templates/vehicles/view.html:414
-#, fuzzy
msgid "Due tomorrow"
-msgstr "In Scadenza"
+msgstr "Scade domani"
#: app/templates/vehicles/view.html:416
#, python-format
msgid "In %(days)s days"
-msgstr ""
+msgstr "Tra %(days)s giorni"
#: app/templates/vehicles/view.html:524
msgid "No parts added yet."
-msgstr ""
+msgstr "Nessun ricambio aggiunto ancora."
#: app/templates/vehicles/view.html:538
-#, fuzzy
msgid "Fuel Consumption Trend"
-msgstr "Consumo di Carburante"
+msgstr "Tendenza Consumo Carburante"
#: app/templates/vehicles/view.html:561
-#, fuzzy
msgid "(Full)"
-msgstr "Carburante"
+msgstr "(Pieno)"
#: app/templates/vehicles/view.html:578
-#, fuzzy
msgid "Delete this fuel log?"
-msgstr "Eliminare questa stazione?"
+msgstr "Eliminare questo registro carburante?"
#: app/templates/vehicles/view.html:593
-#, fuzzy
msgid "No fuel logs yet."
-msgstr "Registri Carburante"
+msgstr "Nessun registro carburante ancora."
#: app/templates/vehicles/view.html:622
-#, fuzzy
msgid "Delete this expense?"
-msgstr "Eliminare questa spesa ricorrente?"
+msgstr "Eliminare questa spesa?"
#: app/templates/vehicles/view.html:637
-#, fuzzy
msgid "No expenses yet."
-msgstr "Altre Spese"
+msgstr "Nessuna spesa ancora."
#: app/templates/vehicles/view.html:653
-#, fuzzy
msgid "Archive this vehicle"
-msgstr "Veicolo non valido"
+msgstr "Archivia questo veicolo"
#: app/templates/vehicles/view.html:654
msgid ""
"Archived vehicles won't appear in regular lists or calculations. You can "
"restore them later."
msgstr ""
+"I veicoli archiviati non appariranno negli elenchi normali o nei "
+"calcoli. Puoi ripristinarli in seguito."
#: app/templates/vehicles/view.html:656
-#, fuzzy
msgid "Restore this vehicle"
-msgstr "I Tuoi Veicoli"
+msgstr "Ripristina questo veicolo"
#: app/templates/vehicles/view.html:657
msgid ""
"Restore this vehicle to make it active again and include it in "
"calculations."
msgstr ""
+"Ripristina questo veicolo per renderlo nuovamente attivo e includerlo nei "
+"calcoli."
#: app/templates/vehicles/view.html:665
-#, fuzzy
msgid "Archive Vehicle"
-msgstr "Veicolo non valido"
+msgstr "Archivia Veicolo"
#: app/templates/vehicles/view.html:673
-#, fuzzy
msgid "Restore Vehicle"
-msgstr "I Tuoi Veicoli"
+msgstr "Ripristina Veicolo"
#: app/templates/vehicles/view.html:683
-#, fuzzy
msgid "Delete this vehicle"
-msgstr "Eliminare questo documento?"
+msgstr "Elimina questo veicolo"
#: app/templates/vehicles/view.html:684
msgid ""
"Once you delete a vehicle, there is no going back. This will also delete "
"all associated fuel logs and expenses."
msgstr ""
+"Una volta eliminato un veicolo, non si può tornare indietro. Questo "
+"eliminerà anche tutti i registri carburante e le spese associate."
#: app/templates/vehicles/view.html:687
msgid ""
"Are you sure you want to delete this vehicle? This action cannot be "
"undone."
msgstr ""
+"Sei sicuro di voler eliminare questo veicolo? Questa azione non può essere"
+" annullata."
#: app/templates/vehicles/view.html:691
-#, fuzzy
msgid "Delete Vehicle"
-msgstr "Tutti i Veicoli"
+msgstr "Elimina Veicolo"
#~ msgid "Make"
#~ msgstr "Marca"
-
diff --git a/config.py b/config.py
index 26da232..0de9047 100644
--- a/config.py
+++ b/config.py
@@ -4,7 +4,7 @@
basedir = Path(__file__).parent.absolute()
-APP_VERSION = '0.21.1'
+APP_VERSION = '0.22.0'
RELEASE_CHANNEL = os.environ.get('RELEASE_CHANNEL', 'stable')
GIT_SHA = os.environ.get('GIT_SHA', '')[:7] # Short SHA
GITHUB_REPO = 'dannymcc/may'
@@ -54,4 +54,4 @@ class Config:
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or f'sqlite:///{basedir}/data/may.db'
SQLALCHEMY_TRACK_MODIFICATIONS = False
UPLOAD_FOLDER = os.environ.get('UPLOAD_FOLDER') or str(basedir / 'data' / 'uploads')
- MAX_CONTENT_LENGTH = 16 * 1024 * 1024 # 16MB max upload
+ MAX_CONTENT_LENGTH = 300 * 1024 * 1024 # 300MB max upload
diff --git a/migrations/versions/42b26bf6d488_add_is_shared_to_vehicles.py b/migrations/versions/42b26bf6d488_add_is_shared_to_vehicles.py
new file mode 100644
index 0000000..bdecdf8
--- /dev/null
+++ b/migrations/versions/42b26bf6d488_add_is_shared_to_vehicles.py
@@ -0,0 +1,38 @@
+"""add is_shared to vehicles
+
+Revision ID: 42b26bf6d488
+Revises: f1a2b3c4d5e6
+Create Date: 2026-05-02 13:25:51.518378
+
+"""
+from alembic import op
+import sqlalchemy as sa
+
+
+# revision identifiers, used by Alembic.
+revision = '42b26bf6d488'
+down_revision = 'f1a2b3c4d5e6'
+branch_labels = None
+depends_on = None
+
+
+def upgrade():
+ # ### commands auto generated by Alembic - please adjust! ###
+ with op.batch_alter_table('charging_sessions', schema=None) as batch_op:
+ batch_op.drop_index(batch_op.f('ix_charging_sessions_tessie_charge_id'))
+
+ with op.batch_alter_table('vehicles', schema=None) as batch_op:
+ batch_op.add_column(sa.Column('is_shared', sa.Boolean(), nullable=False, server_default=sa.false()))
+
+ # ### end Alembic commands ###
+
+
+def downgrade():
+ # ### commands auto generated by Alembic - please adjust! ###
+ with op.batch_alter_table('vehicles', schema=None) as batch_op:
+ batch_op.drop_column('is_shared')
+
+ with op.batch_alter_table('charging_sessions', schema=None) as batch_op:
+ batch_op.create_index(batch_op.f('ix_charging_sessions_tessie_charge_id'), ['tessie_charge_id'], unique=1)
+
+ # ### end Alembic commands ###
diff --git a/migrations/versions/f1a2b3c4d5e6_add_annual_mileage_limit_to_vehicles.py b/migrations/versions/f1a2b3c4d5e6_add_annual_mileage_limit_to_vehicles.py
new file mode 100644
index 0000000..2d6aa37
--- /dev/null
+++ b/migrations/versions/f1a2b3c4d5e6_add_annual_mileage_limit_to_vehicles.py
@@ -0,0 +1,39 @@
+"""add annual mileage limit to vehicles
+
+Revision ID: f1a2b3c4d5e6
+Revises: ee92897cc33b
+Create Date: 2026-04-27 18:00:00.000000
+
+"""
+from alembic import op
+import sqlalchemy as sa
+
+
+# revision identifiers, used by Alembic.
+revision = 'f1a2b3c4d5e6'
+down_revision = 'ee92897cc33b'
+branch_labels = None
+depends_on = None
+
+
+def upgrade():
+ bind = op.get_bind()
+ inspector = sa.inspect(bind)
+ vehicle_cols = [c['name'] for c in inspector.get_columns('vehicles')]
+
+ cols_to_add = []
+ if 'annual_mileage_limit' not in vehicle_cols:
+ cols_to_add.append(sa.Column('annual_mileage_limit', sa.Float(), nullable=True))
+ if 'annual_mileage_start_date' not in vehicle_cols:
+ cols_to_add.append(sa.Column('annual_mileage_start_date', sa.Date(), nullable=True))
+
+ if cols_to_add:
+ with op.batch_alter_table('vehicles', schema=None) as batch_op:
+ for col in cols_to_add:
+ batch_op.add_column(col)
+
+
+def downgrade():
+ with op.batch_alter_table('vehicles', schema=None) as batch_op:
+ batch_op.drop_column('annual_mileage_start_date')
+ batch_op.drop_column('annual_mileage_limit')
diff --git a/requirements.txt b/requirements.txt
index 668c8e1..4597bb3 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,16 +1,16 @@
flask>=3.0.0
flask-sqlalchemy>=3.1.1
-flask-migrate>=4.0.0
+flask-migrate>=4.1.0
flask-login>=0.6.3
flask-wtf>=1.2.1
flask-babel>=4.0.0
-werkzeug>=3.0.1
+werkzeug>=3.1.8
python-dotenv>=1.0.0
pillow>=10.4.0
-gunicorn>=21.2.0
+gunicorn>=25.3.0
weasyprint>=62.0
-requests>=2.31.0
-python-dateutil>=2.8.2
+requests>=2.33.1
+python-dateutil>=2.9.0.post0
pytest>=8.0.0
pytest-cov>=4.1.0
coverage>=7.0.0
diff --git a/tests/test_expenses.py b/tests/test_expenses.py
index 37b219b..19ae998 100644
--- a/tests/test_expenses.py
+++ b/tests/test_expenses.py
@@ -1,6 +1,7 @@
import pytest
+from datetime import date
from app import db
-from app.models import Expense
+from app.models import Expense, EXPENSE_CATEGORIES
class TestExpenseIndex:
@@ -98,3 +99,56 @@ def test_delete_expense(self, auth_client, sample_expense):
resp = auth_client.post(f'/expenses/{expense_id}/delete', follow_redirects=True)
assert resp.status_code == 200
assert Expense.query.get(expense_id) is None
+
+
+class TestExpenseCategories:
+ def test_inspection_category_exists(self):
+ category_keys = [k for k, _ in EXPENSE_CATEGORIES]
+ assert 'inspection' in category_keys
+
+ def test_create_inspection_expense(self, auth_client, sample_vehicle):
+ resp = auth_client.post('/expenses/new', data={
+ 'vehicle_id': str(sample_vehicle.id),
+ 'date': '2024-03-01',
+ 'category': 'inspection',
+ 'description': 'Annual MOT inspection',
+ 'cost': '55.00',
+ }, follow_redirects=True)
+ assert resp.status_code == 200
+ expense = Expense.query.filter_by(description='Annual MOT inspection').first()
+ assert expense is not None
+ assert expense.category == 'inspection'
+
+ def test_expense_list_shows_odometer(self, auth_client, test_user, sample_vehicle):
+ expense = Expense(
+ vehicle_id=sample_vehicle.id,
+ user_id=test_user.id,
+ date=date(2024, 3, 1),
+ category='maintenance',
+ description='Oil change with odometer',
+ cost=40.0,
+ odometer=12345.0,
+ )
+ db.session.add(expense)
+ db.session.commit()
+ resp = auth_client.get('/expenses/')
+ assert resp.status_code == 200
+ assert b'12345' in resp.data
+
+ def test_expense_list_shows_expandable_details(self, auth_client, test_user, sample_vehicle):
+ expense = Expense(
+ vehicle_id=sample_vehicle.id,
+ user_id=test_user.id,
+ date=date(2024, 3, 2),
+ category='repairs',
+ description='Brake pads',
+ cost=120.0,
+ vendor='AutoShop Ltd',
+ notes='Front brakes replaced',
+ )
+ db.session.add(expense)
+ db.session.commit()
+ resp = auth_client.get('/expenses/')
+ assert resp.status_code == 200
+ assert b'AutoShop Ltd' in resp.data
+ assert b'Front brakes replaced' in resp.data
diff --git a/tests/test_vehicles.py b/tests/test_vehicles.py
index 2f4bcdd..10f44de 100644
--- a/tests/test_vehicles.py
+++ b/tests/test_vehicles.py
@@ -123,3 +123,85 @@ def test_archived_vehicles_shown_with_param(self, auth_client, sample_vehicle):
resp = auth_client.get('/vehicles/?archived=true')
assert resp.status_code == 200
assert b'Test Car' in resp.data
+
+
+class TestVehicleSharing:
+ def test_is_shared_defaults_false(self, sample_vehicle):
+ assert sample_vehicle.is_shared is False
+
+ def test_shared_vehicle_visible_to_other_user(self, app, test_user, sample_vehicle):
+ from app.models import User
+ other = User(username='other_user', email='other@example.com')
+ other.set_password('OtherPass123!')
+ db.session.add(other)
+ db.session.commit()
+
+ # Not shared yet — other user should not see it
+ assert sample_vehicle not in other.get_all_vehicles()
+
+ # Mark as shared
+ sample_vehicle.is_shared = True
+ db.session.commit()
+
+ assert sample_vehicle in other.get_all_vehicles()
+
+ def test_edit_vehicle_sets_is_shared(self, auth_client, sample_vehicle):
+ resp = auth_client.post(f'/vehicles/{sample_vehicle.id}/edit', data={
+ 'name': sample_vehicle.name,
+ 'vehicle_type': sample_vehicle.vehicle_type,
+ 'fuel_type': sample_vehicle.fuel_type,
+ 'tracking_unit': 'mileage',
+ 'is_active': 'on',
+ 'is_shared': 'on',
+ }, follow_redirects=True)
+ assert resp.status_code == 200
+ db.session.refresh(sample_vehicle)
+ assert sample_vehicle.is_shared is True
+
+ def test_edit_vehicle_clears_is_shared(self, auth_client, sample_vehicle):
+ sample_vehicle.is_shared = True
+ db.session.commit()
+
+ resp = auth_client.post(f'/vehicles/{sample_vehicle.id}/edit', data={
+ 'name': sample_vehicle.name,
+ 'vehicle_type': sample_vehicle.vehicle_type,
+ 'fuel_type': sample_vehicle.fuel_type,
+ 'tracking_unit': 'mileage',
+ 'is_active': 'on',
+ # is_shared omitted → checkbox unchecked
+ }, follow_redirects=True)
+ assert resp.status_code == 200
+ db.session.refresh(sample_vehicle)
+ assert sample_vehicle.is_shared is False
+
+ def test_shared_badge_shown_in_vehicle_list(self, auth_client, sample_vehicle):
+ sample_vehicle.is_shared = True
+ db.session.commit()
+ resp = auth_client.get('/vehicles/')
+ assert resp.status_code == 200
+ assert b'Shared' in resp.data
+
+
+class TestVehicleViewMaintenancePanel:
+ def test_view_shows_maintenance_panel(self, auth_client, app, test_user, sample_vehicle):
+ from app.models import MaintenanceSchedule
+ from datetime import date, timedelta
+ schedule = MaintenanceSchedule(
+ vehicle_id=sample_vehicle.id,
+ user_id=test_user.id,
+ name='Oil Change',
+ maintenance_type='oil_change',
+ next_due_date=date.today() + timedelta(days=15),
+ is_active=True,
+ )
+ db.session.add(schedule)
+ db.session.commit()
+ resp = auth_client.get(f'/vehicles/{sample_vehicle.id}')
+ assert resp.status_code == 200
+ assert b'Upcoming Maintenance' in resp.data
+ assert b'Oil Change' in resp.data
+
+ def test_view_hides_maintenance_panel_when_empty(self, auth_client, sample_vehicle):
+ resp = auth_client.get(f'/vehicles/{sample_vehicle.id}')
+ assert resp.status_code == 200
+ assert b'Upcoming Maintenance' not in resp.data