summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarius Peter <marius.peter@tutanota.com>2022-05-01 21:38:13 +0200
committerMarius Peter <marius.peter@tutanota.com>2022-05-01 21:38:13 +0200
commitce73f10a4aaa717de025fd2dc591294fea0db8de (patch)
tree6f7850b0ef2d04cbe55c9a532733d98d7c7f94a3
parent9770cf8345d47cb086bd386c0d5c0fca165a6d11 (diff)
Basic app.
-rw-r--r--app/database.py0
-rw-r--r--app/forms.py101
-rw-r--r--app/model.py168
-rw-r--r--app/placeholders.py7
-rw-r--r--app/routes.py254
5 files changed, 317 insertions, 213 deletions
diff --git a/app/database.py b/app/database.py
deleted file mode 100644
index e69de29..0000000
--- a/app/database.py
+++ /dev/null
diff --git a/app/forms.py b/app/forms.py
index daa394b..302db58 100644
--- a/app/forms.py
+++ b/app/forms.py
@@ -1,24 +1,93 @@
+"""
+Form classes must be named 'Add{Item}', Item referring to the
+model concerned.
+"""
+
from flask_wtf import FlaskForm
-from wtforms import StringField, PasswordField, SubmitField, BooleanField
-from wtforms.validators import DataRequired, Length, EqualTo
+from wtforms import (
+ SubmitField,
+ SelectField,
+ RadioField,
+ HiddenField,
+ StringField,
+ PasswordField,
+ IntegerField,
+ FloatField,
+ DateTimeField,
+)
+from wtforms.validators import InputRequired, Length, NumberRange
+
+
+class AddCustomer(FlaskForm):
+ name = StringField("Customer name", validators=[InputRequired()])
+ name_alternative = StringField("Alternative name")
+ # date_time_created = DateTimeField("Creation date")
+ code_customer = StringField("Customer code")
+ code_accounting = StringField("Accounting code")
+ address = StringField("Address")
+ postal_code = StringField("Postal Code")
+ city = StringField("City")
+ country = StringField("Country")
+ phone = StringField("Phone")
+ website = StringField("Website")
+ email = StringField("E-mail")
+ professional_id_1 = StringField("Professional ID 1")
+ professional_id_2 = StringField("Professional ID 2")
+ tax_id = StringField("Tax ID")
+ payment_terms = StringField("Payment Terms", default="Tu vas payer sale chien!")
+ submit = SubmitField("Add/Update Product")
+
+
+class AddProduct(FlaskForm):
+ name = StringField("Product name", validators=[InputRequired()])
+ code_accounting = StringField("Accounting code", default=0)
+ unit_weight = FloatField("Unit weight", default=0)
+ price_net = FloatField("Price (net)", default=0)
+ price_gross = FloatField("Price (gross)", default=0)
+ tax_rate = FloatField("Tax rate", default=0)
+ submit = SubmitField("Add/Update Product")
-class RegistrationForm(FlaskForm):
- alias = StringField("Alias", validators=[DataRequired(), Length(min=2, max=20)])
- password = PasswordField("Password", validators=[DataRequired()])
- password_confirm = PasswordField(
- "Confirm Password", validators=[DataRequired(), EqualTo("password")]
+class AddLog(FlaskForm):
+ target = SelectField(
+ "Type",
+ choices=[("False", "Log"), ("True", "Target")],
+ validators=[InputRequired()],
)
- submit = SubmitField("Create Alias")
+ nno3 = FloatField("NNO3", default=0)
+ p = FloatField("P", default=0)
+ k = FloatField("K", default=0)
+ ca = FloatField("Ca", default=0)
+ mg = FloatField("Mg", default=0)
+ s = FloatField("S", default=0)
+ na = FloatField("Na", default=0)
+ cl = FloatField("Cl", default=0)
+ fe = FloatField("Fe", default=0)
+ zn = FloatField("Zn", default=0)
+ b = FloatField("B", default=0)
+ mn = FloatField("Mn", default=0)
+ cu = FloatField("Cu", default=0)
+ mo = FloatField("Mo", default=0)
+ si = FloatField("Si", default=0)
+ nnh4 = FloatField("NNH4", default=0)
+ submit = SubmitField("Add/Update Log")
-class LoginForm(FlaskForm):
- alias = StringField("Alias", validators=[DataRequired(), Length(min=2, max=20)])
- password = PasswordField("Password", validators=[DataRequired()])
- remember = BooleanField("Remember Alias")
- submit = SubmitField("Login Alias")
+class AddOrder(FlaskForm): # TODO
+ name = StringField("Product name", validators=[InputRequired()])
+ code_accounting = StringField("Accounting code", default=0)
+ unit_weight = FloatField("Unit weight", default=0)
+ price_net = FloatField("Price (net)", default=0)
+ price_gross = FloatField("Price (gross)", default=0)
+ tax_rate = FloatField("Tax rate", default=0)
+ submit = SubmitField("Add/Update Product")
-class NewMessage(FlaskForm):
- recipient = StringField("Recipient", validators=[DataRequired()])
- message = StringField("message", validators=[DataRequired()])
+class AddInvoice(FlaskForm):
+ name = StringField("Product name", validators=[InputRequired()])
+ code_accounting = StringField("Accounting code", default=0)
+ unit_weight = FloatField("Unit weight", default=0)
+ price_net = FloatField("Price (net)", default=0)
+ price_gross = FloatField("Price (gross)", default=0)
+ tax_rate = FloatField("Tax rate", default=0)
+ submit = SubmitField("Add/Update Product")
diff --git a/app/model.py b/app/model.py
index fa4e00a..1cf59d8 100644
--- a/app/model.py
+++ b/app/model.py
@@ -1,39 +1,161 @@
-import SQAlchemy
+# import SQLAlchemy
+from flask_sqlalchemy import SQLAlchemy
+from datetime import datetime
+
+db = SQLAlchemy()
-class Users(db.Model):
- id = db.Column(db.Integer, primary_key=True)
- name_first = db.Column(db.String(20), nullable=False)
- name_last = db.Column(db.String(20), nullable=False)
+
+class Module(db.Model):
+ name = db.Column(
+ "Name", db.String(20), unique=True, nullable=False, primary_key=True
+ )
+ description = db.Column("Description", db.String(50), nullable=False)
def __repr__(self):
- return f"<User {self.name_first} {self.name_last}>"
+ return f"<Module {self.name}>"
-class Projects(db.Model):
- id = db.Column(db.Integer, primary_key=True)
- name = db.Column(db.String(20), nullable=False)
- name_full = db.Column(db.String(20), nullable=False)
- nickname = db.Column(db.String(20), nullable=False)
- city = db.Column(db.String(20), nullable=False)
+class Customer(db.Model):
+ primary_key = db.Column("CustomerId", db.Integer, nullable=False, primary_key=True)
+ name = db.Column("Name", db.String(20), nullable=False)
+ name_alternative = db.Column("NameAlternative", db.String(20))
+ date_time_created = db.Column("DateTimeCreated", db.String(20), nullable=False)
+ date_time_updated = db.Column("DateTimeUpdated", db.String(20), nullable=False)
+ code_customer = db.Column("CodeCustomer", db.String(20), unique=True)
+ code_accounting = db.Column("CodeAccounting", db.String(20), unique=True)
+ address = db.Column("Address", db.String(20))
+ postal_code = db.Column("PostalCode", db.Integer)
+ city = db.Column("City", db.String(20))
+ country = db.Column("Country", db.String(20))
+ phone = db.Column("Phone", db.String(20))
+ website = db.Column("Website", db.String(20))
+ email = db.Column("Email", db.String(20))
+ professional_id_1 = db.Column("ProfessionalId1", db.String(20), unique=True)
+ professional_id_2 = db.Column("ProfessionalId2", db.String(20), unique=True)
+ tax_id = db.Column("TaxId", db.String(20), unique=True)
+ payment_terms = db.Column("PaymentTerms", db.String(20), unique=True)
+
+ def __repr__(self):
+ return f"<Customer {self.name}>"
+
+
+class Product(db.Model):
+ primary_key = db.Column("ProductId", db.Integer, primary_key=True)
+ name = db.Column("Name", db.String(20), nullable=False, unique=True)
+ code_accounting = db.Column("CodeAccounting", db.String(20))
+ unit_weight = db.Column("UnitWeight", db.Float)
+ price_net = db.Column("PriceNet", db.Float)
+ price_gross = db.Column("PriceGross", db.Float)
+ tax_rate = db.Column("TaxRate", db.Float)
+ date_time_created = db.Column(
+ "DateTimeCreated",
+ db.String,
+ default=datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
+ )
+ date_time_updated = db.Column(
+ "DateTimeUpdated",
+ db.String,
+ default=datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
+ )
+
+ def __init__(
+ self,
+ name,
+ code_accounting,
+ unit_weight,
+ price_net,
+ price_gross,
+ tax_rate,
+ ):
+ self.name = name
+ self.code_accounting = code_accounting
+ self.unit_weight = unit_weight
+ self.price_net = price_net
+ self.price_gross = price_gross
+ self.tax_rate = tax_rate
def __repr__(self):
- return f"<Project {self.name}>"
+ return f"<Product {self.name}>"
-class Modules(db.Model):
+class Log(db.Model):
+ primary_key = db.Column("LogId", db.Integer, primary_key=True)
+ target = db.Column("Target", db.String, default="False")
+ nno3 = db.Column("NNO3", db.Float, default=0)
+ p = db.Column("P", db.Float, default=0)
+ k = db.Column("K", db.Float, default=0)
+ ca = db.Column("Ca", db.Float, default=0)
+ mg = db.Column("Mg", db.Float, default=0)
+ s = db.Column("S", db.Float, default=0)
+ na = db.Column("Na", db.Float, default=0)
+ cl = db.Column("Cl", db.Float, default=0)
+ fe = db.Column("Fe", db.Float, default=0)
+ zn = db.Column("Zn", db.Float, default=0)
+ b = db.Column("B", db.Float, default=0)
+ mn = db.Column("Mn", db.Float, default=0)
+ cu = db.Column("Cu", db.Float, default=0)
+ mo = db.Column("Mo", db.Float, default=0)
+ si = db.Column("Si", db.Float, default=0)
+ nnh4 = db.Column("NNH4", db.Float, default=0)
+ date_time_created = db.Column(
+ "DateTimeCreated",
+ db.String,
+ default=datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
+ )
+ date_time_updated = db.Column(
+ "DateTimeUpdated",
+ db.String,
+ default=datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
+ )
+
+ def __init__(
+ self, target, nno3, p, k, ca, mg, s, na, cl, fe, zn, b, mn, cu, mo, si, nnh4
+ ):
+ self.target = target
+ self.nno3 = nno3
+ self.p = p
+ self.k = k
+ self.ca = ca
+ self.mg = mg
+ self.s = s
+ self.na = na
+ self.cl = cl
+ self.fe = fe
+ self.zn = zn
+ self.b = b
+ self.mn = mn
+ self.cu = cu
+ self.mo = mo
+ self.si = si
+ self.nnh4 = nnh4
+ self.date_time_created = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
+
+ def __repr__(self):
+ return f"<Log from {self.date_time_created} updated {self.date_time_updated}>"
+
+
+# Everything after here is garbage
+
+
+class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
- name = db.Column(db.String(20), unique=True, nullable=False)
- description = db.Column(db.String(50), nullable=False)
+ name_first = db.Column(db.String(20), nullable=False)
+ name_last = db.Column(db.String(20), nullable=False)
+ email = db.Column(db.String(20), nullable=False)
+ phone_mobile = db.Column(db.Integer, nullable=False)
+ phone_alternative = db.Column(db.Integer)
+ updated = db.Column(db.String)
def __repr__(self):
- return f"<Module {self.name}>"
+ return f"<User {self.name_first} {self.name_last}>"
-class Doobie:
- def __init__(self, name, prices, quantity):
- self.name = name
- self.prices = prices
- self.quantity = quantity
+class Order(db.Model): # TODO
+ id = db.Column(db.Integer, primary_key=True)
+ date = db.Column(db.String(20), nullable=False)
+ customer = db.Column(db.String(20), nullable=False)
+ content = db.Column(db.String(10), nullable=False)
+ updated = db.Column(db.String)
def __repr__(self):
- return self.name
+ return f"<Order {self.name} at {self.updated}>"
diff --git a/app/placeholders.py b/app/placeholders.py
deleted file mode 100644
index a2360b4..0000000
--- a/app/placeholders.py
+++ /dev/null
@@ -1,7 +0,0 @@
-modules = [
- "catalog",
- "creator",
- "logger",
- "calculator",
- "stock",
-]
diff --git a/app/routes.py b/app/routes.py
index d2bd3f0..11cd3c2 100644
--- a/app/routes.py
+++ b/app/routes.py
@@ -19,161 +19,26 @@ placeholder data for posts' content.
from flask import Flask, render_template, request, redirect, flash, url_for, jsonify
-from flask_sqlalchemy import SQLAlchemy
from flask_bootstrap import Bootstrap
-from flask_wtf import FlaskForm
-from wtforms import (
- SubmitField,
- SelectField,
- RadioField,
- HiddenField,
- StringField,
- IntegerField,
- FloatField,
-)
-from wtforms.validators import InputRequired, Length, Regexp, NumberRange
from datetime import datetime
+import inspect
-import placeholders as p
+from model import *
+from forms import *
app = Flask(__name__)
-# Flask-Bootstrap requires this line
-Bootstrap(app)
-
-
-# Flask-WTF encryption key
-app.config["SECRET_KEY"] = "Scooby_Lu,_where_are_you?"
-
-# Our database name
-db_name = "fapg.db"
-app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///" + db_name
-app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = True
-db = SQLAlchemy(app)
-
-
-class Users(db.Model):
- id = db.Column(db.Integer, primary_key=True)
- name_first = db.Column(db.String(20), nullable=False)
- name_last = db.Column(db.String(20), nullable=False)
- email = db.Column(db.String(20), nullable=False)
- phone_mobile = db.Column(db.Integer, nullable=False)
- phone_alternative = db.Column(db.Integer)
- updated = db.Column(db.String)
-
- def __init__(
- self, name_first, name_last, email, phone_mobile, phone_alternative, updated
- ):
- self.name_first = name_first
- self.name_last = name_last
- self.email = email
- self.phone_mobile = phone_mobile
- self.phone_alternative = phone_alternative
- self.updated = updated
-
- def __repr__(self):
- return f"<User {self.name_first} {self.name_last}>"
-
-
-class Products(db.Model):
- id = db.Column(db.Integer, primary_key=True)
- name = db.Column(db.String(20), nullable=False)
- supplier = db.Column(db.String(20), nullable=False)
- price = db.Column(db.Float(10), nullable=False)
- updated = db.Column(db.String)
-
- def __init__(self, name, supplier, price, updated):
- self.name = name
- self.supplier = supplier
- self.price = price
- self.updated = updated
-
- def __repr__(self):
- return f"<Product {self.name} by {self.supplier}>"
-
-
-class Projects(db.Model):
- id = db.Column(db.Integer, primary_key=True)
- name = db.Column(db.String(20), nullable=False)
- name_full = db.Column(db.String(20), nullable=False)
- nickname = db.Column(db.String(20), nullable=False)
- city = db.Column(db.String(20), nullable=False)
-
- def __repr__(self):
- return f"<Project {self.name}>"
-
-
-class Modules(db.Model):
- id = db.Column(db.Integer, primary_key=True)
- name = db.Column(db.String(20), unique=True, nullable=False)
- description = db.Column(db.String(50), nullable=False)
-
- def __init__(self, name, description, updated):
- self.name = name
- self.description = description
- self.updated = updated
-
- def __repr__(self):
- return f"<Module {self.name}>"
-
-
-class AddProduct(FlaskForm):
- # id used only by update/edit
- id = HiddenField()
- name = StringField("Product name", validators=[InputRequired()])
- supplier = SelectField(
- "Choose a supplier",
- choices=[
- ("", ""),
- ("Mister Brown", "Mister Brown"),
- ("Madame Cerise", "Madame Cerise"),
- ("Biton la Malice", "G. Biton la Malice"),
- ("Leroy Merlin", "Leroy Merlin"),
- ("other", "Other"),
- ],
- )
- price = FloatField("Retail price per unit")
- # updated - date - handled in the route function
- updated = HiddenField()
- submit = SubmitField("Add/Update Product")
-
-
-# add a new product to the database
-@app.route("/add_product", methods=["GET", "POST"])
-def add_product():
- form = AddProduct()
- if form.validate_on_submit():
- name = request.form["name"]
- supplier = request.form["supplier"]
- price = request.form["price"]
- # get today's date from function, above all the routes
- updated = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
- # the data to be inserted into FAPG model - the table, products
- record = Products(name, supplier, price, updated)
- # Flask-SQLAlchemy magic adds record to database
- db.session.add(record)
- db.session.commit()
- # create a message to send to the template
- message = f"The data for product {name} has been submitted."
- return render_template("add_product.html", message=message)
- else:
- # show validaton errors
- # see https://pythonprogramming.net/flash-flask-tutorial/
- for field, errors in form.errors.items():
- for error in errors:
- flash(
- "Error in {}: {}".format(getattr(form, field).label.text, error),
- "error",
- )
- return render_template("add_product.html", form=form)
+
+app.config.from_pyfile("../config.py")
+db.init_app(app)
@app.route("/")
@app.route("/fapg/home")
def project():
"""This is our project welcome page."""
- michel = Users(
+ michel = User(
name_first="Michel",
name_last="Peter",
email="le-boss@fapg.com",
@@ -181,35 +46,90 @@ def project():
phone_alternative="0000000000",
updated="2022-04-21",
)
- modules = Modules.query.all()
+ modules = Module.query.all()
print(module.name for module in modules)
- return render_template("home.html", user=michel, project=fapg, modules=modules)
+ return render_template("home.html", user=michel, project="fapg", modules=modules)
-@app.route("/module/<module>")
+@app.route("/modules")
+def all_modules():
+ return redirect("/")
+
+
+@app.route("/modules/<module>")
def render_module(module):
- modules = Modules.query.all()
- catalog = Products.query.all()
- user_modules = [module.name for module in modules]
- print(user_modules)
- # If a module was purchased by a user and added to their database,
- # they have access to the corresponding module route.
- if module in user_modules:
- return render_template(
- f"modules/{module}.html",
- modules=modules,
- catalog=catalog,
- )
- else:
+ modules = Module.query.all()
+ if module not in [mod.name for mod in modules]:
return render_template("errors/module-not-found.html", module=module)
+ customers = Customer.query.order_by(Customer.primary_key.desc())
+ products = Product.query.order_by(Product.primary_key.desc())
+ logs = Log.query.order_by(Log.primary_key.desc())
+ latest_target = (
+ Log.query.filter_by(target="True").order_by(Log.primary_key.desc()).first()
+ )
+ flash(f"Successfully accessed module {module}.", "info")
+ flash(f"Still fighting against styling in {module}.", "error")
+ return render_template(
+ f"modules/{module}.html",
+ module=module,
+ modules=modules,
+ customers=customers,
+ products=products,
+ logs=logs,
+ target=latest_target,
+ )
+
+
+@app.route("/delete-<pk>-from-<table>", methods=["POST"])
+def delete_item(pk, table):
+ """Delete item with Primary Key = pk from corresponding database
+ table.
+ """
+ model = globals()[table]
+ record = model.query.filter_by(primary_key=pk).first()
+ db.session.delete(record)
+ db.session.commit()
+ flash(f"Successfully removed item #{pk} from {table} table.", "info")
+ return redirect("/modules")
+
+
+@app.route("/add-<item>", methods=["GET", "POST"])
+def add_item(item):
+ """Add a new item to a corresponding database table.
+
+ The item must match a database model class name (table). Then, we
+ match the model class attributes with request.form values.
+
+ """
+ if item not in db.metadata.tables.keys():
+ return render_template("errors/item-not-found.html", item=item)
+ if request.method == "GET":
+ form = globals()[f"Add{item.capitalize()}"]()
+ return render_template("add-item.html", item=item, form=form)
+ if request.method == "POST":
+ table = globals()[item.capitalize()]
+ table_fields = inspect.signature(table).parameters
+ form_values = [request.form[key] for key in table_fields]
+ debug = f"Ready to insert {form_values}"
+ record = table(*form_values)
+ db.session.add(record)
+ db.session.commit()
+ item_pk = table.query.order_by(table.primary_key.desc()).first().primary_key
+ flash(
+ f"Successfully added item #{item_pk} to {table.__table__.name.capitalize()} table.",
+ "info",
+ )
+ return redirect(f"/modules")
+
+
+@app.route("/add-invoice", methods=["GET", "POST"])
+def add_invoice():
+ form = AddInvoice()
+ if request.method == "GET":
+ return render_template("add-invoice.html")
-# If this file is executed as a script (i.e. double-clicked),
-# the Python interpreter will run the Flask process and begin serving
-# the web pages on the standard localhost address (127.0.0.1).
-# But if this file is called as a module by another Python script, it will not
-# serve content to the web pages, but the function definitions contained in
-# this file will be available to the calling script.
-# E.g. calling script will know what the yes() function is.
-if __name__ == "__main__":
- app.run(debug=True)
+@app.route("/preview-invoice", methods=["GET", "POST"])
+def preview_invoice():
+ if request.method == "GET":
+ return render_template("preview-invoice.html")
Copyright 2019--2024 Marius PETER