add page to plan a pitstop
This commit is contained in:
parent
28990f27fa
commit
9427ed50ad
|
@ -190,6 +190,11 @@ class FillingStation(db.Model):
|
||||||
brand = db.Column(db.Text(), nullable=False)
|
brand = db.Column(db.Text(), nullable=False)
|
||||||
lat = db.Column(db.Numeric(2, 5), nullable=False)
|
lat = db.Column(db.Numeric(2, 5), nullable=False)
|
||||||
lng = db.Column(db.Numeric(2, 5), nullable=False)
|
lng = db.Column(db.Numeric(2, 5), nullable=False)
|
||||||
|
last_update = db.Column(db.DateTime)
|
||||||
|
diesel = db.Column(db.Numeric(10, 3), default=0)
|
||||||
|
e5 = db.Column(db.Numeric(10, 3), default=0)
|
||||||
|
e10 = db.Column(db.Numeric(10, 3), default=0)
|
||||||
|
open = db.Column(db.Boolean())
|
||||||
|
|
||||||
def as_dict(self):
|
def as_dict(self):
|
||||||
res = {}
|
res = {}
|
||||||
|
|
|
@ -3,3 +3,4 @@ from .admin import *
|
||||||
from .misc import *
|
from .misc import *
|
||||||
from .pitstop import *
|
from .pitstop import *
|
||||||
from .service import *
|
from .service import *
|
||||||
|
from .filling_stations import *
|
|
@ -6,9 +6,8 @@ from datetime import date
|
||||||
|
|
||||||
from ..entities import Vehicle, Consumable, Pitstop
|
from ..entities import Vehicle, Consumable, Pitstop
|
||||||
from ..forms import SelectVehicleForm, SelectConsumableForm, CreatePitstopForm, EditPitstopForm, DeletePitStopForm
|
from ..forms import SelectVehicleForm, SelectConsumableForm, CreatePitstopForm, EditPitstopForm, DeletePitStopForm
|
||||||
from ..tools import db_log_update, db_log_delete, db_log_add, get_latest_pitstop_for_vehicle, \
|
from ..tools import db_log_update, db_log_delete, db_log_add, pitstop_service_key, \
|
||||||
get_latest_pitstop_for_vehicle_and_consumable, compute_lower_limits_for_new_pitstop, pitstop_service_key, \
|
get_event_line_for_vehicle, update_filling_station_prices
|
||||||
get_event_line_for_vehicle
|
|
||||||
from .. import app, db
|
from .. import app, db
|
||||||
|
|
||||||
|
|
||||||
|
@ -50,6 +49,27 @@ def select_consumable_for_new_pitstop(vid):
|
||||||
return render_template('selectConsumableForVehicle.html', vehicle=vehicle, form=form)
|
return render_template('selectConsumableForVehicle.html', vehicle=vehicle, form=form)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/pitstops/vehicle/<int:vid>/consumable/<int:cid>/plan', methods=['GET', 'POST'])
|
||||||
|
@login_required
|
||||||
|
def plan_pit_stop_form(vid, cid):
|
||||||
|
vehicle = Vehicle.query.get(vid)
|
||||||
|
if vehicle is None or vehicle not in current_user.vehicles:
|
||||||
|
return redirect(url_for('select_vehicle_for_new_pitstop'))
|
||||||
|
|
||||||
|
consumable = Consumable.query.get(cid)
|
||||||
|
if consumable not in vehicle.consumables:
|
||||||
|
return redirect(url_for('select_consumable_for_new_pitstop', vid=vid))
|
||||||
|
|
||||||
|
update_filling_station_prices([x.id for x in current_user.favourite_filling_stations])
|
||||||
|
|
||||||
|
offers = []
|
||||||
|
for fs in current_user.favourite_filling_stations:
|
||||||
|
if fs.open:
|
||||||
|
offers.append((fs, getattr(fs, consumable.ext_id),))
|
||||||
|
|
||||||
|
return render_template('planPitStopForm.html', vehicle=vehicle, consumable=consumable, offers=offers)
|
||||||
|
|
||||||
|
|
||||||
@app.route('/pitstops/vehicle/<int:vid>/consumable/<int:cid>/create', methods=['GET', 'POST'])
|
@app.route('/pitstops/vehicle/<int:vid>/consumable/<int:cid>/create', methods=['GET', 'POST'])
|
||||||
@login_required
|
@login_required
|
||||||
def create_pit_stop_form(vid, cid):
|
def create_pit_stop_form(vid, cid):
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
{% extends "layout.html" %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
<div class="col-md-2" ></div>
|
||||||
|
<div class="col-md-8">
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-body">
|
||||||
|
<h3>Plan Pitstop for '{{ vehicle.name }}'</h3>
|
||||||
|
Price comparision for {{ consumable.name }}:
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table id="compare" class="table table-striped table-bordered table-condensed tablesorter">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Filling Station</th>
|
||||||
|
<th>Price/{{ consumable.unit }}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for offer in offers %}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<div class="row filling_station_info" style="border: 0px">
|
||||||
|
<div class="col-md-8">
|
||||||
|
<div>{{ offer[0].name }}</div>
|
||||||
|
<div>{{ offer[0].street }} {{ offer[0].houseNumber }}</div>
|
||||||
|
<div>{{ offer[0].postCode }} {{ offer[0].place }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4" style="height: 60px;">
|
||||||
|
<img src="/static/logos/{{ offer[0].brand|lower }}.png">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ offer[1] }} €/{{ consumable.unit }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
$("#compare").tablesorter({sortList: [[1,0]]});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<div class="col-md-2" ></div>
|
||||||
|
{% endblock %}
|
83
app/tools.py
83
app/tools.py
|
@ -1,7 +1,10 @@
|
||||||
|
from sqlalchemy import or_
|
||||||
|
import requests
|
||||||
import logging
|
import logging
|
||||||
from datetime import date
|
from datetime import date, datetime, timedelta
|
||||||
|
|
||||||
from .entities import Pitstop
|
from .entities import Pitstop, FillingStation
|
||||||
|
from . import db, app
|
||||||
|
|
||||||
|
|
||||||
class ConsumableStats:
|
class ConsumableStats:
|
||||||
|
@ -34,7 +37,7 @@ class ConsumableStats:
|
||||||
self.average_amount.append(
|
self.average_amount.append(
|
||||||
StatsEvent(
|
StatsEvent(
|
||||||
current_ps.date,
|
current_ps.date,
|
||||||
round(100 * current_ps.amount/(current_ps.odometer - last_ps.odometer), 2)))
|
round(100 * current_ps.amount / (current_ps.odometer - last_ps.odometer), 2)))
|
||||||
|
|
||||||
|
|
||||||
class VehicleStats:
|
class VehicleStats:
|
||||||
|
@ -104,9 +107,9 @@ def get_latest_pitstop_for_vehicle(vehicle_id):
|
||||||
:param vehicle_id: the id of the vehicle
|
:param vehicle_id: the id of the vehicle
|
||||||
:return: the latest pitstop or None if no pitstop exists
|
:return: the latest pitstop or None if no pitstop exists
|
||||||
"""
|
"""
|
||||||
latest_pitstop = Pitstop.query\
|
latest_pitstop = Pitstop.query \
|
||||||
.filter(Pitstop.vehicle_id == vehicle_id)\
|
.filter(Pitstop.vehicle_id == vehicle_id) \
|
||||||
.order_by(Pitstop.id.desc())\
|
.order_by(Pitstop.id.desc()) \
|
||||||
.first()
|
.first()
|
||||||
return latest_pitstop
|
return latest_pitstop
|
||||||
|
|
||||||
|
@ -118,10 +121,10 @@ def get_latest_pitstop_for_vehicle_and_consumable(vehicle_id, consumable_id):
|
||||||
:param consumable_id: the id of the consumable
|
:param consumable_id: the id of the consumable
|
||||||
:return: the latest pitstop or None if no pitstop exists
|
:return: the latest pitstop or None if no pitstop exists
|
||||||
"""
|
"""
|
||||||
latest_pitstop_consumable = Pitstop.query\
|
latest_pitstop_consumable = Pitstop.query \
|
||||||
.filter(Pitstop.vehicle_id == vehicle_id)\
|
.filter(Pitstop.vehicle_id == vehicle_id) \
|
||||||
.filter(Pitstop.consumable_id == consumable_id)\
|
.filter(Pitstop.consumable_id == consumable_id) \
|
||||||
.order_by(Pitstop.id.desc())\
|
.order_by(Pitstop.id.desc()) \
|
||||||
.first()
|
.first()
|
||||||
return latest_pitstop_consumable
|
return latest_pitstop_consumable
|
||||||
|
|
||||||
|
@ -150,33 +153,6 @@ def compute_lower_limits_for_new_pitstop(latest_pitstop, last_pitstop_consumable
|
||||||
return Pitstop(odometer, amount, date_of_pitstop, costs, consumable_id)
|
return Pitstop(odometer, amount, date_of_pitstop, costs, consumable_id)
|
||||||
|
|
||||||
|
|
||||||
# if latest_pitstop is not None:
|
|
||||||
# if last_pitstop_consumable is not None and last_pitstop_consumable != latest_pitstop:
|
|
||||||
# if latest_pitstop.id > last_pitstop_consumable.id:
|
|
||||||
# return Pitstop(latest_pitstop.odometer,
|
|
||||||
# last_pitstop_consumable.overall_amount,
|
|
||||||
# latest_pitstop.date,
|
|
||||||
# last_pitstop_consumable.costs,
|
|
||||||
# consumable_id)
|
|
||||||
# else:
|
|
||||||
# return Pitstop(last_pitstop_consumable.odometer,
|
|
||||||
# last_pitstop_consumable.overall_amount,
|
|
||||||
# last_pitstop_consumable.date,
|
|
||||||
# last_pitstop_consumable.costs,
|
|
||||||
# consumable_id)
|
|
||||||
# else:
|
|
||||||
# # either only one pitstop exists or both are the same
|
|
||||||
# litres = 0
|
|
||||||
# costs = 0
|
|
||||||
# if latest_pitstop.consumable_id == last_pitstop_consumable.consumable_id:
|
|
||||||
# litres = latest_pitstop.overall_amount
|
|
||||||
# costs = latest_pitstop.costs
|
|
||||||
# return Pitstop(latest_pitstop.odometer, litres, latest_pitstop.date, costs, consumable_id)
|
|
||||||
# else:
|
|
||||||
# # No existing pitstop at all: insert fake data
|
|
||||||
# return Pitstop(0, 0, date(1970, 1, 1), 0, None)
|
|
||||||
|
|
||||||
|
|
||||||
def pitstop_service_key(x):
|
def pitstop_service_key(x):
|
||||||
return x.odometer, x.date
|
return x.odometer, x.date
|
||||||
|
|
||||||
|
@ -188,4 +164,35 @@ def get_event_line_for_vehicle(vehicle):
|
||||||
for service in vehicle.services:
|
for service in vehicle.services:
|
||||||
data.append(service)
|
data.append(service)
|
||||||
data.sort(key=pitstop_service_key)
|
data.sort(key=pitstop_service_key)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
def update_filling_station_prices(ids):
|
||||||
|
max_age = (datetime.now() - timedelta(minutes=15)).strftime('%Y-%m-%d %H:%M')
|
||||||
|
|
||||||
|
res = db.session. \
|
||||||
|
query(FillingStation). \
|
||||||
|
filter(FillingStation.id.in_(ids)). \
|
||||||
|
filter(or_(FillingStation.last_update==None, FillingStation.last_update < max_age)).\
|
||||||
|
all()
|
||||||
|
|
||||||
|
if len(res) > 0:
|
||||||
|
map = {x.id:x for x in res}
|
||||||
|
query_ids = [x.id for x in res]
|
||||||
|
api_key = app.config['TANKERKOENIG_API_KEY']
|
||||||
|
url = 'https://creativecommons.tankerkoenig.de/json/prices.php'
|
||||||
|
params = {
|
||||||
|
'apikey': api_key, 'ids': ','.join(query_ids)
|
||||||
|
}
|
||||||
|
response = requests.get(url, params=params)
|
||||||
|
prices = response.json()['prices']
|
||||||
|
for price in prices:
|
||||||
|
id = price
|
||||||
|
station_status = prices[id]
|
||||||
|
print(id, station_status)
|
||||||
|
map[id].diesel = station_status['diesel']
|
||||||
|
map[id].e10 = station_status['e10']
|
||||||
|
map[id].e5 = station_status['e5']
|
||||||
|
map[id].open = station_status['status'] == 'open'
|
||||||
|
map[id].last_update = datetime.now()
|
||||||
|
db.session.commit()
|
||||||
|
|
Loading…
Reference in New Issue