feat: motor vehicle selector in entry form and routes
This commit is contained in:
@@ -37,7 +37,7 @@ def index():
|
|||||||
month_km = {}
|
month_km = {}
|
||||||
month_co2 = 0.0
|
month_co2 = 0.0
|
||||||
for entry in month_entries:
|
for entry in month_entries:
|
||||||
km = compute_km_for_entry(entry.journey_profile_id, journeys)
|
km = compute_km_for_entry(entry.journey_profile_id, journeys, entry.motor_vehicle_id)
|
||||||
for v, d in km.items():
|
for v, d in km.items():
|
||||||
month_km[v] = month_km.get(v, 0) + d
|
month_km[v] = month_km.get(v, 0) + d
|
||||||
month_co2 += compute_co2_grams(km, vehicles)
|
month_co2 += compute_co2_grams(km, vehicles)
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ from datetime import date, time
|
|||||||
import sqlalchemy as sa
|
import sqlalchemy as sa
|
||||||
from app import db
|
from app import db
|
||||||
from app.models import WorkEntry, TimeSlot
|
from app.models import WorkEntry, TimeSlot
|
||||||
from app.config_loader import get_journeys, day_types_without_journey
|
from app.config_loader import get_journeys, get_motor_vehicles, day_types_without_journey, journey_has_motor
|
||||||
|
|
||||||
bp = Blueprint("entries", __name__, url_prefix="/entries")
|
bp = Blueprint("entries", __name__, url_prefix="/entries")
|
||||||
|
|
||||||
@@ -42,6 +42,9 @@ def entry_form(entry_id=None):
|
|||||||
entry_date = date.fromisoformat(request.form["date"])
|
entry_date = date.fromisoformat(request.form["date"])
|
||||||
day_type = request.form["day_type"]
|
day_type = request.form["day_type"]
|
||||||
journey_profile_id = request.form.get("journey_profile_id") or None
|
journey_profile_id = request.form.get("journey_profile_id") or None
|
||||||
|
motor_vehicle_id = request.form.get("motor_vehicle_id") or None
|
||||||
|
if not journey_has_motor(journey_profile_id):
|
||||||
|
motor_vehicle_id = None
|
||||||
comment = request.form.get("comment") or None
|
comment = request.form.get("comment") or None
|
||||||
|
|
||||||
if day_type in day_types_without_journey():
|
if day_type in day_types_without_journey():
|
||||||
@@ -60,6 +63,7 @@ def entry_form(entry_id=None):
|
|||||||
entry.day_type = day_type
|
entry.day_type = day_type
|
||||||
entry.journey_profile_id = journey_profile_id
|
entry.journey_profile_id = journey_profile_id
|
||||||
entry.comment = comment
|
entry.comment = comment
|
||||||
|
entry.motor_vehicle_id = motor_vehicle_id
|
||||||
|
|
||||||
for slot in list(entry.time_slots):
|
for slot in list(entry.time_slots):
|
||||||
db.session.delete(slot)
|
db.session.delete(slot)
|
||||||
@@ -84,6 +88,7 @@ def entry_form(entry_id=None):
|
|||||||
entry=entry,
|
entry=entry,
|
||||||
day_types=DAY_TYPES,
|
day_types=DAY_TYPES,
|
||||||
journeys=journeys,
|
journeys=journeys,
|
||||||
|
motor_vehicles=get_motor_vehicles(),
|
||||||
day_types_without_journey=day_types_without_journey(),
|
day_types_without_journey=day_types_without_journey(),
|
||||||
today=date.today().isoformat(),
|
today=date.today().isoformat(),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ def index():
|
|||||||
total_km = {}
|
total_km = {}
|
||||||
total_co2 = 0.0
|
total_co2 = 0.0
|
||||||
for entry in entries:
|
for entry in entries:
|
||||||
km = compute_km_for_entry(entry.journey_profile_id, journeys)
|
km = compute_km_for_entry(entry.journey_profile_id, journeys, entry.motor_vehicle_id)
|
||||||
for v, d in km.items():
|
for v, d in km.items():
|
||||||
total_km[v] = total_km.get(v, 0) + d
|
total_km[v] = total_km.get(v, 0) + d
|
||||||
total_co2 += compute_co2_grams(km, vehicles)
|
total_co2 += compute_co2_grams(km, vehicles)
|
||||||
|
|||||||
@@ -37,11 +37,13 @@
|
|||||||
<div id="journey-section"
|
<div id="journey-section"
|
||||||
class="{% if entry and entry.day_type in day_types_without_journey %}hidden{% endif %}">
|
class="{% if entry and entry.day_type in day_types_without_journey %}hidden{% endif %}">
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-1">Trajet domicile-travail</label>
|
<label class="block text-sm font-medium text-gray-700 mb-1">Trajet domicile-travail</label>
|
||||||
<select name="journey_profile_id"
|
<select name="journey_profile_id" id="journey_profile_id"
|
||||||
|
onchange="updateMotorVehicleVisibility(this.value)"
|
||||||
class="w-full border rounded-lg px-3 py-2 text-sm">
|
class="w-full border rounded-lg px-3 py-2 text-sm">
|
||||||
<option value="">— Pas de déplacement —</option>
|
<option value="">— Pas de déplacement —</option>
|
||||||
{% for jid, jdata in journeys.items() %}
|
{% for jid, jdata in journeys.items() %}
|
||||||
<option value="{{ jid }}"
|
<option value="{{ jid }}"
|
||||||
|
data-has-motor="{{ 'true' if 'moteur' in jdata.distances else 'false' }}"
|
||||||
{% if entry and entry.journey_profile_id == jid %}selected{% endif %}>
|
{% if entry and entry.journey_profile_id == jid %}selected{% endif %}>
|
||||||
{{ jdata.name }}
|
{{ jdata.name }}
|
||||||
({% for v, d in jdata.distances.items() %}{{ d }} km {{ v }}{% if not loop.last %} + {% endif %}{% endfor %})
|
({% for v, d in jdata.distances.items() %}{{ d }} km {{ v }}{% if not loop.last %} + {% endif %}{% endfor %})
|
||||||
@@ -50,6 +52,24 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="motor-vehicle-section" class="{% if not entry or not entry.motor_vehicle_id %}hidden{% endif %}">
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-1">Véhicule à moteur utilisé</label>
|
||||||
|
<div class="grid grid-cols-2 gap-2">
|
||||||
|
{% for vid, vdata in motor_vehicles.items() %}
|
||||||
|
<label class="cursor-pointer">
|
||||||
|
<input type="radio" name="motor_vehicle_id" value="{{ vid }}"
|
||||||
|
{% if entry and entry.motor_vehicle_id == vid %}checked{% endif %}
|
||||||
|
class="sr-only peer">
|
||||||
|
<div class="text-center text-sm py-2 px-1 rounded-lg border-2 border-gray-200
|
||||||
|
peer-checked:border-orange-500 peer-checked:bg-orange-50 peer-checked:text-orange-700
|
||||||
|
hover:border-gray-300 transition">
|
||||||
|
{{ vdata.name }}
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">Plages horaires</label>
|
<label class="block text-sm font-medium text-gray-700 mb-2">Plages horaires</label>
|
||||||
<div id="time-slots" class="space-y-2">
|
<div id="time-slots" class="space-y-2">
|
||||||
@@ -101,8 +121,23 @@
|
|||||||
const NO_JOURNEY_TYPES = {{ day_types_without_journey | list | tojson }};
|
const NO_JOURNEY_TYPES = {{ day_types_without_journey | list | tojson }};
|
||||||
|
|
||||||
function updateJourneyVisibility(dayType) {
|
function updateJourneyVisibility(dayType) {
|
||||||
const section = document.getElementById('journey-section');
|
const journeySection = document.getElementById('journey-section');
|
||||||
section.classList.toggle('hidden', NO_JOURNEY_TYPES.includes(dayType));
|
const hidden = NO_JOURNEY_TYPES.includes(dayType);
|
||||||
|
journeySection.classList.toggle('hidden', hidden);
|
||||||
|
if (hidden) {
|
||||||
|
updateMotorVehicleVisibility('');
|
||||||
|
} else {
|
||||||
|
const select = document.getElementById('journey_profile_id');
|
||||||
|
if (select) updateMotorVehicleVisibility(select.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateMotorVehicleVisibility(journeyId) {
|
||||||
|
const section = document.getElementById('motor-vehicle-section');
|
||||||
|
const select = document.getElementById('journey_profile_id');
|
||||||
|
const selectedOption = select ? select.querySelector(`option[value="${journeyId}"]`) : null;
|
||||||
|
const hasMotor = selectedOption && selectedOption.dataset.hasMotor === 'true';
|
||||||
|
section.classList.toggle('hidden', !hasMotor);
|
||||||
}
|
}
|
||||||
|
|
||||||
function addTimeSlot() {
|
function addTimeSlot() {
|
||||||
|
|||||||
Reference in New Issue
Block a user