Began project refactoring.

This commit is contained in:
Alexis Lahouze
2013-12-03 20:36:41 +01:00
parent d7fd74fb17
commit ab4df80963
13 changed files with 0 additions and 0 deletions

0
api/__init__.py Normal file
View File

View File

145
api/controller/accounts.py Normal file
View File

@ -0,0 +1,145 @@
"""
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 app import app
from app import db
from api.model.accounts import Account
from api.model.entries import Entry
from api.model.operations import Operation
from flask import json, request
from sqlalchemy import func, case, cast, extract, distinct
@app.route("/api/accounts", methods=["GET"])
def get_accounts():
"""
Returns accounts with their solds.
"""
session = db.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")
).outerjoin(Entry).group_by(Account.id).order_by(Account.id)
return json.dumps([{
"id": i.id,
"name": i.name,
"authorized_overdraft": i.authorized_overdraft,
"current": str(i.current),
"pointed": str(i.pointed),
"future": str(i.future)
} for i in query.all()])
@app.route("/api/accounts/<account_id>/<year>/<month>/")
def get_account_status(account_id, year, month):
session = db.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(Operation.value).label("balance")
).filter(
Operation.account_id == account_id
).filter(
func.date_trunc('month', Operation.operation_date) == "%s-%s-01" % (year, month)
).group_by(Operation.account_id)
if query.count() == 1:
result = query.one()
revenues = result.revenues
expenses = result.expenses
balance = result.balance
else:
revenues = 0.0
expenses = 0.0
balance = 0.0
return json.dumps({
"expenses": str(expenses),
"revenues": str(revenues),
"balance": str(balance)
})
@app.route("/api/accounts/<account_id>/months")
def get_months(account_id):
session = db.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")
).filter(Entry.account_id == account_id).order_by("year", "month")
return json.dumps([{
"year": i.year,
"month": i.month.rjust(2, '0')
} for i in query.all()])
@app.route("/api/accounts", methods=["PUT"])
def add_account():
session = db.session
try:
account = Account(request.json['name'], request.json['authorized_overdraft'])
session.add(account)
session.commit()
return json.dumps("Account added.")
except:
session.rollback()
raise
@app.route("/api/accounts/<account_id>", methods=["PUT"])
def update_account(account_id):
session = db.session
try:
account = session.query(Account).filter(Account.id == account_id).first()
account.name = request.json['name']
account.authorized_overdraft = request.json['authorized_overdraft']
session.merge(account)
session.commit()
return json.dumps("Account #%s updated." % account_id)
except:
session.rollback()
raise
@app.route("/api/accounts/<account_id>", methods=["DELETE"])
def delete_account(account_id):
session = db.session
try:
account = session.query(Account).filter(Account.id == account_id).first()
session.delete(account)
session.commit()
return json.dumps("Account #%s deleted." % account_id)
except:
session.rollback()
raise

125
api/controller/entries.py Normal file
View File

@ -0,0 +1,125 @@
"""
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 app import app
from app import db
from api.model.entries import Entry
from api.model.operations import Operation
from api.model.scheduled_operations import ScheduledOperation
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
#from sqlalchemy import *
from flask import json, request
@app.route("/api/entries/<account_id>/<year>/<month>")
def get_entries(account_id, year, month):
"""
Return entries for an account, year, and month.
"""
session = db.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")
).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))
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
} for i in query.all()])
@app.route("/api/entries", methods=["PUT"])
def add_entry():
session = db.session
try:
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']
)
session.add(entry)
session.commit()
return json.dumps("Entry added.")
except:
session.rollback()
raise
@app.route("/api/entries/<entry_id>", methods=["PUT"])
def update_entry(entry_id):
session = db.session
try:
entry = session.query(Entry).filter(Entry.id == entry_id).first()
entry.id = entry_id
entry.operation_date = request.json['operation_date']
entry.pointed = request.json['pointed']
entry.label = request.json['label']
entry.value = request.json['value']
entry.category = request.json['category']
entry.account_id = request.json['account_id']
entry.scheduled_operation_id = request.json['scheduled_operation_id']
session.merge(entry)
session.commit()
return json.dumps("Entry #%s updated." % entry_id)
except:
session.rollback()
raise
@app.route("/api/entries/<entry_id>", methods=["DELETE"])
def delete_entry(entry_id):
session = db.session
try:
entry = session.query(Entry).filter(Entry.id == entry_id).first()
session.delete(entry)
session.commit()
return json.dumps("Entry #%s deleted." % entry_id)
except:
session.rollback()
raise

