Refactoring.

This commit is contained in:
Alexis Lahouze 2015-06-06 14:04:48 +02:00
parent 6c24fb27be
commit 069fbe8f8e
12 changed files with 285 additions and 168 deletions

View File

@ -14,14 +14,11 @@
You should have received a copy of the GNU Affero General Public License You should have received a copy of the GNU Affero General Public License
along with Accountant. If not, see <http://www.gnu.org/licenses/>. along with Accountant. If not, see <http://www.gnu.org/licenses/>.
""" """
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 import Flask
from flask.ext.sqlalchemy import SQLAlchemy from flask.ext.sqlalchemy import SQLAlchemy
from .frontend import frontend
from sqlalchemy.orm import sessionmaker
from . import config from . import config
# The app # The app
@ -32,9 +29,25 @@ app.config['SQLALCHEMY_RECORD_QUERIES'] = config.debug
app.config['WTF_CSRF_ENABLED'] = False app.config['WTF_CSRF_ENABLED'] = False
app.config['SECRET_KEY'] = 'my_secret_key' app.config['SECRET_KEY'] = 'my_secret_key'
db.init_app(app) db = SQLAlchemy(app)
#login_manager.init_app(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(frontend, url_prefix='')
app.register_blueprint(api, url_prefix='/api') app.register_blueprint(api, url_prefix='/api')

View File

@ -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 <http://www.gnu.org/licenses/>.
"""
from flask import Blueprint from flask import Blueprint
api = Blueprint('api', __name__) api = Blueprint('api', __name__)
# Load all views.
from .controller import * from .controller import *

View File

@ -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 <http://www.gnu.org/licenses/>.
"""
import pkgutil import pkgutil
from flask.ext.httpauth import HTTPBasicAuth from flask.ext.httpauth import HTTPBasicAuth
@ -7,6 +23,3 @@ __all__ = []
for loader, module_name, is_pkg in pkgutil.walk_packages(__path__): for loader, module_name, is_pkg in pkgutil.walk_packages(__path__):
__all__.append(module_name) __all__.append(module_name)
from . import *

View File

