From 79620f8cbbdfd2ca2877664291f7894f056f863a Mon Sep 17 00:00:00 2001 From: Frederik Jaeckel Date: Mon, 5 Sep 2022 10:13:20 +0200 Subject: [PATCH] transaktionen: export + test --- __init__.py | 3 +- book.py | 20 ++++------- locale/de.po | 4 +++ locale/en.po | 8 +++-- qif_export.py | 37 ++++++++++++++++++++ qif_export.xml | 14 ++++++++ qiftool.py | 73 +++++++++++++++++++++++++++++++++++++++ setup.py | 2 +- tests/test_transaction.py | 24 +++++++++++++ 9 files changed, 168 insertions(+), 17 deletions(-) diff --git a/__init__.py b/__init__.py index ed4330c..ca56a2a 100644 --- a/__init__.py +++ b/__init__.py @@ -8,7 +8,7 @@ from .category import Category from .book import Book from .qiftool import QifTool from .qif_import_wiz import ImportQifWizard, ImportQifWizardStart, ImportQifWizardInfo -from .qif_export import QifCategoryExport +from .qif_export import QifCategoryExport, QifBookExport def register(): Pool.register( @@ -20,6 +20,7 @@ def register(): module='cashbook_dataexchange', type_='model') Pool.register( QifCategoryExport, + QifBookExport, module='cashbook_dataexchange', type_='report') Pool.register( ImportQifWizard, diff --git a/book.py b/book.py index 56c728b..4c44c74 100644 --- a/book.py +++ b/book.py @@ -10,20 +10,14 @@ from trytond.pool import Pool, PoolMeta class Book(metaclass=PoolMeta): __name__ = 'cashbook.book' - # ~ @classmethod - # ~ def export_as_qif(cls): - # ~ """ export all transactions as QIF - # ~ """ - # ~ pool = Pool() - # ~ Category2 = pool.get('cashbook.category') - # ~ QifTool = pool.get('cashbook_dataexchange.qiftool') + @classmethod + def export_as_qif(cls, book): + """ export all transactions as QIF + """ + pool = Pool() + QifTool = pool.get('cashbook_dataexchange.qiftool') - # ~ categories = Category2.search([], - # ~ order=[('cattype', 'ASC'), ('rec_name', 'ASC')]) - - # ~ export = ['!Type:Cat'] - # ~ export.extend([QifTool.qif_export_category(x) for x in categories]) - # ~ return '\n'.join(export) + return QifTool.qif_export_book(book) @classmethod def create_from_qif(cls, book, qifdata): diff --git a/locale/de.po b/locale/de.po index b452c61..3aace03 100644 --- a/locale/de.po +++ b/locale/de.po @@ -66,6 +66,10 @@ msgctxt "model:ir.action,name:qif_category_report" msgid "Export QIF-File" msgstr "QIF-Datei exportieren" +msgctxt "model:ir.action,name:qif_transaction_report" +msgid "Export QIF-File" +msgstr "QIF-Datei exportieren" + ##################################### # cashbook_dataexchange.qif_imp_wiz # diff --git a/locale/en.po b/locale/en.po index 455bf50..4afb36c 100644 --- a/locale/en.po +++ b/locale/en.po @@ -7,8 +7,8 @@ msgid "The following categories are now imported:\n%(categories)s" msgstr "The following categories are now imported:\n%(categories)s" msgctxt "model:ir.message,text:msg_wiz_transactions_found" -msgid "The following transactionen are now imported:\nBalance: %(balance)s\nNumber of transactions: %(quantity)s" -msgstr "The following transactionen are now imported:\nBalance: %(balance)s\nNumber of transactions: %(quantity)s" +msgid "The following transactionen are now imported:\nCredit: %(credit)s\nDebit: %(debit)s\nBalance: %(balance)s\nNumber of transactions: %(quantity)s" +msgstr "The following transactionen are now imported:\nCredit: %(credit)s\nDebit: %(debit)s\nBalance: %(balance)s\nNumber of transactions: %(quantity)s" msgctxt "model:ir.message,text:msg_wiz_parties_found" msgid "The following %(numparties)s parties are now imported:" @@ -58,6 +58,10 @@ msgctxt "model:ir.action,name:qif_category_report" msgid "Export QIF-File" msgstr "Export QIF-File" +msgctxt "model:ir.action,name:qif_transaction_report" +msgid "Export QIF-File" +msgstr "Export QIF-File" + msgctxt "model:cashbook_dataexchange.qif_imp_wiz,name:" msgid "Import QIF-File" msgstr "Import QIF-File" diff --git a/qif_export.py b/qif_export.py index d54d9c4..b764cd7 100644 --- a/qif_export.py +++ b/qif_export.py @@ -5,6 +5,8 @@ from trytond.report import Report from trytond.pool import Pool +from slugify import slugify + class QifCategoryExport(Report): @@ -25,3 +27,38 @@ class QifCategoryExport(Report): '%s-categories' % IrDate.today().isoformat().replace('-', '')) # end QifCategoryExport + + +class QifBookExport(Report): + __name__ = 'cashbook_dataexchange.rep_book' + + @classmethod + def execute(cls, ids, data): + """ filename for export + """ + pool = Pool() + IrDate = pool.get('ir.date') + Book = pool.get('cashbook.book') + + books = Book.search([('id', '=', data.get('id', -1))]) + if len(books) == 1: + return ( + 'qif', + Book.export_as_qif(books[0]), + False, + slugify('%(date)s-transactions-%(book)s' % { + 'date': IrDate.today().isoformat().replace('-', ''), + 'book': books[0].name, + }, max_length=100, word_boundary=True, save_order=True), + ) + else : + return ( + 'txt', + 'not cashbook found', + False, + '%(date)s-transactions-%(book)s' % { + 'date': IrDate.today().isoformat().replace('-', ''), + 'book': 'not-found', + }) + +# end QifBookExport diff --git a/qif_export.xml b/qif_export.xml index 26507a9..b9b32f6 100644 --- a/qif_export.xml +++ b/qif_export.xml @@ -19,5 +19,19 @@ full copyright notices and license terms. --> + + Export QIF-File + cashbook.book + cashbook_dataexchange.rep_book + cashbook_dataexchange/report/export.fods + ods + + + + form_action + cashbook.book,-1 + + + diff --git a/qiftool.py b/qiftool.py index 2625775..1f9e48c 100644 --- a/qiftool.py +++ b/qiftool.py @@ -6,6 +6,7 @@ from trytond.pool import Pool from trytond.model import Model from trytond.i18n import gettext +from trytond.report import Report from decimal import Decimal from datetime import datetime @@ -119,6 +120,78 @@ class QifTool(Model): result.append(booking) return result + @classmethod + def qif_export_book(cls, book): + """ export book + """ + result = ['!Type:Bank'] + + def get_amount_by_bookingstate(amount, line): + """ get amount with sign + """ + if line.bookingtype in ['in', 'spin', 'mvin']: + return amount + elif line.bookingtype in ['out', 'spout', 'mvout']: + return amount * Decimal('-1.0') + else : + raise ValueError('invalid bookingtype: %s' % line.bookingtype) + + for line in book.lines: + # date + result.append('D%(date)s' % { + 'date': Report.format_date(line.date, None), + }) + # total + result.append('T%(total)s' % { + 'total': Report.format_number(get_amount_by_bookingstate(line.amount, line), None), + }) + # state + result.append('C%(state)s' % { + 'state': 'X' if line.state in ['check', 'done'] else '*', + }) + # party + if line.party: + result.append('P%(party)s' % { + 'party': line.party.rec_name, + }) + # address + p_address = line.party.address_get() + if p_address: + if len(p_address.full_address.strip()) > 0: + result.append('A%(address)s' % { + 'address': p_address.full_address.replace('\n', ', ').strip(), + }) + # category + if line.category: + result.append('L%(category)s' % { + 'category': line.category.rec_name.replace('/', ':'), + }) + # account + if line.booktransf: + result.append('L[%(account)s]' % { + 'account': line.booktransf.name, + }) + # description + if line.description: + result.append('M%(memo)s' % { + 'memo': line.description.replace('\n', '; ') + }) + + # split-booking + for splitline in line.splitlines: + result.append('S%(category)s' % { + 'category': splitline.category.rec_name.replace('/', ':'), + }) + if splitline.description: + result.append('E%(memo)s' % { + 'memo': splitline.description.replace('\n', '; ') + }) + result.append('$%(total)s' % { + 'total': Report.format_number(get_amount_by_bookingstate(splitline.amount, line), None), + }) + result.append('^') + return '\n'.join(result) + @classmethod def get_party_by_name(cls, partyname): """ find party diff --git a/setup.py b/setup.py index 61227b6..acb487d 100644 --- a/setup.py +++ b/setup.py @@ -42,7 +42,7 @@ with open(path.join(here, 'versiondep.txt'), encoding='utf-8') as f: major_version = 6 minor_version = 0 -requires = [] +requires = ['python-slugify'] for dep in info.get('depends', []): if not re.match(r'(ir|res|webdav)(\W|$)', dep): if dep in modversion.keys(): diff --git a/tests/test_transaction.py b/tests/test_transaction.py index b400b73..49b6c0a 100644 --- a/tests/test_transaction.py +++ b/tests/test_transaction.py @@ -87,6 +87,8 @@ class TransactionTestCase(ModuleTestCase): self.assertEqual(result['view']['defaults']['company'], company.id) self.assertEqual(result['view']['defaults']['info'], """The following transactionen are now imported: +Credit: usd297.12 +Debit: usd56.37 Balance: usd240.75 Number of transactions: 3""") @@ -105,4 +107,26 @@ Number of transactions: 3""") self.assertEqual(book.lines[1].rec_name, '12/05/2013|Rev|290.00 usd|05.12/06.42UHR TT TELTOW [S-Giro]') self.assertEqual(book.lines[2].rec_name, '12/05/2013|Exp|-56.37 usd|some food [Lebensmittel]') + self.assertEqual(Book.export_as_qif(book), """!Type:Bank +D12/04/2013 +T7.12 +CX +POpening Balance +LBargeld +^ +D12/05/2013 +T290.00 +CX +PGA NR00002168 BLZ10000000 0 +LS-Giro +M05.12/06.42UHR TT TELTOW +^ +D12/05/2013 +T-56.37 +CX +PFoodshop Zehlendorf +LLebensmittel +Msome food +^""") + # end PartyTestCase