From 3eb4aebe0ad28ae747f2f83efd743f9f9fa5570b Mon Sep 17 00:00:00 2001 From: Frederik Jaeckel Date: Wed, 31 Aug 2022 10:30:49 +0200 Subject: [PATCH 01/49] Version 6.0.1 --- README.rst | 4 ++++ versiondep.txt | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index a7e7424..4f14e24 100644 --- a/README.rst +++ b/README.rst @@ -14,6 +14,10 @@ Requires Changes ======= +*6.0.1 - 31.08.2022* + +- add: qif - category - import + *6.0.0 - 28.08.2022* - init diff --git a/versiondep.txt b/versiondep.txt index 1b31d78..4a857da 100644 --- a/versiondep.txt +++ b/versiondep.txt @@ -1 +1 @@ -cashbook;6.0.1;6.0.999;mds +cashbook;6.0.3;6.0.999;mds From ac9400c085fdeb9ce1c4406e2fe63de3d6d83765 Mon Sep 17 00:00:00 2001 From: Frederik Jaeckel Date: Wed, 31 Aug 2022 17:32:01 +0200 Subject: [PATCH 03/49] kategorie: export als qif --- __init__.py | 4 + category.py | 15 +++ locale/de.po | 4 + qif_export.py | 27 +++++ qif_export.xml | 23 ++++ qiftool.py | 12 +++ report/exort.fods | 240 +++++++++++++++++++++++++++++++++++++++++ setup.py | 3 +- tests/test_category.py | 48 +++++++++ tryton.cfg | 1 + 10 files changed, 376 insertions(+), 1 deletion(-) create mode 100644 qif_export.py create mode 100644 qif_export.xml create mode 100644 report/exort.fods diff --git a/__init__.py b/__init__.py index 780ef43..d703d42 100644 --- a/__init__.py +++ b/__init__.py @@ -7,6 +7,7 @@ from trytond.pool import Pool from .category import Category from .qiftool import QifTool from .qif_import_wiz import ImportQifWizard, ImportQifWizardStart, ImportQifWizardInfo +from .qif_export import QifCategoryExport def register(): Pool.register( @@ -15,6 +16,9 @@ def register(): ImportQifWizardStart, ImportQifWizardInfo, module='cashbook_dataexchange', type_='model') + Pool.register( + QifCategoryExport, + module='cashbook_dataexchange', type_='report') Pool.register( ImportQifWizard, module='cashbook_dataexchange', type_='wizard') diff --git a/category.py b/category.py index 05f31de..d347f34 100644 --- a/category.py +++ b/category.py @@ -10,6 +10,21 @@ from trytond.pool import Pool, PoolMeta class Category(metaclass=PoolMeta): __name__ = 'cashbook.category' + @classmethod + def export_as_qif(cls): + """ export all accessible categories as QIF + """ + pool = Pool() + Category2 = pool.get('cashbook.category') + 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) + @classmethod def create_from_qif(cls, qifdata): """ add categories from QIF-File-content diff --git a/locale/de.po b/locale/de.po index 09c0727..730f94e 100644 --- a/locale/de.po +++ b/locale/de.po @@ -18,6 +18,10 @@ msgctxt "model:ir.action,name:act_import_qif_wizard" msgid "Import QIF-File" msgstr "QIF-Datei importieren" +msgctxt "model:ir.action,name:qif_category_report" +msgid "Export QIF-File" +msgstr "QIF-Datei exportieren" + msgctxt "model:ir.action,name:msg_wiz_no_categories" msgid "No categories were found in the file." msgstr "In der Datei wurden keine Kategorien gefunden." diff --git a/qif_export.py b/qif_export.py new file mode 100644 index 0000000..d54d9c4 --- /dev/null +++ b/qif_export.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +# This file is part of the cashbook-module from m-ds for Tryton. +# The COPYRIGHT file at the top level of this repository contains the +# full copyright notices and license terms. + +from trytond.report import Report +from trytond.pool import Pool + + +class QifCategoryExport(Report): + __name__ = 'cashbook_dataexchange.rep_category' + + @classmethod + def execute(cls, ids, data): + """ filename for export + """ + pool = Pool() + IrDate = pool.get('ir.date') + Category = pool.get('cashbook.category') + + return ( + 'qif', + Category.export_as_qif(), + False, + '%s-categories' % IrDate.today().isoformat().replace('-', '')) + +# end QifCategoryExport diff --git a/qif_export.xml b/qif_export.xml new file mode 100644 index 0000000..26507a9 --- /dev/null +++ b/qif_export.xml @@ -0,0 +1,23 @@ + + + + + + + Export QIF-File + cashbook.category + cashbook_dataexchange.rep_category + cashbook_dataexchange/report/export.fods + ods + + + + form_action + cashbook.category,-1 + + + + + diff --git a/qiftool.py b/qiftool.py index 0743f3b..c00bdd2 100644 --- a/qiftool.py +++ b/qiftool.py @@ -78,4 +78,16 @@ class QifTool(Model): categories[cattype] = add_category(categories[cattype], catname, cattype) return categories + @classmethod + def qif_export_category(cls, record): + """ export single category as qif + """ + return '\n'.join([ + 'N%(cname)s' % { + 'cname': record.rec_name.replace('/', ':'), + }, + 'E' if record.cattype == 'out' else 'I', + '^', + ]) + # end QifTool diff --git a/report/exort.fods b/report/exort.fods new file mode 100644 index 0000000..86a7924 --- /dev/null +++ b/report/exort.fods @@ -0,0 +1,240 @@ + + + + 2017-10-20T23:41:04.964000000LibreOffice/6.0.7.3$Linux_X86_64 LibreOffice_project/00m0$Build-3 + + + 0 + 0 + 2257 + 451 + + + view1 + + + 0 + 0 + 0 + 0 + 0 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 100 + 60 + true + false + + + Sheet1 + 1828 + 0 + 100 + 60 + false + true + true + true + 12632256 + true + true + true + true + false + false + false + 1270 + 1270 + 1 + 1 + true + false + + + + + 7 + true + false + false + 0 + true + owH+/0hQX0xhc2VySmV0X01GUF9NNDI2ZmRuX0IyNUM3Ml8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQ1VQUzpIUF9MYXNlckpldF9NRlBfTTQyNmZkbl9CMgAWAAMAxAAAAAAAAAAEAAhSAAAEdAAASm9iRGF0YSAxCnByaW50ZXI9SFBfTGFzZXJKZXRfTUZQX000MjZmZG5fQjI1QzcyXwpvcmllbnRhdGlvbj1Qb3J0cmFpdApjb3BpZXM9MQpjb2xsYXRlPWZhbHNlCm1hcmdpbmRhanVzdG1lbnQ9MCwwLDAsMApjb2xvcmRlcHRoPTI0CnBzbGV2ZWw9MApwZGZkZXZpY2U9MQpjb2xvcmRldmljZT0wClBQRENvbnRleERhdGEKUGFnZVNpemU6QTQAABIAQ09NUEFUX0RVUExFWF9NT0RFDwBEdXBsZXhNb2RlOjpPZmY= + HP_LaserJet_MFP_M426fdn_B25C72_ + true + 3 + true + false + true + true + 12632256 + true + true + true + false + true + false + true + 1 + false + 1270 + 1270 + false + 1 + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ??? + + + + Page 1 + + + + + + + ???(???) + + + 00.00.0000, 00:00:00 + + + + + Page 1/ 99 + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/setup.py b/setup.py index 1eff6ad..61227b6 100644 --- a/setup.py +++ b/setup.py @@ -97,7 +97,8 @@ setup(name='%s_%s' % (PREFIX, MODULE), package_data={ 'trytond.modules.%s' % MODULE: (info.get('xml', []) + ['tryton.cfg', 'locale/*.po', 'tests/*.py', - 'view/*.xml', 'versiondep.txt', 'README.rst']), + 'report/*.fods', 'view/*.xml', + 'versiondep.txt', 'README.rst']), }, install_requires=requires, diff --git a/tests/test_category.py b/tests/test_category.py index 753aab5..1487cc9 100644 --- a/tests/test_category.py +++ b/tests/test_category.py @@ -123,6 +123,54 @@ Lebensmittel (out)""") self.assertEqual(records[13].rec_name, 'Telekommunikation/Telefon') self.assertEqual(records[14].rec_name, 'Telekommunikation/Telefon/Test1') + result = Category.export_as_qif() + self.assertEqual(result, """!Type:Cat +NFernsehen +E +^ +NFernsehen:GEZ +E +^ +NFernsehen:TV-Company +E +^ +NLebensmittel +E +^ +NTelefon +E +^ +NTelefon:Telco1-Tablett +E +^ +NTelefon:Telco2-Handy +E +^ +NTelefon:Telco3 +E +^ +NTelekommunikation +E +^ +NTelekommunikation:Fernsehen +E +^ +NTelekommunikation:Online-Dienste +E +^ +NTelekommunikation:Telefon +E +^ +NTelekommunikation:Telefon:Test1 +E +^ +NGehalt +I +^ +NGehalt:Zulagen +I +^""") + @with_transaction() def test_category_create_by_qif_existing_categories(self): """ create categories by import a qif-file, diff --git a/tryton.cfg b/tryton.cfg index df0875c..914e6da 100644 --- a/tryton.cfg +++ b/tryton.cfg @@ -5,3 +5,4 @@ depends: xml: message.xml qif_import_wiz.xml + qif_export.xml From b50927753bb884dfcfc9b661d3d57c3dd77c2fc8 Mon Sep 17 00:00:00 2001 From: Frederik Jaeckel Date: Wed, 31 Aug 2022 17:32:01 +0200 Subject: [PATCH 04/49] kategorie: export als qif --- __init__.py | 4 + category.py | 15 +++ locale/de.po | 4 + qif_export.py | 27 +++++ qif_export.xml | 23 ++++ qiftool.py | 12 +++ report/exort.fods | 240 +++++++++++++++++++++++++++++++++++++++++ setup.py | 3 +- tests/test_category.py | 48 +++++++++ tryton.cfg | 1 + 10 files changed, 376 insertions(+), 1 deletion(-) create mode 100644 qif_export.py create mode 100644 qif_export.xml create mode 100644 report/exort.fods diff --git a/__init__.py b/__init__.py index 780ef43..d703d42 100644 --- a/__init__.py +++ b/__init__.py @@ -7,6 +7,7 @@ from trytond.pool import Pool from .category import Category from .qiftool import QifTool from .qif_import_wiz import ImportQifWizard, ImportQifWizardStart, ImportQifWizardInfo +from .qif_export import QifCategoryExport def register(): Pool.register( @@ -15,6 +16,9 @@ def register(): ImportQifWizardStart, ImportQifWizardInfo, module='cashbook_dataexchange', type_='model') + Pool.register( + QifCategoryExport, + module='cashbook_dataexchange', type_='report') Pool.register( ImportQifWizard, module='cashbook_dataexchange', type_='wizard') diff --git a/category.py b/category.py index 05f31de..d347f34 100644 --- a/category.py +++ b/category.py @@ -10,6 +10,21 @@ from trytond.pool import Pool, PoolMeta class Category(metaclass=PoolMeta): __name__ = 'cashbook.category' + @classmethod + def export_as_qif(cls): + """ export all accessible categories as QIF + """ + pool = Pool() + Category2 = pool.get('cashbook.category') + 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) + @classmethod def create_from_qif(cls, qifdata): """ add categories from QIF-File-content diff --git a/locale/de.po b/locale/de.po index 09c0727..730f94e 100644 --- a/locale/de.po +++ b/locale/de.po @@ -18,6 +18,10 @@ msgctxt "model:ir.action,name:act_import_qif_wizard" msgid "Import QIF-File" msgstr "QIF-Datei importieren" +msgctxt "model:ir.action,name:qif_category_report" +msgid "Export QIF-File" +msgstr "QIF-Datei exportieren" + msgctxt "model:ir.action,name:msg_wiz_no_categories" msgid "No categories were found in the file." msgstr "In der Datei wurden keine Kategorien gefunden." diff --git a/qif_export.py b/qif_export.py new file mode 100644 index 0000000..d54d9c4 --- /dev/null +++ b/qif_export.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +# This file is part of the cashbook-module from m-ds for Tryton. +# The COPYRIGHT file at the top level of this repository contains the +# full copyright notices and license terms. + +from trytond.report import Report +from trytond.pool import Pool + + +class QifCategoryExport(Report): + __name__ = 'cashbook_dataexchange.rep_category' + + @classmethod + def execute(cls, ids, data): + """ filename for export + """ + pool = Pool() + IrDate = pool.get('ir.date') + Category = pool.get('cashbook.category') + + return ( + 'qif', + Category.export_as_qif(), + False, + '%s-categories' % IrDate.today().isoformat().replace('-', '')) + +# end QifCategoryExport diff --git a/qif_export.xml b/qif_export.xml new file mode 100644 index 0000000..26507a9 --- /dev/null +++ b/qif_export.xml @@ -0,0 +1,23 @@ + + + + + + + Export QIF-File + cashbook.category + cashbook_dataexchange.rep_category + cashbook_dataexchange/report/export.fods + ods + + + + form_action + cashbook.category,-1 + + + + + diff --git a/qiftool.py b/qiftool.py index 0743f3b..c00bdd2 100644 --- a/qiftool.py +++ b/qiftool.py @@ -78,4 +78,16 @@ class QifTool(Model): categories[cattype] = add_category(categories[cattype], catname, cattype) return categories + @classmethod + def qif_export_category(cls, record): + """ export single category as qif + """ + return '\n'.join([ + 'N%(cname)s' % { + 'cname': record.rec_name.replace('/', ':'), + }, + 'E' if record.cattype == 'out' else 'I', + '^', + ]) + # end QifTool diff --git a/report/exort.fods b/report/exort.fods new file mode 100644 index 0000000..86a7924 --- /dev/null +++ b/report/exort.fods @@ -0,0 +1,240 @@ + + + + 2017-10-20T23:41:04.964000000LibreOffice/6.0.7.3$Linux_X86_64 LibreOffice_project/00m0$Build-3 + + + 0 + 0 + 2257 + 451 + + + view1 + + + 0 + 0 + 0 + 0 + 0 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 100 + 60 + true + false + + + Sheet1 + 1828 + 0 + 100 + 60 + false + true + true + true + 12632256 + true + true + true + true + false + false + false + 1270 + 1270 + 1 + 1 + true + false + + + + + 7 + true + false + false + 0 + true + owH+/0hQX0xhc2VySmV0X01GUF9NNDI2ZmRuX0IyNUM3Ml8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQ1VQUzpIUF9MYXNlckpldF9NRlBfTTQyNmZkbl9CMgAWAAMAxAAAAAAAAAAEAAhSAAAEdAAASm9iRGF0YSAxCnByaW50ZXI9SFBfTGFzZXJKZXRfTUZQX000MjZmZG5fQjI1QzcyXwpvcmllbnRhdGlvbj1Qb3J0cmFpdApjb3BpZXM9MQpjb2xsYXRlPWZhbHNlCm1hcmdpbmRhanVzdG1lbnQ9MCwwLDAsMApjb2xvcmRlcHRoPTI0CnBzbGV2ZWw9MApwZGZkZXZpY2U9MQpjb2xvcmRldmljZT0wClBQRENvbnRleERhdGEKUGFnZVNpemU6QTQAABIAQ09NUEFUX0RVUExFWF9NT0RFDwBEdXBsZXhNb2RlOjpPZmY= + HP_LaserJet_MFP_M426fdn_B25C72_ + true + 3 + true + false + true + true + 12632256 + true + true + true + false + true + false + true + 1 + false + 1270 + 1270 + false + 1 + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ??? + + + + Page 1 + + + + + + + ???(???) + + + 00.00.0000, 00:00:00 + + + + + Page 1/ 99 + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/setup.py b/setup.py index 1eff6ad..61227b6 100644 --- a/setup.py +++ b/setup.py @@ -97,7 +97,8 @@ setup(name='%s_%s' % (PREFIX, MODULE), package_data={ 'trytond.modules.%s' % MODULE: (info.get('xml', []) + ['tryton.cfg', 'locale/*.po', 'tests/*.py', - 'view/*.xml', 'versiondep.txt', 'README.rst']), + 'report/*.fods', 'view/*.xml', + 'versiondep.txt', 'README.rst']), }, install_requires=requires, diff --git a/tests/test_category.py b/tests/test_category.py index 753aab5..1487cc9 100644 --- a/tests/test_category.py +++ b/tests/test_category.py @@ -123,6 +123,54 @@ Lebensmittel (out)""") self.assertEqual(records[13].rec_name, 'Telekommunikation/Telefon') self.assertEqual(records[14].rec_name, 'Telekommunikation/Telefon/Test1') + result = Category.export_as_qif() + self.assertEqual(result, """!Type:Cat +NFernsehen +E +^ +NFernsehen:GEZ +E +^ +NFernsehen:TV-Company +E +^ +NLebensmittel +E +^ +NTelefon +E +^ +NTelefon:Telco1-Tablett +E +^ +NTelefon:Telco2-Handy +E +^ +NTelefon:Telco3 +E +^ +NTelekommunikation +E +^ +NTelekommunikation:Fernsehen +E +^ +NTelekommunikation:Online-Dienste +E +^ +NTelekommunikation:Telefon +E +^ +NTelekommunikation:Telefon:Test1 +E +^ +NGehalt +I +^ +NGehalt:Zulagen +I +^""") + @with_transaction() def test_category_create_by_qif_existing_categories(self): """ create categories by import a qif-file, diff --git a/tryton.cfg b/tryton.cfg index df0875c..914e6da 100644 --- a/tryton.cfg +++ b/tryton.cfg @@ -5,3 +5,4 @@ depends: xml: message.xml qif_import_wiz.xml + qif_export.xml From be9c584feaeb425d10c3610b437c877e5a347789 Mon Sep 17 00:00:00 2001 From: Frederik Jaeckel Date: Thu, 1 Sep 2022 14:48:04 +0200 Subject: [PATCH 05/49] import der transaktionen begonnen --- __init__.py | 2 + book.py | 52 +++++++++ locale/de.po | 52 +++++++-- locale/en.po | 72 ++++++++++++ message.xml | 22 +++- qif_import_wiz.py | 81 ++++++++++++- qif_import_wiz.xml | 7 ++ qiftool.py | 186 ++++++++++++++++++++++++++++++ tests/test_category.py | 173 ++++++++++++++++++++++++++- view/wiz_qifimport_info_form.xml | 3 + view/wiz_qifimport_start_form.xml | 2 + 11 files changed, 637 insertions(+), 15 deletions(-) create mode 100644 book.py diff --git a/__init__.py b/__init__.py index d703d42..ed4330c 100644 --- a/__init__.py +++ b/__init__.py @@ -5,6 +5,7 @@ from trytond.pool import Pool 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 @@ -13,6 +14,7 @@ def register(): Pool.register( QifTool, Category, + Book, ImportQifWizardStart, ImportQifWizardInfo, module='cashbook_dataexchange', type_='model') diff --git a/book.py b/book.py new file mode 100644 index 0000000..261cb64 --- /dev/null +++ b/book.py @@ -0,0 +1,52 @@ +# -*- coding: utf-8 -*- +# This file is part of the cashbook-module from m-ds for Tryton. +# The COPYRIGHT file at the top level of this repository contains the +# full copyright notices and license terms. + +from trytond.transaction import Transaction +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') + + # ~ 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) + + @classmethod + def create_from_qif(cls, book, qifdata): + """ add transactions from QIF-File-content + """ + pool = Pool() + QifTool = pool.get('cashbook_dataexchange.qiftool') + Book2 = pool.get('cashbook.book') + + qif_content = QifTool.split_by_type(qifdata) + if not 'Bank' in qif_content.keys(): + return None + + (to_create, msg_list) = QifTool.convert_transactions_to_create( + QifTool.qif_read_transactions(qif_content['Bank']) + ) + if msg_list == []: + Book2.write(*[ + [book], + { + 'lines': [('create', to_create)], + }]) + return [book] + return None + +# end Category diff --git a/locale/de.po b/locale/de.po index 730f94e..124fc7b 100644 --- a/locale/de.po +++ b/locale/de.po @@ -10,6 +10,38 @@ msgctxt "model:ir.message,text:msg_wiz_categories_found" msgid "The following categories are now imported:\n%(categories)s" msgstr "Die folgenden Kategorien werden nun importiert:\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 "Die folgenden Transaktionen werden nun importiert:\nSaldo: %(balance)s\nAnzahl Transactionen: %(quantity)s" + +msgctxt "model:ir.message,name:msg_wiz_no_categories" +msgid "No categories were found in the file." +msgstr "In der Datei wurden keine Kategorien gefunden." + +msgctxt "model:ir.message,name:msg_wiz_no_bank" +msgid "No transactions were found in the file." +msgstr "In der Datei wurden keine Transaktionen gefunden." + +msgctxt "model:ir.message,name:mds_import_category_notfound" +msgid "The category '%(catname)s' (Type: %(cattype)s) was not found." +msgstr "Die Kategorie '%(catname)s' (Typ: %(cattype)s) wurde nicht gefunden." + +msgctxt "model:ir.message,name:mds_import_many_categories_found" +msgid "For the category '%(catname1)s' (type: '%(cattype)s') of the import, several categories were found in the system. Use: '%(catname2)s'" +msgstr "Für die Kategorie '%(catname1)s' (Typ: '%(cattype)s') des Imports wurden mehrere Kategorien im System gefunden. Verwende: '%(catname2)s'" + +msgctxt "model:ir.message,name:mds_import_checknumber" +msgid "Cheque No." +msgstr "Scheck-Nr:" + +msgctxt "model:ir.message,name:mds_import_address" +msgid "Address" +msgstr "Adresse" + +msgctxt "model:ir.message,name:msg_wiz_transactions_error" +msgid "When reading the QIF file, there were the following problems:" +msgstr "Beim Einlesen der QIF-Datei gab es folgende Probleme:" + ############# # ir.action # @@ -22,10 +54,6 @@ msgctxt "model:ir.action,name:qif_category_report" msgid "Export QIF-File" msgstr "QIF-Datei exportieren" -msgctxt "model:ir.action,name:msg_wiz_no_categories" -msgid "No categories were found in the file." -msgstr "In der Datei wurden keine Kategorien gefunden." - ##################################### # cashbook_dataexchange.qif_imp_wiz # @@ -47,8 +75,8 @@ msgid "Cancel" msgstr "Abbruch" msgctxt "wizard_button:cashbook_dataexchange.qif_imp_wiz,showinfo,importf:" -msgid "Import Categories" -msgstr "Kategorien importieren" +msgid "Import Data" +msgstr "Daten Kategorien" ########################################### @@ -62,6 +90,10 @@ msgctxt "field:cashbook_dataexchange.qif_imp_wiz.start,company:" msgid "Company" msgstr "Unternehmen" +msgctxt "field:cashbook_dataexchange.qif_imp_wiz.start,book:" +msgid "Cashbook" +msgstr "Kassenbuch" + msgctxt "field:cashbook_dataexchange.qif_imp_wiz.start,file_:" msgid "QIF-File" msgstr "QIF-Datei" @@ -82,10 +114,14 @@ msgctxt "view:cashbook_dataexchange.qif_imp_wiz.info:" msgid "Information" msgstr "Information" -msgctxt "field:cashbook_dataexchange.qif_imp_wiz.start,company:" +msgctxt "field:cashbook_dataexchange.qif_imp_wiz.info,book:" +msgid "Cashbook" +msgstr "Kassenbuch" + +msgctxt "field:cashbook_dataexchange.qif_imp_wiz.info,company:" msgid "Company" msgstr "Unternehmen" -msgctxt "field:cashbook_dataexchange.qif_imp_wiz.start,info:" +msgctxt "field:cashbook_dataexchange.qif_imp_wiz.info,info:" msgid "Information" msgstr "Information" diff --git a/locale/en.po b/locale/en.po index df5fa3e..1bc2211 100644 --- a/locale/en.po +++ b/locale/en.po @@ -2,10 +2,50 @@ msgid "" msgstr "Content-Type: text/plain; charset=utf-8\n" +msgctxt "model:ir.message,text:msg_wiz_categories_found" +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" + +msgctxt "model:ir.message,name:msg_wiz_no_categories" +msgid "No categories were found in the file." +msgstr "No categories were found in the file." + +msgctxt "model:ir.message,name:msg_wiz_no_bank" +msgid "No transactions were found in the file." +msgstr "No transactions were found in the file." + +msgctxt "model:ir.message,name:mds_import_category_notfound" +msgid "The category '%(catname)s' (Type: %(cattype)s) was not found." +msgstr "The category '%(catname)s' (Type: %(cattype)s) was not found." + +msgctxt "model:ir.message,name:mds_import_many_categories_found" +msgid "For the category '%(catname1)s' (type: '%(cattype)s') of the import, several categories were found in the system. Use: '%(catname2)s'" +msgstr "For the category '%(catname1)s' (type: '%(cattype)s') of the import, several categories were found in the system. Use: '%(catname2)s'" + +msgctxt "model:ir.message,name:mds_import_checknumber" +msgid "Cheque No." +msgstr "Cheque No." + +msgctxt "model:ir.message,name:mds_import_address" +msgid "Address" +msgstr "Address" + +msgctxt "model:ir.message,name:msg_wiz_transactions_error" +msgid "When reading the QIF file, there were the following problems:" +msgstr "When reading the QIF file, there were the following problems:" + msgctxt "model:ir.action,name:act_import_qif_wizard" msgid "Import QIF-File" msgstr "Import QIF-File" +msgctxt "model:ir.action,name:qif_category_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" @@ -18,6 +58,14 @@ msgctxt "wizard_button:cashbook_dataexchange.qif_imp_wiz,start,readf:" msgid "Read File" msgstr "Read File" +msgctxt "wizard_button:cashbook_dataexchange.qif_imp_wiz,showinfo,end:" +msgid "Cancel" +msgstr "Cancel" + +msgctxt "wizard_button:cashbook_dataexchange.qif_imp_wiz,showinfo,importf:" +msgid "Import Data" +msgstr "Import Data" + msgctxt "model:cashbook_dataexchange.qif_imp_wiz.start,name:" msgid "Import QIF-File" msgstr "Import QIF-File" @@ -26,7 +74,31 @@ msgctxt "field:cashbook_dataexchange.qif_imp_wiz.start,company:" msgid "Company" msgstr "Company" +msgctxt "field:cashbook_dataexchange.qif_imp_wiz.start,book:" +msgid "Cashbook" +msgstr "Cashbook" + msgctxt "field:cashbook_dataexchange.qif_imp_wiz.start,file_:" msgid "QIF-File" msgstr "QIF-File" +msgctxt "help:cashbook_dataexchange.qif_imp_wiz.start,file_:" +msgid "Quicken Interchange Format" +msgstr "Quicken Interchange Format" + +msgctxt "model:cashbook_dataexchange.qif_imp_wiz.info,name:" +msgid "Import QIF-File" +msgstr "Import QIF-File" + +msgctxt "view:cashbook_dataexchange.qif_imp_wiz.info:" +msgid "Information" +msgstr "Information" + +msgctxt "field:cashbook_dataexchange.qif_imp_wiz.info,book:" +msgid "Cashbook" +msgstr "Cashbook" + +msgctxt "field:cashbook_dataexchange.qif_imp_wiz.info,company:" +msgid "Company" +msgstr "Company" + diff --git a/message.xml b/message.xml index fe4a54e..b03a6a2 100644 --- a/message.xml +++ b/message.xml @@ -8,10 +8,30 @@ full copyright notices and license terms. --> The following categories are now imported:\n%(categories)s - No categories were found in the file. + + No transactions were found in the file. + + + The following transactionen are now imported:\nBalance: %(balance)s\nNumber of transactions: %(quantity)s + + + When reading the QIF file, there were the following problems: + + + The category '%(catname)s' (Type: %(cattype)s) was not found. + + + For the category '%(catname1)s' (type: '%(cattype)s') of the import, several categories were found in the system. Use: '%(catname2)s' + + + Cheque No. + + + Address + diff --git a/qif_import_wiz.py b/qif_import_wiz.py index 0687533..ef50af0 100644 --- a/qif_import_wiz.py +++ b/qif_import_wiz.py @@ -9,6 +9,9 @@ from trytond.model import ModelView, fields from trytond.wizard import Wizard, StateTransition, StateView, Button from trytond.transaction import Transaction from trytond.i18n import gettext +from trytond.pyson import Eval, Bool +from trytond.report import Report +from decimal import Decimal class ImportQifWizardStart(ModelView): @@ -18,6 +21,11 @@ class ImportQifWizardStart(ModelView): company = fields.Many2One(model_name='company.company', string="Company", required=True, states={'invisible': True}) + book = fields.Many2One(string='Cashbook', readonly=True, + model_name='cashbook.book', + states={ + 'invisible': ~Bool(Eval('book')), + }) file_ = fields.Binary(string="QIF-File", required=True, help='Quicken Interchange Format') @@ -35,6 +43,13 @@ class ImportQifWizardInfo(ModelView): company = fields.Many2One(model_name='company.company', string="Company", required=True, states={'invisible': True}) + book = fields.Many2One(string='Cash Book', readonly=True, + model_name='cashbook.book', + states={ + 'invisible': ~Bool(Eval('book')), + }) + allowimport = fields.Boolean(string='Import Enabled', + states={'invisible': True}) info = fields.Text(string='Information', readonly=True) # end ImportQifWizardInfo @@ -55,18 +70,38 @@ class ImportQifWizard(Wizard): view='cashbook_dataexchange.qif_imp_wiz_info_form', \ buttons=[ Button(string='Cancel', state='end', icon='tryton-cancel'), - Button(string='Import Categories', state='importf', icon='tryton-import', default=True), + Button(string='Import Data', state='importf', icon='tryton-import', default=True, + states={ + 'readonly': Eval('allowimport', False) == False, + }), ]) readf = StateTransition() importf = StateTransition() + def default_start(self, fields): + """ show book, company + """ + context = Transaction().context + + values = { + 'company': Transaction().context.get('company'), + 'book': None, + } + + model = context.get('active_model', '') + if model == 'cashbook.book': + values['book'] = context.get('active_id', None) + return values + def default_showinfo(self, fields): """ show import-info """ values = { 'company': self.start.company.id, 'info': getattr(self.showinfo, 'info', None), + 'book': getattr(getattr(self.start, 'book', None), 'id', None), + 'allowimport': getattr(self.showinfo, 'allowimport', False), } return values @@ -74,13 +109,14 @@ class ImportQifWizard(Wizard): """ read file, show number of objects """ pool = Pool() - QitTool = pool.get('cashbook_dataexchange.qiftool') + QifTool = pool.get('cashbook_dataexchange.qiftool') model = Transaction().context.get('active_model', '') file_content = None if isinstance(self.start.file_, bytes): file_content = self.start.file_.decode('utf8') + self.showinfo.allowimport = False if model == 'cashbook.category': def get_catlist(catlist, parent_name=None): """ generate list of categories @@ -97,9 +133,9 @@ class ImportQifWizard(Wizard): return names # read file content, extract categories - qif_content = QitTool.split_by_type(file_content) + qif_content = QifTool.split_by_type(file_content) if 'Cat' in qif_content.keys(): - categories = QitTool.qif_read_categories(qif_content['Cat']) + categories = QifTool.qif_read_categories(qif_content['Cat']) self.showinfo.info = gettext( 'cashbook_dataexchange.msg_wiz_categories_found', categories = '\n'.join( @@ -109,8 +145,40 @@ class ImportQifWizard(Wizard): ['%s (out)' % x for x in get_catlist(categories['out'], None)] ) ) + self.showinfo.allowimport = True else : self.showinfo.info = gettext('cashbook_dataexchange.msg_wiz_no_categories') + elif model == 'cashbook.book': + # read file content, extract categories + qif_content = QifTool.split_by_type(file_content) + if 'Bank' in qif_content.keys(): + (to_create, msg_list) = QifTool.convert_transactions_to_create( + QifTool.qif_read_transactions(qif_content['Bank']) + ) + if len(msg_list) > 0: + short_lst = [] + for x in msg_list: + if x not in short_lst: + short_lst.append(x) + + self.showinfo.info = '%s\n\n%s' % ( + gettext('cashbook_dataexchange.msg_wiz_transactions_error'), + '\n'.join(short_lst), + ) + else : + # count + balance = sum([ + x['amount'] \ + if x['bookingtype'] in ['in', 'spin'] else x['amount'].copy_sign(Decimal('-1.0')) \ + for x in to_create]) + self.showinfo.info = gettext( + 'cashbook_dataexchange.msg_wiz_transactions_found', + quantity = len(to_create), + balance = Report.format_currency(balance, None, self.start.book.currency), + ) + self.showinfo.allowimport = True + else : + self.showinfo.info = gettext('cashbook_dataexchange.msg_wiz_no_bank') return 'showinfo' @@ -119,6 +187,7 @@ class ImportQifWizard(Wizard): """ pool = Pool() Category = pool.get('cashbook.category') + Book = pool.get('cashbook.book') model = Transaction().context.get('active_model', '') file_content = None @@ -128,7 +197,9 @@ class ImportQifWizard(Wizard): if model == 'cashbook.category': if file_content: records = Category.create_from_qif(file_content) - + elif model == 'cashbook.book': + if file_content: + Book.create_from_qif(self.showinfo.book, file_content) return 'end' # end ImportQifWizard diff --git a/qif_import_wiz.xml b/qif_import_wiz.xml index f354c18..cb345e2 100644 --- a/qif_import_wiz.xml +++ b/qif_import_wiz.xml @@ -29,5 +29,12 @@ full copyright notices and license terms. --> + + + form_action + cashbook.book,-1 + + + diff --git a/qiftool.py b/qiftool.py index c00bdd2..29b454d 100644 --- a/qiftool.py +++ b/qiftool.py @@ -5,6 +5,9 @@ from trytond.pool import Pool from trytond.model import Model +from trytond.i18n import gettext +from decimal import Decimal +from datetime import datetime class QifTool(Model): @@ -34,6 +37,189 @@ class QifTool(Model): blocks[block] = '\n'.join(blocks[block]) return blocks + @classmethod + def get_amount_from_txt(cls, amount_txt): + """ convert text to Decimal + """ + if (',' in amount_txt) and (amount_txt[-3] == '.'): + # '.' = decimal, ',' = tousand + amount_txt = amount_txt.replace(',', '.') + elif ('.' in amount_txt) and (amount_txt[-3] == ','): + # ',' = decimal, '.' = tousand + amount_txt = amount_txt.replace('.', '') + amount_txt = amount_txt.replace(',', '.') + elif ',' in amount_txt: + amount_txt = amount_txt.replace(',', '.') + return Decimal(amount_txt) + + @classmethod + def qif_read_transactions(cls, transactiondata): + """ read transactions from text + result: [{ + 'split': [{ + 'amount': , + 'description': 'purpose', + 'category': 'name of categroy', + },...], + 'date': , + 'amount': , + 'party': 'name of party', + 'address': 'address of party', + 'checknumber': 'number', + 'description': 'purpose', + 'state': 'check|edit', + 'account': 'name of cashbook', + 'category': 'name of category', + }, ...] + """ + result = [] + for booktxt in transactiondata.split('^'): + if len(booktxt.strip()) == 0: + continue + + booking = {'split': []} + for line in booktxt.strip().split('\n'): + line_txt = line[1:].strip() + if line.startswith('D'): # date + booking['date'] = datetime.strptime(line_txt, '%d.%m.%Y').date() + elif line.startswith('T'): # total + booking['amount'] = cls.get_amount_from_txt(line_txt) + elif line.startswith('U'): # total + booking['amount'] = cls.get_amount_from_txt(line_txt) + elif line.startswith('P'): # party + booking['party'] = line_txt + elif line.startswith('A'): # address + booking['address'] = line_txt + elif line.startswith('N'): # address + booking['checknumber'] = line_txt + elif line.startswith('M'): # memo + booking['description'] = line_txt + elif line.startswith('C'): # state + booking['state'] = { + 'X': 'check', + '*': 'edit', + }.get(line_txt, 'edit') + elif line.startswith('L'): # category, account + if line_txt.startswith('[') and line_txt.endswith(']'): + 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('E'): # split: memo + booking['split'][-1]['description'] = line_txt + elif line.startswith('$'): # split: amount + booking['split'][-1]['amount'] = cls.get_amount_from_txt(line_txt) + elif line.startswith('£'): # split: amount + booking['split'][-1]['amount'] = cls.get_amount_from_txt(line_txt) + else : + raise ValueError('unknown line-code: %s' % (line)) + result.append(booking) + return result + + @classmethod + def get_category_by_name(cls, catname, cattype): + """ find category + """ + Category = Pool().get('cashbook.category') + + cat_id = None + msg_txt = None + categories = Category.search([ + ('cattype', '=', cattype), + ('rec_name', '=', catname.replace(':', '/')), + ]) + if len(categories) == 1: + cat_id = categories[0].id + elif len(categories) == 0: + msg_txt = gettext( + 'cashbook_dataexchange.mds_import_category_notfound', + catname = catname, + cattype = cattype, + ) + else : + msg_txt = gettext( + 'cashbook_dataexchange.mds_import_many_categories_found', + catname1 = catname, + catname2 = categories[0].rec_name, + cattype = cattype, + ) + cat_id = categories[0].id + return (cat_id, msg_txt) + + @classmethod + def convert_transactions_to_create(cls, transactions, split2edit=True): + """ convert read transactions to create-command + split2edit: True = split-bokings are 'edit', False = dont change + """ + to_create = [] + msg_list = [] + for transaction in transactions: + line = {x:transaction[x] for x in [ + 'date', 'amount', 'description', 'state', + ] if x in transaction.keys()} + + if len(transaction['split']) > 0: + if line['amount'] >= Decimal('0.0'): + line['bookingtype'] = 'spin' + else : + line['bookingtype'] = 'spout' + line['amount'] = line['amount'].copy_sign(Decimal('1.0')) + else : + if line['amount'] >= Decimal('0.0'): + line['bookingtype'] = 'in' + else : + line['bookingtype'] = 'out' + line['amount'] = line['amount'].copy_sign(Decimal('1.0')) + + # store 'account' like 'category' + cat_name = transaction.get('category', transaction.get('account', None)) + cat_type = 'in' if line['bookingtype'] in ['in', 'spin'] else 'out' + if cat_name is not None: + (cat_id, msg_txt) = cls.get_category_by_name(cat_name, cat_type) + if cat_id is None: + msg_list.append(msg_txt) + continue + else : + line['category'] = cat_id + if msg_txt is not None: + msg_list.append(msg_txt) + + for x in ['address', 'checknumber']: + if x in transaction.keys(): + line['description'] = ', '.join([ + line.get('description', ''), + '%s %s' % ( + gettext('cashbook_dataexchange.mds_import_%s' % x), + transaction[x] + ), + ]) + + split_lines = [] + for sp_line in transaction['split']: + (cat_id, msg_txt) = cls.get_category_by_name(sp_line['category'], cat_type) + + if msg_txt is not None: + msg_list.append(msg_txt) + + if cat_id is not None: + split_lines.append({ + 'amount': sp_line['amount'].copy_sign(Decimal('1.0')), + 'description': sp_line.get('description', None), + 'category': cat_id, + }) + if len(split_lines) > 0: + line['splitlines'] = [('create', split_lines)] + + if split2edit == True: + if 'splitlines' in line.keys(): + line['state'] = 'edit' + + to_create.append(line) + return (to_create, msg_list) + @classmethod def qif_read_categories(cls, catdata): """ read categories from text diff --git a/tests/test_category.py b/tests/test_category.py index 1487cc9..7cb1b65 100644 --- a/tests/test_category.py +++ b/tests/test_category.py @@ -3,6 +3,8 @@ # The COPYRIGHT file at the top level of this repository contains the # full copyright notices and license terms. +from datetime import date +from decimal import Decimal from trytond.tests.test_tryton import ModuleTestCase, with_transaction from trytond.pool import Pool from trytond.transaction import Transaction @@ -48,7 +50,7 @@ class CategoryTestCase(CashbookTestCase): self.assertEqual(list(result.keys()), ['view']) self.assertEqual(result['view']['defaults']['company'], company.id) self.assertEqual(result['view']['defaults']['info'], -"""The following categories are now imported:\\n +"""The following categories are now imported:\n Gehalt (in) Gehalt/Zulagen (in) @@ -238,6 +240,175 @@ I 'PGA NR00002168 BLZ10000000 0\nL[S-Giro]\n^\nD05.12.2013\nCX\nMsome food\n'+ 'T-56,37\nPFoodshop Zehlendorf\nLLebensmittel\n^\n') + @with_transaction() + def test_qiftool_convert_transactions(self): + """ convert_transactions_to_create + """ + pool = Pool() + QifTool = pool.get('cashbook_dataexchange.qiftool') + Category = pool.get('cashbook.category') + Book = pool.get('cashbook.book') + + company = self.prep_company() + with Transaction().set_context({ + 'company': company.id, + }): + types = self.prep_type() + book, = Book.create([{ + 'name': 'Cash Book', + 'btype': types.id, + 'company': company.id, + 'currency': company.currency.id, + 'number_sequ': self.prep_sequence().id, + 'start_date': date(2010, 1, 1), + 'start_balance': Decimal('0.0'), + }]) + self.assertEqual(book.name, 'Cash Book') + self.assertEqual(book.btype.rec_name, 'CAS - Cash') + + Category.create([{ + 'name': 'Lebensmittel', + 'cattype': 'out', + 'company': company.id, + }, { + 'name': 'Haushaltschemie', + 'cattype': 'out', + 'company': company.id, + }, { + 'name': 'Kosmetik', + 'cattype': 'out', + 'company': company.id, + }, { + 'name': 'S-Giro', + 'cattype': 'in', + 'company': company.id, + }, { + 'name': 'Bargeld', + 'cattype': 'in', + 'company': company.id, + }, ]) + + tr_list = QifTool.qif_read_transactions('D04.12.2013\nT7,12\nCX\n'+ + 'POpening Balance\nL[Bargeld]\n^\nD05.12.2013\nCX\n'+ + 'M05.12/06.42UHR TT TELTOW\nT290,00\nPGA NR00002168 BLZ10000000 0\n'+ + 'L[S-Giro]\n^\nD05.12.2013\nCX\nMsome food\nT-56,37\n'+ + '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') + + (to_create, msg_txt) = QifTool.convert_transactions_to_create(tr_list) + self.assertEqual(msg_txt, []) + self.assertEqual(to_create, [{ + 'date': date(2013, 12, 4), + 'amount': Decimal('7.12'), + 'state': 'check', + 'bookingtype': 'in', + 'category': 74, + }, { + 'date': date(2013, 12, 5), + 'amount': Decimal('290.00'), + 'description': '05.12/06.42UHR TT TELTOW', + 'state': 'check', + 'bookingtype': 'in', + 'category': 73, + }, { + 'date': date(2013, 12, 5), + 'amount': Decimal('56.37'), + 'description': 'some food', + 'state': 'check', + 'bookingtype': 'out', + 'category': 70, + }, { + 'date': date(2020, 10, 22), + 'amount': Decimal('55.84'), + 'description': 'Lebensmittel', + 'state': 'edit', + 'bookingtype': 'spout', + 'category': 70, + 'splitlines': [ + ('create', [{ + 'amount': Decimal('49.36'), + 'description': 'Lebensmittel', + 'category': 70, + }, { + 'amount': Decimal('2.99'), + 'description': 'Klopapier', + 'category': 72, + }, { + 'amount': Decimal('3.49'), + 'description': 'Sagrotan', + 'category': 71, + }], + )], + }]) + Book.write(*[ + [book], + { + 'lines': [('create', to_create)], + }]) + self.assertEqual(len(book.lines), 4) + self.assertEqual(book.balance, Decimal('184.91')) + + @with_transaction() + def test_qiftool_read_transactions(self): + """ read transaction data from text + """ + QifTool = Pool().get('cashbook_dataexchange.qiftool') + + result = QifTool.qif_read_transactions('D04.12.2013\nT7,12\nCX\n'+ + 'POpening Balance\nL[Bargeld]\n^\nD05.12.2013\nCX\n'+ + 'M05.12/06.42UHR TT TELTOW\nT290,00\nPGA NR00002168 BLZ10000000 0\n'+ + 'L[S-Giro]\n^\nD05.12.2013\nCX\nMsome food\nT-56,37\n'+ + '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') + self.assertEqual(result, [{ + 'split': [], + 'date': date(2013, 12, 4), + 'amount': Decimal('7.12'), + 'state': 'check', + 'party': 'Opening Balance', + 'account': 'Bargeld', + }, { + 'split': [], + 'date': date(2013, 12, 5), + 'state': 'check', + 'description': '05.12/06.42UHR TT TELTOW', + 'amount': Decimal('290.00'), + 'party': 'GA NR00002168 BLZ10000000 0', + 'account': 'S-Giro', + }, { + 'split': [], + 'date': date(2013, 12, 5), + 'state': 'check', + 'description': 'some food', + 'amount': Decimal('-56.37'), + 'party': 'Foodshop Zehlendorf', + 'category': 'Lebensmittel', + }, { + 'split': [{ + 'category': 'Lebensmittel', + 'description': 'Lebensmittel', + 'amount': Decimal('-49.36'), + }, { + 'category': 'Kosmetik', + 'description': 'Klopapier', + 'amount': Decimal('-2.99'), + }, { + 'category': 'Haushaltschemie', + 'description': 'Sagrotan', + 'amount': Decimal('-3.49'), + }], + 'date': date(2020, 10, 22), + 'state': 'check', + 'description': 'Lebensmittel', + 'amount': Decimal('-55.84'), + 'party': 'real,- Teltow', + 'category': 'Lebensmittel', + }]) + @with_transaction() def test_qiftool_read_categories(self): """ read category-data from text diff --git a/view/wiz_qifimport_info_form.xml b/view/wiz_qifimport_info_form.xml index caff918..9b38048 100644 --- a/view/wiz_qifimport_info_form.xml +++ b/view/wiz_qifimport_info_form.xml @@ -5,9 +5,12 @@ full copyright notices and license terms. -->