import der transaktionen begonnen
This commit is contained in:
parent
b50927753b
commit
0287452fe8
11 changed files with 637 additions and 15 deletions
|
@ -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')
|
||||
|
|
52
book.py
Normal file
52
book.py
Normal file
|
@ -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
|
52
locale/de.po
52
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"
|
||||
|
|
72
locale/en.po
72
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"
|
||||
|
||||
|
|
22
message.xml
22
message.xml
|
@ -8,10 +8,30 @@ full copyright notices and license terms. -->
|
|||
<record model="ir.message" id="msg_wiz_categories_found">
|
||||
<field name="text">The following categories are now imported:\n%(categories)s</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.message" id="msg_wiz_no_categories">
|
||||
<field name="text">No categories were found in the file.</field>
|
||||
</record>
|
||||
<record model="ir.message" id="msg_wiz_no_bank">
|
||||
<field name="text">No transactions were found in the file.</field>
|
||||
</record>
|
||||
<record model="ir.message" id="msg_wiz_transactions_found">
|
||||
<field name="text">The following transactionen are now imported:\nBalance: %(balance)s\nNumber of transactions: %(quantity)s</field>
|
||||
</record>
|
||||
<record model="ir.message" id="msg_wiz_transactions_error">
|
||||
<field name="text">When reading the QIF file, there were the following problems:</field>
|
||||
</record>
|
||||
<record model="ir.message" id="mds_import_category_notfound">
|
||||
<field name="text">The category '%(catname)s' (Type: %(cattype)s) was not found.</field>
|
||||
</record>
|
||||
<record model="ir.message" id="mds_import_many_categories_found">
|
||||
<field name="text">For the category '%(catname1)s' (type: '%(cattype)s') of the import, several categories were found in the system. Use: '%(catname2)s'</field>
|
||||
</record>
|
||||
<record model="ir.message" id="mds_import_checknumber">
|
||||
<field name="text">Cheque No.</field>
|
||||
</record>
|
||||
<record model="ir.message" id="mds_import_address">
|
||||
<field name="text">Address</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</tryton>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -29,5 +29,12 @@ full copyright notices and license terms. -->
|
|||
<field name="action" ref="act_import_qif_wizard"/>
|
||||
</record>
|
||||
|
||||
<!-- import transactions -->
|
||||
<record model="ir.action.keyword" id="act_import_qif_wizard-book-keyword">
|
||||
<field name="keyword">form_action</field>
|
||||
<field name="model">cashbook.book,-1</field>
|
||||
<field name="action" ref="act_import_qif_wizard"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</tryton>
|
||||
|
|
186
qiftool.py
186
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': <Decimal>,
|
||||
'description': 'purpose',
|
||||
'category': 'name of categroy',
|
||||
},...],
|
||||
'date': <date of transaction>,
|
||||
'amount': <Decimal>,
|
||||
'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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -5,9 +5,12 @@ full copyright notices and license terms. -->
|
|||
<form col="2">
|
||||
<label name="company"/>
|
||||
<field name="company"/>
|
||||
<label name="book"/>
|
||||
<field name="book"/>
|
||||
|
||||
<group col="1" name="info" colspan="2" string="Information" yexpand="1">
|
||||
<field name="info"/>
|
||||
</group>
|
||||
<field name="allowimport"/>
|
||||
|
||||
</form>
|
||||
|
|
|
@ -5,6 +5,8 @@ full copyright notices and license terms. -->
|
|||
<form col="2">
|
||||
<label name="company"/>
|
||||
<field name="company"/>
|
||||
<label name="book"/>
|
||||
<field name="book"/>
|
||||
|
||||
<label name="file_"/>
|
||||
<field name="file_"/>
|
||||
|
|
Loading…
Reference in a new issue