From 5fbfd382185171222560b0c25ce92664844aada5 Mon Sep 17 00:00:00 2001 From: Doug Le Tough Date: Mon, 23 Oct 2017 13:42:49 +0200 Subject: [PATCH] "New stable" --- static/scripts/tetalab.js | 123 ++++++++++++++++++-- static/style/style.css | 12 +- templates/componant.html | 4 +- templates/componants.html | 51 +++----- templates/result.html | 31 +++++ tetastock.py | 236 ++++++++++++++++++++++++++------------ 6 files changed, 338 insertions(+), 119 deletions(-) create mode 100644 templates/result.html diff --git a/static/scripts/tetalab.js b/static/scripts/tetalab.js index f706fc8..0061ee9 100644 --- a/static/scripts/tetalab.js +++ b/static/scripts/tetalab.js @@ -5,6 +5,121 @@ var light_green = "#D5FCD8"; var base_bg = "#FEFEFE"; var base_border = "#555555"; +/////////////////////////////////////////// +// Cookies +/////////////////////////////////////////// +function setcookie(cname, cvalue, exdays) { + var d = new Date(); + d.setTime(d.getTime() + (exdays*24*60*60*1000)); + var expires = "expires="+ d.toUTCString(); + document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/"; +} + +/////////////////////////////////////////// +// Update result +/////////////////////////////////////////// +function update_componants() { + obj = document.getElementById('result_container'); + var xhttp = new XMLHttpRequest(); + xhttp.onerror = function(){ + obj.innerHTML = "Erreur lors de la mise à jour de la liste (1)" + }; + + xhttp.onload = function(){ + if (xhttp.status == 200) { + var response = xhttp.responseText; + obj.innerHTML = response; + return; + } + obj.innerHTML = "Erreur lors de la mise à jour de la liste (2)" + }; + + xhttp.onreadystatechange = function() { + if (xhttp.readyState == 4 && xhttp.status == 200) { + var response = xhttp.responseText; + obj.innerHTML = response; + } + }; + xhttp.open('POST', '/componants/update', true); + xhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); + xhttp.send(); +} + +/////////////////////////////////////////// +// Result ordering +/////////////////////////////////////////// +function update_componants_by_reference(order) { + setcookie('c_order', order, 30); + setcookie('c_sort', 'reference', 30); + setcookie('c_order_refresh', '1', 30); + update_componants(); +} + +function update_componants_by_designation(order) { + setcookie('c_order', order, 30); + setcookie('c_sort', 'designation', 30); + setcookie('c_order_refresh', '1', 30); + update_componants(); +} + +function update_componants_by_quantity(order) { + setcookie('c_order', order, 30); + setcookie('c_sort', 'quantity', 30); + setcookie('c_order_refresh', '1', 30); + update_componants(); +} + +function update_componants_by_place(order) { + setcookie('c_order', order, 30); + setcookie('c_sort', 'place', 30); + setcookie('c_order_refresh', '1', 30); + update_componants(); +} + +function previous_page(prevhop) { + setcookie('c_offset', prevhop, 30); + update_componants(); +} + +function next_page(nexthop) { + setcookie('c_offset', nexthop, 30); + update_componants(); +} + +/////////////////////////////////////////// +// Search componants +/////////////////////////////////////////// +function search_componants_by_reference(obj) { + setcookie('c_reference', obj.value, 30); + update_componants(); +} + +function search_componants_by_designation(obj) { + setcookie('c_designation', obj.value, 30); + update_componants(); +} + +function search_componants_by_place(obj) { + setcookie('c_place', obj.value, 30); + update_componants(); +} + +function search_componants_by_provider(obj) { + setcookie('c_provider', obj.value, 30); + update_componants(); +} + +/////////////////////////////////////////// +// Delete componant +/////////////////////////////////////////// +function confirm_delete() { + var msg="La suppression est définitive \net n'est pas autorisée si le \ncomposant fait partie d'un Kit.\n\nConfirmer ?"; + return confirm(msg) +} + +/////////////////////////////////////////// +// Update componant +/////////////////////////////////////////// function update_componant(obj, componant_id, type) { if (type == 'numeric') { if (isNaN(obj.value)) { @@ -47,13 +162,7 @@ function update_componant(obj, componant_id, type) { obj.style.backgroundColor = light_red; } }; - - xhttp.open('POST', '/componant/update/'+componant_id, true); + xhttp.open('POST', '/componants/update/'+componant_id, true); xhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); xhttp.send('field='+obj.id+'&value='+obj.value); } - -function confirm_delete() { - var msg="La suppression est définitive \net n'est pas autorisée si le \ncomposant fait partie d'un Kit.\n\nConfirmer ?"; - return confirm(msg) -} diff --git a/static/style/style.css b/static/style/style.css index 35242f5..7f3eefe 100644 --- a/static/style/style.css +++ b/static/style/style.css @@ -185,9 +185,17 @@ div.footer { } /* *********************************** - * Tables + * Résultats *********************************** */ +div.row_count { + padding: 5px; +} + +div.result_container { + text-align: left; +} + .border_left { border-left-width: 1px; border-left-style: solid; @@ -200,7 +208,6 @@ div.footer { div.block { overflow: hidden; - width: 1000px; border-top-style: solid; border-top-width: 1px; height: 20px; @@ -379,6 +386,7 @@ div.block input { width: 300px; } + /* *********************************** * Classes génériques *********************************** */ diff --git a/templates/componant.html b/templates/componant.html index d5f798c..04ee284 100644 --- a/templates/componant.html +++ b/templates/componant.html @@ -1,9 +1,9 @@ {% extends "index.html" %} {% block title %}Éditer un composant{% endblock %} {% block top_menu %} + Rechercher un composant + Éditer un composant Nouveau composant - Rechercher un composant - Éditer un composant Entrée de stock Sortie de stock {% endblock %} diff --git a/templates/componants.html b/templates/componants.html index e26c64d..5f3c628 100644 --- a/templates/componants.html +++ b/templates/componants.html @@ -1,8 +1,8 @@ {% extends "index.html" %} {% block title %}Liste des composants{% endblock %} {% block top_menu %} + Rechercher un composant Nouveau composant - Rechercher un composant Entrée de stock Sortie de stock {% endblock %} @@ -33,11 +33,11 @@ id='reference' type='text' class='editable' - onchange='javascript:search_componant(this, "text");' + onkeyup='javascript:search_componants_by_reference(this, "text");' maxlength='20' title='Référence interne unique (max. 20)' placeholder='Référence interne unique (max. 20)' - value='' /> + value='{{ reference }}' />
@@ -45,11 +45,11 @@ id='designation' type='text' class='editable' - onchange='javascript:search_componant(this, "text");' + onkeyup='javascript:search_componants_by_designation(this, "text");' maxlength='50' title='Désignation (max. 50)' placeholder='Désignation (max. 50)' - value='' /> + value='{{ designation }}' />
@@ -57,54 +57,35 @@ id='place' type='text' class='editable' - onchange='javascript:search_componant(this, "text");' + onkeyup='javascript:search_componants_by_place(this, "text");' maxlength='15' title='Emplacement (max. 15)' placeholder='Emplacement (max. 15)' - value='' /> + value='{{ place }}' />
- +
-

