finance-watcher / api / endpoints / transaction.py
transaction.py
Raw
from pathlib import Path
import sys

sys.path.append(str(Path(__file__).parent.parent.parent))

from flask import request
from flask_restx import Namespace, Resource, fields, reqparse
from database.finance_database import FinanceDatabase
from database.database_classes import Transaction
from helpers.helper_functions import (
    json_success_response, 
    json_error_response, 
    get_string_from_date,
    get_date_from_string
)

namespace = Namespace(
    'transaction', 
    description='API endpoints related to Transaction resource'
)

transaction_payload = namespace.model("Payload", {
    "user_id": fields.Integer(required=True, description='id of the user'),
    "transactions": fields.List(fields.Nested(namespace.model("data", {
        "amount":fields.Integer(required=True, description='amount of the transaction'),
        "business_id":fields.Integer(required=True, description='id of business'),
        "is_expense":fields.Boolean(required=True, description='if its an expense'),
        "created_date":fields.DateTime(required=True, 
            description='date of transaction', dt_format='iso8601'
        )
        })), required=True, description="list of transactions to insert")
})


get_transaction_parser = reqparse.RequestParser()
get_transaction_parser.add_argument('user_id', required=True, type=int, help='id of the user')
get_transaction_parser.add_argument('page', required=False, type=int, help='page number')
get_transaction_parser.add_argument('business_type_id', required=False, type=int, help='id of business type')
get_transaction_parser.add_argument('start_date', required=False, type=str, help='start date of target period')
get_transaction_parser.add_argument('end_date', required=False, type=str, help='end date of target period')

@namespace.route('')
class TransactionAPI(Resource):
    """
    API for the Transaction resource.
    """
    @namespace.expect(get_transaction_parser)
    def get(self):
        """
        Gets a list of transactions.

        :param user_id: id of the user
        :param page: page number (default: 1)
        :param business_type_id: id of the business type
        :param start_date: start date interval
        :param end_date: end date interval
        """
        args = get_transaction_parser.parse_args()

        user_id = args['user_id']
        page = args.get('page')
        business_type_id = args.get('business_type_id')
        start_date = args.get('start_date')
        end_date = args.get('end_date')

        if start_date:
            start_date = get_date_from_string(start_date)

        if end_date:
            end_date = get_date_from_string(end_date)

        if (start_date is None) ^ (end_date is None):
            return json_error_response(
                'ERROR: One of the dates provided is invalid'
            )
        
        if (start_date and end_date) and (start_date > end_date):
            return json_error_response(
                'ERROR: End date is earlier than start date.'
            )

        finance_db = FinanceDatabase()

        transactions = finance_db.get_transactions(
            user_id=user_id,
            page=page if page else 1,
            business_type_id=business_type_id,
            start_date=start_date,
            end_date=end_date
        )


        if transactions is None:
            return json_error_response("ERROR: Failed to get transactions.")

        return json_success_response([
            {
                'amount': transaction.amount,
                'business_id': transaction.business_id,
                'is_expense': 'True' if transaction.is_expense else 'False',
                'created_date': get_string_from_date(transaction.created_date),
            }
            for transaction in transactions
        ])

    @namespace.expect(transaction_payload)
    def post(self):
        """
        Inserts multiple transactions into the database.
        
        Expected payload:
        {
            user_id: int,
            transactions: [
                amount: int,
                business_id: int,
                is_expense: bool,
                created_date: datetime
            ]
        }
        """
        payload = request.json

        finance_db = FinanceDatabase()

        transactions_to_insert = []
        for values in payload['transactions']:
            transactions_to_insert.append(
                Transaction(
                    id=0,
                    dashboard_user_id=payload['user_id'],
                    amount=values['amount'],
                    business_id=values['business_id'],
                    is_expense=True,
                    created_date=values['created_date'],
                )
            )
        is_insert_successful = finance_db.insert_transactions(
            transactions_to_insert
        )

        if is_insert_successful is False:
            return json_error_response(
                'ERROR: Failed to insert transactions.'
            )
        return json_success_response()