View File

@ -0,0 +1,107 @@
from app import app
from app import db
from api.model.scheduled_operations import ScheduledOperation
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 flask import json, request
@app.route("/api/scheduled_operations/<account_id>")
def get_scheduled_operations(account_id):
"""
Return entries for an account, year, and month.
"""
session = db.session
query = session.query(
ScheduledOperation
).select_from(
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
} for i in query.all()])
@app.route("/api/scheduled_operations", methods=["PUT"])
def add_scheduled_operation():
session = db.session
try:
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']
)
session.add(scheduledOperation)
session.commit()
return json.dumps("Scheduled operation added.")
except:
session.rollback()
raise
@app.route("/api/scheduled_operations/<scheduled_operation_id>", methods=["PUT"])
def update_scheduled_operation(scheduled_operation_id):
session = db.session
try:
scheduledOperation = session.query(ScheduledOperation).filter(ScheduledOperation.id == scheduled_operation_id).first()
scheduledOperation.id = scheduled_operation_id
scheduledOperation.start_date = request.json['start_date'],
scheduledOperation.stop_date = request.json['stop_date'],
scheduledOperation.day = request.json['day'],
scheduledOperation.frequency = request.json['frequency'],
scheduledOperation.label = request.json['label']
scheduledOperation.value = request.json['value']
scheduledOperation.category = request.json['category']
scheduledOperation.account_id = request.json['account_id']
session.merge(scheduledOperation)
session.commit()
return json.dumps("Scheduled operation #%s updated." % scheduled_operation_id)
except:
session.rollback()
raise
@app.route("/api/scheduled_operations/<scheduled_operation_id>", methods=["DELETE"])
def delete_scheduled_operation(scheduled_operation_id):
session = db.session
try:
scheduledOperation = session.query(ScheduledOperation).filter(ScheduledOperation.id == scheduled_operation_id).first()
session.delete(scheduledOperation)
session.commit()
return json.dumps("Scheduled operation #%s deleted." % scheduled_operation_id)
except:
session.rollback()
raise

0
api/model/__init__.py Normal file
View File

28
api/model/accounts.py Normal file
View File

@ -0,0 +1,28 @@
"""
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 app import app
from app 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)
def __init__(self, name, authorized_overdraft):
self.name = name
self.authorized_overdraft = authorized_overdraft

49
api/model/entries.py Normal file
View File

@ -0,0 +1,49 @@
"""
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 app import app
from app import db
from api.model.accounts import Account
from api.model.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)
account_id = db.Column(db.Integer, db.ForeignKey('account.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"))
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):
self.pointed = pointed
self.operation_date = operation_date
self.label = label
self.value = value
self.account_id = account_id
self.category = category
self.scheduled_operation_id = scheduled_operation_id

49
api/model/operations.py Normal file
View File

@ -0,0 +1,49 @@
"""
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 app import app
from app import db
from api.model.accounts import Account
from api.model.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)
account_id = db.Column(db.Integer, db.ForeignKey('account.id'))
scheduled_operation_id = db.Column(db.Integer, db.ForeignKey('scheduled_operation.id'))
account = db.relationship(Account, backref = db.backref('operation', lazy="Dynamic"))
category = db.Column(db.String(100), nullable = True)
canceled = db.Column(db.Boolean, nullable = False)
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

View File

@ -0,0 +1,33 @@
from app import app
from app import db
from api.model.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)
account_id = db.Column(db.Integer, db.ForeignKey('account.id'))
account = db.relationship(Account, backref = db.backref('scheduled_operation', lazy="Dynamic"))
category = db.Column(db.String(100), nullable = True)
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
self.frequency = frequency
self.label = label
self.value = value
self.account_id = account_id
self.category = category