Résultat

-
- - - - - -
- {% set row_class = cycler('odd', 'even') %} - {% for componant in componants %} -
- {{ componant.reference }} - {{ componant.designation }} - {{ componant.quantity }} - {{ componant.place }} -
- - -
-
- {% endfor %} -
- < - {{ page }} / {{ page_count }} - > +
+
{% endblock %} diff --git a/templates/result.html b/templates/result.html new file mode 100644 index 0000000..4a5896e --- /dev/null +++ b/templates/result.html @@ -0,0 +1,31 @@ +

Résultat:

+ {% set ss='' %} + {% if row_count > 1 %} + {% set ss='s' %} + {% endif %} +
{{ row_count }} objet{{ ss }} selectionné{{ ss }}
+
+ + + + + +
+ {% set row_class = cycler('odd', 'even') %} + {% for componant in componants %} +
+ {{ componant.reference }} + {{ componant.designation }} + {{ componant.quantity }} + {{ componant.place }} +
+ + +
+
+ {% endfor %} +
+ < + {{ page }} / {{ page_count }} + > +
diff --git a/tetastock.py b/tetastock.py index 958e95e..08d7b4e 100755 --- a/tetastock.py +++ b/tetastock.py @@ -4,7 +4,11 @@ import math from flask import Flask, request, session, g, redirect, url_for, abort, render_template, flash from flask_sqlalchemy import SQLAlchemy +from functools import wraps +######################################################################## +# App settings +######################################################################## app = Flask(__name__) app.config.from_pyfile('config.py') app.secret_key = '446307a5f61c2bb810436b2ee0f903f2' @@ -12,6 +16,9 @@ app.debug = True app.static_url_path='/static' db = SQLAlchemy(app) +######################################################################## +# Database +######################################################################## class Stock_users(db.Model): id = db.Column(db.Integer, primary_key=True) mail = db.Column(db.Text, nullable=False) @@ -47,6 +54,62 @@ class Stock_kit_compositions(db.Model): component_id = db.Column(db.Integer, db.ForeignKey('Stock_componants.id'), nullable=False) component_quantity = db.Column(db.Integer, nullable=False) +def resume_session(func): + @wraps(func) + def check(*args, **kwargs): + # default + limit = 8 + offset = 0 + nexthop = offset + limit + prevhop = offset + sort = 'reference' + order = 'asc' + order_refresh = 0 + c_empty = '' + c_provider = 1 + if not 'c_limit' in session: + session['c_limit'] = limit + if not 'c_offest' in session: + session['c_offset'] = offset + if not 'c_sort' in session: + session['c_sort'] = sort + if not 'c_order' in session: + session['c_order'] = order + if not 'c_order_refresh' in session: + session['c_order_refresh'] = order_refresh + if not 'c_nexthop' in session: + session['c_nexthop'] = nexthop + if not 'c_prevhop' in session: + session['c_prevhop'] = prevhop + if not 'c_reference' in session: + session['c_reference'] = c_empty + if not 'c_designation' in session: + session['c_designation'] = c_empty + if not 'c_place' in session: + session['c_place'] = c_empty + if not 'c_provider' in session: + session['c_provider'] = c_provider + # Cookies/session sync + for key in request.cookies: + try: + session[key] = int(str(request.cookies[key])) + except ValueError: + # Value is not an int, will be treated as string + session[key] = str(request.cookies[key]) + if key != 'session': + print '+', key, request.cookies[key] + + # Switch sort order + if session['c_order_refresh'] == 1: + refresh = {'desc': 'asc', 'asc': 'desc'} + session['c_order'] = refresh[session['c_order']] + session['c_order_refresh'] = 0 + return func(*args, **kwargs) + return check + +######################################################################## +# Routes +######################################################################## @app.errorhandler(404) def page_not_found(e): return render_template('error.html'), 404 @@ -59,58 +122,22 @@ def authenticate(): ######################################################################## # Componants ######################################################################## -@app.route('/componants', methods=['GET', 'POST']) -def get_componants(): - if not session or not session['plop']: - session['plop']='plip' - limit = 8 - offset = 0 - sort = 'reference' - order = 'asc' - norder = 'desc' - print '*', sort - if len(request.args): - if 'offset' in request.args: - offset = request.args['offset'] - if 's' in request.args: - sort = request.args['s'] - if 'o' in request.args: - order = request.args['o'] - try: - offset = int(offset) - except ValueError: - offset = 0 - providers = Stock_providers.query.order_by(Stock_providers.name).all() - row_count = db.session.query(Stock_componants.id).count() - page_count = int(math.ceil(row_count / float(limit))) - page = int(math.ceil(float(offset + 1) / float(limit))) - nexthop = offset + limit - if nexthop > row_count - 1: - nexthop = offset - prevhop = offset - limit - if prevhop < 0: - prevhop = 0 - if order == 'asc': - norder = 'desc' - componants = Stock_componants.query.order_by(getattr(Stock_componants, sort)).offset(offset).limit(limit).all() - else: - norder = 'asc' - componants = Stock_componants.query.order_by(getattr(Stock_componants, sort).desc()).offset(offset).limit(limit).all() - return render_template('componants.html', - componants=componants, - providers = providers, - offset=offset, - nexthop=nexthop, - prevhop=prevhop, - page_count=page_count, - page=page, - sort=sort, - order=order, - norder=norder) +## Main ## +@app.route('/componants', methods=['GET', 'POST']) +@resume_session +def get_componants(): + providers = Stock_providers.query.order_by(Stock_providers.name).all() + return render_template('componants.html', + providers=providers, + reference=session['c_reference'], + designation=session['c_designation'], + place=session['c_place'], + provider_id=session['c_provider']) + +## Componant edition ## @app.route('/componants/') def get_componant(componant_id): - print session['plop'] try: componant_id = int(componant_id) except ValueError as e: @@ -123,30 +150,9 @@ def get_componant(componant_id): return render_template('componant.html', componant=componant, providers=providers, provider=provider) return render_template('error.html'), 404 -@app.route('/componants/delete/') -def delete_componant(componant_id): - try: - componant_id = int(componant_id) - except ValueError as e: - return render_template('error.html'), 404 - Stock_componants.query.filter_by(id=componant_id).delete() - db.session.commit() - return get_componants() - -@app.route('/componants/new/') -def add_componant(componant_id): - return render_template('wip.html') - -@app.route('/componants/in/') -def in_componants(): - return render_template('wip.html') - -@app.route('/componants/out/') -def out_componants(): - return render_template('wip.html') - -@app.route('/componant/update/', methods=['POST']) -def update_componants(componant_id): +## Componant update ## +@app.route('/componants/update/', methods=['POST']) +def update_componant(componant_id): field = request.form['field'] value = request.form['value'] if field and value: @@ -158,6 +164,90 @@ def update_componants(componant_id): return 'KO' return 'OK' +## Componant deletion ## +@app.route('/componants/delete/') +def delete_componant(componant_id): + try: + componant_id = int(componant_id) + except ValueError as e: + return render_template('error.html'), 404 + Stock_componants.query.filter_by(id=componant_id).delete() + db.session.commit() + return get_componants() + +## Componant creation ## +@app.route('/componants/new/') +def add_componant(componant_id): + return render_template('wip.html') + +## Componants stock in ## +@app.route('/componants/in/') +def in_componants(): + return render_template('wip.html') + +## Componants stock out ## +@app.route('/componants/out/') +def out_componants(): + return render_template('wip.html') + +## Componants update result set +@app.route('/componants/update', methods=['POST']) +@resume_session +def update_componants(): + # search by reference + like = '%'+str(session['c_reference'])+'%' + componants = Stock_componants.query.filter(Stock_componants.reference.like(like)) + # search by designation + like = '%'+str(session['c_designation'])+'%' + componants = componants.filter(Stock_componants.designation.like(like)) + # search by place + like = '%'+str(session['c_place'])+'%' + componants = componants.filter(Stock_componants.place.like(like)) + # search by provider + if session['c_provider'] > 0: + componants = componants.filter_by(provider_id=session['c_provider']) + # Pages calculation + row_count = componants.count() + session['c_pagecount'] = int(math.ceil(row_count / float(session['c_limit']))) + session['c_page'] = int(math.ceil(float(float(session['c_offset']) + 1) / float(session['c_limit']))) + if session['c_page'] > session['c_pagecount']: + session['c_page'] = session['c_pagecount'] + session['c_offset'] = 0 + print "*****", componants.count(), session['c_pagecount'], session['c_page'] + session['c_nexthop'] = session['c_offset'] + session['c_limit'] + if session['c_nexthop'] > row_count - 1: + session['c_nexthop'] = int(session['c_offset']) + session['c_prevhop'] = int(session['c_offset']) - session['c_limit'] + if session['c_prevhop'] < 0: + session['c_prevhop'] = 0 + # Sorting + sort = getattr(Stock_componants, session['c_sort']) + if session['c_order'] == 'desc': + sort = getattr(Stock_componants, session['c_sort']).desc() + componants = componants.order_by(sort) + # Applying offset + componants = componants.offset(session['c_offset']) + # Applying limit + componants = componants.limit(session['c_limit']) + # Get result + componants = componants.all() + + response = app.make_response(render_template('result.html', + componants=componants, + offset=session['c_offset'] , + nexthop=session['c_nexthop'], + prevhop=session['c_prevhop'], + page_count=session['c_pagecount'], + page=session['c_page'], + sort=session['c_sort'], + order=session['c_order'], + row_count=row_count)) + for key in session: + response.set_cookie(key, value=str(session[key])) + if key != 'session': + print '++', key, session[key] + return response + ######################################################################## # Kits