diff --git a/qiftool.py b/qiftool.py index 6692c2a..2647767 100644 --- a/qiftool.py +++ b/qiftool.py @@ -105,10 +105,15 @@ class QifTool(Model): booking['account'] = line_txt[1:-1] else : booking['category'] = line_txt - elif line.startswith('S'): # split: category - booking['split'].append({ - 'category': line_txt, - }) + elif line.startswith('S'): # split: category, account + if line_txt.startswith('[') and line_txt.endswith(']'): + booking['split'].append({ + 'account': line_txt[1:-1], + }) + else : + booking['split'].append({ + 'category': line_txt, + }) elif line.startswith('E'): # split: memo booking['split'][-1]['description'] = line_txt elif line.startswith('$'): # split: amount @@ -367,6 +372,27 @@ class QifTool(Model): else : return False + @classmethod + def get_category_account(cls, book, transaction): + """ get category or account + """ + cat_name = transaction.get('category', None) + account_name = transaction.get('account', None) + msg_list = [] + fail_cnt = 0 + category = account = None + if cat_name is not None: + (category, msg_txt) = cls.get_category_by_name(book.company, cat_name) + if category is None: + msg_list.append(msg_txt) + fail_cnt += 1 + elif account_name is not None: + (account, msg_txt) = cls.get_account_by_name(book, account_name) + if account is None: + msg_list.append(msg_txt) + fail_cnt += 1 + return (category, account, msg_list, fail_cnt) + @classmethod def convert_transactions_to_create(cls, book, transactions, split2edit=True): """ convert read transactions to create-command @@ -390,57 +416,45 @@ class QifTool(Model): if 'description' in line.keys(): line['description'] = updt_description(line['description']) - cat_name = transaction.get('category', None) - account_name = transaction.get('account', None) - if cat_name is not None: - (category, msg_txt) = cls.get_category_by_name(book.company, cat_name) - if category is None: - msg_list.append(msg_txt) - fail_cnt += 1 - continue + (category, account, msg_lst2, fail_cnt2) = cls.get_category_account(book, transaction) + msg_list.extend(msg_lst2) + if fail_cnt2 > 0: + fail_cnt += fail_cnt2 + continue + + if category: + cat_type = category.cattype + line['category'] = category.id + + if cat_type == 'out': + # amount of usually out-transaction are negative in QIF, + # if its a return-transaction it should be positive + line['amount'] = line['amount'].copy_negate() + + line['bookingtype'] = cat_type + if len(transaction['split']) > 0: + line['bookingtype'] = { + 'in': 'spin', + 'out': 'spout', + }[cat_type] + elif account: + if line['amount'] < Decimal('0.0'): + line['bookingtype'] = 'mvout' + line['amount'] = line['amount'].copy_negate() else : - cat_type = category.cattype - line['category'] = category.id - if msg_txt is not None: - msg_list.append(msg_txt) + line['bookingtype'] = 'mvin' - if cat_type == 'out': - # amount of usually out-transaction are negative in QIF, - # if its a return-transaction it should be positive - line['amount'] = line['amount'].copy_negate() - - line['bookingtype'] = cat_type - if len(transaction['split']) > 0: - line['bookingtype'] = { - 'in': 'spin', - 'out': 'spout', - }[cat_type] - elif account_name is not None: - (account, msg_txt) = cls.get_account_by_name(book, account_name) - if account is None: - msg_list.append(msg_txt) - fail_cnt += 1 + line['booktransf'] = account.id + descr_lst = [transaction.get('party', '-')] + if 'description' in line.keys(): + descr_lst.append(line['description']) + if 'party' in transaction.keys(): + del transaction['party'] + line['description'] = '; '.join(descr_lst) + line['state'] = 'edit' + if cls.check_counter_transaction(book, line) == True: + # counter-transaction already exists continue - else : - if msg_txt is not None: - msg_list.append(msg_txt) - if line['amount'] < Decimal('0.0'): - line['bookingtype'] = 'mvout' - line['amount'] = line['amount'].copy_negate() - else : - line['bookingtype'] = 'mvin' - - line['booktransf'] = account.id - descr_lst = [transaction.get('party', '-')] - if 'description' in line.keys(): - descr_lst.append(line['description']) - if 'party' in transaction.keys(): - del transaction['party'] - line['description'] = '; '.join(descr_lst) - line['state'] = 'edit' - if cls.check_counter_transaction(book, line) == True: - # counter-transaction already exists - continue else : # transaction: no category, no account - ignore? if line.get('amount', Decimal('0.0')) == Decimal('0.0'): @@ -482,31 +496,40 @@ class QifTool(Model): split_lines = [] for sp_line in transaction['split']: - (cat_obj, msg_txt) = cls.get_category_by_name(book.company, sp_line['category']) + (category, account, msg_lst2, fail_cnt2) = cls.get_category_account(book, sp_line) + msg_list.extend(msg_lst2) + if fail_cnt2 > 0: + fail_cnt += fail_cnt2 + continue - if msg_txt is not None: - msg_list.append(msg_txt) + split_line = { + 'amount': sp_line['amount'] \ + if line['bookingtype'].endswith('in') else sp_line['amount'].copy_negate(), + 'description': updt_description(sp_line.get('description', None)), + } - if cat_obj is not None: + if category: # category match to bookingtype? - if ((cat_obj.cattype == 'in') and line['bookingtype'].endswith('out')) or\ - ((cat_obj.cattype == 'out') and line['bookingtype'].endswith('in')): + if ((category.cattype == 'in') and line['bookingtype'].endswith('out')) or\ + ((category.cattype == 'out') and line['bookingtype'].endswith('in')): msg_list.append(gettext( 'cashbook_dataexchange.mds_import_category_not_match', - catname = '%s [%s]' % (cat_obj.rec_name, cat_obj.cattype), + catname = '%s [%s]' % (category.rec_name, category.cattype), bktype = line['bookingtype'], data = str(transaction), )) fail_cnt += 1 - - split_lines.append({ - 'amount': sp_line['amount'] \ - if line['bookingtype'] in ['in', 'spin'] else sp_line['amount'].copy_negate(), - 'description': updt_description(sp_line.get('description', None)), - 'category': cat_obj.id, - }) + continue + split_line['splittype'] = 'cat' + split_line['category'] = category.id + elif account: + split_line['splittype'] = 'tr' + split_line['booktransf'] = account.id else : - fail_cnt += 1 + continue + + split_lines.append(split_line) + if len(split_lines) > 0: line['splitlines'] = [('create', split_lines)] diff --git a/tests/test_category.py b/tests/test_category.py index 56ae211..6fed058 100644 --- a/tests/test_category.py +++ b/tests/test_category.py @@ -323,7 +323,8 @@ I 'PFoodshop Zehlendorf\nLLebensmittel\n^\nD22.10.2020\n'+ 'CX\nMLebensmittel\nT-55,84\nPreal,- Teltow\nLLebensmittel\n'+ 'SLebensmittel\nELebensmittel\n$-49,36\nSKosmetik\nEKlopapier\n'+ - '$-2,99\nSHaushaltschemie\nESagrotan\n$-3,49\n^\n') + '$-2,99\nSHaushaltschemie\nESagrotan\n$-3,49\n'+ + 'S[S-Giro]\nEtransfer out\n$-3,49\n^\n') (to_create, msg_txt, fail_cnt) = QifTool.convert_transactions_to_create(books[0], tr_list) self.assertEqual(msg_txt, []) @@ -360,17 +361,25 @@ I 'party': parties[3].id, 'splitlines': [ ('create', [{ + 'splittype': 'cat', 'amount': Decimal('49.36'), 'description': 'Lebensmittel', 'category': categories[0].id, }, { + 'splittype': 'cat', 'amount': Decimal('2.99'), 'description': 'Klopapier', 'category': categories[2].id, }, { + 'splittype': 'cat', 'amount': Decimal('3.49'), 'description': 'Sagrotan', 'category': categories[1].id, + }, { + 'splittype': 'tr', + 'amount': Decimal('3.49'), + 'description': 'transfer out', + 'booktransf': books[1].id, }], )], }]) @@ -380,7 +389,7 @@ I 'lines': [('create', to_create)], }]) self.assertEqual(len(books[0].lines), 4) - self.assertEqual(books[0].balance, Decimal('-134.09')) + self.assertEqual(books[0].balance, Decimal('-137.58')) @with_transaction() def test_qiftool_read_transactions(self): diff --git a/tests/test_transaction.py b/tests/test_transaction.py index 0ec7da4..23d563d 100644 --- a/tests/test_transaction.py +++ b/tests/test_transaction.py @@ -313,7 +313,6 @@ Number of transactions: 2""") self.assertEqual(books[1].lines[0].rec_name, '12/04/2013|from|7.30 usd|Transfer to book [From Book | -57.55 usd | Open]') self.assertEqual(books[1].lines[0].state, 'check') - # run wizard again - import to 'To Book' (sess_id, start_state, end_state) = ImportWiz.create() w_obj = ImportWiz(sess_id)