@ -14,15 +14,21 @@
You should have received a copy of the GNU Affero General Public License You should have received a copy of the GNU Affero General Public License
along with Accountant. If not, see <http://www.gnu.org/licenses/>. along with Accountant. If not, see <http://www.gnu.org/licenses/>.
""" """
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 auth
from .. import api from .. import api
from ..model import db, session_scope
from ..model.accounts import Account from ..model.accounts import Account
from ..model.entries import Entry from ..model.entries import Entry
from ..model.operations import Operation 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"]) @api.route("/accounts", methods=["GET"])
@auth.login_required @auth.login_required
@ -36,8 +42,10 @@ def get_accounts():
Account.name.label("name"), Account.name.label("name"),
Account.authorized_overdraft.label("authorized_overdraft"), Account.authorized_overdraft.label("authorized_overdraft"),
func.sum(Entry.value).label("future"), 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.pointed, Entry.value,)],
func.sum(case([(Entry.operation_date < func.now(), Entry.value,)], else_=cast(0, db.Numeric(15, 2)))).label("current") 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) ).outerjoin(Entry).group_by(Account.id).order_by(Account.id)
return json.dumps([{ return json.dumps([{
@ -49,18 +57,23 @@ def get_accounts():
"future": str(i.future) "future": str(i.future)
} for i in query.all()]) } for i in query.all()])
@api.route("/accounts/<account_id>/<year>/<month>/") @api.route("/accounts/<account_id>/<year>/<month>/")
@auth.login_required @auth.login_required
def get_account_status(account_id, year, month): def get_account_status(account_id, year, month):
with session_scope() as session: with session_scope() as session:
query = session.query( 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)],
func.sum(case([(func.sign(Operation.value) == 1, Operation.value)], else_=0)).label("revenues"), else_=0)).label("expenses"),
func.sum(case([(func.sign(Operation.value) == 1, Operation.value)],
else_=0)).label("revenues"),
func.sum(Operation.value).label("balance") func.sum(Operation.value).label("balance")
).filter( ).filter(
Operation.account_id == account_id Operation.account_id == account_id
).filter( ).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) ).group_by(Operation.account_id)
if query.count() == 1: if query.count() == 1:
@ -79,13 +92,16 @@ def get_account_status(account_id, year, month):
"balance": str(balance) "balance": str(balance)
}) })
@api.route("/accounts/<account_id>/months") @api.route("/accounts/<account_id>/months")
@auth.login_required @auth.login_required
def get_months(account_id): def get_months(account_id):
with session_scope() as session: with session_scope() as session:
query = session.query( query = session.query(
distinct(func.lpad(cast(extract("year", Entry.operation_date), db.String), 4, '0')).label("year"), distinct(func.lpad(cast(extract("year", Entry.operation_date),
func.lpad(cast(extract("month", Entry.operation_date), db.String), 2, '0').label("month") 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") ).filter(Entry.account_id == account_id).order_by("year", "month")
return json.dumps([{ return json.dumps([{
@ -93,11 +109,13 @@ def get_months(account_id):
"month": i.month.rjust(2, '0') "month": i.month.rjust(2, '0')
} for i in query.all()]) } for i in query.all()])
@api.route("/accounts", methods=["PUT"]) @api.route("/accounts", methods=["PUT"])
@auth.login_required @auth.login_required
def add_account(): def add_account():
with session_scope() as session: 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) session.add(account)
@ -111,7 +129,10 @@ def update_account(account_id):
if account_form.validate(): if account_form.validate():
with session_scope() as session: 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.name = request.json['name']
account.authorized_overdraft = request.json['authorized_overdraft'] account.authorized_overdraft = request.json['authorized_overdraft']
@ -120,15 +141,22 @@ def update_account(account_id):
return json.dumps("Account #%s updated." % account_id) return json.dumps("Account #%s updated." % account_id)
else: 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/<account_id>", methods=["DELETE"]) @api.route("/accounts/<account_id>", methods=["DELETE"])
@auth.login_required @auth.login_required
def delete_account(account_id): def delete_account(account_id):
with session_scope() as session: 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) session.delete(account)
return json.dumps("Account #%s deleted." % account_id) return json.dumps("Account #%s deleted." % account_id)

View File

@ -14,16 +14,17 @@
You should have received a copy of the GNU Affero General Public License You should have received a copy of the GNU Affero General Public License
along with Accountant. If not, see <http://www.gnu.org/licenses/>. along with Accountant. If not, see <http://www.gnu.org/licenses/>.
""" """
from flask import json, request
from sqlalchemy import func, case, desc
from accountant import session_scope
from .. import api from .. import api
from ..model import db, session_scope
from ..model.entries import Entry from ..model.entries import Entry
from ..model.operations import Operation 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/<account_id>/<year>/<month>") @api.route("/entries/<account_id>/<year>/<month>")
def get_entries(account_id, year, month): def get_entries(account_id, year, month):
@ -33,14 +34,21 @@ def get_entries(account_id, year, month):
with session_scope() as session: with session_scope() as session:
base_query = session.query( base_query = session.query(
Operation, 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( ).filter(Operation.account_id == account_id).order_by(
desc(Operation.operation_date), desc(Operation.operation_date),
Operation.value, Operation.value,
Operation.label, Operation.label,
).subquery() ).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([{ return json.dumps([{
"id": i.id, "id": i.id,
@ -55,6 +63,7 @@ def get_entries(account_id, year, month):
"scheduled_operation_id": i.scheduled_operation_id "scheduled_operation_id": i.scheduled_operation_id
} for i in query.all()]) } for i in query.all()])
@api.route("/entries", methods=["PUT"]) @api.route("/entries", methods=["PUT"])
def add_entry(): def add_entry():
with session_scope() as session: with session_scope() as session:
@ -72,6 +81,7 @@ def add_entry():
return json.dumps("Entry added.") return json.dumps("Entry added.")
@api.route("/entries/<entry_id>", methods=["PUT"]) @api.route("/entries/<entry_id>", methods=["PUT"])
def update_entry(entry_id): def update_entry(entry_id):
with session_scope() as session: with session_scope() as session:
@ -90,6 +100,7 @@ def update_entry(entry_id):
return json.dumps("Entry #%s updated." % entry_id) return json.dumps("Entry #%s updated." % entry_id)
@api.route("/entries/<entry_id>", methods=["DELETE"]) @api.route("/entries/<entry_id>", methods=["DELETE"])
def delete_entry(entry_id): def delete_entry(entry_id):
with session_scope() as session: with session_scope() as session:
@ -98,4 +109,3 @@ def delete_entry(entry_id):
session.delete(entry) session.delete(entry)
return json.dumps("Entry #%s deleted." % entry_id) return json.dumps("Entry #%s deleted." % entry_id)

View File

@ -1,11 +1,28 @@
from .. import api """
from ..model import db, session_scope This file is part of Accountant.
from ..model.scheduled_operations import ScheduledOperation
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 <http://www.gnu.org/licenses/>.
"""
from flask import json, request from flask import json, request
from sqlalchemy import func, desc
from sqlalchemy.ext.hybrid import hybrid_property, hybrid_method from sqlalchemy import desc
from sqlalchemy.orm import sessionmaker, column_property
from sqlalchemy.sql import func, select from accountant import session_scope
from .. import api
from ..model.scheduled_operations import ScheduledOperation
@api.route("/scheduled_operations/<account_id>") @api.route("/scheduled_operations/<account_id>")
def get_scheduled_operations(account_id): def get_scheduled_operations(account_id):
@ -37,6 +54,7 @@ def get_scheduled_operations(account_id):
"account_id": i.account_id "account_id": i.account_id
} for i in query.all()]) } for i in query.all()])
@api.route("/scheduled_operations", methods=["PUT"]) @api.route("/scheduled_operations", methods=["PUT"])
def add_scheduled_operation(): def add_scheduled_operation():
with session_scope() as session: with session_scope() as session:
@ -55,10 +73,14 @@ def add_scheduled_operation():
return json.dumps("Scheduled operation added.") return json.dumps("Scheduled operation added.")
@api.route("/scheduled_operations/<scheduled_operation_id>", methods=["PUT"]) @api.route("/scheduled_operations/<scheduled_operation_id>", methods=["PUT"])
def update_scheduled_operation(scheduled_operation_id): def update_scheduled_operation(scheduled_operation_id):
with session_scope() as session: 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.id = scheduled_operation_id
scheduledOperation.start_date = request.json['start_date'], scheduledOperation.start_date = request.json['start_date'],
@ -72,14 +94,18 @@ def update_scheduled_operation(scheduled_operation_id):
session.merge(scheduledOperation) 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/<scheduled_operation_id>", methods=["DELETE"]) @api.route("/scheduled_operations/<scheduled_operation_id>", methods=["DELETE"])
def delete_scheduled_operation(scheduled_operation_id): def delete_scheduled_operation(scheduled_operation_id):
with session_scope() as session: 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) session.delete(scheduledOperation)
return json.dumps("Scheduled operation #%s deleted." % scheduled_operation_id) return json.dumps(
"Scheduled operation #%s deleted." % scheduled_operation_id)

