Compare commits
2 Commits
master
...
selectable
Author | SHA1 | Date |
---|---|---|
Joachim Lusiardi | 00e3544a2d | |
Joachim Lusiardi | 4ad838e0bc |
|
@ -83,6 +83,8 @@ class Vehicle(db.Model):
|
|||
regulars = db.relationship("RegularCost")
|
||||
consumables = db.relationship("Consumable", secondary=vehicles_consumables)
|
||||
is_active = db.Column(db.Boolean(), default=True)
|
||||
distance_unit = db.Column(db.String(255), default="km")
|
||||
currency_unit = db.Column(db.String(255), default="€")
|
||||
# allow vehicle names to be duplicated between different owners but must still be uniq for each owner
|
||||
__table_args__ = (db.UniqueConstraint("owner_id", "name", name="_owner_name_uniq"),)
|
||||
|
||||
|
|
|
@ -23,6 +23,47 @@ def regular_costs_days_check(form, field):
|
|||
except Exception:
|
||||
raise ValidationError("{}-{} is not a valid date".format(m, d))
|
||||
|
||||
def odomoder_check(distance_unit):
|
||||
def odometer_date_check(form, field):
|
||||
"""
|
||||
Checks that the entered date and odometer of the pit stop is conformant to
|
||||
the existing pit stops. That means, if a pitstops date is between two
|
||||
other pit stops, the odometer should be as well.
|
||||
|
||||
:param form:
|
||||
:param field:
|
||||
:return:
|
||||
"""
|
||||
odometer = form.odometer.data
|
||||
date = form.date.data
|
||||
pitstops = form.pitstops
|
||||
|
||||
if len(pitstops) > 0:
|
||||
if date < pitstops[0].date and odometer >= pitstops[0].odometer:
|
||||
raise ValidationError(
|
||||
"The new odometer value must be less than {} {}".format(pitstops[0].odometer, distance_unit)
|
||||
)
|
||||
|
||||
if date >= pitstops[-1].date and odometer <= pitstops[-1].odometer:
|
||||
raise ValidationError(
|
||||
"The new odometer value must be greater than {} {}".format(pitstops[-1].odometer, distance_unit)
|
||||
)
|
||||
|
||||
if len(pitstops) > 1:
|
||||
for index in range(0, len(pitstops) - 1):
|
||||
if pitstops[index].date <= date < pitstops[index + 1].date:
|
||||
if (
|
||||
odometer <= pitstops[index].odometer
|
||||
or odometer >= pitstops[index + 1].odometer
|
||||
):
|
||||
raise ValidationError(
|
||||
"The new odometer value must be greater than {} {du} and less than {} {du}".format( pitstops[index].odometer,
|
||||
pitstops[index + 1].odometer,
|
||||
du=distance_unit
|
||||
)
|
||||
)
|
||||
return odometer_date_check
|
||||
|
||||
|
||||
def odometer_date_check(form, field):
|
||||
"""
|
||||
|
|
|
@ -16,6 +16,22 @@ class EditPitstopForm(FlaskForm):
|
|||
submit = SubmitField(label='Update it!')
|
||||
same_odometer_allowed = True
|
||||
pitstops = []
|
||||
distance_unit = "km"
|
||||
currency = "€"
|
||||
|
||||
def set_units(self, distance_unit, currency_unit):
|
||||
self.distance_unit = distance_unit
|
||||
self.currency_unit = currency_unit
|
||||
|
||||
self.odometer.label = "Odometer ({})".format(distance_unit)
|
||||
self.odometer.validators = [odomoder_check(distance_unit)]
|
||||
|
||||
self.costs.label = "Costs ({}, overall)".format(currency_unit)
|
||||
|
||||
|
||||
def set_units(self, distance_unit, currency_unit):
|
||||
self.odometer.label = "Odometer ({})".format(distance_unit)
|
||||
self.costs.label = "Costs ({}, overall)".format(currency_unit)
|
||||
|
||||
def set_pitstops(self, pitstops):
|
||||
self.pitstops = pitstops
|
||||
|
@ -49,6 +65,17 @@ class CreatePitstopForm(FlaskForm):
|
|||
submit = SubmitField(label='Do it!')
|
||||
same_odometer_allowed = True
|
||||
pitstops = []
|
||||
distance_unit = "km"
|
||||
currency = "€"
|
||||
|
||||
def set_units(self, distance_unit, currency_unit):
|
||||
self.distance_unit = distance_unit
|
||||
self.currency_unit = currency_unit
|
||||
|
||||
self.odometer.label = "Odometer ({})".format(distance_unit)
|
||||
self.odometer.validators = [odomoder_check(distance_unit)]
|
||||
|
||||
self.costs.label = "Costs ({}, overall)".format(currency_unit)
|
||||
|
||||
def set_pitstops(self, pitstops):
|
||||
self.pitstops = pitstops
|
||||
|
@ -86,7 +113,7 @@ class CreatePitstopForm(FlaskForm):
|
|||
def get_hint_messages(self):
|
||||
messages = {
|
||||
'litres': 'Litres must be higher than 0.01 L.',
|
||||
'costs': 'Costs must be higher than 0.01 €.'
|
||||
'costs': 'Costs must be higher than 0.01 {}.'.format(self.currency_unit)
|
||||
}
|
||||
return messages
|
||||
|
||||
|
|
|
@ -95,6 +95,7 @@ def create_pit_stop_form(vid, cid):
|
|||
return redirect(url_for("select_consumable_for_new_pitstop", vid=vid))
|
||||
|
||||
form = CreatePitstopForm()
|
||||
form.set_units(vehicle.distance_unit, vehicle.currency_unit)
|
||||
|
||||
data = get_event_line_for_vehicle(vehicle)
|
||||
if len(data) > 0:
|
||||
|
@ -179,6 +180,7 @@ def edit_pit_stop_form(pid):
|
|||
return redirect(url_for("get_pit_stops"))
|
||||
|
||||
form = EditPitstopForm()
|
||||
form.set_units(vehicle.distance_unit, vehicle.currency_unit)
|
||||
data = get_event_line_for_vehicle(vehicle)
|
||||
data = [x for x in data if x != edit_pitstop]
|
||||
form.set_pitstops(data)
|
||||
|
@ -210,7 +212,11 @@ def edit_pit_stop_form(pid):
|
|||
@login_required
|
||||
def get_pit_stops():
|
||||
user = {"vehicles": []}
|
||||
for vehicle in current_user.vehicles:
|
||||
def key(v):
|
||||
return (not v.is_active, v.name)
|
||||
|
||||
vehicles = sorted(current_user.vehicles, key=key)
|
||||
for vehicle in vehicles:
|
||||
data = []
|
||||
for pitstop in vehicle.pitstops:
|
||||
data.append(pitstop)
|
||||
|
@ -225,6 +231,8 @@ def get_pit_stops():
|
|||
"name": vehicle.name,
|
||||
"data": data,
|
||||
"regulars": vehicle.regulars,
|
||||
"distance_unit": vehicle.distance_unit,
|
||||
"currency_unit": vehicle.currency_unit,
|
||||
}
|
||||
user["vehicles"].append(v)
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ from ..tools import (
|
|||
db_log_delete,
|
||||
get_event_line_for_vehicle,
|
||||
get_latest_pitstop_for_vehicle,
|
||||
get_users_active_vehicle,
|
||||
)
|
||||
from .. import app, db
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{% extends "layout.html" %}
|
||||
|
||||
{% macro regular(field, vindex, loop) -%}
|
||||
{% macro regular(field, vindex, loop, currency_unit) -%}
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-body">
|
||||
<div style="text-align: left; font-size: 20px;">
|
||||
|
@ -15,9 +15,9 @@
|
|||
<th>Costs</th>
|
||||
<td id="vehicle_{{vindex}}_pitstop_{{loop.index}}_cost">
|
||||
{% if field.costs %}
|
||||
{{field.costs}} €
|
||||
{{field.costs}} {{ currency_unit }}
|
||||
{% else %}
|
||||
-- €
|
||||
-- {{ currency_unit }}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -46,7 +46,7 @@
|
|||
</div>
|
||||
{%- endmacro %}
|
||||
|
||||
{% macro regular_instance(field, vindex, loop) -%}
|
||||
{% macro regular_instance(field, vindex, loop, currency_unit) -%}
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-body">
|
||||
<div style="text-align: left; font-size: 20px;">
|
||||
|
@ -65,9 +65,9 @@
|
|||
<th>Costs</th>
|
||||
<td id="vehicle_{{vindex}}_pitstop_{{loop.index}}_cost">
|
||||
{% if field.costs %}
|
||||
{{field.costs}} €
|
||||
{{field.costs}} {{ currency_unit }}
|
||||
{% else %}
|
||||
-- €
|
||||
-- {{ currency_unit }}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -87,7 +87,7 @@
|
|||
</div>
|
||||
{%- endmacro %}
|
||||
|
||||
{% macro pitstop(field, vindex, loop) -%}
|
||||
{% macro pitstop(field, vindex, loop, distance_unit, currency_unit) -%}
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-body">
|
||||
<div style="text-align: left; font-size: 20px;">
|
||||
|
@ -100,7 +100,7 @@
|
|||
</tr>
|
||||
<tr>
|
||||
<th>Odometer</th>
|
||||
<td id="vehicle_{{vindex}}_pitstop_{{loop.index}}_odo">{{field.odometer}} km</td>
|
||||
<td id="vehicle_{{vindex}}_pitstop_{{loop.index}}_odo">{{field.odometer}} {{ distance_unit }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{ field.consumable.name }}</th>
|
||||
|
@ -110,9 +110,9 @@
|
|||
<th>Costs</th>
|
||||
<td id="vehicle_{{vindex}}_pitstop_{{loop.index}}_cost">
|
||||
{% if field.costs %}
|
||||
{{field.costs}} €
|
||||
{{field.costs}} {{ currency_unit }}
|
||||
{% else %}
|
||||
-- €
|
||||
-- {{ currency_unit }}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -129,7 +129,7 @@
|
|||
</div>
|
||||
{%- endmacro %}
|
||||
|
||||
{% macro service(field, vindex, loop) -%}
|
||||
{% macro service(field, vindex, loop, distance_unit, currency_unit) -%}
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-body">
|
||||
<div style="text-align: left; font-size: 20px;">
|
||||
|
@ -142,7 +142,7 @@
|
|||
</tr>
|
||||
<tr>
|
||||
<th>Odometer</th>
|
||||
<td id="vehicle_{{vindex}}_pitstop_{{loop.index}}_desc">{{field.odometer}} km</td>
|
||||
<td id="vehicle_{{vindex}}_pitstop_{{loop.index}}_desc">{{field.odometer}} {{ distance_unit }} </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Description</th>
|
||||
|
@ -152,9 +152,9 @@
|
|||
<th>Costs</th>
|
||||
<td id="vehicle_{{vindex}}_pitstop_{{loop.index}}_cost">
|
||||
{% if field.costs %}
|
||||
{{field.costs}} €
|
||||
{{field.costs}} {{ currency_unit }}
|
||||
{% else %}
|
||||
-- €
|
||||
-- {{ currency_unit }}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -192,13 +192,13 @@
|
|||
{% if vehicle.data %}
|
||||
{% for data in vehicle.data|reverse %}
|
||||
{% if 'Pitstop' in data.__class__.__name__ %}
|
||||
{{ pitstop(data, vehicleloop.index, loop) }}
|
||||
{{ pitstop(data, vehicleloop.index, loop, vehicle.distance_unit, vehicle.currency_unit) }}
|
||||
{% endif %}
|
||||
{% if 'Service' in data.__class__.__name__ %}
|
||||
{{ service(data, vehicleloop.index, loop) }}
|
||||
{{ service(data, vehicleloop.index, loop, vehicle.distance_unit, vehicle.currency_unit) }}
|
||||
{% endif %}
|
||||
{% if 'Regular' in data.__class__.__name__ %}
|
||||
{{ regular_instance(data, vehicleloop.index, loop) }}
|
||||
{{ regular_instance(data, vehicleloop.index, loop, vehicle.currency_unit) }}
|
||||
{% endif %}
|
||||
|
||||
{% endfor %}
|
||||
|
@ -210,7 +210,7 @@
|
|||
{% if vehicle.regulars %}
|
||||
<h4>Regular Costs</h4>
|
||||
{% for data in vehicle.regulars %}
|
||||
{{ regular(data, vehicleloop.index, loop) }}
|
||||
{{ regular(data, vehicleloop.index, loop, vehicle.currency_unit) }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
|
|
@ -61,11 +61,11 @@
|
|||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro print_consumable_table(consumable) %}
|
||||
{% macro print_consumable_table(consumable, distance_unit) %}
|
||||
<table class="table table-striped table-bordered table-condensed">
|
||||
<tr>
|
||||
<th>Average Distance:</th>
|
||||
<td>{{ consumable.average_distance | round(2) }} km</td>
|
||||
<td>{{ consumable.average_distance | round(2) }} {{ distance_unit }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Amount fuelled:</th>
|
||||
|
@ -77,7 +77,7 @@
|
|||
</tr>
|
||||
<tr>
|
||||
<th>Average Amount used:</th>
|
||||
<td>{{ consumable.average_amount_used | round(2) }} {{ consumable.unit }}/100km</td>
|
||||
<td>{{ consumable.average_amount_used | round(2) }} {{ consumable.unit }}/100{{ distance_unit }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
{% endmacro %}
|
||||
|
@ -88,16 +88,16 @@
|
|||
<table class="table table-striped table-bordered table-condensed">
|
||||
<tr>
|
||||
<th>Logged Distance:</th>
|
||||
<td>{{ vehicle.overall_distance | round(2) }} km</td>
|
||||
<td>{{ vehicle.overall_distance | round(2) }} {{ vehicle.distance_unit }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Logged Costs:</th>
|
||||
<td>{{ vehicle.overall_costs | round(2) }} €</td>
|
||||
<td>{{ vehicle.overall_costs | round(2) }} {{ vehicle.currency_unit }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Logged Costs per km:</th>
|
||||
<th>Logged Costs per {{ vehicle.distance_unit }}:</th>
|
||||
{% if vehicle.costs_per_distance != 'N/A' %}
|
||||
<td>{{ vehicle.costs_per_distance | round(2) }} €/100km</td>
|
||||
<td>{{ vehicle.costs_per_distance | round(2) }} {{ vehicle.currency_unit }}/{{ vehicle.distance_unit }}</td>
|
||||
{% else %}
|
||||
<td>{{ vehicle.costs_per_distance }}</td>
|
||||
{% endif %}
|
||||
|
@ -141,7 +141,7 @@
|
|||
chart(
|
||||
vehicle.odometers,
|
||||
'ref_' + vehicle.id|string + '_odometer',
|
||||
'km',
|
||||
vehicle.distance_unit,
|
||||
url_for('select_consumable_for_new_pitstop', vid=vehicle.id)
|
||||
),
|
||||
true
|
||||
|
@ -152,7 +152,7 @@
|
|||
chart(
|
||||
vehicle.costs,
|
||||
'ref_' + vehicle.id|string + '_costs',
|
||||
'€',
|
||||
vehicle.currency_unit,
|
||||
url_for('select_consumable_for_new_pitstop', vid=vehicle.id)
|
||||
),
|
||||
false
|
||||
|
@ -160,7 +160,7 @@
|
|||
}}
|
||||
{% for consumable in vehicle.consumables %}
|
||||
<div class="tab-pane" id="ref_{{vehicle.id}}_{{consumable.id}}">
|
||||
{{ print_consumable_table(consumable) }}
|
||||
{{ print_consumable_table(consumable, vehicle.distance_unit) }}
|
||||
<ul id="consumable_{{vehicle.id}}_{{consumable.id}}_tabs" class="nav nav-tabs" data-tabs="tabs">
|
||||
{{ nav_tab(vehicle.id|string + '_' + consumable.id|string + '_consumption', 'Consumption', true) }}
|
||||
{{ nav_tab(vehicle.id|string + '_' + consumable.id|string + '_amount', 'Amount', false) }}
|
||||
|
@ -171,7 +171,7 @@
|
|||
chart(
|
||||
consumable.average_amount,
|
||||
'ref_' + vehicle.id|string + '_' + consumable.id|string + '_consumption',
|
||||
consumable.unit + '/100km',
|
||||
consumable.unit + '/100'+vehicle.distance_unit,
|
||||
url_for('create_pit_stop_form', vid=vehicle.id, cid=consumable.id)
|
||||
),
|
||||
true
|
||||
|
|
|
@ -72,6 +72,8 @@ class VehicleStats:
|
|||
self.odometers = []
|
||||
self.costs = []
|
||||
self.costs_per_distance = "N/A"
|
||||
self.distance_unit = vehicle.distance_unit
|
||||
self.currency_unit = vehicle.currency_unit
|
||||
|
||||
for consumable in vehicle.consumables:
|
||||
self.consumables.append(ConsumableStats(vehicle, consumable))
|
||||
|
|
Loading…
Reference in New Issue