Extract accommodation, trip statistics, holiday mapping and debug helpers
This commit is contained in:
parent
e3eb3e5af8
commit
cb370b9378
5 changed files with 204 additions and 169 deletions
|
|
@ -1,8 +1,12 @@
|
||||||
"""Accommodation."""
|
"""Accommodation."""
|
||||||
|
|
||||||
|
from collections import defaultdict
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
from .event import Event
|
from .event import Event
|
||||||
|
from .types import StrDict, Trip
|
||||||
|
|
||||||
|
|
||||||
def get_events(filepath: str) -> list[Event]:
|
def get_events(filepath: str) -> list[Event]:
|
||||||
|
|
@ -22,3 +26,52 @@ def get_events(filepath: str) -> list[Event]:
|
||||||
)
|
)
|
||||||
for item in yaml.safe_load(f)
|
for item in yaml.safe_load(f)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def prepare_accommodation_list(
|
||||||
|
items: list[StrDict], trips: list[Trip], now: datetime
|
||||||
|
) -> StrDict:
|
||||||
|
"""Link stays to trips and prepare date groups and annual night counts."""
|
||||||
|
# Create a dictionary to hold stats for each year
|
||||||
|
year_stats: defaultdict[int, dict[str, int]] = defaultdict(
|
||||||
|
lambda: {"total_nights": 0, "nights_abroad": 0}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Calculate stats for each year
|
||||||
|
for stay in items:
|
||||||
|
current_date = stay["from"].date()
|
||||||
|
end_date = stay["to"].date()
|
||||||
|
while current_date < end_date:
|
||||||
|
year = current_date.year
|
||||||
|
year_stats[year]["total_nights"] += 1
|
||||||
|
if stay.get("country") != "gb":
|
||||||
|
year_stats[year]["nights_abroad"] += 1
|
||||||
|
current_date += timedelta(days=1)
|
||||||
|
|
||||||
|
# Sort the stats by year in descending order
|
||||||
|
sorted_year_stats = sorted(
|
||||||
|
year_stats.items(), key=lambda item: item[0], reverse=True
|
||||||
|
)
|
||||||
|
|
||||||
|
trip_lookup = {}
|
||||||
|
|
||||||
|
for trip in trips:
|
||||||
|
for trip_stay in trip.accommodation:
|
||||||
|
key = (trip_stay["from"], trip_stay["name"])
|
||||||
|
trip_lookup[key] = trip
|
||||||
|
|
||||||
|
for item in items:
|
||||||
|
key = (item["from"], item["name"])
|
||||||
|
if this_trip := trip_lookup.get(key):
|
||||||
|
item["linked_trip"] = this_trip
|
||||||
|
|
||||||
|
past = [conf for conf in items if conf["to"] < now]
|
||||||
|
current = [conf for conf in items if conf["from"] <= now and conf["to"] >= now]
|
||||||
|
future = [conf for conf in items if conf["from"] > now]
|
||||||
|
|
||||||
|
return {
|
||||||
|
"past": past,
|
||||||
|
"current": current,
|
||||||
|
"future": future,
|
||||||
|
"year_stats": sorted_year_stats,
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -182,3 +182,30 @@ def get_all(last_year: date, next_year: date, data_dir: str) -> list[Holiday]:
|
||||||
holiday_list += get_holidays(country, last_year, next_year)
|
holiday_list += get_holidays(country, last_year, next_year)
|
||||||
|
|
||||||
return holiday_list
|
return holiday_list
|
||||||
|
|
||||||
|
|
||||||
|
def trip_school_holiday_map(trips: list[Trip], data_dir: str) -> dict[str, list[Event]]:
|
||||||
|
"""Map trip-start ISO date to overlapping UK school holidays."""
|
||||||
|
if not trips:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
starts = [trip.start for trip in trips]
|
||||||
|
ends = [trip.end or trip.start for trip in trips]
|
||||||
|
school_holidays = get_school_holidays(
|
||||||
|
min(starts),
|
||||||
|
max(ends),
|
||||||
|
data_dir,
|
||||||
|
)
|
||||||
|
|
||||||
|
result: dict[str, list[Event]] = {}
|
||||||
|
for trip in trips:
|
||||||
|
trip_end = trip.end or trip.start
|
||||||
|
overlaps = [
|
||||||
|
school_holiday
|
||||||
|
for school_holiday in school_holidays
|
||||||
|
if school_holiday.as_date <= trip_end
|
||||||
|
and school_holiday.end_as_date >= trip.start
|
||||||
|
]
|
||||||
|
result[trip.start.isoformat()] = overlaps
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
|
||||||
|
|
@ -151,3 +151,38 @@ def calculate_yearly_stats(
|
||||||
travel_legs(trip, yearly_stats[year])
|
travel_legs(trip, yearly_stats[year])
|
||||||
|
|
||||||
return dict(yearly_stats)
|
return dict(yearly_stats)
|
||||||
|
|
||||||
|
|
||||||
|
def calc_total_distance(trips: list[Trip]) -> float:
|
||||||
|
"""Total distance for trips."""
|
||||||
|
total = 0.0
|
||||||
|
for item in trips:
|
||||||
|
if dist := item.total_distance():
|
||||||
|
total += dist
|
||||||
|
|
||||||
|
return total
|
||||||
|
|
||||||
|
|
||||||
|
def calc_total_co2_kg(trips: list[Trip]) -> float:
|
||||||
|
"""Total CO₂ for trips."""
|
||||||
|
return sum(item.total_co2_kg() or 0.0 for item in trips)
|
||||||
|
|
||||||
|
|
||||||
|
def sum_distances_by_transport_type(trips: list[Trip]) -> list[tuple[str, float]]:
|
||||||
|
"""Sum distances by transport type."""
|
||||||
|
distances_by_transport_type: defaultdict[str, float] = defaultdict(float)
|
||||||
|
for trip in trips:
|
||||||
|
for transport_type, dist in trip.distances_by_transport_type():
|
||||||
|
distances_by_transport_type[transport_type] += dist
|
||||||
|
|
||||||
|
return list(distances_by_transport_type.items())
|
||||||
|
|
||||||
|
|
||||||
|
def sum_co2_by_transport_type(trips: list[Trip]) -> list[tuple[str, float]]:
|
||||||
|
"""Sum CO₂ by transport type."""
|
||||||
|
co2_by_transport_type: defaultdict[str, float] = defaultdict(float)
|
||||||
|
for trip in trips:
|
||||||
|
for transport_type, co2_kg in trip.co2_by_transport_type():
|
||||||
|
co2_by_transport_type[transport_type] += co2_kg
|
||||||
|
|
||||||
|
return list(co2_by_transport_type.items())
|
||||||
|
|
|
||||||
61
agenda/trip_debug.py
Normal file
61
agenda/trip_debug.py
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
"""Serialize trip details for the debug page."""
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
from agenda.types import Trip
|
||||||
|
|
||||||
|
|
||||||
|
def serialize_trip(trip: Trip) -> tuple[str, str]:
|
||||||
|
"""Return JSON and YAML including computed trip properties."""
|
||||||
|
# Convert trip object to dictionary for display
|
||||||
|
trip_dict = {
|
||||||
|
"start": trip.start.isoformat(),
|
||||||
|
"name": trip.name,
|
||||||
|
"private": trip.private,
|
||||||
|
"travel": trip.travel,
|
||||||
|
"accommodation": trip.accommodation,
|
||||||
|
"conferences": trip.conferences,
|
||||||
|
"events": trip.events,
|
||||||
|
"flight_bookings": trip.flight_bookings,
|
||||||
|
"computed_properties": {
|
||||||
|
"title": trip.title,
|
||||||
|
"end": trip.end.isoformat() if trip.end else None,
|
||||||
|
"countries": [
|
||||||
|
{"name": c.name, "alpha_2": c.alpha_2, "flag": c.flag}
|
||||||
|
for c in trip.countries
|
||||||
|
],
|
||||||
|
"locations": [
|
||||||
|
{
|
||||||
|
"location": loc,
|
||||||
|
"country": {"name": country.name, "alpha_2": country.alpha_2},
|
||||||
|
}
|
||||||
|
for loc, country in trip.locations()
|
||||||
|
],
|
||||||
|
"total_distance": trip.total_distance(),
|
||||||
|
"total_co2_kg": trip.total_co2_kg(),
|
||||||
|
"distances_by_transport_type": trip.distances_by_transport_type(),
|
||||||
|
"co2_by_transport_type": trip.co2_by_transport_type(),
|
||||||
|
},
|
||||||
|
"schengen_compliance": (
|
||||||
|
{
|
||||||
|
"total_days_used": trip.schengen_compliance.total_days_used,
|
||||||
|
"days_remaining": trip.schengen_compliance.days_remaining,
|
||||||
|
"is_compliant": trip.schengen_compliance.is_compliant,
|
||||||
|
"current_180_day_period": [
|
||||||
|
trip.schengen_compliance.current_180_day_period[0].isoformat(),
|
||||||
|
trip.schengen_compliance.current_180_day_period[1].isoformat(),
|
||||||
|
],
|
||||||
|
"days_over_limit": trip.schengen_compliance.days_over_limit,
|
||||||
|
}
|
||||||
|
if trip.schengen_compliance
|
||||||
|
else None
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
# Convert to JSON for pretty printing
|
||||||
|
trip_json = json.dumps(trip_dict, indent=2, default=str)
|
||||||
|
trip_yaml = yaml.safe_dump(json.loads(trip_json), sort_keys=False)
|
||||||
|
|
||||||
|
return trip_json, trip_yaml
|
||||||
197
web_view.py
197
web_view.py
|
|
@ -3,23 +3,21 @@
|
||||||
"""Web page to show upcoming events."""
|
"""Web page to show upcoming events."""
|
||||||
|
|
||||||
import inspect
|
import inspect
|
||||||
import json
|
|
||||||
import os.path
|
import os.path
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
import typing
|
import typing
|
||||||
from collections import defaultdict
|
|
||||||
from datetime import date
|
from datetime import date
|
||||||
from datetime import datetime, timedelta, timezone
|
from datetime import datetime, timedelta, timezone
|
||||||
|
|
||||||
import flask
|
import flask
|
||||||
import werkzeug
|
import werkzeug
|
||||||
import werkzeug.debug.tbtools
|
import werkzeug.debug.tbtools
|
||||||
import yaml
|
|
||||||
from authlib.integrations.flask_client import OAuth
|
from authlib.integrations.flask_client import OAuth
|
||||||
from werkzeug.middleware.proxy_fix import ProxyFix
|
from werkzeug.middleware.proxy_fix import ProxyFix
|
||||||
|
|
||||||
|
import agenda.accommodation
|
||||||
import agenda.conference
|
import agenda.conference
|
||||||
import agenda.conference_ical
|
import agenda.conference_ical
|
||||||
import agenda.conference_list
|
import agenda.conference_list
|
||||||
|
|
@ -31,13 +29,13 @@ import agenda.meteors
|
||||||
import agenda.stats
|
import agenda.stats
|
||||||
import agenda.thespacedevs
|
import agenda.thespacedevs
|
||||||
import agenda.trip
|
import agenda.trip
|
||||||
|
import agenda.trip_debug
|
||||||
import agenda.trip_schengen
|
import agenda.trip_schengen
|
||||||
import agenda.trip_timezones
|
import agenda.trip_timezones
|
||||||
import agenda.uk_school_holiday
|
import agenda.uk_school_holiday
|
||||||
import agenda.utils
|
import agenda.utils
|
||||||
import agenda.weather
|
import agenda.weather
|
||||||
from agenda import calendar, format_list_with_ampersand, travel, uk_tz
|
from agenda import calendar, format_list_with_ampersand, travel, uk_tz
|
||||||
from agenda.event import Event
|
|
||||||
from agenda.types import StrDict, Trip
|
from agenda.types import StrDict, Trip
|
||||||
|
|
||||||
app = flask.Flask(__name__)
|
app = flask.Flask(__name__)
|
||||||
|
|
@ -492,51 +490,13 @@ def accommodation_list() -> str:
|
||||||
data_dir = app.config["PERSONAL_DATA"]
|
data_dir = app.config["PERSONAL_DATA"]
|
||||||
items = travel.parse_yaml("accommodation", data_dir)
|
items = travel.parse_yaml("accommodation", data_dir)
|
||||||
|
|
||||||
# Create a dictionary to hold stats for each year
|
context = agenda.accommodation.prepare_accommodation_list(
|
||||||
year_stats: defaultdict[int, dict[str, int]] = defaultdict(
|
items, agenda.trip.build_trip_list(), uk_tz.localize(datetime.now())
|
||||||
lambda: {"total_nights": 0, "nights_abroad": 0}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Calculate stats for each year
|
|
||||||
for stay in items:
|
|
||||||
current_date = stay["from"].date()
|
|
||||||
end_date = stay["to"].date()
|
|
||||||
while current_date < end_date:
|
|
||||||
year = current_date.year
|
|
||||||
year_stats[year]["total_nights"] += 1
|
|
||||||
if stay.get("country") != "gb":
|
|
||||||
year_stats[year]["nights_abroad"] += 1
|
|
||||||
current_date += timedelta(days=1)
|
|
||||||
|
|
||||||
# Sort the stats by year in descending order
|
|
||||||
sorted_year_stats = sorted(
|
|
||||||
year_stats.items(), key=lambda item: item[0], reverse=True
|
|
||||||
)
|
|
||||||
|
|
||||||
trip_lookup = {}
|
|
||||||
|
|
||||||
for trip in agenda.trip.build_trip_list():
|
|
||||||
for trip_stay in trip.accommodation:
|
|
||||||
key = (trip_stay["from"], trip_stay["name"])
|
|
||||||
trip_lookup[key] = trip
|
|
||||||
|
|
||||||
for item in items:
|
|
||||||
key = (item["from"], item["name"])
|
|
||||||
if this_trip := trip_lookup.get(key):
|
|
||||||
item["linked_trip"] = this_trip
|
|
||||||
|
|
||||||
now = uk_tz.localize(datetime.now())
|
|
||||||
|
|
||||||
past = [conf for conf in items if conf["to"] < now]
|
|
||||||
current = [conf for conf in items if conf["from"] <= now and conf["to"] >= now]
|
|
||||||
future = [conf for conf in items if conf["from"] > now]
|
|
||||||
|
|
||||||
return flask.render_template(
|
return flask.render_template(
|
||||||
"accommodation.html",
|
"accommodation.html",
|
||||||
past=past,
|
**context,
|
||||||
current=current,
|
|
||||||
future=future,
|
|
||||||
year_stats=sorted_year_stats,
|
|
||||||
get_country=agenda.get_country,
|
get_country=agenda.get_country,
|
||||||
fx_rate=agenda.fx.get_rates(app.config),
|
fx_rate=agenda.fx.get_rates(app.config),
|
||||||
)
|
)
|
||||||
|
|
@ -558,41 +518,6 @@ def trip_ical() -> werkzeug.Response:
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
def calc_total_distance(trips: list[Trip]) -> float:
|
|
||||||
"""Total distance for trips."""
|
|
||||||
total = 0.0
|
|
||||||
for item in trips:
|
|
||||||
if dist := item.total_distance():
|
|
||||||
total += dist
|
|
||||||
|
|
||||||
return total
|
|
||||||
|
|
||||||
|
|
||||||
def calc_total_co2_kg(trips: list[Trip]) -> float:
|
|
||||||
"""Total CO₂ for trips."""
|
|
||||||
return sum(item.total_co2_kg() or 0.0 for item in trips)
|
|
||||||
|
|
||||||
|
|
||||||
def sum_distances_by_transport_type(trips: list[Trip]) -> list[tuple[str, float]]:
|
|
||||||
"""Sum distances by transport type."""
|
|
||||||
distances_by_transport_type: defaultdict[str, float] = defaultdict(float)
|
|
||||||
for trip in trips:
|
|
||||||
for transport_type, dist in trip.distances_by_transport_type():
|
|
||||||
distances_by_transport_type[transport_type] += dist
|
|
||||||
|
|
||||||
return list(distances_by_transport_type.items())
|
|
||||||
|
|
||||||
|
|
||||||
def sum_co2_by_transport_type(trips: list[Trip]) -> list[tuple[str, float]]:
|
|
||||||
"""Sum CO₂ by transport type."""
|
|
||||||
co2_by_transport_type: defaultdict[str, float] = defaultdict(float)
|
|
||||||
for trip in trips:
|
|
||||||
for transport_type, co2_kg in trip.co2_by_transport_type():
|
|
||||||
co2_by_transport_type[transport_type] += co2_kg
|
|
||||||
|
|
||||||
return list(co2_by_transport_type.items())
|
|
||||||
|
|
||||||
|
|
||||||
def get_home_weather() -> list[StrDict]:
|
def get_home_weather() -> list[StrDict]:
|
||||||
"""Get Bristol home weather forecast, with date objects added for templates."""
|
"""Get Bristol home weather forecast, with date objects added for templates."""
|
||||||
|
|
||||||
|
|
@ -614,33 +539,6 @@ def get_trip_list() -> list[Trip]:
|
||||||
return agenda.trip.get_trip_list(route_distances)
|
return agenda.trip.get_trip_list(route_distances)
|
||||||
|
|
||||||
|
|
||||||
def trip_school_holiday_map(trips: list[Trip]) -> dict[str, list[Event]]:
|
|
||||||
"""Map trip-start ISO date to overlapping UK school holidays."""
|
|
||||||
if not trips:
|
|
||||||
return {}
|
|
||||||
|
|
||||||
starts = [trip.start for trip in trips]
|
|
||||||
ends = [trip.end or trip.start for trip in trips]
|
|
||||||
school_holidays = agenda.holidays.get_school_holidays(
|
|
||||||
min(starts),
|
|
||||||
max(ends),
|
|
||||||
app.config["DATA_DIR"],
|
|
||||||
)
|
|
||||||
|
|
||||||
result: dict[str, list[Event]] = {}
|
|
||||||
for trip in trips:
|
|
||||||
trip_end = trip.end or trip.start
|
|
||||||
overlaps = [
|
|
||||||
school_holiday
|
|
||||||
for school_holiday in school_holidays
|
|
||||||
if school_holiday.as_date <= trip_end
|
|
||||||
and school_holiday.end_as_date >= trip.start
|
|
||||||
]
|
|
||||||
result[trip.start.isoformat()] = overlaps
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/trip/past")
|
@app.route("/trip/past")
|
||||||
def trip_past_list() -> str:
|
def trip_past_list() -> str:
|
||||||
"""Page showing a list of past trips."""
|
"""Page showing a list of past trips."""
|
||||||
|
|
@ -652,17 +550,19 @@ def trip_past_list() -> str:
|
||||||
"trip/list.html",
|
"trip/list.html",
|
||||||
heading="Past trips",
|
heading="Past trips",
|
||||||
trips=reversed(past),
|
trips=reversed(past),
|
||||||
trip_school_holiday_map=trip_school_holiday_map(past),
|
trip_school_holiday_map=agenda.holidays.trip_school_holiday_map(
|
||||||
|
past, app.config["DATA_DIR"]
|
||||||
|
),
|
||||||
coordinates=coordinates,
|
coordinates=coordinates,
|
||||||
routes=routes,
|
routes=routes,
|
||||||
today=today,
|
today=today,
|
||||||
get_country=agenda.get_country,
|
get_country=agenda.get_country,
|
||||||
format_list_with_ampersand=format_list_with_ampersand,
|
format_list_with_ampersand=format_list_with_ampersand,
|
||||||
fx_rate=agenda.fx.get_rates(app.config),
|
fx_rate=agenda.fx.get_rates(app.config),
|
||||||
total_distance=calc_total_distance(past),
|
total_distance=agenda.stats.calc_total_distance(past),
|
||||||
total_co2_kg=calc_total_co2_kg(past),
|
total_co2_kg=agenda.stats.calc_total_co2_kg(past),
|
||||||
distances_by_transport_type=sum_distances_by_transport_type(past),
|
distances_by_transport_type=agenda.stats.sum_distances_by_transport_type(past),
|
||||||
co2_by_transport_type=sum_co2_by_transport_type(past),
|
co2_by_transport_type=agenda.stats.sum_co2_by_transport_type(past),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -714,7 +614,9 @@ def trip_future_list() -> str:
|
||||||
"trip/list.html",
|
"trip/list.html",
|
||||||
heading="Future trips",
|
heading="Future trips",
|
||||||
trips=shown,
|
trips=shown,
|
||||||
trip_school_holiday_map=trip_school_holiday_map(shown),
|
trip_school_holiday_map=agenda.holidays.trip_school_holiday_map(
|
||||||
|
shown, app.config["DATA_DIR"]
|
||||||
|
),
|
||||||
trip_weather_map=trip_weather_map,
|
trip_weather_map=trip_weather_map,
|
||||||
coordinates=coordinates,
|
coordinates=coordinates,
|
||||||
routes=routes,
|
routes=routes,
|
||||||
|
|
@ -722,10 +624,12 @@ def trip_future_list() -> str:
|
||||||
get_country=agenda.get_country,
|
get_country=agenda.get_country,
|
||||||
format_list_with_ampersand=format_list_with_ampersand,
|
format_list_with_ampersand=format_list_with_ampersand,
|
||||||
fx_rate=agenda.fx.get_rates(app.config),
|
fx_rate=agenda.fx.get_rates(app.config),
|
||||||
total_distance=calc_total_distance(current + future),
|
total_distance=agenda.stats.calc_total_distance(current + future),
|
||||||
total_co2_kg=calc_total_co2_kg(current + future),
|
total_co2_kg=agenda.stats.calc_total_co2_kg(current + future),
|
||||||
distances_by_transport_type=sum_distances_by_transport_type(current + future),
|
distances_by_transport_type=agenda.stats.sum_distances_by_transport_type(
|
||||||
co2_by_transport_type=sum_co2_by_transport_type(current + future),
|
current + future
|
||||||
|
),
|
||||||
|
co2_by_transport_type=agenda.stats.sum_co2_by_transport_type(current + future),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -835,54 +739,7 @@ def trip_debug_page(start: str) -> str:
|
||||||
# Add Schengen compliance information
|
# Add Schengen compliance information
|
||||||
trip = agenda.trip_schengen.add_schengen_compliance_to_trip(trip)
|
trip = agenda.trip_schengen.add_schengen_compliance_to_trip(trip)
|
||||||
|
|
||||||
# Convert trip object to dictionary for display
|
trip_json, trip_yaml = agenda.trip_debug.serialize_trip(trip)
|
||||||
trip_dict = {
|
|
||||||
"start": trip.start.isoformat(),
|
|
||||||
"name": trip.name,
|
|
||||||
"private": trip.private,
|
|
||||||
"travel": trip.travel,
|
|
||||||
"accommodation": trip.accommodation,
|
|
||||||
"conferences": trip.conferences,
|
|
||||||
"events": trip.events,
|
|
||||||
"flight_bookings": trip.flight_bookings,
|
|
||||||
"computed_properties": {
|
|
||||||
"title": trip.title,
|
|
||||||
"end": trip.end.isoformat() if trip.end else None,
|
|
||||||
"countries": [
|
|
||||||
{"name": c.name, "alpha_2": c.alpha_2, "flag": c.flag}
|
|
||||||
for c in trip.countries
|
|
||||||
],
|
|
||||||
"locations": [
|
|
||||||
{
|
|
||||||
"location": loc,
|
|
||||||
"country": {"name": country.name, "alpha_2": country.alpha_2},
|
|
||||||
}
|
|
||||||
for loc, country in trip.locations()
|
|
||||||
],
|
|
||||||
"total_distance": trip.total_distance(),
|
|
||||||
"total_co2_kg": trip.total_co2_kg(),
|
|
||||||
"distances_by_transport_type": trip.distances_by_transport_type(),
|
|
||||||
"co2_by_transport_type": trip.co2_by_transport_type(),
|
|
||||||
},
|
|
||||||
"schengen_compliance": (
|
|
||||||
{
|
|
||||||
"total_days_used": trip.schengen_compliance.total_days_used,
|
|
||||||
"days_remaining": trip.schengen_compliance.days_remaining,
|
|
||||||
"is_compliant": trip.schengen_compliance.is_compliant,
|
|
||||||
"current_180_day_period": [
|
|
||||||
trip.schengen_compliance.current_180_day_period[0].isoformat(),
|
|
||||||
trip.schengen_compliance.current_180_day_period[1].isoformat(),
|
|
||||||
],
|
|
||||||
"days_over_limit": trip.schengen_compliance.days_over_limit,
|
|
||||||
}
|
|
||||||
if trip.schengen_compliance
|
|
||||||
else None
|
|
||||||
),
|
|
||||||
}
|
|
||||||
|
|
||||||
# Convert to JSON for pretty printing
|
|
||||||
trip_json = json.dumps(trip_dict, indent=2, default=str)
|
|
||||||
trip_yaml = yaml.safe_dump(json.loads(trip_json), sort_keys=False)
|
|
||||||
|
|
||||||
return flask.render_template(
|
return flask.render_template(
|
||||||
"trip_debug.html",
|
"trip_debug.html",
|
||||||
|
|
@ -946,10 +803,12 @@ def trip_stats() -> str:
|
||||||
return flask.render_template(
|
return flask.render_template(
|
||||||
"trip/stats.html",
|
"trip/stats.html",
|
||||||
count=len(trip_list),
|
count=len(trip_list),
|
||||||
total_distance=calc_total_distance(trip_list),
|
total_distance=agenda.stats.calc_total_distance(trip_list),
|
||||||
total_co2_kg=calc_total_co2_kg(trip_list),
|
total_co2_kg=agenda.stats.calc_total_co2_kg(trip_list),
|
||||||
distances_by_transport_type=sum_distances_by_transport_type(trip_list),
|
distances_by_transport_type=agenda.stats.sum_distances_by_transport_type(
|
||||||
co2_by_transport_type=sum_co2_by_transport_type(trip_list),
|
trip_list
|
||||||
|
),
|
||||||
|
co2_by_transport_type=agenda.stats.sum_co2_by_transport_type(trip_list),
|
||||||
yearly_stats=yearly_stats,
|
yearly_stats=yearly_stats,
|
||||||
overall_stats=overall_stats,
|
overall_stats=overall_stats,
|
||||||
conferences=conferences,
|
conferences=conferences,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue