diff --git a/accountant/views/accounts.py b/accountant/views/accounts.py index a855e4f..efe1225 100644 --- a/accountant/views/accounts.py +++ b/accountant/views/accounts.py @@ -14,6 +14,8 @@ You should have received a copy of the GNU Affero General Public License along with Accountant. If not, see . """ +import dateutil.parser + from flask_restplus import Resource, fields, marshal_with_field from accountant import db @@ -25,14 +27,113 @@ from ..models.operations import Operation from ..fields import Object -from .models import (account_model, solds_model, balance_model, - category_model, ohlc_model) -from .parsers import range_parser from .users import requires_auth ns = api.namespace('account', description='Account management') +# Account model. +account_model = ns.model('Account', { + 'id': fields.Integer( + default=None, + readonly=True, + description='Id of the account'), + 'name': fields.String( + required=True, + description='Name of the account'), + 'authorized_overdraft': fields.Float( + required=True, + description='Authorized overdraft') +}) + +# Account status model. +solds_model = ns.model('Solds', { + 'current': fields.Float( + readonly=True, + description='Current sold of the account'), + 'pointed': fields.Float( + readonly=True, + description='Pointed sold of the account'), + 'future': fields.Float( + readonly=True, + description='Future sold of the account') +}) + +# Account balance model. +balance_model = ns.model('Balance', { + 'expenses': fields.Float( + readonly=True, + description='Total amount of expenses'), + 'revenues': fields.Float( + readonly=True, + description='Total amount of revenues'), + 'balance': fields.Float( + readonly=True, + description='Balance'), +}) + +# Category with expenses and revenues. +category_model = ns.model('Category', { + 'category': fields.String( + readonly=True, + description='Category name'), + 'expenses': fields.Float( + readonly=True, + description='Total amount of expenses for the category'), + 'revenues': fields.Float( + readonly=True, + description='Total amount of revenues for the category') +}) + +# OHLC model. +ohlc_model = ns.model('OHLC', { + 'operation_date': fields.DateTime( + dt_format='iso8601', + readonly=True, + required=True, + description='Date of the OHLC object' + ), + 'open': fields.Float( + readonly=True, + required=True, + description='Open value' + ), + 'high': fields.Float( + readonly=True, + required=True, + description='High value' + ), + 'low': fields.Float( + readonly=True, + required=True, + description='Low value' + ), + 'close': fields.Float( + readonly=True, + required=True, + description='Close value' + ) +}) + +# Parser for a date range. +range_parser = ns.parser() +range_parser.add_argument( + 'begin', + type=lambda a: dateutil.parser.parse(a) if a else None, + required=False, + default=None, + location='args', + help='Begin date of the time period' +) +range_parser.add_argument( + 'end', + type=lambda a: dateutil.parser.parse(a) if a else None, + required=False, + default=None, + location='args', + help='End date of the time period' +) + @ns.route('/') @api.doc( diff --git a/accountant/views/models.py b/accountant/views/models.py deleted file mode 100644 index 7ceed60..0000000 --- a/accountant/views/models.py +++ /dev/null @@ -1,230 +0,0 @@ -""" - 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_restplus import fields - -from .. import api - -# Account model. -account_model = api.model('Account', { - 'id': fields.Integer( - default=None, - readonly=True, - description='Id of the account'), - 'name': fields.String( - required=True, - description='Name of the account'), - 'authorized_overdraft': fields.Float( - required=True, - description='Authorized overdraft') -}) - -# Account status model. -solds_model = api.model('Solds', { - 'current': fields.Float( - readonly=True, - description='Current sold of the account'), - 'pointed': fields.Float( - readonly=True, - description='Pointed sold of the account'), - 'future': fields.Float( - readonly=True, - description='Future sold of the account') -}) - -# Account balance model. -balance_model = api.model('Balance', { - 'expenses': fields.Float( - readonly=True, - description='Total amount of expenses'), - 'revenues': fields.Float( - readonly=True, - description='Total amount of revenues'), - 'balance': fields.Float( - readonly=True, - description='Balance'), -}) - -# Category with expenses and revenues. -category_model = api.model('Category', { - 'category': fields.String( - readonly=True, - description='Category name'), - 'expenses': fields.Float( - readonly=True, - description='Total amount of expenses for the category'), - 'revenues': fields.Float( - readonly=True, - description='Total amount of revenues for the category') -}) - -# OHLC model. -ohlc_model = api.model('OHLC', { - 'operation_date': fields.DateTime( - dt_format='iso8601', - readonly=True, - required=True, - description='Date of the OHLC object' - ), - 'open': fields.Float( - readonly=True, - required=True, - description='Open value' - ), - 'high': fields.Float( - readonly=True, - required=True, - description='High value' - ), - 'low': fields.Float( - readonly=True, - required=True, - description='Low value' - ), - 'close': fields.Float( - readonly=True, - required=True, - description='Close value' - ) -}) - -# Operation with sold model. -operation_model = api.model('Operation', { - 'id': fields.Integer( - default=None, - readonly=True, - description='Id of the operation'), - 'operation_date': fields.DateTime( - dt_format='iso8601', - required=True, - description='Date of the operation'), - 'label': fields.String( - required=True, - description='Label of the operation'), - 'value': fields.Float( - required=True, - description='Value of the operation'), - 'pointed': fields.Boolean( - required=True, - description='Pointed status of the operation'), - 'category': fields.String( - required=False, - default=None, - description='Category of the operation'), - 'account_id': fields.Integer( - required=True, - readonly=True, - description='Account id of the operation'), - 'scheduled_operation_id': fields.Integer( - default=None, - readonly=True, - description='Scheduled operation ID of the operation'), - 'confirmed': fields.Boolean( - description='Confirmed status of the operation'), - 'canceled': fields.Boolean( - description='Canceled status of the operation (for a scheduled one)') -}) - -operation_with_sold_model = api.clone( - 'OperationWithSold', operation_model, { - 'sold': fields.Float( - readonly=True, - description='Cumulated sold' - ), - } -) - -# Scheduled operation model. -scheduled_operation_model = api.model('ScheduledOperation', { - 'id': fields.Integer( - description='Id of the scheduled operation', - readonly=True, - default=None), - 'start_date': fields.DateTime( - dt_format='iso8601', - required=True, - description='Start date of the scheduled operation'), - 'stop_date': fields.DateTime( - dt_format='iso8601', - required=True, - description='End date of the scheduled operation'), - 'day': fields.Integer( - required=True, - description='Day of month for the scheduled operation'), - 'frequency': fields.Integer( - required=True, - description='Frequency of the scheduling in months'), - 'label': fields.String( - required=True, - description='Label of the generated operations'), - 'value': fields.Float( - required=True, - description='Value of the generated operations'), - 'category': fields.String( - required=False, - description='Category of the generated operations'), - 'account_id': fields.Integer( - default=None, - readonly=True, - required=True, - description='Account id of the scheduled operation'), -}) - -# Token with expiration time and type. -token_model = api.model('Token', { - 'token': fields.String( - required=True, - readonly=True, - description='Token value'), - 'expiration': fields.DateTime( - dt_format='iso8601', - required=True, - readonly=True, - description='Expiration time of the token'), - 'token_type': fields.String( - required=True, - readonly=True, - description='Token type') -}) - -# User model. -user_model = api.model('User', { - 'id': fields.Integer( - default=None, - required=True, - readonly=True, - description='Id of the user'), - 'email': fields.String( - required=True, - readonly=True, - decription='Email address of the user'), - 'active': fields.Boolean( - required=True, - readonly=True, - description='Active state of the user') -}) - -# Login model. -login_model = api.model('Login', { - 'email': fields.String( - required=True, - description='Email to use for login' - ), - 'password': fields.String( - required=True, - description='Plain text password to use for login' - ) -}) diff --git a/accountant/views/operations.py b/accountant/views/operations.py index 9a82aff..87c95c3 100644 --- a/accountant/views/operations.py +++ b/accountant/views/operations.py @@ -14,6 +14,8 @@ You should have received a copy of the GNU Affero General Public License along with Accountant. If not, see . """ +import dateutil.parser + from flask_restplus import Resource, fields, marshal_with_field from accountant import db @@ -23,8 +25,6 @@ from .. import api from ..models.accounts import Account from ..models.operations import Operation -from .models import operation_model, operation_with_sold_model -from .parsers import account_range_parser from .users import requires_auth from ..fields import Object @@ -32,6 +32,78 @@ from ..fields import Object ns = api.namespace('operation', description='Operation management') +# Operation with sold model. +operation_model = ns.model('Operation', { + 'id': fields.Integer( + default=None, + readonly=True, + description='Id of the operation'), + 'operation_date': fields.DateTime( + dt_format='iso8601', + required=True, + description='Date of the operation'), + 'label': fields.String( + required=True, + description='Label of the operation'), + 'value': fields.Float( + required=True, + description='Value of the operation'), + 'pointed': fields.Boolean( + required=True, + description='Pointed status of the operation'), + 'category': fields.String( + required=False, + default=None, + description='Category of the operation'), + 'account_id': fields.Integer( + required=True, + readonly=True, + description='Account id of the operation'), + 'scheduled_operation_id': fields.Integer( + default=None, + readonly=True, + description='Scheduled operation ID of the operation'), + 'confirmed': fields.Boolean( + description='Confirmed status of the operation'), + 'canceled': fields.Boolean( + description='Canceled status of the operation (for a scheduled one)') +}) + +operation_with_sold_model = ns.clone( + 'OperationWithSold', operation_model, { + 'sold': fields.Float( + readonly=True, + description='Cumulated sold' + ), + } +) + +# Parser for a date range and an account id. +account_range_parser = ns.parser() +account_range_parser.add_argument( + 'begin', + type=lambda a: dateutil.parser.parse(a) if a else None, + required=False, + default=None, + location='args', + help='Begin date of the time period' +) +account_range_parser.add_argument( + 'end', + type=lambda a: dateutil.parser.parse(a) if a else None, + required=False, + default=None, + location='args', + help='End date of the time period' +) +account_range_parser.add_argument( + 'account_id', + type=int, + required=True, + location='args', + help='Id of the account' +) + @ns.route('/') @api.doc( diff --git a/accountant/views/parsers.py b/accountant/views/parsers.py deleted file mode 100644 index 1c6e929..0000000 --- a/accountant/views/parsers.py +++ /dev/null @@ -1,60 +0,0 @@ -""" - 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 dateutil.parser - -from flask_restplus import reqparse - -from .. import api - -# Parser for a date range. -range_parser = api.parser() -range_parser.add_argument( - 'begin', - type=lambda a: dateutil.parser.parse(a) if a else None, - required=False, - default=None, - location='args', - help='Begin date of the time period' -) -range_parser.add_argument( - 'end', - type=lambda a: dateutil.parser.parse(a) if a else None, - required=False, - default=None, - location='args', - help='End date of the time period' -) - -# Parser for an account id. -account_id_parser = reqparse.RequestParser() -account_id_parser.add_argument( - 'account_id', - type=int, - required=True, - location='args', - help='Id of the account' -) - -# Parser for a date range and an account id. -account_range_parser = range_parser.copy() -account_range_parser.add_argument( - 'account_id', - type=int, - required=True, - location='args', - help='Id of the account' -) diff --git a/accountant/views/scheduled_operations.py b/accountant/views/scheduled_operations.py index 217fb64..a6fd85d 100644 --- a/accountant/views/scheduled_operations.py +++ b/accountant/views/scheduled_operations.py @@ -26,8 +26,6 @@ from ..models.accounts import Account from ..models.operations import Operation from ..models.scheduled_operations import ScheduledOperation -from .models import scheduled_operation_model -from .parsers import account_id_parser from .users import requires_auth from ..fields import Object @@ -38,6 +36,52 @@ ns = api.namespace( description='Scheduled operation management' ) +# Scheduled operation model. +scheduled_operation_model = ns.model('ScheduledOperation', { + 'id': fields.Integer( + description='Id of the scheduled operation', + readonly=True, + default=None), + 'start_date': fields.DateTime( + dt_format='iso8601', + required=True, + description='Start date of the scheduled operation'), + 'stop_date': fields.DateTime( + dt_format='iso8601', + required=True, + description='End date of the scheduled operation'), + 'day': fields.Integer( + required=True, + description='Day of month for the scheduled operation'), + 'frequency': fields.Integer( + required=True, + description='Frequency of the scheduling in months'), + 'label': fields.String( + required=True, + description='Label of the generated operations'), + 'value': fields.Float( + required=True, + description='Value of the generated operations'), + 'category': fields.String( + required=False, + description='Category of the generated operations'), + 'account_id': fields.Integer( + default=None, + readonly=True, + required=True, + description='Account id of the scheduled operation'), +}) + +# Parser for an account id. +account_id_parser = ns.parser() +account_id_parser.add_argument( + 'account_id', + type=int, + required=True, + location='args', + help='Id of the account' +) + @ns.route('/') @api.doc( diff --git a/accountant/views/users.py b/accountant/views/users.py index da4caef..adb140b 100644 --- a/accountant/views/users.py +++ b/accountant/views/users.py @@ -22,7 +22,7 @@ import arrow from functools import wraps from flask import request, g -from flask_restplus import Resource, marshal_with_field +from flask_restplus import Resource, fields, marshal_with_field from .. import app, api @@ -85,6 +85,52 @@ def requires_auth(f): ns = api.namespace('user', description='User management') +# Token with expiration time and type. +token_model = ns.model('Token', { + 'token': fields.String( + required=True, + readonly=True, + description='Token value'), + 'expiration': fields.DateTime( + dt_format='iso8601', + required=True, + readonly=True, + description='Expiration time of the token'), + 'token_type': fields.String( + required=True, + readonly=True, + description='Token type') +}) + +# User model. +user_model = ns.model('User', { + 'id': fields.Integer( + default=None, + required=True, + readonly=True, + description='Id of the user'), + 'email': fields.String( + required=True, + readonly=True, + decription='Email address of the user'), + 'active': fields.Boolean( + required=True, + readonly=True, + description='Active state of the user') +}) + +# Login model. +login_model = ns.model('Login', { + 'email': fields.String( + required=True, + description='Email to use for login' + ), + 'password': fields.String( + required=True, + description='Plain text password to use for login' + ) +}) + @ns.route('/login') class LoginResource(Resource):