View File

@ -14,10 +14,11 @@
You should have received a copy of the GNU Affero General Public License You should have received a copy of the GNU Affero General Public License
along with Accountant. If not, see <http://www.gnu.org/licenses/>. along with Accountant. If not, see <http://www.gnu.org/licenses/>.
""" """
#from accountant import session_scope
from . import auth from . import auth
from .. import api #from .. import api
from ..model import db, session_scope
@auth.verify_password @auth.verify_password
def verify_password(username, password): def verify_password(username, password):

View File

@ -1,25 +1,19 @@
from contextlib import contextmanager """
from flask.ext.sqlalchemy import SQLAlchemy This file is part of Accountant.
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import scoped_session, sessionmaker
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 Accountant is distributed in the hope that it will be useful,
def session_scope(): but WITHOUT ANY WARRANTY; without even the implied warranty of
#session = scoped_session(sessionmaker(autocommit = False, autoflush = False, bind = engine)) MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
session = db.session GNU Affero General Public License for more details.
#Base.query = session.query_property()
try:
yield session
session.commit()
except:
session.rollback()
raise
finally:
session.close()
You should have received a copy of the GNU Affero General Public License
along with Accountant. If not, see <http://www.gnu.org/licenses/>.
"""
import pkgutil import pkgutil
__all__ = [] __all__ = []
@ -27,5 +21,4 @@ __all__ = []
for loader, module_name, is_pkg in pkgutil.walk_packages(__path__): for loader, module_name, is_pkg in pkgutil.walk_packages(__path__):
__all__.append(module_name) __all__.append(module_name)
from . import * #from . import *

