Author: Pedro Lucas Porcellis <pedrolucasporcellis@gmail.com>
Throw all the views and bind to the controllers
core/blueprints/cycles.py | 83 +++++++++++++++++++ core/blueprints/orders.py | 61 ++++++++++++++ core/templates/cycle.html | 83 +++++++++++++++++++ core/templates/cycles.html | 48 +++++++++++ core/templates/index.html | 20 ++++ core/templates/layout.html | 8 + core/templates/new_cycle.html | 159 +++++++++++++++++++++++++++++++++++++ core/templates/orders.html | 29 ++++++
diff --git a/core/blueprints/cycles.py b/core/blueprints/cycles.py new file mode 100644 index 0000000000000000000000000000000000000000..d641bb3078fac75bfa959aa6142f98cb4dbf4551 --- /dev/null +++ b/core/blueprints/cycles.py @@ -0,0 +1,83 @@ +from flask import Blueprint, jsonify, url_for, request, render_template, redirect +from flask_login import current_user +from datetime import datetime as dt + +import pdb +cycles = Blueprint('cycles', __name__, url_prefix = '/cycles') + +from core.database import db + +from core.types.cycle import Cycle, CycleStatus +from core.types.product import Product +from core.types.order import OrderStatus +#from core.types.configuration import Configuration + +@cycles.route('/', methods = ['GET', 'POST']) +def index(): + if request.method == 'GET': + current_cycle = Cycle.query.filter_by(status = 'published').first() + + closed_cycles = Cycle.query.filter_by(status = 'delivered').all() + + return render_template('cycles.html', current_cycle = current_cycle, closed_cycles = closed_cycles, title = "Ciclos - Feira Virtual Bem da Terra") + else: + return create(request.form) + +@cycles.route('/new', methods = ['GET']) +def new(): + cycle_status_options = [(cycle.value, cycle.name) for cycle in CycleStatus] + # configuration = Configuration.query.first() + return render_template('new_cycle.html', cycles = cycle_status_options, title = "Abrir novo Ciclo - Feira Virtual Bem da Terra") + +@cycles.route('/<id>', methods = ['GET']) +def show(id): + cycle = Cycle.query.filter_by(id = id).first() + products = Product.query.all() + current_order = current_user.current_order() + if not cycle: + return "Not found", 404 + + return render_template('cycle.html', cycle = cycle, current_order = current_order, products = products, title = "Carrinho - Feira Virtual") + +@cycles.route('/<id>/close', methods = ['GET']) +def close(id): + if current_user.is_admin(): + cycle = Cycle.query.get(id) + cycle.close() + db.commit() + + return redirect(url_for('cycles.index')) + else: + return "Not found", 404 + +def create(params): + cycle = Cycle.query.filter_by(status = CycleStatus.published.value).first() + + # TODO: Better handling an ongoing cycle when create another one + if cycle: + return "there's an ongoing cycle" + + start_at = build_date_from_params(params.get('start_at_day'), params.get('start_at_month'), params.get('start_at_year')) + end_at = build_date_from_params(params.get('end_at_day'), params.get('end_at_month'), params.get('end_at_year')) + + delivery_start_at = build_date_from_params(params.get('delivery_start_at_day'), params.get('delivery_start_at_month'), params.get('delivery_start_at_year')) + delivery_end_at = build_date_from_params(params.get('delivery_end_at_day'), params.get('delivery_end_at_month'), params.get('delivery_end_at_year')) + + cycle = Cycle( + name = params.get('name'), + description = params.get('description'), + start_at = start_at, + end_at = end_at, + delivery_start_at = delivery_start_at, + delivery_end_at = delivery_end_at, + status = params.get('status'), + price_margin = float(params.get('price_margin')) + ) + + db.add(cycle) + db.commit() + + return redirect(url_for('cycles.index')) + +def build_date_from_params(day, month, year): + return dt(int(year), int(month), int(day)) diff --git a/core/blueprints/orders.py b/core/blueprints/orders.py new file mode 100644 index 0000000000000000000000000000000000000000..64bce6378b386a550adf32c326d65e2d3277aa4c --- /dev/null +++ b/core/blueprints/orders.py @@ -0,0 +1,61 @@ +from flask import request, redirect, url_for, Blueprint, jsonify, render_template +from flask_login import current_user + +from core.types.cycle import Cycle, CycleStatus +from core.types.order import Order +from core.database import db + +import pdb + +orders = Blueprint('orders', __name__, url_prefix = '/orders') + +@orders.route('/', methods = ['GET', 'POST']) +def index(): + orders = Order.query.filter(Order.user.has(id = current_user.id)).order_by(Order.id.desc()).all() + + return render_template('orders.html', orders = orders, title = "Seus Pedidos") + +@orders.route('/create') +def create(): + current_cycle = Cycle.query.filter_by(status = CycleStatus.published).first() + if not current_cycle: + return '', 401 + + Order.create_for(current_user, current_cycle) + return redirect(url_for('cycles.show', id = current_cycle.id)) + +@orders.route('/<id>', methods = ['POST']) +def update(id): + order = Order.query.filter_by(id = id).first() + + current_cycle = Cycle.query.filter_by(status = CycleStatus.published).first() + if not order: + order = Order.create_for(current_user, current_cycle) + + order.add_products(request.form.getlist('product_ids')) + + if 'confirm' in request.form: + order.confirm() + db.commit() + + return redirect(url_for('cycles.show', id = current_cycle.id)) + +@orders.route('/<id>/reopen', methods = ['GET']) +def reopen(id): + order = Order.query.get(id) + + order.reopen() + db.commit() + + current_cycle = Cycle.query.filter_by(status = CycleStatus.published).first() + return redirect(url_for('cycles.show', id = current_cycle.id)) + +@orders.route('/<id>/cancel', methods = ['GET']) +def cancel(id): + order = Order.query.get(id) + + db.delete(order) + db.commit() + + current_cycle = Cycle.query.filter_by(status = CycleStatus.published).first() + return redirect(url_for('cycles.show', id = current_cycle.id)) diff --git a/core/templates/cycle.html b/core/templates/cycle.html new file mode 100644 index 0000000000000000000000000000000000000000..e934b27ebdc0961d98337b89c7ef13d7b9166de3 --- /dev/null +++ b/core/templates/cycle.html @@ -0,0 +1,83 @@ +{% extends 'layout.html' %} +{% block body %} +<section class="a"> + <h1>{{ cycle.name }}</h1> + <em class="white-space-pre">{{ cycle.description }}</em> +</section> + +{% if current_order and current_order.status.value == 'confirmed' %} +<strong> Seu pedido está {{ current_order.status.value }} <a href="{{ url_for('orders.reopen', id = current_order.id) }}">Deseja reabrir?</a></strong> +{% endif %} + +<section> + {% if not current_order and cycle.status.value == 'published' %} + <strong>Você não tem um pedido nesse ciclo. <a href="{{ url_for('orders.create') }}">Abrir um</a></strong> + {% endif %} +</section> + +<section class="products"> + <form action="{{url_for('orders.update', id = current_order.id)}}" method="POST"> + <table> + <thead> + <tr> + <th></th> + <th>Nome do Produto</th> + <th>Grupo</th> + <th>Categoria</th> + <th>Preço</th> + </tr> + </thead> + <tbody> + {% with selected_product_ids = current_order.selected_product_ids() if current_order else [] %} + {% for product in products %} + <tr> + <td> + {% if current_order %} + <input type="checkbox" name="product_ids" {{ 'checked' if product.id in selected_product_ids }} {{ 'disabled' if current_order.status.value == 'confirmed' }} value="{{product.id}}"> + {% endif %} + </td> + <td> {{ product.title }} </td> + <td> {{ product.group.name }} </td> + <td> {{ product.category.name }}</td> + <td> {{ product.price_on(cycle) | as_currency }} </td> + </tr> + {% endfor %} + {% endwith %} + </tbody> + </table> + + {% if current_order %} + <section class="box p-5 mt-5"> + <h4> O que você vai levar: </h4> + <ul> + {% for product in current_order.products() %} + <li>{{ product.title }} - {{ product.group.name }}</li> + {% endfor %} + </ul> + + <div style="text-align: left;"> + Total: <em>{{ current_order.total() | as_currency }}</em> + </div> + </section> + {% endif %} + + <div class="form-action"> + {% if current_order %} + {# + TODO: There's gotta a simpler way to this. + Instead of having two actions we could have only one. + If you added something to your order, you already confirmed it + #} + <button type="submit" class="btn btn-primary f-right" {{ "disabled" if current_order.status.value == 'confirmed' }} name="confirm" rel="button"> + Fechar pedido + </button> + {% if current_order.status.value == 'draft' %} + <button type="submit" name="draft" rel="button" class="btn btn-secondary">Adicionar a cesta os produtos selecionados</button> + {% endif %} + + <a class=" destructive" href="{{url_for('orders.cancel', id = current_order.id)}}">Cancelar Pedido</a> + {% endif %} + </div> + </form> +</section> +{% endblock %} diff --git a/core/templates/cycles.html b/core/templates/cycles.html new file mode 100644 index 0000000000000000000000000000000000000000..6c44eef9bba549ce23d715b8a0b53e0df8d4a1d5 --- /dev/null +++ b/core/templates/cycles.html @@ -0,0 +1,48 @@ +{% extends "layout.html" %} +{% block body %} +{% if current_cycle or closed_cycles %} + <section class="cycles"> + <h1>Ciclo em aberto</h1> + <section> + <div class="{{ "box" if current_cycle.status.value == 'published' }}"> + <strong>Compras:</strong> {{ current_cycle.start_at.strftime("%A, %d/%m") }} até {{ current_cycle.end_at.strftime("%A, %d/%m") }} + {% if current_cycle.status.value == 'published' %} + <strong class="pl-5 f-right"> ACONTECENDO </strong> + {% endif %} + </div> + <div class="{{ "box" if current_cycle.status.value == 'delivery' }}"> + <strong>Entrega:</strong> {{ current_cycle.delivery_start_at.strftime("%d/%m/%Y ") }} até {{ current_cycle.delivery_end_at.strftime("%d/%m/%Y") }} + {% if current_cycle.status.value == 'delivery' %} + <strong class="pl-5 f-right"> ACONTECENDO </strong> + {% endif %} + </div> + </section> + <div class="cycle"> + <h2>{{ current_cycle.title }}</h2> + <p class="white-space-pre">{{ current_cycle.description }}</p> + <a href="{{url_for('cycles.show', id = current_cycle.id)}}">Ver ciclo</a> + <a href="{{url_for('cycles.close', id = current_cycle.id)}}">Fechar ciclo</a> + </div> + </section> + + <section class="closed-cycles"> + <h1>Ciclos passados</h1> + {% if closed_cycles %} + {% for cycle in closed_cycles %} + <div class="cycle"> + <h2>{{ cycle.name }}</h2> + <em>Ciclo fechado em {{ cycle.delivery_end_at.strftime("%d/%m/%Y") }} </em> + </div> + {% endfor %} + {% else %} + <h2> Nenhum ciclo encerrado ainda </h2> + {% endif %} + </section> +{% else %} +<h1> Nenhum ciclo criado </h1> + +<div> + <a href="{{ url_for('cycles.new') }}"> Abrir novo Ciclo </a> +</div> +{% endif %} +{% endblock %} diff --git a/core/templates/index.html b/core/templates/index.html index 0a77cbc6d2790e67b071754055442c5deb1c01f7..f91fb1ed6023901d886dafb37606a49232180408 100644 --- a/core/templates/index.html +++ b/core/templates/index.html @@ -14,4 +14,24 @@