diff options
Diffstat (limited to 'app')
| -rw-r--r-- | app/database.py | 0 | ||||
| -rw-r--r-- | app/forms.py | 101 | ||||
| -rw-r--r-- | app/model.py | 168 | ||||
| -rw-r--r-- | app/placeholders.py | 7 | ||||
| -rw-r--r-- | app/routes.py | 254 | 
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") | 
