From 069fbe8f8e685420da0cc265af9df21e14b0ba0c Mon Sep 17 00:00:00 2001 From: Alexis Lahouze Date: Sat, 6 Jun 2015 14:04:48 +0200 Subject: [PATCH] Refactoring. --- accountant/__init__.py | 31 ++++-- accountant/api/__init__.py | 18 +++- accountant/api/controller/__init__.py | 19 +++- accountant/api/controller/accounts.py | 68 ++++++++---- accountant/api/controller/entries.py | 64 ++++++----- .../api/controller/scheduled_operations.py | 100 +++++++++++------- accountant/api/controller/users.py | 5 +- accountant/api/model/__init__.py | 35 +++--- accountant/api/model/accounts.py | 10 +- accountant/api/model/entries.py | 31 +++--- accountant/api/model/operations.py | 28 +++-- accountant/api/model/scheduled_operations.py | 44 +++++--- 12 files changed, 285 insertions(+), 168 deletions(-) diff --git a/accountant/__init__.py b/accountant/__init__.py index 9964e2d..6b5eefb 100644 --- a/accountant/__init__.py +++ b/accountant/__init__.py @@ -14,27 +14,40 @@ You should have received a copy of the GNU Affero General Public License along with Accountant. If not, see . """ +from contextlib import contextmanager -from .api import api -#from api.controller import login_manager -from .api.model import db from flask import Flask from flask.ext.sqlalchemy import SQLAlchemy -from .frontend import frontend -from sqlalchemy.orm import sessionmaker + from . import config # The app -app = Flask(__name__, static_folder = None) +app = Flask(__name__, static_folder=None) app.config['SQLALCHEMY_DATABASE_URI'] = config.db_uri app.config['SQLALCHEMY_RECORD_QUERIES'] = config.debug app.config['WTF_CSRF_ENABLED'] = False app.config['SECRET_KEY'] = 'my_secret_key' -db.init_app(app) -#login_manager.init_app(app) +db = SQLAlchemy(app) + +@contextmanager +def session_scope(): + from accountant import db + session = db.session + + try: + yield session + session.commit() + except: + session.rollback() + raise + finally: + session.close() + +# Must be after db declaration because the blueprints may need it. +from .api import api +from .frontend import frontend app.register_blueprint(frontend, url_prefix='') app.register_blueprint(api, url_prefix='/api') - diff --git a/accountant/api/__init__.py b/accountant/api/__init__.py index c1bb42d..ddfb551 100644 --- a/accountant/api/__init__.py +++ b/accountant/api/__init__.py @@ -1,6 +1,22 @@ +""" + This file is part of Accountant. + + Accountant is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Accountant is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with Accountant. If not, see . +""" from flask import Blueprint api = Blueprint('api', __name__) +# Load all views. from .controller import * - diff --git a/accountant/api/controller/__init__.py b/accountant/api/controller/__init__.py index a27d8eb..44ca585 100644 --- a/accountant/api/controller/__init__.py +++ b/accountant/api/controller/__init__.py @@ -1,3 +1,19 @@ +""" + This file is part of Accountant. + + Accountant is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Accountant is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with Accountant. If not, see . +""" import pkgutil from flask.ext.httpauth import HTTPBasicAuth @@ -7,6 +23,3 @@ __all__ = [] for loader, module_name, is_pkg in pkgutil.walk_packages(__path__): __all__.append(module_name) - -from . import * - diff --git a/accountant/api/controller/accounts.py b/accountant/api/controller/accounts.py index c7ce08c..a93602d 100644 --- a/accountant/api/controller/accounts.py +++ b/accountant/api/controller/accounts.py @@ -14,15 +14,21 @@ You should have received a copy of the GNU Affero General Public License along with Accountant. If not, see . """ +from flask import json, request + +from sqlalchemy import func, case, cast, extract, distinct + +from forms.accounts import AccountForm + +from accountant import db, session_scope + from . import auth from .. import api -from ..model import db, session_scope + from ..model.accounts import Account from ..model.entries import Entry from ..model.operations import Operation -from flask import json, request -from sqlalchemy import func, case, cast, extract, distinct -from forms.accounts import AccountIdForm, AccountForm + @api.route("/accounts", methods=["GET"]) @auth.login_required @@ -32,12 +38,14 @@ def get_accounts(): """ with session_scope() as session: query = session.query( - Account.id.label("id"), - Account.name.label("name"), - Account.authorized_overdraft.label("authorized_overdraft"), - func.sum(Entry.value).label("future"), - func.sum(case([(Entry.pointed, Entry.value,)], else_=cast(0, db.Numeric(15, 2)))).label("pointed"), - func.sum(case([(Entry.operation_date < func.now(), Entry.value,)], else_=cast(0, db.Numeric(15, 2)))).label("current") + Account.id.label("id"), + Account.name.label("name"), + Account.authorized_overdraft.label("authorized_overdraft"), + func.sum(Entry.value).label("future"), + func.sum(case([(Entry.pointed, Entry.value,)], + else_=cast(0, db.Numeric(15, 2)))).label("pointed"), + func.sum(case([(Entry.operation_date < func.now(), Entry.value,)], + else_=cast(0, db.Numeric(15, 2)))).label("current") ).outerjoin(Entry).group_by(Account.id).order_by(Account.id) return json.dumps([{ @@ -49,18 +57,23 @@ def get_accounts(): "future": str(i.future) } for i in query.all()]) + @api.route("/accounts////") @auth.login_required def get_account_status(account_id, year, month): with session_scope() as session: query = session.query( - func.sum(case([(func.sign(Operation.value) == -1, Operation.value)], else_=0)).label("expenses"), - func.sum(case([(func.sign(Operation.value) == 1, Operation.value)], else_=0)).label("revenues"), + func.sum(case([(func.sign(Operation.value) == -1, Operation.value)], + else_=0)).label("expenses"), + func.sum(case([(func.sign(Operation.value) == 1, Operation.value)], + else_=0)).label("revenues"), func.sum(Operation.value).label("balance") ).filter( Operation.account_id == account_id ).filter( - func.date_trunc('month', Operation.operation_date) == "%s-%s-01" % (year, month) + func.date_trunc('month', + Operation.operation_date) == "%s-%s-01" % (year, + month) ).group_by(Operation.account_id) if query.count() == 1: @@ -79,13 +92,16 @@ def get_account_status(account_id, year, month): "balance": str(balance) }) + @api.route("/accounts//months") @auth.login_required def get_months(account_id): with session_scope() as session: query = session.query( - distinct(func.lpad(cast(extract("year", Entry.operation_date), db.String), 4, '0')).label("year"), - func.lpad(cast(extract("month", Entry.operation_date), db.String), 2, '0').label("month") + distinct(func.lpad(cast(extract("year", Entry.operation_date), + db.String), 4, '0')).label("year"), + func.lpad(cast(extract("month", Entry.operation_date), + db.String), 2, '0').label("month") ).filter(Entry.account_id == account_id).order_by("year", "month") return json.dumps([{ @@ -93,11 +109,13 @@ def get_months(account_id): "month": i.month.rjust(2, '0') } for i in query.all()]) + @api.route("/accounts", methods=["PUT"]) @auth.login_required def add_account(): with session_scope() as session: - account = Account(request.json['name'], request.json['authorized_overdraft']) + account = Account(request.json['name'], + request.json['authorized_overdraft']) session.add(account) @@ -111,7 +129,10 @@ def update_account(account_id): if account_form.validate(): with session_scope() as session: - account = session.query(Account).filter(Account.id == account_id).first() + query = session.query(Account) + query = query.filter(Account.id == account_id) + + account = query.first() account.name = request.json['name'] account.authorized_overdraft = request.json['authorized_overdraft'] @@ -120,15 +141,22 @@ def update_account(account_id): return json.dumps("Account #%s updated." % account_id) else: - return json.dumps({'ok': False, 'error_type': 'validation', 'errors': account_form.errors}) + return json.dumps({ + 'ok': False, + 'error_type': 'validation', + 'errors': account_form.errorsi + }) + @api.route("/accounts/", methods=["DELETE"]) @auth.login_required def delete_account(account_id): with session_scope() as session: - account = session.query(Account).filter(Account.id == account_id).first() + query = session.query(Account) + query = query.filter(Account.id == account_id) + + account = query.first() session.delete(account) return json.dumps("Account #%s deleted." % account_id) - diff --git a/accountant/api/controller/entries.py b/accountant/api/controller/entries.py index d23cbac..676a36e 100644 --- a/accountant/api/controller/entries.py +++ b/accountant/api/controller/entries.py @@ -14,16 +14,17 @@ You should have received a copy of the GNU Affero General Public License along with Accountant. If not, see . """ +from flask import json, request + +from sqlalchemy import func, case, desc + +from accountant import session_scope + from .. import api -from ..model import db, session_scope + from ..model.entries import Entry from ..model.operations import Operation -from ..model.scheduled_operations import ScheduledOperation -from flask import json, request -from sqlalchemy import func, desc -from sqlalchemy.ext.hybrid import hybrid_property, hybrid_method -from sqlalchemy.orm import sessionmaker, column_property, aliased -from sqlalchemy.sql import func, select, case + @api.route("/entries///") def get_entries(account_id, year, month): @@ -33,45 +34,54 @@ def get_entries(account_id, year, month): with session_scope() as session: base_query = session.query( Operation, - case(whens={Operation.canceled: None}, else_=func.sum(Operation.value).over(partition_by="canceled", order_by="operation_date, value desc, label desc")).label("sold") + case( + whens={Operation.canceled: None}, + else_=func.sum(Operation.value).over( + partition_by="canceled", + order_by="operation_date, value desc, label desc") + ).label("sold") ).filter(Operation.account_id == account_id).order_by( desc(Operation.operation_date), Operation.value, Operation.label, ).subquery() - query = session.query(base_query).select_from(base_query).filter(func.date_trunc('month', base_query.c.operation_date) == "%s-%s-01" % (year, month)) + query = session.query(base_query).select_from(base_query) + query = query.filter(func.date_trunc( + 'month', base_query.c.operation_date) == "%s-%s-01" % (year, month)) return json.dumps([{ - "id": i.id, - "pointed": i.pointed, - "operation_date": i.operation_date.strftime("%Y-%m-%d"), - "label": i.label, - "value": str(i.value), - "category": i.category, - "sold": str(i.sold) if not i.canceled else None, - "account_id": i.account_id, - "canceled": i.canceled, - "scheduled_operation_id": i.scheduled_operation_id + "id": i.id, + "pointed": i.pointed, + "operation_date": i.operation_date.strftime("%Y-%m-%d"), + "label": i.label, + "value": str(i.value), + "category": i.category, + "sold": str(i.sold) if not i.canceled else None, + "account_id": i.account_id, + "canceled": i.canceled, + "scheduled_operation_id": i.scheduled_operation_id } for i in query.all()]) + @api.route("/entries", methods=["PUT"]) def add_entry(): with session_scope() as session: entry = Entry( - operation_date = request.json['operation_date'], - pointed = request.json['pointed'], - label = request.json['label'], - value = request.json['value'], - category = request.json['category'], - account_id = request.json['account_id'], - scheduled_operation_id = request.json['scheduled_operation_id'] + operation_date=request.json['operation_date'], + pointed=request.json['pointed'], + label=request.json['label'], + value=request.json['value'], + category=request.json['category'], + account_id=request.json['account_id'], + scheduled_operation_id=request.json['scheduled_operation_id'] ) session.add(entry) return json.dumps("Entry added.") + @api.route("/entries/", methods=["PUT"]) def update_entry(entry_id): with session_scope() as session: @@ -90,6 +100,7 @@ def update_entry(entry_id): return json.dumps("Entry #%s updated." % entry_id) + @api.route("/entries/", methods=["DELETE"]) def delete_entry(entry_id): with session_scope() as session: @@ -98,4 +109,3 @@ def delete_entry(entry_id): session.delete(entry) return json.dumps("Entry #%s deleted." % entry_id) - diff --git a/accountant/api/controller/scheduled_operations.py b/accountant/api/controller/scheduled_operations.py index f69148e..0df8042 100644 --- a/accountant/api/controller/scheduled_operations.py +++ b/accountant/api/controller/scheduled_operations.py @@ -1,11 +1,28 @@ -from .. import api -from ..model import db, session_scope -from ..model.scheduled_operations import ScheduledOperation +""" + This file is part of Accountant. + + Accountant is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Accountant is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with Accountant. If not, see . +""" from flask import json, request -from sqlalchemy import func, desc -from sqlalchemy.ext.hybrid import hybrid_property, hybrid_method -from sqlalchemy.orm import sessionmaker, column_property -from sqlalchemy.sql import func, select + +from sqlalchemy import desc + +from accountant import session_scope + +from .. import api +from ..model.scheduled_operations import ScheduledOperation + @api.route("/scheduled_operations/") def get_scheduled_operations(account_id): @@ -14,51 +31,56 @@ def get_scheduled_operations(account_id): """ with session_scope() as session: query = session.query( - ScheduledOperation + ScheduledOperation ).select_from( - session.query(ScheduledOperation) - .filter(ScheduledOperation.account_id == account_id) - .order_by( - desc(ScheduledOperation.day), - ScheduledOperation.value, - ScheduledOperation.label, - ).subquery() + session.query(ScheduledOperation) + .filter(ScheduledOperation.account_id == account_id) + .order_by( + desc(ScheduledOperation.day), + ScheduledOperation.value, + ScheduledOperation.label, + ).subquery() ) return json.dumps([{ - "id": i.id, - "start_date": i.start_date.strftime("%Y-%m-%d"), - "stop_date": i.stop_date.strftime("%Y-%m-%d"), - "day": str(i.day), - "frequency": str(i.frequency), - "label": i.label, - "value": str(i.value), - "category": i.category, - "account_id": i.account_id + "id": i.id, + "start_date": i.start_date.strftime("%Y-%m-%d"), + "stop_date": i.stop_date.strftime("%Y-%m-%d"), + "day": str(i.day), + "frequency": str(i.frequency), + "label": i.label, + "value": str(i.value), + "category": i.category, + "account_id": i.account_id } for i in query.all()]) + @api.route("/scheduled_operations", methods=["PUT"]) def add_scheduled_operation(): with session_scope() as session: scheduledOperation = ScheduledOperation( - start_date = request.json['start_date'], - stop_date = request.json['stop_date'], - day = request.json['day'], - frequency = request.json['frequency'], - label = request.json['label'], - value = request.json['value'], - category = request.json['category'], - account_id = request.json['account_id'] + start_date=request.json['start_date'], + stop_date=request.json['stop_date'], + day=request.json['day'], + frequency=request.json['frequency'], + label=request.json['label'], + value=request.json['value'], + category=request.json['category'], + account_id=request.json['account_id'] ) session.add(scheduledOperation) return json.dumps("Scheduled operation added.") + @api.route("/scheduled_operations/", methods=["PUT"]) def update_scheduled_operation(scheduled_operation_id): with session_scope() as session: - scheduledOperation = session.query(ScheduledOperation).filter(ScheduledOperation.id == scheduled_operation_id).first() + query = session.query(ScheduledOperation) + query = query.filter(ScheduledOperation.id == scheduled_operation_id) + + scheduledOperation = query.first() scheduledOperation.id = scheduled_operation_id scheduledOperation.start_date = request.json['start_date'], @@ -72,14 +94,18 @@ def update_scheduled_operation(scheduled_operation_id): session.merge(scheduledOperation) - return json.dumps("Scheduled operation #%s updated." % scheduled_operation_id) + return json.dumps( + "Scheduled operation #%s updated." % scheduled_operation_id) + @api.route("/scheduled_operations/", methods=["DELETE"]) def delete_scheduled_operation(scheduled_operation_id): with session_scope() as session: - scheduledOperation = session.query(ScheduledOperation).filter(ScheduledOperation.id == scheduled_operation_id).first() + query = session.query(ScheduledOperation) + query = query.filter(ScheduledOperation.id == scheduled_operation_id) + scheduledOperation = query.first() session.delete(scheduledOperation) - return json.dumps("Scheduled operation #%s deleted." % scheduled_operation_id) - + return json.dumps( + "Scheduled operation #%s deleted." % scheduled_operation_id) diff --git a/accountant/api/controller/users.py b/accountant/api/controller/users.py index 2abf1c5..9ecf21a 100644 --- a/accountant/api/controller/users.py +++ b/accountant/api/controller/users.py @@ -14,10 +14,11 @@ You should have received a copy of the GNU Affero General Public License along with Accountant. If not, see . """ +#from accountant import session_scope from . import auth -from .. import api -from ..model import db, session_scope +#from .. import api + @auth.verify_password def verify_password(username, password): diff --git a/accountant/api/model/__init__.py b/accountant/api/model/__init__.py index 58959f2..96f3e44 100644 --- a/accountant/api/model/__init__.py +++ b/accountant/api/model/__init__.py @@ -1,25 +1,19 @@ -from contextlib import contextmanager -from flask.ext.sqlalchemy import SQLAlchemy -from sqlalchemy.ext.declarative import declarative_base -from sqlalchemy.orm import scoped_session, sessionmaker +""" + This file is part of Accountant. -db = SQLAlchemy() + Accountant is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. -@contextmanager -def session_scope(): - #session = scoped_session(sessionmaker(autocommit = False, autoflush = False, bind = engine)) - session = db.session - #Base.query = session.query_property() - - try: - yield session - session.commit() - except: - session.rollback() - raise - finally: - session.close() + Accountant is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + You should have received a copy of the GNU Affero General Public License + along with Accountant. If not, see . +""" import pkgutil __all__ = [] @@ -27,5 +21,4 @@ __all__ = [] for loader, module_name, is_pkg in pkgutil.walk_packages(__path__): __all__.append(module_name) -from . import * - +#from . import * diff --git a/accountant/api/model/accounts.py b/accountant/api/model/accounts.py index 1bbbaf1..a8cf396 100644 --- a/accountant/api/model/accounts.py +++ b/accountant/api/model/accounts.py @@ -14,14 +14,14 @@ You should have received a copy of the GNU Affero General Public License along with Accountant. If not, see . """ -from . import db +from accountant import db + class Account(db.Model): - id = db.Column(db.Integer, primary_key = True) - name = db.Column(db.String(200), nullable = False) - authorized_overdraft = db.Column(db.Integer, nullable = True, default = 0) + id = db.Column(db.Integer, primary_key=True) + name = db.Column(db.String(200), nullable=False) + authorized_overdraft = db.Column(db.Integer, nullable=True, default=0) def __init__(self, name, authorized_overdraft): self.name = name self.authorized_overdraft = authorized_overdraft - diff --git a/accountant/api/model/entries.py b/accountant/api/model/entries.py index 225fb39..a59d252 100644 --- a/accountant/api/model/entries.py +++ b/accountant/api/model/entries.py @@ -14,28 +14,32 @@ You should have received a copy of the GNU Affero General Public License along with Accountant. If not, see . """ -from . import db +from accountant import db + from .accounts import Account from .scheduled_operations import ScheduledOperation -from sqlalchemy import func, desc -from sqlalchemy.orm import column_property -from sqlalchemy.sql import func, select + class Entry(db.Model): id = db.Column(db.Integer, primary_key=True) - pointed = db.Column(db.Boolean, nullable = False, default = False) - operation_date = db.Column(db.Date, nullable = False) - label = db.Column(db.String(500), nullable = False) - value = db.Column(db.Numeric(15, 2), nullable = False) + pointed = db.Column(db.Boolean, nullable=False, default=False) + operation_date = db.Column(db.Date, nullable=False) + label = db.Column(db.String(500), nullable=False) + value = db.Column(db.Numeric(15, 2), nullable=False) account_id = db.Column(db.Integer, db.ForeignKey('account.id')) - scheduled_operation_id = db.Column(db.Integer, db.ForeignKey('scheduled_operation.id')) + scheduled_operation_id = db.Column(db.Integer, + db.ForeignKey('scheduled_operation.id')) - account = db.relationship(Account, backref = db.backref('entry', lazy="dynamic")) - scheduled_operation = db.relationship(ScheduledOperation, backref = db.backref('entry', lazy="dynamic")) + account = db.relationship(Account, backref=db.backref('entry', + lazy="dynamic")) + scheduled_operation = db.relationship(ScheduledOperation, + backref=db.backref('entry', + lazy="dynamic")) - category = db.Column(db.String(100), nullable = True) + category = db.Column(db.String(100), nullable=True) - def __init__(self, pointed, label, value, account_id, operation_date = None, category = None, scheduled_operation_id = None): + def __init__(self, pointed, label, value, account_id, operation_date=None, + category=None, scheduled_operation_id=None): self.pointed = pointed self.operation_date = operation_date self.label = label @@ -43,4 +47,3 @@ class Entry(db.Model): self.account_id = account_id self.category = category self.scheduled_operation_id = scheduled_operation_id - diff --git a/accountant/api/model/operations.py b/accountant/api/model/operations.py index 42a67aa..4f7d757 100644 --- a/accountant/api/model/operations.py +++ b/accountant/api/model/operations.py @@ -14,35 +14,33 @@ You should have received a copy of the GNU Affero General Public License along with Accountant. If not, see . """ -from . import db +from accountant import db from .accounts import Account -from .scheduled_operations import ScheduledOperation -from sqlalchemy import func, desc -from sqlalchemy.orm import column_property -from sqlalchemy.sql import func, select class Operation(db.Model): id = db.Column(db.Integer, primary_key=True) - pointed = db.Column(db.Boolean, nullable = False, default = False) - operation_date = db.Column(db.Date, nullable = False) - label = db.Column(db.String(500), nullable = False) - value = db.Column(db.Numeric(15, 2), nullable = False) + pointed = db.Column(db.Boolean, nullable=False, default=False) + operation_date = db.Column(db.Date, nullable=False) + label = db.Column(db.String(500), nullable=False) + value = db.Column(db.Numeric(15, 2), nullable=False) account_id = db.Column(db.Integer, db.ForeignKey('account.id')) - scheduled_operation_id = db.Column(db.Integer, db.ForeignKey('scheduled_operation.id')) + scheduled_operation_id = db.Column(db.Integer, + db.ForeignKey('scheduled_operation.id')) - account = db.relationship(Account, backref = db.backref('operation', lazy="dynamic")) + account = db.relationship(Account, backref=db.backref('operation', + lazy="dynamic")) - category = db.Column(db.String(100), nullable = True) + category = db.Column(db.String(100), nullable=True) - canceled = db.Column(db.Boolean, nullable = False) + canceled = db.Column(db.Boolean, nullable=False) - def __init__(self, pointed, label, value, account_id, operation_date = None, category = None): + def __init__(self, pointed, label, value, account_id, operation_date=None, + category=None): self.pointed = pointed self.operation_date = operation_date self.label = label self.value = value self.account_id = account_id self.category = category - diff --git a/accountant/api/model/scheduled_operations.py b/accountant/api/model/scheduled_operations.py index 098ed62..c517821 100644 --- a/accountant/api/model/scheduled_operations.py +++ b/accountant/api/model/scheduled_operations.py @@ -1,24 +1,41 @@ -from . import db +""" + This file is part of Accountant. + + Accountant is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Foobar is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with Accountant. If not, see . +""" +from accountant import db + from .accounts import Account -from sqlalchemy import func, desc -from sqlalchemy.orm import column_property -from sqlalchemy.sql import func, select + class ScheduledOperation(db.Model): id = db.Column(db.Integer, primary_key=True) - start_date = db.Column(db.Date, nullable = False) - stop_date = db.Column(db.Date, nullable = False) - day = db.Column(db.Integer, nullable = False) - frequency = db.Column(db.Integer, nullable = False) - label = db.Column(db.String(500), nullable = False) - value = db.Column(db.Numeric(15, 2), nullable = False) + start_date = db.Column(db.Date, nullable=False) + stop_date = db.Column(db.Date, nullable=False) + day = db.Column(db.Integer, nullable=False) + frequency = db.Column(db.Integer, nullable=False) + label = db.Column(db.String(500), nullable=False) + value = db.Column(db.Numeric(15, 2), nullable=False) account_id = db.Column(db.Integer, db.ForeignKey('account.id')) - account = db.relationship(Account, backref = db.backref('scheduled_operation', lazy="dynamic")) + account = db.relationship(Account, backref=db.backref('scheduled_operation', + lazy="dynamic")) - category = db.Column(db.String(100), nullable = True) + category = db.Column(db.String(100), nullable=True) - def __init__(self, start_date, stop_date, day, frequency, label, value, account_id, category = None): + def __init__(self, start_date, stop_date, day, frequency, label, value, + account_id, category=None): self.start_date = start_date self.stop_date = stop_date self.day = day @@ -27,4 +44,3 @@ class ScheduledOperation(db.Model): self.value = value self.account_id = account_id self.category = category -