def test_add_item():
    repo = Repository()

    repo.add_item(1)
    assert repo.get_items() == [1]
    repo.undo()
    assert repo.get_items() == []
def test_replace_item():
    repo = Repository()

    repo.add_item(0)
    repo.add_item(1)
    repo.add_item(1)
    repo.add_item(1)

    repo.replace_item(lambda item: item == 1, 0)
    assert repo.get_items() == [0, 0, 1, 1]
    repo.undo()
    assert repo.get_items() == [0, 1, 1, 1]
def test_get_items():
    repo = Repository()

    repo.add_item(0)
    repo.add_item(1)
    assert repo.get_item(lambda item: item == 1) == 1

    repo.add_item(1)
    assert repo.get_items() == [0, 1, 1]
    assert repo.get_items(lambda item: item == 1) == [1, 1]
    assert not repo.get_items(lambda item: item > 1)

    repo.add_item(2)
    assert repo.get_items(lambda item: item > 1) == [2]
Exemple #4
0
def get_balance(repo: Repository, day: int):
    """
    Returns the account balance on a day.
    :param repo: The transactions repository.
    :param day: A day.
    :return balance: The balance on the given day.
    """
    in_transactions = repo.get_items(
        lambda t: t.get_type() == 'in' and t.get_day() <= day)
    out_transactions = repo.get_items(
        lambda t: t.get_type() == 'out' and t.get_day() <= day)

    balance = 0

    for in_transaction in in_transactions:
        balance += in_transaction.get_money_amount()

    for out_transaction in out_transactions:
        balance -= out_transaction.get_money_amount()

    return balance
Exemple #5
0
def get_sum(repo: Repository, type: str):
    """
    Returns the total amount from a transaction type.
    :param repo: The transactions repository.
    :param type: The transaction type.
    :return type_amount: The total amount from a transaction type.
    """
    transactions = repo.get_items(lambda t: t.get_type() == type)

    type_amount = 0

    for transaction in transactions:
        type_amount += transaction.get_money_amount()

    return type_amount
Exemple #6
0
def get_max(repo: Repository, type: str, day: int):
    """
    Returns the transaction with the maximum amount from a day, of a type.
    :param repo: The transactions repository.
    :param type: The transaction type.
    :param day: The transaction day.
    :return max_transaction: The transaction with the maximum amount from a day, of a type.
    """
    transactions = repo.get_items(
        lambda t: t.get_day() == day and t.get_type() == type)

    if len(transactions) == 0:
        return None

    max_transaction: Transaction = transactions[0]

    for transaction in transactions:
        if transaction.get_money_amount() > max_transaction.get_money_amount():
            max_transaction = transaction

    return max_transaction
