ciclos

commit c14a14eb37257a38a5330063c2c7b7759dfe3e85

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 @@     
  • Auto Gestão
  • <li> Consumo Responsável </li> </ul> </section> + +<section> + {% if current_user.is_authenticated %} + {% if current_user.is_admin() %} + <h2>Gerenciamento</h2> + <ul> + <li> <a href="{{url_for('groups.index')}}">Ver Fornecedores cadastrados </a> </li> + <li> <a href="{{url_for('products.index')}}">Ver produtos cadastrados </a> </li> + <li> <a href="{{url_for('product_categories.index')}}">Ver categorias</a> </li> + </ul> + {% endif %} + + <ul> + <li> <a href="{{url_for('cycles.index')}}">Ver ciclos</a> </li> + </ul> + {% else %} + <a href="{{url_for('auth.login')}}">Entrar</a> + {% endif %} +</section> + {% endblock %} diff --git a/core/templates/layout.html b/core/templates/layout.html index 478cb167d55fe9ce9350b1cfde1d2428ae63ed01..e3239a2e07527cd56f1b6303baaa81db75181eb6 100644 --- a/core/templates/layout.html +++ b/core/templates/layout.html @@ -29,6 +29,14 @@ Bem da Terra <ul> <li> <a class="mr-5" href="{{ url_for('basic.about') }}">Sobre</a> </li> <li> <a class="mr-5" href="#">Contato</a> </li> + + {% if current_user.is_authenticated %} + <li> <a class="mr-5" href="{{ url_for('orders.index') }}">Seus Pedidos</a> </li> + <li> <a class="mr-5" href="{{ url_for('cycles.index') }}">Ciclos</a></li> + {% if current_user.is_admin() %} + <li> <a class="mr-5" href="#">Relatórios</a></li> + {% endif %} + {% endif %} </ul> <div class="login"> diff --git a/core/templates/new_cycle.html b/core/templates/new_cycle.html new file mode 100644 index 0000000000000000000000000000000000000000..cc97f9bc9700589f3affee8766671b1990b85dfb --- /dev/null +++ b/core/templates/new_cycle.html @@ -0,0 +1,159 @@ +{% extends 'layout.html' %} + +{% block body %} + <form action="/cycles/" method="POST"> + <div class="form-section"> + <label for="">Título desse ciclo</label> + <input type="text" name="name"> + </div> + <div class="form-section"> + <label for="">Descrição</label> + <textarea rows="10" columns="10" name="description"></textarea> + </div> + + <fieldset> + <legend class="legend-xl"> + <h1> Quando esse ciclo se inicia? </h1> + </legend> + + <span class="hint"> + Por exemplo, 25 04 2020 + </span> + + <div class="form-date-group"> + <div class="date-group-item"> + <div class="form-section"> + <label for="">Dia</label> + <input class="form-input-width-2" name="start_at_day" type="text"> + </div> + </div> + <div class="date-group-item"> + <div class="form-section"> + <label for="">Mês</label> + <input class="form-input-width-2" name="start_at_month" type="text"> + </div> + </div> + <div class="date-group-item"> + <div class="form-section"> + <label for="">Ano</label> + <input class="form-input-width-4" name="start_at_year" type="text" readonly value="2020"> + </div> + </div> + </div> + </fieldset> + + + <fieldset> + <legend class="legend-xl"> + <h1> Quando esse ciclo se encerra? </h1> + </legend> + + <span class="hint"> + Por exemplo, 25 04 2020 + </span> + + <div class="form-date-group"> + <div class="date-group-item"> + <div class="form-section"> + <label for="">Dia</label> + <input class="form-input-width-2" name="end_at_day" type="text"> + </div> + </div> + <div class="date-group-item"> + <div class="form-section"> + <label for="">Mês</label> + <input class="form-input-width-2" name="end_at_month" type="text"> + </div> + </div> + <div class="date-group-item"> + <div class="form-section"> + <label for="">Ano</label> + <input class="form-input-width-4" name="end_at_year" type="text" readonly value="2020"> + </div> + </div> + </div> + </fieldset> + + + <fieldset> + <legend class="legend-xl"> + <h1> Quando começa o período de entrega? </h1> + </legend> + + <span class="hint"> + Por exemplo, 25 04 2020 + </span> + + <div class="form-date-group"> + <div class="date-group-item"> + <div class="form-section"> + <label for="">Dia</label> + <input class="form-input-width-2" name="delivery_start_at_day" type="text"> + </div> + </div> + <div class="date-group-item"> + <div class="form-section"> + <label for="">Mês</label> + <input class="form-input-width-2" name="delivery_start_at_month" type="text"> + </div> + </div> + <div class="date-group-item"> + <div class="form-section"> + <label for="">Ano</label> + <input class="form-input-width-4" name="delivery_start_at_year" type="text" readonly value="2020"> + </div> + </div> + </div> + </fieldset> + + + <fieldset> + <legend class="legend-xl"> + <h1> Quando se encerra o período de entrega? </h1> + </legend> + + <span class="hint"> + Por exemplo, 25 04 2020 + </span> + + <div class="form-date-group"> + <div class="date-group-item"> + <div class="form-section"> + <label for="">Dia</label> + <input class="form-input-width-2" name="delivery_end_at_day" type="text"> + </div> + </div> + <div class="date-group-item"> + <div class="form-section"> + <label for="">Mês</label> + <input class="form-input-width-2" name="delivery_end_at_month" type="text"> + </div> + </div> + <div class="date-group-item"> + <div class="form-section"> + <label for="">Ano</label> + <input class="form-input-width-4" name="delivery_end_at_year" type="text" readonly value="2020"> + </div> + </div> + </div> + </fieldset> + + <div class="form-section"> + <label for="">Margem sobre o valor dos produtos nesse ciclo</label> + <input name="price_margin" type="number" step="0.1" class="form-input-width-4" /> + </div> + + <div class="form-section"> + <label for="">Estado inicial desse ciclo</label> + <select name="status"> + {% for cycle in cycles %} + <option value="{{cycle[0]}}">{{cycle[1]}}</option> + {% endfor %} + </select> + </div> + + <div class="form-action"> + <button class="btn btn-primary" type="submit">Criar Ciclo</button> + </div> + </form> +{% endblock %} diff --git a/core/templates/orders.html b/core/templates/orders.html new file mode 100644 index 0000000000000000000000000000000000000000..43788260ba9e115f975ab93131b557aa9af78f17 --- /dev/null +++ b/core/templates/orders.html @@ -0,0 +1,29 @@ +{% extends "layout.html" %} +{% block body %} + <section> + <h1> Seus pedidos </h1> + + {% for order in orders %} + <div class="order p-5 {{ 'current-cycle' if order.cycle.status.value == "published" }}"> + Seu pedido no ciclo <strong>{{ order.cycle.name }}</strong>: + <div> + <small>{{ order.cycle.start_at.strftime("%d/%m/%Y") }} até {{ order.cycle.end_at.strftime("%d/%m/%Y") }}</small> + </div> + + <ul> + {% for product in order.products() %} + <li>{{ product.title }}</li> + {% endfor %} + </ul> + + <div> + <strong> Total: </strong> <em>{{ order.total() | as_currency }}</em> + </div> + + <div class="pt-5 pb-5"> + <a href="{{url_for('cycles.show', id = order.cycle.id)}}">Ver ciclo</a> + </div> + </div> + {% endfor %} + </section> +{% endblock %}