def build_transaction(column_indices, row): ta = Transaction() if config.ACCOUNT_NO_COL in column_indices: ta.set_account_no( row[column_indices[config.ACCOUNT_NO_COL]].strip()) ta.date = util.parse_date(row[column_indices[config.DATE_COL]]) ta.amount = float(row[column_indices[config.AMOUNT_COL]].replace( '.', '').replace(',', '.')) if config.PAYMENT_REASON_COL in column_indices: ta.payment_reason = re.sub( r' +', ' ', row[column_indices[config.PAYMENT_REASON_COL]].strip()) if config.RECIPIENT_COL in column_indices: ta.recipient = re.sub( r' +', ' ', row[column_indices[config.RECIPIENT_COL]].strip()) if config.OTHER_ACCOUNT_NO_COL in column_indices: ta.set_other_account_no( row[column_indices[config.OTHER_ACCOUNT_NO_COL]].strip()) return ta
def test_aggregate_transactions_by_year(self): transactions = [ Transaction('123456', datetime(year=2018, month=3, day=5), 120.0, 'reason', 'recipient', config.INCOME_CATEGORY), Transaction('123456', datetime(year=2018, month=5, day=18), -50.0, 'reason', 'recipient', self.category1), Transaction('123456', datetime(year=2018, month=8, day=15), -30.0, 'reason', 'recipient', self.category1), Transaction('123456', datetime(year=2018, month=9, day=3), -100.0, 'reason', 'recipient', self.category2), Transaction('123456', datetime(year=2019, month=6, day=21), -150.0, 'reason', 'recipient', self.category2), ] data_provider = DataProvider.load(transactions) df_all = data_provider.get_all_transactions() x_axis, category_values = data_provider.aggregate_by_category_as_tuple( df_all, 'YS', config.CATEGORY_MAIN_COL) self.assertEqual(2, len(x_axis)) self.assertEqual(3, len( category_values.keys())) # includes income category self.assertListEqual([120.0, 0.0], list(category_values[config.INCOME_CATEGORY])) self.assertListEqual([80.0, 0.0], list(category_values[self.category1])) self.assertListEqual([100.0, 150.0], list(category_values[self.category2]))
def test_aggregate_different_expenses_by_month(self): transactions = [ Transaction('123456', datetime(year=2019, month=3, day=1), -20.0, 'reason', 'recipient', self.category1), Transaction('123456', datetime(year=2019, month=3, day=18), -50.0, 'reason', 'recipient', self.category2), Transaction('123456', datetime(year=2019, month=4, day=15), -30.0, 'reason', 'recipient', self.category1), Transaction('123456', datetime(year=2019, month=6, day=5), -100.0, 'reason', 'recipient', self.category2), Transaction('123456', datetime(year=2019, month=6, day=21), -150.0, 'reason', 'recipient', self.category2), ] data_provider = DataProvider.load(transactions) df_all = data_provider.get_all_transactions() x_axis, category_values = data_provider.aggregate_by_category_as_tuple( df_all, 'MS', config.CATEGORY_MAIN_COL) self.assertEqual(4, len(x_axis)) self.assertEqual(3, len(category_values.keys())) self.assertListEqual([20.0, 30.0, 0.0, 0.0], list(category_values[self.category1])) self.assertListEqual([50.0, 0.0, 0.0, 250.0], list(category_values[self.category2]))
def find_category(self, transaction: Transaction): """ Finds a matching category for the given transaction. If the amount of the transaction is positive, the INCOME category is returned, otherwise the first category with a matching keyword is used. If no matching keyword could be found the MISC category is used. :param transaction: :return: (main_category, sub_category) """ category = None # income if not transaction.is_expense(): category = self.find_sub_category(transaction, config.INCOME_CATEGORY) if category is None: category = config.INCOME_CATEGORY, self._empty_category else: # expense for main_cat in config.categories.keys(): if main_cat is not config.INCOME_CATEGORY: category = self.find_sub_category(transaction, main_cat) if category: break if category is None: category = config.MISC_CATEGORY, self._empty_category return category
def test_aggregate_income_by_month(self): transactions = [ Transaction('123456', datetime(year=2019, month=3, day=5), 20.0, 'reason', 'recipient', config.INCOME_CATEGORY), Transaction('123456', datetime(year=2019, month=3, day=18), 50.0, 'reason', 'recipient', config.INCOME_CATEGORY), Transaction('123456', datetime(year=2019, month=5, day=8), 100.0, 'reason', 'recipient', config.INCOME_CATEGORY), ] data_provider = DataProvider.load(transactions) df_all = data_provider.get_all_transactions() x_axis, category_values = data_provider.aggregate_by_category_as_tuple( df_all, 'MS', config.CATEGORY_MAIN_COL) self.assertEqual(3, len(x_axis)) self.assertEqual(3, len(category_values.keys())) self.assertListEqual([70.0, 0.0, 100.0], list(category_values[config.INCOME_CATEGORY]))
def test_transaction_without_matching_keyword_expect_misc_category(self): ta = Transaction('123456', datetime.datetime.now(), -40, 'Shoes', 'Amazon', '') finder = CategoryFinder() finder.assign_category([ta]) self.assertEqual(config.MISC_CATEGORY, ta.main_category)
def test_transaction_with_recipient_expect_car_category(self): ta = Transaction('123456', datetime.datetime.now(), -30, '', 'Aral', '') finder = CategoryFinder() finder.assign_category([ta]) self.assertEqual('Car', ta.main_category)
def test_transaction_with_positive_amount_expect_income_category(self): ta = Transaction('123456', datetime.datetime.now(), 100, 'salary', '', '') finder = CategoryFinder() finder.assign_category([ta]) self.assertEqual(config.INCOME_CATEGORY, ta.main_category)