Exemple #7
0
class TransactionCommands(clisys.CLISys):
    def __init__(self):
        super().__init__()
        self.__repo = Repository()
        self.init_repo()

    @clisys.command(name='help')
    def help(self, args):
        """
        Displays help for all commands or a single command.
            help
            help <command>
        """
        count = len(args)
        commands = self.get_commands()

        if count == 0:
            for cmd_name, cmd in commands.items():
                print(f'{cmd_name}: {cmd.__doc__}')

        elif count == 1:
            cmd_name = args[0]

            if not (cmd_name in commands.keys()):
                raise clisys.InvalidArgument(args[0])

            cmd = commands[cmd_name]

            print(f'{cmd_name}: {cmd.__doc__}')

    @clisys.command(name='test')
    def test(self, args):
        """
        Test command.
        """
        print('TEST')

    @clisys.command(name='exit')
    def exit_command(self, args):
        """
        Exits the program.
        """
        exit(0)

    @clisys.command(name='add')
    def add_transaction(self, args):
        """
        Add a transaction to the list.
            add <value> <type> <description>
        """
        try:
            value = int(args[0])

        except ValueError:
            raise clisys.InvalidArgument(args[0])

        type = args[1]
        description = args[2]

        transaction = Transaction(int(datetime.today().strftime('%d')), value,
                                  type, description)
        self.__repo.add_item(transaction)

    @clisys.command(name='insert')
    def insert_transaction(self, args):
        """
        Insert a transaction in the list.
            insert <day> <value> <type> <description>
        """
        try:
            day = int(args[0])

        except ValueError:
            raise clisys.InvalidArgument(args[0])

        try:
            value = int(args[1])

        except ValueError:
            raise clisys.InvalidArgument(args[1])

        type = args[2]
        description = args[3]

        transaction = Transaction(day, value, type, description)
        self.__repo.add_item(transaction)

    @clisys.command(name='remove')
    def remove_transaction(self, args):
        """
        Remove transactions from the list.
            remove <day>
            remove <start day> to <end day>
            remove <type>
        """
        count = len(args)
        if count == 1:
            try:
                day = int(args[0])
                self.__repo.remove_items(lambda t: t.get_day() == day)

            except ValueError:
                type = args[0]
                self.__repo.remove_items(lambda t: t.get_type() == type)

        elif count == 3:
            if args[1] != 'to':
                raise clisys.InvalidArgument(args[1])

            start_day = int(args[0])
            end_day = int(args[2])
            self.__repo.remove_items(
                lambda t: start_day <= t.get_day() <= end_day)

        else:
            raise clisys.InvalidArgumentCount

    @clisys.command(name='replace')
    def replace_transaction(self, args):
        """
        Replace the amount of a transaction with a given value.
            replace <day> <type> <description> with <value>
        """
        if len(args) != 5:
            raise clisys.InvalidArgumentCount

        if args[3] != 'with':
            raise clisys.InvalidArgument(args[3])

        try:
            day = int(args[0])

        except ValueError:
            raise clisys.InvalidArgument(args[0])

        type = args[1]
        description = args[2]
        try:
            value = int(args[4])
        except ValueError:
            raise clisys.InvalidArgument(args[4])

        self.__repo.replace_item(
            lambda t: t.get_day() == day and t.get_type() == type and t.
            get_description() == description,
            Transaction(day, value, type, description))

    @clisys.command(name='list')
    def list_transactions(self, args):
        """
        Display the list of transactions.
            list
            list <type>
            list [ < | = | > ] <value>
            list balance <day>
        """
        count = len(args)
        if count == 0:
            display_transactions(self.__repo.get_items())

        elif count == 1:
            type = args[0]
            display_transactions(
                self.__repo.get_items(lambda t: t.get_type() == type))

        elif count == 2:
            option = args[0]
            if option == 'balance':
                try:
                    day = int(args[1])

                except ValueError:
                    raise clisys.InvalidArgument(args[1])

                balance = get_balance(self.__repo, day)

                print(f"Balance on day {day}: {balance}")

            elif option in ['<', '=', '>']:
                try:
                    amount = int(args[1])

                except ValueError:
                    raise clisys.InvalidArgument(args[1])

                if option == '<':
                    display_transactions(
                        self.__repo.get_items(
                            lambda t: t.get_money_amount() < amount))

                elif option == '=':
                    display_transactions(
                        self.__repo.get_items(
                            lambda t: t.get_money_amount() == amount))

                elif option == '>':
                    display_transactions(
                        self.__repo.get_items(
                            lambda t: t.get_money_amount() > amount))

            else:
                raise clisys.InvalidArgument(args[0])

        else:
            raise clisys.InvalidArgumentCount

    @clisys.command(name='sum')
    def sum_transactions(self, args):
        """
        Displays the total amount from a transaction type.
            sum <type>
        """
        if len(args) > 1:
            raise clisys.InvalidArgumentCount

        type = args[0]
        result = get_sum(self.__repo, type)

        print(f'Total amount from "{type}" transactions: {result}')

    @clisys.command(name='max')
    def max_transaction(self, args):
        if len(args) != 2:
            raise clisys.InvalidArgumentCount

        type = args[0]
        try:
            day = int(args[1])

        except ValueError:
            raise clisys.InvalidArgument(args[1])

        result = get_max(self.__repo, type, day)

        if result is None:
            print(f'No transaction of type "{type}" on day {day}.')

        else:
            print(
                f'The maximum "{type}" transaction on  day {day}: "{result.get_description()}: {result.get_money_amount()}"'
            )

    @clisys.command(name='filter')
    def filter_transactions(self, args):
        """
        Filters the transactions.
            filter <type>
            filter <type> <value>
        """
        count = len(args)

        if count == 1:
            type = args[0]

            self.__repo.remove_items(lambda t: t.get_type() != type)

        elif count == 2:
            type = args[0]

            try:
                value = int(args[1])

            except ValueError:
                raise clisys.InvalidArgument([args[1]])

            self.__repo.remove_items(lambda t: t.get_type() != type or t.
                                     get_money_amount() >= value)

        print('Transactions filtered successfully!')

    @clisys.command(name='undo')
    def undo(self, args):
        """
        Undo the last command that changed the transactions list.
            undo
        """
        try:
            self.__repo.undo()
            print('Undo executed successfully!')

        except cmdsys.EmptyActionsStack:
            print('Nothing to undo.')

    @clisys.command(name='redo')
    def redo(self, args):
        """
        Redo the last undo-ed command.
            redo
        """
        try:
            self.__repo.redo()
            print('Redo executed successfully!')

        except cmdsys.EmptyUndoStack:
            print('Nothing to redo.')

    @clisys.exception_handler
    def handle_exceptions(self, exception: Exception):
        """
        Handles exceptions raised in commands.
        :param exception: The exception.
        :return:
        """
        try:
            raise exception

        except clisys.InvalidCommand as e:
            print(f'Invalid command: "{str(e.command_name)}" .')

        except clisys.InvalidArgument as e:
            print(f'Invalid argument: "{str(e.argument_name)}" .')

        except clisys.InvalidArgumentCount:
            print(f'Invalid argument count.')

    @clisys.input_handler
    def get_input(self):
        """
        Gets the input and returns it as a list
        :return: A list of strings.
        """
        i = input('\n> ')
        i = re.split(r' +', i)

        return i

    def init_repo(self):
        self.__repo.add_item(Transaction(2, 1909, 'in', 'freelancing'))
        self.__repo.add_item(Transaction(24, 178, 'out', 'food'))
        self.__repo.add_item(Transaction(1, 1200, 'out', 'rent'))
        self.__repo.add_item(Transaction(14, 54, 'out', 'food'))
        self.__repo.add_item(Transaction(14, 55023, 'in', 'salary'))
        self.__repo.add_item(Transaction(16, 550, 'in', 'freelancing'))
        self.__repo.add_item(Transaction(23, 1200, 'out', 'project'))
        self.__repo.add_item(Transaction(2, 230, 'out', 'food'))
        self.__repo.add_item(Transaction(16, 176, 'out', 'food'))
        self.__repo.add_item(Transaction(5, 188, 'out', 'food'))
