From a8f0deab285761a1198609f0159589012d6fd48e Mon Sep 17 00:00:00 2001 From: ydb5755 Date: Sun, 29 Sep 2024 12:38:32 +0300 Subject: [PATCH] too much to enumerate, too little time, have to push --- .gitignore | 2 - app/__init__.py | 3 - app/models.py | 6 +- app/routes.py | 99 ++++++++++++++++++++- app/templates/index.html | 126 +++++++++++++++++++++++++-- app/templates/view_month.html | 37 ++++++++ instance/site.db | Bin 0 -> 36864 bytes migrations/README | 1 + migrations/alembic.ini | 50 +++++++++++ migrations/env.py | 113 ++++++++++++++++++++++++ migrations/script.py.mako | 24 +++++ migrations/versions/8960c74c29df_.py | 51 +++++++++++ pythonFiles/playground.py | 67 ++++++++++++++ wsgi.py | 5 ++ 14 files changed, 567 insertions(+), 17 deletions(-) create mode 100644 app/templates/view_month.html create mode 100644 instance/site.db create mode 100644 migrations/README create mode 100644 migrations/alembic.ini create mode 100644 migrations/env.py create mode 100644 migrations/script.py.mako create mode 100644 migrations/versions/8960c74c29df_.py create mode 100644 pythonFiles/playground.py create mode 100644 wsgi.py diff --git a/.gitignore b/.gitignore index c8fb93a..7b82e54 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,2 @@ **/__pycache__/ -instance/ -migrations/ static/ \ No newline at end of file diff --git a/app/__init__.py b/app/__init__.py index 02712ce..3eb4590 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -16,6 +16,3 @@ migrate.init_app(app,db) from app import models #.models import Vendor, LineItem, BudgetCategory from app import routes - -if __name__ == '__main__': - app.run(debug=True) diff --git a/app/models.py b/app/models.py index fc75980..262828e 100644 --- a/app/models.py +++ b/app/models.py @@ -3,18 +3,18 @@ from sqlalchemy import Column, INTEGER, String class Vendor(db.Model): __tablename__ = 'vendor' - id = Column('id', INTEGER(), primary_key=True) + id = Column('id', INTEGER(), primary_key=True, autoincrement=True) name = Column('name', String(), nullable=False) bc_id = Column('bc_id', INTEGER(), nullable=True) class BudgetCategory(db.Model): __tablename__ = 'budget_category' - id = Column('id', INTEGER(), primary_key=True) + id = Column('id', INTEGER(), primary_key=True, autoincrement=True) name = Column('name', String(), nullable=False) class LineItem(db.Model): __tablename__ = 'line_item' - id = Column('id', INTEGER(), primary_key=True) + id = Column('id', INTEGER(), primary_key=True, autoincrement=True) parent_line_item_id = Column('parent_line_item_id', INTEGER(), nullable=True) amount = Column('amount', INTEGER(), nullable=False) currency_type = Column('currency_type', String(), default='shekel') diff --git a/app/routes.py b/app/routes.py index e28f7c7..3b71427 100644 --- a/app/routes.py +++ b/app/routes.py @@ -1,8 +1,99 @@ -from app import app -from flask import render_template - +from app import app, db +from flask import render_template, redirect, url_for, request +from sqlalchemy import select, delete, update +from app.models import LineItem, BudgetCategory, Vendor +import datetime +import os +import openpyxl +import time @app.route('/') def home(): - return render_template('index.html') \ No newline at end of file + this_year = datetime.datetime.now().date().year + this_month = datetime.datetime.now().date().month + # line_item_dates = db.session.query(select(LineItem.date).order_by(LineItem.date)) + notes = db.session.execute(select(LineItem.note)).all() + vendors = db.session.execute(select(Vendor)).all() + budget_categories = db.session.execute(select(BudgetCategory)).all() + files = os.listdir('C:/Users/Lenovo/Desktop/BudgetingApp/app/static/uploadable') + return render_template('index.html', + files=files, + notes=notes, + vendors=vendors, + budget_categories=budget_categories) + +@app.route('/upload_file/') +def upload_file(filename): + + file_path = 'C:/Users/Lenovo/Desktop/BudgetingApp/app/static/uploadable/' + filename + xl = openpyxl.load_workbook(file_path, read_only=True) + wb = xl.worksheets[0] + + items_to_add = [] + + vendors = db.session.execute(select(Vendor.name)).all() + vendors_added = [vendor[0] for vendor in vendors] + + for line, row in enumerate(wb.rows): + row = [x.value for x in row] + if line == 0: + columns = {x: i for i,x in enumerate(row)} + continue + if row[columns['Charge']]: + amount=row[columns['Charge']] * -1 + else: + amount=row[columns['Deposit']] + + date = row[0] + date = time.mktime(date.timetuple()) + + if not row[columns['Vendor']] in vendors_added: + vendors_added.append(row[columns['Vendor']]) + vendor = Vendor( + name=row[columns['Vendor']] + ) + db.session.add(vendor) + db.session.commit() + + line_item = LineItem( + parent_line_item_id=None, + amount=amount, + currency_type='shekel', + vendor_id=None, + date=date, + confirmation_code=row[columns['Confirmation Code']], + note=row[columns['Note']] + ) + items_to_add.append(line_item) + + xl.close() + + db.session.add_all(items_to_add) + db.session.commit() + + # os.remove(file_path) + return redirect(url_for('home')) + +@app.route('/view_month//') +def view_month(year, month): + return render_template('view_month.html', + month=month, + year=year) + +@app.route('/add_budget_category', methods=['POST']) +def add_budget_category(): + if request.method == 'POST': + + category_name = request.form['category_name'] + bc = BudgetCategory(name=category_name) + db.session.add(bc) + db.session.commit() + return redirect(url_for('home')) + +@app.route('/delete_budget_category/', methods=['POST']) +def delete_budget_category(id): + db.session.execute(update(Vendor).where(Vendor.bc_id==id).values(bc_id=None)) + db.session.execute(delete(BudgetCategory).where(BudgetCategory.id==id)) + db.session.commit() + return {"status":'success'} \ No newline at end of file diff --git a/app/templates/index.html b/app/templates/index.html index cda7f5d..fce93cd 100644 --- a/app/templates/index.html +++ b/app/templates/index.html @@ -1,11 +1,127 @@ - - - Budgeting + + + Budgeting + - +
+ {% if files %} +
+
+ File available in static folder for upload +
+
+
+ + + + + + + + {% for file in files %} + + + + {% endfor %} + +
Filename
{{file}}
+
+
+
+ {% else %} +
+
+ No files in the upload folder +
+
+ {% endif %} +
+
+ Budget Categories +
+
+ +
+
+ + +
+ +
+
+ + + + + + + + + + {% for bc in budget_categories %} + + + + + + {% endfor %} + +
IDNameDelete
{{bc[0].id}}{{bc[0].name}}
+
+
+
+
+
+ Vendors +
+
+
+ + + + + + + + + {% for vendor in vendors %} + + + + + {% endfor %} + +
IDName
{{vendor[0].id}}{{vendor[0].name}}
+
+
+
+
+
+ Notes +
+
+
+ + + {% for note in notes %} + {% if note[0] %} + + + + {% endif %} + {% endfor %} + +
{{note[0]}}
+
+
+
+
+ + + - \ No newline at end of file + diff --git a/app/templates/view_month.html b/app/templates/view_month.html new file mode 100644 index 0000000..780e1a7 --- /dev/null +++ b/app/templates/view_month.html @@ -0,0 +1,37 @@ + + + + + + Budgeting + + + +
+ {% if files %} +
+
+ {{month}} - {{year}} +
+
+
+ + + + + + + + + +
Line
+
+
+
+ {% endif %} +
+ + + + + diff --git a/instance/site.db b/instance/site.db new file mode 100644 index 0000000000000000000000000000000000000000..132c548199dbdd5f56593282829bcb45bc66c33e GIT binary patch literal 36864 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
  • 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 + return current_app.extensions['migrate'].db.engine + + +def get_engine_url(): + try: + return get_engine().url.render_as_string(hide_password=False).replace( + '%', '%%') + except AttributeError: + return str(get_engine().url).replace('%', '%%') + + +# add your model's MetaData object here +# for 'autogenerate' support +# from myapp import mymodel +# target_metadata = mymodel.Base.metadata +config.set_main_option('sqlalchemy.url', get_engine_url()) +target_db = current_app.extensions['migrate'].db + +# other values from the config, defined by the needs of env.py, +# can be acquired: +# my_important_option = config.get_main_option("my_important_option") +# ... etc. + + +def get_metadata(): + if hasattr(target_db, 'metadatas'): + return target_db.metadatas[None] + return target_db.metadata + + +def run_migrations_offline(): + """Run migrations in 'offline' mode. + + This configures the context with just a URL + and not an Engine, though an Engine is acceptable + here as well. By skipping the Engine creation + we don't even need a DBAPI to be available. + + Calls to context.execute() here emit the given string to the + script output. + + """ + url = config.get_main_option("sqlalchemy.url") + context.configure( + url=url, target_metadata=get_metadata(), literal_binds=True + ) + + with context.begin_transaction(): + context.run_migrations() + + +def run_migrations_online(): + """Run migrations in 'online' mode. + + In this scenario we need to create an Engine + and associate a connection with the context. + + """ + + # this callback is used to prevent an auto-migration from being generated + # when there are no changes to the schema + # reference: http://alembic.zzzcomputing.com/en/latest/cookbook.html + def process_revision_directives(context, revision, directives): + if getattr(config.cmd_opts, 'autogenerate', False): + script = directives[0] + if script.upgrade_ops.is_empty(): + directives[:] = [] + logger.info('No changes in schema detected.') + + conf_args = current_app.extensions['migrate'].configure_args + if conf_args.get("process_revision_directives") is None: + conf_args["process_revision_directives"] = process_revision_directives + + connectable = get_engine() + + with connectable.connect() as connection: + context.configure( + connection=connection, + target_metadata=get_metadata(), + **conf_args + ) + + with context.begin_transaction(): + context.run_migrations() + + +if context.is_offline_mode(): + run_migrations_offline() +else: + run_migrations_online() diff --git a/migrations/script.py.mako b/migrations/script.py.mako new file mode 100644 index 0000000..2c01563 --- /dev/null +++ b/migrations/script.py.mako @@ -0,0 +1,24 @@ +"""${message} + +Revision ID: ${up_revision} +Revises: ${down_revision | comma,n} +Create Date: ${create_date} + +""" +from alembic import op +import sqlalchemy as sa +${imports if imports else ""} + +# revision identifiers, used by Alembic. +revision = ${repr(up_revision)} +down_revision = ${repr(down_revision)} +branch_labels = ${repr(branch_labels)} +depends_on = ${repr(depends_on)} + + +def upgrade(): + ${upgrades if upgrades else "pass"} + + +def downgrade(): + ${downgrades if downgrades else "pass"} diff --git a/migrations/versions/8960c74c29df_.py b/migrations/versions/8960c74c29df_.py new file mode 100644 index 0000000..71b40f1 --- /dev/null +++ b/migrations/versions/8960c74c29df_.py @@ -0,0 +1,51 @@ +"""empty message + +Revision ID: 8960c74c29df +Revises: +Create Date: 2024-09-29 08:46:22.567795 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '8960c74c29df' +down_revision = None +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('budget_category', + sa.Column('id', sa.INTEGER(), nullable=False), + sa.Column('name', sa.String(), nullable=False), + sa.PrimaryKeyConstraint('id') + ) + op.create_table('line_item', + sa.Column('id', sa.INTEGER(), nullable=False), + sa.Column('parent_line_item_id', sa.INTEGER(), nullable=True), + sa.Column('amount', sa.INTEGER(), nullable=False), + sa.Column('currency_type', sa.String(), nullable=True), + sa.Column('vendor_id', sa.INTEGER(), nullable=True), + sa.Column('date', sa.INTEGER(), nullable=False), + sa.Column('confirmation_code', sa.INTEGER(), nullable=True), + sa.Column('note', sa.String(), nullable=True), + sa.PrimaryKeyConstraint('id') + ) + op.create_table('vendor', + sa.Column('id', sa.INTEGER(), nullable=False), + sa.Column('name', sa.String(), nullable=False), + sa.Column('bc_id', sa.INTEGER(), nullable=True), + sa.PrimaryKeyConstraint('id') + ) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table('vendor') + op.drop_table('line_item') + op.drop_table('budget_category') + # ### end Alembic commands ### diff --git a/pythonFiles/playground.py b/pythonFiles/playground.py new file mode 100644 index 0000000..8904127 --- /dev/null +++ b/pythonFiles/playground.py @@ -0,0 +1,67 @@ +import datetime +import openpyxl +import time +from sqlalchemy import create_engine, MetaData, Table +import os + +def engineer(): + path1 = 'C:/Users/Lenovo/Desktop/BudgetingApp/instance/site.db' + # path2 = '' + # path3 = '' + + for p in [path1]: + if os.path.exists(p): + path = p + break + engine = create_engine(f'sqlite:///{path}') + metadata_obj = MetaData() + metadata_obj.reflect(bind=engine) + return engine, metadata_obj + +def playground(): + engine, metadata_obj = engineer() + line_item_table = Table("line_item", metadata_obj, autoload_with=engine) + budget_category_table = Table("budget_category", metadata_obj, autoload_with=engine) + vendor_table = Table("vendor", metadata_obj, autoload_with=engine) + + # xl = openpyxl.load_workbook('C:/Users/Lenovo/Desktop/BudgetingApp/app/static/uploadable/Bulk_Line_Item_Upload.xlsx',read_only=True) + # wb = xl.worksheets[0] + # items_to_add = [] + # for line, row in enumerate(wb.rows): + # row = [x.value for x in row] + # if line == 0: + # columns = {x: i for i,x in enumerate(row)} + # continue + # if row[columns['Charge']]: + # amount=row[columns['Charge']] * -1 + # else: + # amount=row[columns['Deposit']] + # date = row[0] + # date = time.mktime(date.timetuple()) + # line_item = { + # 'parent_line_item_id':None, + # 'amount':amount, + # 'currency_type':'shekel', + # 'vendor_id':None, + # 'date':date, + # 'confirmation_code':row[columns['Confirmation Code']], + # 'note':row[columns['Note']] + # } + # items_to_add.append(line_item) + # print(len(items_to_add)) + # print(items_to_add[51]) + + # month = datetime.datetime.now().date().month + # year = datetime.datetime.now().date().year + # print(month) + # print(year) + # print(type(month)) + # print(type(year)) + # print(datetime.datetime.now(datetime.timezone.utc).timestamp()) + + # today = datetime.datetime.today().date() + # today = time.mktime(today.timetuple()) + # print(today) + +if __name__ == '__main__': + playground() \ No newline at end of file diff --git a/wsgi.py b/wsgi.py new file mode 100644 index 0000000..0b835ac --- /dev/null +++ b/wsgi.py @@ -0,0 +1,5 @@ +from app import app + + +if __name__ == '__main__': + app.run(debug=True)