View File

@ -14,7 +14,8 @@
You should have received a copy of the GNU Affero General Public License You should have received a copy of the GNU Affero General Public License
along with Accountant. If not, see <http://www.gnu.org/licenses/>. along with Accountant. If not, see <http://www.gnu.org/licenses/>.
""" """
from . import db from accountant import db
class Account(db.Model): class Account(db.Model):
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
@ -24,4 +25,3 @@ class Account(db.Model):
def __init__(self, name, authorized_overdraft): def __init__(self, name, authorized_overdraft):
self.name = name self.name = name
self.authorized_overdraft = authorized_overdraft self.authorized_overdraft = authorized_overdraft

View File

@ -14,12 +14,11 @@
You should have received a copy of the GNU Affero General Public License You should have received a copy of the GNU Affero General Public License
along with Accountant. If not, see <http://www.gnu.org/licenses/>. along with Accountant. If not, see <http://www.gnu.org/licenses/>.
""" """
from . import db from accountant import db
from .accounts import Account from .accounts import Account
from .scheduled_operations import ScheduledOperation 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): class Entry(db.Model):
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
@ -28,14 +27,19 @@ class Entry(db.Model):
label = db.Column(db.String(500), nullable=False) label = db.Column(db.String(500), nullable=False)
value = db.Column(db.Numeric(15, 2), nullable=False) value = db.Column(db.Numeric(15, 2), nullable=False)
account_id = db.Column(db.Integer, db.ForeignKey('account.id')) 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")) account = db.relationship(Account, backref=db.backref('entry',
scheduled_operation = db.relationship(ScheduledOperation, backref = db.backref('entry', lazy="dynamic")) 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.pointed = pointed
self.operation_date = operation_date self.operation_date = operation_date
self.label = label self.label = label
@ -43,4 +47,3 @@ class Entry(db.Model):
self.account_id = account_id self.account_id = account_id
self.category = category self.category = category
self.scheduled_operation_id = scheduled_operation_id self.scheduled_operation_id = scheduled_operation_id

View File

@ -14,14 +14,10 @@
You should have received a copy of the GNU Affero General Public License You should have received a copy of the GNU Affero General Public License
along with Accountant. If not, see <http://www.gnu.org/licenses/>. along with Accountant. If not, see <http://www.gnu.org/licenses/>.
""" """
from . import db from accountant import db
from .accounts import Account 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): class Operation(db.Model):
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
@ -30,19 +26,21 @@ class Operation(db.Model):
label = db.Column(db.String(500), nullable=False) label = db.Column(db.String(500), nullable=False)
value = db.Column(db.Numeric(15, 2), nullable=False) value = db.Column(db.Numeric(15, 2), nullable=False)
account_id = db.Column(db.Integer, db.ForeignKey('account.id')) 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.pointed = pointed
self.operation_date = operation_date self.operation_date = operation_date
self.label = label self.label = label
self.value = value self.value = value
self.account_id = account_id self.account_id = account_id
self.category = category self.category = category

View File

@ -1,8 +1,23 @@
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 <http://www.gnu.org/licenses/>.
"""
from accountant import db
from .accounts import Account 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): class ScheduledOperation(db.Model):
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
@ -14,11 +29,13 @@ class ScheduledOperation(db.Model):
value = db.Column(db.Numeric(15, 2), nullable=False) value = db.Column(db.Numeric(15, 2), nullable=False)
account_id = db.Column(db.Integer, db.ForeignKey('account.id')) 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.start_date = start_date
self.stop_date = stop_date self.stop_date = stop_date
self.day = day self.day = day
@ -27,4 +44,3 @@ class ScheduledOperation(db.Model):
self.value = value self.value = value
self.account_id = account_id self.account_id = account_id
self.category = category self.category = category