Exemple #8
0
class UI(clisys.CLISys):
    def __init__(self):
        super().__init__()
        self.__repo = Repository()
        self.init_repo()

    @clisys.command('1', description='Add expense.')
    def add_expense(self, args):
        try:
            expense = read_expense()

        except ValueError:
            raise ExpenseError('Invalid expense.')

        self.__repo.add_item(expense)
        print('Expense added successfully!')

    @clisys.command('2', description='Show expenses.')
    def list_expenses(self, args):
        """
        Displays the list of expenses.
        :param args:
        :return:
        """
        expenses = self.__repo.get_items()

        print('Id\t|\tDay\t|\tAmount\t|\tType', end='\n\n')
        for i, expense in enumerate(expenses):
            print(f'{i + 1}.\t\t{expense.day}\t\t{expense.money_amount}\t\t\t{expense.type}')

    @clisys.command(name='3', description='Filter expenses.')
    def filter_expenses(self, args):
        """
        Filter the expenses list
        :param args:
        :return:
        """
        try:
            min_value = int(input('Input the minimum value: '))

        except ValueError:
            raise ValueError('Invalid minimum value.')

        self.__repo.remove_items(lambda e: e.money_amount <= min_value)

        print('Expenses filtered successfully!')

    @clisys.command(name='4', description='Undo.')
    def undo(self, args):
        """
        Undo the last command that changed the expenses list.
        :param args:
        :return:
        """
        self.__repo.undo()
        print('Undo executed successfully!')

    @clisys.command(name='5', description='Redo.')
    def redo(self, args):
        """
        Undo the last command that changed the expenses list.
        :param args:
        :return:
        """
        self.__repo.redo()
        print('Redo executed successfully!')

    @clisys.command(name='-1', description='Exit.')
    def exit_program(self, args):
        """
        Exits the program.
        """
        exit(0)

    @clisys.exception_handler
    def handle_exceptions(self, exception: Exception):
        """
        Handles exceptions raised in commands.
        :param exception: The exception.
        :return:
        """
        try:
            raise exception

        except clisys.InvalidCommand as e:
            print(f'Invalid option: "{str(e.command_name)}" .')

        except clisys.InvalidArgument as e:
            print(f'Invalid argument: "{str(e.argument_name)}" .')

        except clisys.InvalidArgumentCount:
            print('Invalid argument count.')

        except cmdsys.EmptyActionsStack:
            print('Nothing to undo.')

        except cmdsys.EmptyUndoStack:
            print('Nothing to redo.')

        except ExpenseError as e:
            print(e)

        except ValueError as e:
            print(e)

    def display_options(self):
        """
        Displays the list of options.
        :return:
        """
        print()
        options = list(self.get_commands().values())
        options.sort(key=lambda op: op.name)

        for option in options:
            print(f'{option.name}. {option.description}')

    @clisys.input_handler
    def get_option(self):
        """
        Gets the input and returns it as a list
        :return: A list of strings. (first element is the name of the command)
        """
        self.display_options()
        i = input('\nOption: ')

        return [i]

    def init_repo(self):
        self.__repo.add_item(Expense(1, 10, 'food'))
        self.__repo.add_item(Expense(1, 120, 'internet'))
        self.__repo.add_item(Expense(1, 112, 'food'))
        self.__repo.add_item(Expense(4, 20, 'food'))
        self.__repo.add_item(Expense(4, 100, 'electricity'))
        self.__repo.add_item(Expense(6, 980, 'phone'))
        self.__repo.add_item(Expense(8, 1, 'food'))
        self.__repo.add_item(Expense(8, 16, 'food'))
        self.__repo.add_item(Expense(23, 100, 'food'))
        self.__repo.add_item(Expense(30, 233, 'gas'))