line: spalte 'empfänger', Feld 'reference' + tests

This commit is contained in:
Frederik Jaeckel 2022-08-16 14:16:14 +02:00
parent 30b91cf518
commit 5fdbb0ce89
10 changed files with 510 additions and 42 deletions

119
line.py
View file

@ -17,6 +17,11 @@ from sql.conditionals import Case
from .book import sel_state_book
sel_payee = [
('cashbook.book', 'Cashbook'),
('party.party', 'Party')
]
sel_linetype = [
('edit', 'Edit'),
('check', 'Checked'),
@ -51,13 +56,15 @@ class Line(Workflow, ModelSQL, ModelView):
'on_change_with_month', searcher='search_month')
description = fields.Text(string='Description',
states=STATES, depends=DEPENDS)
category = fields.Many2One(string='Category', required=True,
category = fields.Many2One(string='Category',
model_name='cashbook.category', ondelete='RESTRICT',
states={
'readonly': Or(
STATES['readonly'],
Bool(Eval('bookingtype')) == False,
),
'required': Eval('bookingtype', '').in_(['in', 'out']),
'invisible': ~Eval('bookingtype', '').in_(['in', 'out']),
}, depends=DEPENDS+['bookingtype'],
domain=[
If(
@ -78,14 +85,18 @@ class Line(Workflow, ModelSQL, ModelView):
credit = fields.Numeric(string='Credit', digits=(16, Eval('currency_digits', 2)),
required=True, readonly=True, depends=['currency_digits'])
booktransf = fields.Many2One(string='Transfer Cashbook',
# party or cashbook as counterpart
booktransf = fields.Many2One(string='Source/Dest',
ondelete='RESTRICT', model_name='cashbook.book',
domain=[('cashbook.owner.id', '=', Eval('context',{}).get('user', -1))],
domain=[
('owner.id', '=', Eval('owner_cashbook', -1)),
('id', '!=', Eval('cashbook', -1)),
],
states={
'readonly': STATES['readonly'],
'invisible': ~Eval('bookingtype', '').in_(['mvin', 'mvout']),
'required': Eval('bookingtype', '').in_(['mvin', 'mvout']),
}, depends=DEPENDS+['bookingtype'])
}, depends=DEPENDS+['bookingtype', 'owner_cashbook', 'cashbook'])
party = fields.Many2One(string='Party', model_name='party.party',
ondelete='RESTRICT',
states={
@ -93,6 +104,20 @@ class Line(Workflow, ModelSQL, ModelView):
'invisible': ~Eval('bookingtype', '').in_(['in', 'out']),
'required': Eval('bookingtype', '').in_(['in', 'out']),
}, depends=DEPENDS+['bookingtype'])
payee = fields.Function(fields.Reference(string='Payee', readonly=True,
selection=sel_payee), 'on_change_with_payee', searcher='search_payee')
# link to lines created by this record
reference = fields.Many2One(string='Reference', readonly=True, select=True,
states={
'invisible': ~Bool(Eval('reference')),
}, model_name='cashbook.line', ondelete='CASCADE',
help='The current row was created by and is controlled by the reference row.')
references = fields.One2Many(string='References', model_name='cashbook.line',
help='The rows are created and managed by the current record.',
states={
'invisible': ~Bool(Eval('references')),
}, field='reference', readonly=True)
reconciliation = fields.Many2One(string='Reconciliation', readonly=True,
model_name='cashbook.recon', ondelete='SET NULL',
@ -116,6 +141,9 @@ class Line(Workflow, ModelSQL, ModelView):
state_cashbook = fields.Function(fields.Selection(string='State of Cashbook',
readonly=True, states={'invisible': True}, selection=sel_state_book),
'on_change_with_state_cashbook', searcher='search_state_cashbook')
owner_cashbook = fields.Function(fields.Many2One(string='Owner', readonly=True,
states={'invisible': True}, model_name='res.user'),
'on_change_with_owner_cashbook')
#image = fields.Binary...
@ -138,7 +166,8 @@ class Line(Workflow, ModelSQL, ModelView):
cls._buttons.update({
'wfedit': {
'invisible': Eval('state', '') != 'check',
'depends': ['state'],
'readonly': Bool(Eval('reference')),
'depends': ['state', 'reference'],
},
'wfcheck': {
'invisible': Eval('state') != 'edit',
@ -156,7 +185,27 @@ class Line(Workflow, ModelSQL, ModelView):
def wfedit(cls, lines):
""" edit line
"""
pass
pool = Pool()
Line2 = pool.get('cashbook.line')
to_delete_line = []
for line in lines:
if line.reference:
if Transaction().context.get('line.allow.wfedit', False) == False:
raise UserError(gettext(
'cashbook.msg_line_denywf_by_reference',
recname = line.reference.rec_name,
cbook = line.reference.cashbook.rec_name,
))
# delete references
to_delete_line.extend(list(line.references))
if len(to_delete_line) > 0:
with Transaction().set_context({
'line.allow.wfedit': True,
}):
Line2.wfedit(to_delete_line)
Line2.delete(to_delete_line)
@classmethod
@ModelView.button
@ -166,7 +215,9 @@ class Line(Workflow, ModelSQL, ModelView):
"""
pool = Pool()
Recon = pool.get('cashbook.recon')
Line2 = pool.get('cashbook.line')
to_create_line = []
for line in lines:
# deny if date is in range of existing reconciliation
# allow cashbook-line at range-limits
@ -194,6 +245,23 @@ class Line(Workflow, ModelSQL, ModelView):
'cashbook.msg_line_err_write_to_reconciled',
datetxt = Report.format_date(line.date),
))
# in case of 'mvin' or 'mvout' - create counterpart
if (line.bookingtype in ['mvout', 'mvin']) and (line.reference is None):
to_create_line.append({
'cashbook': line.booktransf.id,
'bookingtype': 'mvin' if line.bookingtype == 'mvout' else 'mvout',
'date': line.date,
'description': line.description,
'amount': line.amount,
'credit': line.debit,
'debit': line.credit,
'booktransf': line.cashbook.id,
'reference': line.id,
})
if len(to_create_line) > 0:
new_lines = Line2.create(to_create_line)
Line2.wfcheck(new_lines)
@classmethod
@ModelView.button
@ -232,12 +300,17 @@ class Line(Workflow, ModelSQL, ModelView):
def get_rec_name(self, name):
""" short + name
"""
return '%(date)s|%(amount)s %(symbol)s|%(desc)s [%(category)s]' % {
credit = self.credit if self.credit is not None else Decimal('0.0')
debit = self.debit if self.debit is not None else Decimal('0.0')
return '%(date)s|%(type)s|%(amount)s %(symbol)s|%(desc)s [%(category)s]' % {
'date': Report.format_date(self.date),
'desc': (self.description or '-')[:40],
'amount': Report.format_number(self.amount or 0.0, None),
'amount': Report.format_number(credit - debit, None),
'symbol': getattr(self.currency, 'symbol', '-'),
'category': self.category_view,
'category': self.category_view \
if self.bookingtype in ['in', 'out'] \
else getattr(self.booktransf, 'rec_name', '-'),
'type': gettext('cashbook.msg_line_bookingtype_%s' % self.bookingtype),
}
@staticmethod
@ -271,6 +344,27 @@ class Line(Workflow, ModelSQL, ModelView):
return [tab2]
@fields.depends('party', 'booktransf', 'bookingtype')
def on_change_with_payee(self, name=None):
""" get party or cashbook
"""
if self.bookingtype:
if self.bookingtype in ['in', 'out']:
if self.party:
return 'party.party,%d' % self.party.id
elif self.bookingtype in ['mvin', 'mvout']:
if self.booktransf:
return 'cashbook.book,%d' % self.booktransf.id
@classmethod
def search_payee(cls, names, clause):
""" search in payee for party or cashbook
"""
return ['OR',
('party.rec_name',) + tuple(clause[1:]),
('booktransf.rec_name',) + tuple(clause[1:]),
]
@fields.depends('category')
def on_change_with_category_view(self, name=None):
""" show optimizef form of category for list-view
@ -320,6 +414,13 @@ class Line(Workflow, ModelSQL, ModelView):
)
return [('id', 'in', query)]
@fields.depends('cashbook', '_parent_cashbook.owner')
def on_change_with_owner_cashbook(self, name=None):
""" get current owner
"""
if self.cashbook:
return self.cashbook.owner.id
@fields.depends('cashbook', '_parent_cashbook.state')
def on_change_with_state_cashbook(self, name=None):
""" get state of cashbook

View file

@ -102,6 +102,26 @@ msgctxt "model:ir.message,text:msg_recon_predecessor_not_done"
msgid "The predecessor '%(recname_p)s' must be in the 'Done' state before you can check the current reconciliation '%(recname_c)s'."
msgstr "Der Vorgänger '%(recname_p)s' muss sich im Status 'Fertig' befinden, bevor Sie den aktuellen Abgleich '%(recname_c)s' prüfen können."
msgctxt "model:ir.message,text:msg_line_bookingtype_in"
msgid "Rev"
msgstr "Einn."
msgctxt "model:ir.message,text:msg_line_bookingtype_out"
msgid "Exp"
msgstr "Ausg."
msgctxt "model:ir.message,text:msg_line_bookingtype_mvin"
msgid "from"
msgstr "von"
msgctxt "model:ir.message,text:msg_line_bookingtype_mvout"
msgid "to"
msgstr "nach"
msgctxt "model:ir.message,text:msg_line_denywf_by_reference"
msgid "The current line is managed by the cashbook line '%(recname)s', cashbook: '%(cbook)s'."
msgstr "Die aktuelle Zeile wird durch die Kassenbuchzeile '%(recname)s' verwaltet, Kassenbuch: '%(cbook)s'."
#############
# res.group #
@ -494,6 +514,42 @@ msgctxt "field:cashbook.line,party:"
msgid "Party"
msgstr "Partei"
msgctxt "field:cashbook.line,booktransf:"
msgid "Source/Dest"
msgstr "Quelle/Ziel"
msgctxt "field:cashbook.line,owner_cashbook:"
msgid "Owner"
msgstr "Eigentümer"
msgctxt "field:cashbook.line,reference:"
msgid "Reference"
msgstr "Referenz"
msgctxt "help:cashbook.line,reference:"
msgid "The current row was created by and is controlled by the reference row."
msgstr "Die aktuelle Zeile wurde durch die Referenzzeile erstellt und wird von dieser gesteuert."
msgctxt "field:cashbook.line,references:"
msgid "References"
msgstr "Referenzen"
msgctxt "help:cashbook.line,references:"
msgid "The rows are created and managed by the current record."
msgstr "Die Zeilen werden durch den aktuellen Datensatz erstellt und verwaltet."
msgctxt "field:cashbook.line,payee:"
msgid "Payee"
msgstr "Empfänger"
msgctxt "selection:cashbook.line,payee:"
msgid "Cashbook"
msgstr "Kassenbuch"
msgctxt "selection:cashbook.line,payee:"
msgid "Party"
msgstr "Partei"
#################
# cashbook.type #

View file

@ -35,8 +35,8 @@ msgid "The cashbook line '%(linetxt)s' cannot be deleted, its in state '%(linest
msgstr "The cashbook line '%(linetxt)s' cannot be deleted, its in state '%(linestate)s'."
msgctxt "model:ir.message,text:msg_line_deny_stateedit_with_recon"
msgid "The status cannot be changed to 'Edit' as long as the line '%(recname)s' is associated with a reconciliation."
msgstr "The status cannot be changed to 'Edit' as long as the line '%(recname)s' is associated with a reconciliation."
msgid "The status cannot be changed to 'Edit' while the line '%(recname)s' is associated with a reconciliation."
msgstr "The status cannot be changed to 'Edit' while the line '%(recname)s' is associated with a reconciliation."
msgctxt "model:ir.message,text:msg_line_deny_write"
msgid "The cashbook line '%(recname)s' is '%(state_txt)s' and cannot be changed."
@ -82,6 +82,42 @@ msgctxt "model:ir.message,text:msg_recon_err_overlap"
msgid "The date range overlaps with another reconciliation."
msgstr "The date range overlaps with another reconciliation."
msgctxt "model:ir.message,text:msg_line_err_write_to_reconciled"
msgid "For the date '%(datetxt)s' there is already a completed reconciliation. Use a different date."
msgstr "For the date '%(datetxt)s' there is already a completed reconciliation. Use a different date."
msgctxt "model:ir.message,text:msg_recon_lines_no_linked"
msgid "In the date range from %(date_from)s to %(date_to)s, there are still cashbook lines that do not belong to any reconciliation."
msgstr "In the date range from %(date_from)s to %(date_to)s, there are still cashbook lines that do not belong to any reconciliation."
msgctxt "model:ir.message,text:msg_recon_date_from_to_mismatch"
msgid "The start date '%(datefrom)s' of the current reconciliation '%(recname)s' must correspond to the end date '%(dateto)s' of the predecessor."
msgstr "The start date '%(datefrom)s' of the current reconciliation '%(recname)s' must correspond to the end date '%(dateto)s' of the predecessor."
msgctxt "model:ir.message,text:msg_recon_predecessor_not_done"
msgid "The predecessor '%(recname_p)s' must be in the 'Done' state before you can check the current reconciliation '%(recname_c)s'."
msgstr "The predecessor '%(recname_p)s' must be in the 'Done' state before you can check the current reconciliation '%(recname_c)s'."
msgctxt "model:ir.message,text:msg_line_bookingtype_in"
msgid "Rev"
msgstr "Rev"
msgctxt "model:ir.message,text:msg_line_bookingtype_out"
msgid "Exp"
msgstr "Exp"
msgctxt "model:ir.message,text:msg_line_bookingtype_mvin"
msgid "from"
msgstr "from"
msgctxt "model:ir.message,text:msg_line_bookingtype_mvout"
msgid "to"
msgstr "to"
msgctxt "model:ir.message,text:msg_line_denywf_by_reference"
msgid "The current line is managed by the cashbook line '%(recname)s', cashbook: '%(cbook)s'."
msgstr "The current line is managed by the cashbook line '%(recname)s', cashbook: '%(cbook)s'."
msgctxt "model:res.group,name:group_cashbook"
msgid "Cashbook"
msgstr "Cashbook"
@ -438,6 +474,46 @@ msgctxt "field:cashbook.line,reconciliation:"
msgid "Reconciliation"
msgstr "Reconciliation"
msgctxt "field:cashbook.line,party:"
msgid "Party"
msgstr "Party"
msgctxt "field:cashbook.line,booktransf:"
msgid "Source/Dest"
msgstr "Source/Dest"
msgctxt "field:cashbook.line,owner_cashbook:"
msgid "Owner"
msgstr "Owner"
msgctxt "field:cashbook.line,reference:"
msgid "Reference"
msgstr "Reference"
msgctxt "help:cashbook.line,reference:"
msgid "The current row was created by and is controlled by the reference row."
msgstr "The current row was created by and is controlled by the reference row."
msgctxt "field:cashbook.line,references:"
msgid "References"
msgstr "References"
msgctxt "help:cashbook.line,references:"
msgid "The rows are created and managed by the current record."
msgstr "The rows are created and managed by the current record."
msgctxt "field:cashbook.line,payee:"
msgid "Payee"
msgstr "Payee"
msgctxt "selection:cashbook.line,payee:"
msgid "Cashbook"
msgstr "Cashbook"
msgctxt "selection:cashbook.line,payee:"
msgid "Party"
msgstr "Party"
msgctxt "model:cashbook.type,name:"
msgid "Cashbook Type"
msgstr "Cashbook Type"
@ -738,3 +814,7 @@ msgctxt "field:cashbook.recon,start_amount:"
msgid "Start Amount"
msgstr "Start Amount"
msgctxt "field:cashbook.recon,end_amount:"
msgid "End Amount"
msgstr "End Amount"

View file

@ -77,6 +77,22 @@ full copyright notices and license terms. -->
<record model="ir.message" id="msg_recon_predecessor_not_done">
<field name="text">The predecessor '%(recname_p)s' must be in the 'Done' state before you can check the current reconciliation '%(recname_c)s'.</field>
</record>
<record model="ir.message" id="msg_line_bookingtype_in">
<field name="text">Rev</field>
</record>
<record model="ir.message" id="msg_line_bookingtype_out">
<field name="text">Exp</field>
</record>
<record model="ir.message" id="msg_line_bookingtype_mvin">
<field name="text">from</field>
</record>
<record model="ir.message" id="msg_line_bookingtype_mvout">
<field name="text">to</field>
</record>
<record model="ir.message" id="msg_line_denywf_by_reference">
<field name="text">The current line is managed by the cashbook line '%(recname)s', cashbook: '%(cbook)s'.</field>
</record>
</data>
</tryton>

View file

@ -45,6 +45,7 @@ class BookTestCase(ModuleTestCase):
types = self.prep_type()
category = self.prep_category(cattype='in')
company = self.prep_company()
party = self.prep_party()
book, = Book.create([{
'name': 'Book 1',
'btype': types.id,
@ -56,6 +57,7 @@ class BookTestCase(ModuleTestCase):
'category': category.id,
'bookingtype': 'in',
'amount': Decimal('1.0'),
'party': party.id,
}])],
}])
self.assertEqual(book.name, 'Book 1')
@ -76,6 +78,7 @@ class BookTestCase(ModuleTestCase):
types = self.prep_type()
category = self.prep_category(cattype='in')
company = self.prep_company()
party = self.prep_party()
book, = Book.create([{
'name': 'Book 1',
'btype': types.id,
@ -87,6 +90,7 @@ class BookTestCase(ModuleTestCase):
'category': category.id,
'bookingtype': 'in',
'amount': Decimal('1.0'),
'party': party.id,
}])],
}])
self.assertEqual(book.name, 'Book 1')
@ -109,6 +113,7 @@ class BookTestCase(ModuleTestCase):
types = self.prep_type()
category = self.prep_category(cattype='in')
company = self.prep_company()
party = self.prep_party()
book, = Book.create([{
'name': 'Book 1',
'btype': types.id,
@ -120,6 +125,7 @@ class BookTestCase(ModuleTestCase):
'category': category.id,
'bookingtype': 'in',
'amount': Decimal('1.0'),
'party': party.id,
}])],
}])
self.assertEqual(book.name, 'Book 1')
@ -202,6 +208,7 @@ class BookTestCase(ModuleTestCase):
types = self.prep_type()
company = self.prep_company()
category = self.prep_category(cattype='in')
party = self.prep_party()
book, = Book.create([{
'name': 'Book 1',
'btype': types.id,
@ -228,6 +235,7 @@ class BookTestCase(ModuleTestCase):
'description': 'Test',
'category': category.id,
'bookingtype': 'in',
'party': party.id,
}])],
}])
self.assertEqual(book.start_balance, Decimal('1.0'))

View file

@ -43,6 +43,16 @@ class ConfigTestCase(ModuleTestCase):
self.assertEqual(cfg2.catnamelong, True)
return cfg2
def prep_party(self, name='Party'):
""" new party
"""
Party = Pool().get('party.party')
party, = Party.create([{
'name': name,
'addresses': [('create', [{}])],
}])
return party
@with_transaction()
def test_config_create(self):
""" create config

View file

@ -27,6 +27,7 @@ class LineTestCase(ModuleTestCase):
types = self.prep_type()
category = self.prep_category(cattype='in')
company = self.prep_company()
party = self.prep_party()
book, = Book.create([{
'name': 'Book 1',
'btype': types.id,
@ -38,12 +39,14 @@ class LineTestCase(ModuleTestCase):
'category': category.id,
'bookingtype': 'in',
'amount': Decimal('1.0'),
'party': party.id,
}, {
'date': date(2022, 5, 2),
'description': 'Text 2',
'category': category.id,
'bookingtype': 'in',
'amount': Decimal('1.0'),
'party': party.id,
}])],
}])
self.assertEqual(book.name, 'Book 1')
@ -51,10 +54,10 @@ class LineTestCase(ModuleTestCase):
self.assertEqual(book.state, 'open')
self.assertEqual(len(book.lines), 2)
self.assertEqual(book.lines[0].date, date(2022, 5, 1))
self.assertEqual(book.lines[0].rec_name, '05/01/2022|1.00 usd|Text 1 [Cat1]')
self.assertEqual(book.lines[0].rec_name, '05/01/2022|Rev|1.00 usd|Text 1 [Cat1]')
self.assertEqual(book.lines[0].state_cashbook, 'open')
self.assertEqual(book.lines[1].date, date(2022, 5, 2))
self.assertEqual(book.lines[1].rec_name, '05/02/2022|1.00 usd|Text 2 [Cat1]')
self.assertEqual(book.lines[1].rec_name, '05/02/2022|Rev|1.00 usd|Text 2 [Cat1]')
self.assertEqual(Lines.search_count([('rec_name', '=', 'Text 1')]), 1)
self.assertEqual(Lines.search_count([('rec_name', '=', 'Text 1a')]), 0)
@ -67,9 +70,9 @@ class LineTestCase(ModuleTestCase):
# sorting: date -> state -> id
self.assertEqual(len(book.lines), 2)
self.assertEqual(book.lines[0].rec_name, '05/01/2022|1.00 usd|Text 1 [Cat1]')
self.assertEqual(book.lines[0].rec_name, '05/01/2022|Rev|1.00 usd|Text 1 [Cat1]')
self.assertEqual(book.lines[0].state, 'edit')
self.assertEqual(book.lines[1].rec_name, '05/02/2022|1.00 usd|Text 2 [Cat1]')
self.assertEqual(book.lines[1].rec_name, '05/02/2022|Rev|1.00 usd|Text 2 [Cat1]')
self.assertEqual(book.lines[1].state, 'edit')
# set to same date
@ -80,17 +83,17 @@ class LineTestCase(ModuleTestCase):
}])
# check again
book, = Book.search([])
self.assertEqual(book.lines[0].rec_name, '05/01/2022|1.00 usd|Text 1 [Cat1]')
self.assertEqual(book.lines[0].rec_name, '05/01/2022|Rev|1.00 usd|Text 1 [Cat1]')
self.assertEqual(book.lines[0].state, 'edit')
self.assertEqual(book.lines[1].rec_name, '05/01/2022|1.00 usd|Text 2 [Cat1]')
self.assertEqual(book.lines[1].rec_name, '05/01/2022|Rev|1.00 usd|Text 2 [Cat1]')
self.assertEqual(book.lines[1].state, 'edit')
# set to 'check', will sort first
Lines.wfcheck([book.lines[1]])
book, = Book.search([])
self.assertEqual(book.lines[0].rec_name, '05/01/2022|1.00 usd|Text 2 [Cat1]')
self.assertEqual(book.lines[0].rec_name, '05/01/2022|Rev|1.00 usd|Text 2 [Cat1]')
self.assertEqual(book.lines[0].state, 'check')
self.assertEqual(book.lines[1].rec_name, '05/01/2022|1.00 usd|Text 1 [Cat1]')
self.assertEqual(book.lines[1].rec_name, '05/01/2022|Rev|1.00 usd|Text 1 [Cat1]')
self.assertEqual(book.lines[1].state, 'edit')
@with_transaction()
@ -104,6 +107,7 @@ class LineTestCase(ModuleTestCase):
types = self.prep_type()
category = self.prep_category(cattype='in')
company = self.prep_company()
party = self.prep_party()
book, = Book.create([{
'name': 'Book 1',
'btype': types.id,
@ -115,12 +119,14 @@ class LineTestCase(ModuleTestCase):
'category': category.id,
'bookingtype': 'in',
'amount': Decimal('1.0'),
'party': party.id,
}, {
'date': date(2022, 6, 1),
'description': 'Text 2',
'category': category.id,
'bookingtype': 'in',
'amount': Decimal('1.0'),
'party': party.id,
}])],
}])
self.assertEqual(book.name, 'Book 1')
@ -170,6 +176,7 @@ class LineTestCase(ModuleTestCase):
types = self.prep_type()
category = self.prep_category(cattype='in')
company = self.prep_company()
party = self.prep_party()
IrDate.today = MagicMock(return_value=date(2022, 6, 1))
book, = Book.create([{
@ -183,12 +190,14 @@ class LineTestCase(ModuleTestCase):
'category': category.id,
'bookingtype': 'in',
'amount': Decimal('1.0'),
'party': party.id,
}, {
'date': date(2022, 6, 1),
'description': 'Text 2',
'category': category.id,
'bookingtype': 'in',
'amount': Decimal('1.0'),
'party': party.id,
}])],
}])
self.assertEqual(book.name, 'Book 1')
@ -221,6 +230,135 @@ class LineTestCase(ModuleTestCase):
IrDate.today = MagicMock(return_value=date.today())
@with_transaction()
def test_line_check_bookingtype_mvout(self):
""" create cashbook + line, bookingtype 'mvout'
"""
pool = Pool()
Book = pool.get('cashbook.book')
Line = pool.get('cashbook.line')
Category = pool.get('cashbook.category')
types = self.prep_type()
category_in = self.prep_category(cattype='in')
category_out = self.prep_category(name='Out Category', cattype='out')
company = self.prep_company()
party = self.prep_party()
book2, = Book.create([{
'name': 'Book 2',
'btype': types.id,
'company': company.id,
'currency': company.currency.id,
}])
book, = Book.create([{
'name': 'Book 1',
'btype': types.id,
'company': company.id,
'currency': company.currency.id,
'lines': [('create', [{
'date': date(2022, 5, 1),
'description': 'Transfer Out',
'category': category_out.id,
'bookingtype': 'mvout',
'amount': Decimal('1.0'),
'booktransf': book2.id,
}])],
}])
self.assertEqual(book.rec_name, 'Book 1 | -1.00 usd | Open')
self.assertEqual(len(book.lines), 1)
self.assertEqual(len(book2.lines), 0)
self.assertEqual(book.lines[0].rec_name, '05/01/2022|to|-1.00 usd|Transfer Out [Book 2 | 0.00 usd | Open]')
self.assertEqual(len(book.lines[0].references), 0)
# check payee
self.assertEqual(book.lines[0].payee.rec_name, 'Book 2 | 0.00 usd | Open')
self.assertEqual(Line.search_count([('payee', 'ilike', 'book 2%')]), 1)
# set line to 'checked', this creates the counterpart
Line.wfcheck(list(book.lines))
self.assertEqual(len(book.lines), 1)
self.assertEqual(book.lines[0].rec_name, '05/01/2022|to|-1.00 usd|Transfer Out [Book 2 | 1.00 usd | Open]')
self.assertEqual(book.lines[0].state, 'check')
self.assertEqual(len(book.lines[0].references), 1)
self.assertEqual(book.lines[0].reference, None)
self.assertEqual(book.lines[0].references[0].id, book2.lines[0].id)
self.assertEqual(len(book2.lines), 1)
self.assertEqual(book2.lines[0].rec_name, '05/01/2022|from|1.00 usd|Transfer Out [Book 1 | -1.00 usd | Open]')
self.assertEqual(book2.lines[0].state, 'check')
self.assertEqual(book2.lines[0].reference.rec_name, '05/01/2022|to|-1.00 usd|Transfer Out [Book 2 | 1.00 usd | Open]')
self.assertEqual(len(book2.lines[0].references), 0)
@with_transaction()
def test_line_check_bookingtype_mvin(self):
""" create cashbook + line, bookingtype 'mvin'
"""
pool = Pool()
Book = pool.get('cashbook.book')
Line = pool.get('cashbook.line')
Category = pool.get('cashbook.category')
types = self.prep_type()
category_in = self.prep_category(cattype='in')
category_out = self.prep_category(name='Out Category', cattype='out')
company = self.prep_company()
party = self.prep_party()
book2, = Book.create([{
'name': 'Book 2',
'btype': types.id,
'company': company.id,
'currency': company.currency.id,
}])
book, = Book.create([{
'name': 'Book 1',
'btype': types.id,
'company': company.id,
'currency': company.currency.id,
'lines': [('create', [{
'date': date(2022, 5, 1),
'description': 'Transfer In',
'category': category_in.id,
'bookingtype': 'mvin',
'amount': Decimal('1.0'),
'booktransf': book2.id,
}])],
}])
self.assertEqual(book.rec_name, 'Book 1 | 1.00 usd | Open')
self.assertEqual(len(book.lines), 1)
self.assertEqual(len(book2.lines), 0)
self.assertEqual(book.lines[0].rec_name, '05/01/2022|from|1.00 usd|Transfer In [Book 2 | 0.00 usd | Open]')
self.assertEqual(len(book.lines[0].references), 0)
# set line to 'checked', this creates the counterpart
Line.wfcheck(list(book.lines))
self.assertEqual(len(book.lines), 1)
self.assertEqual(book.lines[0].rec_name, '05/01/2022|from|1.00 usd|Transfer In [Book 2 | -1.00 usd | Open]')
self.assertEqual(book.lines[0].state, 'check')
self.assertEqual(len(book.lines[0].references), 1)
self.assertEqual(book.lines[0].reference, None)
self.assertEqual(book.lines[0].references[0].id, book2.lines[0].id)
self.assertEqual(len(book2.lines), 1)
self.assertEqual(book2.lines[0].rec_name, '05/01/2022|to|-1.00 usd|Transfer In [Book 1 | 1.00 usd | Open]')
self.assertEqual(book2.lines[0].state, 'check')
self.assertEqual(book2.lines[0].reference.rec_name, '05/01/2022|from|1.00 usd|Transfer In [Book 2 | -1.00 usd | Open]')
self.assertEqual(len(book2.lines[0].references), 0)
# tryt wfedit to 'book2.lines[0]'
self.assertRaisesRegex(UserError,
"The current line is managed by the cashbook line '05/01/2022|from|1.00 usd|Transfer In [Book 2 | -1.00 usd | Open]', cashbook: 'Book 1 | 1.00 usd | Open'.",
Line.wfedit,
[book2.lines[0]])
Line.wfedit([book.lines[0]])
self.assertEqual(len(book2.lines), 0)
@with_transaction()
def test_line_create_check_debit_credit(self):
""" create cashbook + line, check calculation of debit/credit
@ -235,6 +373,14 @@ class LineTestCase(ModuleTestCase):
category_in = self.prep_category(cattype='in')
category_out = self.prep_category(name='Out Category', cattype='out')
company = self.prep_company()
party = self.prep_party()
book2, = Book.create([{
'name': 'Book 2',
'btype': types.id,
'company': company.id,
'currency': company.currency.id,
}])
book, = Book.create([{
'name': 'Book 1',
@ -247,24 +393,28 @@ class LineTestCase(ModuleTestCase):
'category': category_in.id,
'bookingtype': 'in',
'amount': Decimal('1.0'),
'party': party.id,
}, {
'date': date(2022, 6, 1),
'description': 'Expense',
'category': category_out.id,
'bookingtype': 'out',
'amount': Decimal('1.0'),
'party': party.id,
}, {
'date': date(2022, 6, 1),
'description': 'Transfer from',
'category': category_in.id,
'bookingtype': 'mvin',
'amount': Decimal('1.0'),
'booktransf': book2.id,
}, {
'date': date(2022, 6, 1),
'description': 'Transfer to',
'category': category_out.id,
'bookingtype': 'mvout',
'amount': Decimal('1.0'),
'booktransf': book2.id,
}])],
}])
self.assertEqual(book.name, 'Book 1')
@ -276,6 +426,11 @@ class LineTestCase(ModuleTestCase):
self.assertEqual(book.lines[0].credit, Decimal('1.0'))
self.assertEqual(book.lines[0].debit, Decimal('0.0'))
# check payee
self.assertEqual(book.lines[0].payee.rec_name, 'Party')
self.assertEqual(Line.search_count([('payee', 'ilike', 'party%')]), 2)
self.assertEqual(Line.search_count([('payee', 'ilike', 'book%')]), 2)
self.assertEqual(book.lines[1].amount, Decimal('1.0'))
self.assertEqual(book.lines[1].bookingtype, 'out')
self.assertEqual(book.lines[1].credit, Decimal('0.0'))
@ -318,6 +473,7 @@ class LineTestCase(ModuleTestCase):
'category': category_in.id,
'bookingtype': 'mvin',
'amount': Decimal('3.0'),
'booktransf': book2.id,
}])
self.assertEqual(book.lines[0].amount, Decimal('3.0'))
self.assertEqual(book.lines[0].bookingtype, 'mvin')
@ -337,6 +493,7 @@ class LineTestCase(ModuleTestCase):
types = self.prep_type()
category = self.prep_category(cattype='in')
company = self.prep_company()
party = self.prep_party()
with Transaction().set_context({
'company': company.id,
@ -370,12 +527,14 @@ class LineTestCase(ModuleTestCase):
'category': category2.id,
'bookingtype': 'in',
'amount': Decimal('1.0'),
'party': party.id,
}, {
'date': date(2022, 6, 1),
'description': 'Text 2',
'category': category2.childs[0].id,
'bookingtype': 'in',
'amount': Decimal('1.0'),
'party': party.id,
}])],
}])
self.assertEqual(book.name, 'Book 1')
@ -407,6 +566,7 @@ class LineTestCase(ModuleTestCase):
types = self.prep_type()
category = self.prep_category(cattype='in')
company = self.prep_company()
party = self.prep_party()
book, = Book.create([{
'name': 'Book 1',
'btype': types.id,
@ -418,12 +578,14 @@ class LineTestCase(ModuleTestCase):
'category': category.id,
'bookingtype': 'in',
'amount': Decimal('1.0'),
'party': party.id,
}, {
'date': date(2022, 5, 2),
'description': 'Text 2',
'category': category.id,
'bookingtype': 'in',
'amount': Decimal('1.0'),
'party': party.id,
}])],
}])
self.assertEqual(book.name, 'Book 1')
@ -443,6 +605,7 @@ class LineTestCase(ModuleTestCase):
types = self.prep_type()
category = self.prep_category(cattype='in')
company = self.prep_company()
party = self.prep_party()
book, = Book.create([{
'name': 'Book 1',
'btype': types.id,
@ -454,12 +617,14 @@ class LineTestCase(ModuleTestCase):
'category': category.id,
'bookingtype': 'in',
'amount': Decimal('1.0'),
'party': party.id,
}, {
'date': date(2022, 5, 2),
'description': 'Text 2',
'category': category.id,
'bookingtype': 'in',
'amount': Decimal('1.0'),
'party': party.id,
}])],
}])
self.assertEqual(book.name, 'Book 1')
@ -484,6 +649,7 @@ class LineTestCase(ModuleTestCase):
types = self.prep_type()
category = self.prep_category(cattype='in')
company = self.prep_company()
party = self.prep_party()
book, = Book.create([{
'name': 'Book 1',
'btype': types.id,
@ -495,12 +661,14 @@ class LineTestCase(ModuleTestCase):
'category': category.id,
'bookingtype': 'in',
'amount': Decimal('1.0'),
'party': party.id,
}, {
'date': date(2022, 5, 2),
'description': 'Text 2',
'category': category.id,
'bookingtype': 'in',
'amount': Decimal('1.0'),
'party': party.id,
}])],
}])
self.assertEqual(book.name, 'Book 1')
@ -529,6 +697,7 @@ class LineTestCase(ModuleTestCase):
types = self.prep_type()
category = self.prep_category(cattype='in')
company = self.prep_company()
party = self.prep_party()
grp_cashbook, = ResGroup.search([('name', '=', 'Cashbook')])
usr_lst = ResUser.create([{
'login': 'frida',
@ -559,6 +728,7 @@ class LineTestCase(ModuleTestCase):
'category': category.id,
'bookingtype': 'in',
'amount': Decimal('1.0'),
'party': party.id,
}])],
}])
self.assertEqual(book.rec_name, 'Fridas book | 1.00 usd | Open'),
@ -577,14 +747,15 @@ class LineTestCase(ModuleTestCase):
lines = Line.search([])
self.assertEqual(len(lines), 1)
self.assertEqual(lines[0].cashbook.rec_name, 'Fridas book | 1.00 usd | Open')
self.assertEqual(lines[0].rec_name, '05/01/2022|1.00 usd|Test 1 [Cat1]')
self.assertEqual(lines[0].rec_name, '05/01/2022|Rev|1.00 usd|Test 1 [Cat1]')
Line.write(*[
lines,
{
'description': 'Test 2',
}])
self.assertEqual(lines[0].rec_name, '05/01/2022|1.00 usd|Test 2 [Cat1]')
self.assertEqual(lines[0].rec_name, '05/01/2022|Rev|1.00 usd|Test 2 [Cat1]')
self.assertEqual(lines[0].owner_cashbook.rec_name, 'Frida')
@with_transaction()
def test_line_permission_reviewer(self):
@ -599,6 +770,7 @@ class LineTestCase(ModuleTestCase):
types = self.prep_type()
category = self.prep_category(cattype='in')
company = self.prep_company()
party = self.prep_party()
grp_cashbook, = ResGroup.search([('name', '=', 'Cashbook')])
grp_reviewer, = ResGroup.create([{
'name': 'Cashbook Reviewer',
@ -636,6 +808,7 @@ class LineTestCase(ModuleTestCase):
'category': category.id,
'bookingtype': 'in',
'amount': Decimal('1.0'),
'party': party.id,
}])],
}])
self.assertEqual(book.rec_name, 'Fridas book | 1.00 usd | Open'),
@ -650,25 +823,25 @@ class LineTestCase(ModuleTestCase):
self.assertEqual(len(lines), 1)
self.assertEqual(len(lines[0].cashbook.reviewer.users), 1)
self.assertEqual(lines[0].cashbook.reviewer.users[0].rec_name, 'Diego')
self.assertEqual(lines[0].rec_name, '05/01/2022|1.00 usd|Test 1 [Cat1]')
self.assertEqual(lines[0].rec_name, '05/01/2022|Rev|1.00 usd|Test 1 [Cat1]')
Line.write(*[
lines,
{
'description': 'Test 2',
}])
self.assertEqual(lines[0].rec_name, '05/01/2022|1.00 usd|Test 2 [Cat1]')
self.assertEqual(lines[0].rec_name, '05/01/2022|Rev|1.00 usd|Test 2 [Cat1]')
# change to user 'frida' read/write line
with Transaction().set_user(usr_lst[0].id):
lines = Line.search([])
self.assertEqual(len(lines), 1)
self.assertEqual(lines[0].rec_name, '05/01/2022|1.00 usd|Test 2 [Cat1]')
self.assertEqual(lines[0].rec_name, '05/01/2022|Rev|1.00 usd|Test 2 [Cat1]')
Line.write(*[
lines,
{
'description': 'Test 3',
}])
self.assertEqual(lines[0].rec_name, '05/01/2022|1.00 usd|Test 3 [Cat1]')
self.assertEqual(lines[0].rec_name, '05/01/2022|Rev|1.00 usd|Test 3 [Cat1]')
@with_transaction()
def test_line_permission_observer(self):
@ -683,6 +856,7 @@ class LineTestCase(ModuleTestCase):
types = self.prep_type()
category = self.prep_category(cattype='in')
company = self.prep_company()
party = self.prep_party()
grp_cashbook, = ResGroup.search([('name', '=', 'Cashbook')])
grp_observer, = ResGroup.create([{
'name': 'Cashbook Observer',
@ -720,6 +894,7 @@ class LineTestCase(ModuleTestCase):
'category': category.id,
'bookingtype': 'in',
'amount': Decimal('1.0'),
'party': party.id,
}])],
}])
self.assertEqual(book.rec_name, 'Fridas book | 1.00 usd | Open'),
@ -734,7 +909,7 @@ class LineTestCase(ModuleTestCase):
self.assertEqual(len(lines), 1)
self.assertEqual(len(lines[0].cashbook.observer.users), 1)
self.assertEqual(lines[0].cashbook.observer.users[0].rec_name, 'Diego')
self.assertEqual(lines[0].rec_name, '05/01/2022|1.00 usd|Test 1 [Cat1]')
self.assertEqual(lines[0].rec_name, '05/01/2022|Rev|1.00 usd|Test 1 [Cat1]')
self.assertRaisesRegex(UserError,
'You are not allowed to write to records "[0-9]{1,}" of "Cashbook Line" because of at least one of these rules:\nOwners and reviewers: Cashbook line write - ',
@ -750,12 +925,12 @@ class LineTestCase(ModuleTestCase):
with Transaction().set_user(usr_lst[0].id):
lines = Line.search([])
self.assertEqual(len(lines), 1)
self.assertEqual(lines[0].rec_name, '05/01/2022|1.00 usd|Test 1 [Cat1]')
self.assertEqual(lines[0].rec_name, '05/01/2022|Rev|1.00 usd|Test 1 [Cat1]')
Line.write(*[
lines,
{
'description': 'Test 2',
}])
self.assertEqual(lines[0].rec_name, '05/01/2022|1.00 usd|Test 2 [Cat1]')
self.assertEqual(lines[0].rec_name, '05/01/2022|Rev|1.00 usd|Test 2 [Cat1]')
# end LineTestCase

View file

@ -202,6 +202,7 @@ class ReconTestCase(ModuleTestCase):
types = self.prep_type()
company = self.prep_company()
category = self.prep_category(cattype='in')
party = self.prep_party()
book, = Book.create([{
'name': 'Book 1',
'btype': types.id,
@ -219,12 +220,14 @@ class ReconTestCase(ModuleTestCase):
'category': category.id,
'description': 'Line 1',
'amount': Decimal('5.0'),
'party': party.id,
}, {
'date': date(2022, 5, 5),
'bookingtype': 'in',
'category': category.id,
'description': 'Line 2',
'amount': Decimal('7.0'),
'party': party.id,
'amount': Decimal('7.0'),
},])],
}])
self.assertEqual(book.name, 'Book 1')
@ -344,6 +347,7 @@ class ReconTestCase(ModuleTestCase):
types = self.prep_type()
category = self.prep_category(cattype='in')
company = self.prep_company()
party = self.prep_party()
book, = Book.create([{
'name': 'Book 1',
'btype': types.id,
@ -355,12 +359,14 @@ class ReconTestCase(ModuleTestCase):
'category': category.id,
'bookingtype': 'in',
'amount': Decimal('1.0'),
'party': party.id,
}, {
'date': date(2022, 5, 5),
'description': 'Text 2',
'category': category.id,
'bookingtype': 'in',
'amount': Decimal('1.0'),
'party': party.id,
}])],
'reconciliations': [('create', [{
'date': date(2022, 5, 28),
@ -371,14 +377,14 @@ class ReconTestCase(ModuleTestCase):
self.assertEqual(book.name, 'Book 1')
self.assertEqual(book.state, 'open')
self.assertEqual(len(book.lines), 2)
self.assertEqual(book.lines[0].rec_name, '05/01/2022|1.00 usd|Text 1 [Cat1]')
self.assertEqual(book.lines[1].rec_name, '05/05/2022|1.00 usd|Text 2 [Cat1]')
self.assertEqual(book.lines[0].rec_name, '05/01/2022|Rev|1.00 usd|Text 1 [Cat1]')
self.assertEqual(book.lines[1].rec_name, '05/05/2022|Rev|1.00 usd|Text 2 [Cat1]')
self.assertEqual(len(book.reconciliations), 1)
self.assertEqual(book.reconciliations[0].rec_name, '05/01/2022 - 05/31/2022 | 0.00 usd - 0.00 usd [0]')
self.assertEqual(len(book.reconciliations[0].lines), 0)
self.assertRaisesRegex(UserError,
"For reconciliation, the line '05/01/2022|1.00 usd|Text 1 [Cat1]' must be in the status 'Check' or 'Done'.",
"For reconciliation, the line '05/01/2022|Rev|1.00 usd|Text 1 [Cat1]' must be in the status 'Check' or 'Done'.",
Lines.write,
*[
[book.lines[0]],
@ -420,9 +426,9 @@ class ReconTestCase(ModuleTestCase):
Reconciliation.wfcheck(list(book.reconciliations))
self.assertEqual(book.reconciliations[0].state, 'check')
self.assertEqual(len(book.reconciliations[0].lines), 1)
self.assertEqual(book.reconciliations[0].lines[0].rec_name, '05/01/2022|1.00 usd|Text 1 [Cat1]')
self.assertEqual(book.lines[0].rec_name, '05/01/2022|1.00 usd|Text 1 [Cat1]')
self.assertEqual(book.lines[1].rec_name, '06/01/2022|1.00 usd|Text 2 [Cat1]')
self.assertEqual(book.reconciliations[0].lines[0].rec_name, '05/01/2022|Rev|1.00 usd|Text 1 [Cat1]')
self.assertEqual(book.lines[0].rec_name, '05/01/2022|Rev|1.00 usd|Text 1 [Cat1]')
self.assertEqual(book.lines[1].rec_name, '06/01/2022|Rev|1.00 usd|Text 2 [Cat1]')
# move 2nd line into date-range of checked-reconciliation, wf-check
Lines.write(*[
@ -481,6 +487,7 @@ class ReconTestCase(ModuleTestCase):
types = self.prep_type()
category = self.prep_category(cattype='in')
company = self.prep_company()
party = self.prep_party()
book, = Book.create([{
'name': 'Book 1',
'btype': types.id,
@ -492,12 +499,14 @@ class ReconTestCase(ModuleTestCase):
'category': category.id,
'bookingtype': 'in',
'amount': Decimal('1.0'),
'party': party.id,
}, {
'date': date(2022, 6, 5),
'description': 'Text 2',
'category': category.id,
'bookingtype': 'in',
'amount': Decimal('1.0'),
'party': party.id,
}])],
'reconciliations': [('create', [{
'date': date(2022, 5, 28),
@ -508,13 +517,13 @@ class ReconTestCase(ModuleTestCase):
self.assertEqual(book.name, 'Book 1')
self.assertEqual(book.state, 'open')
self.assertEqual(len(book.lines), 2)
self.assertEqual(book.lines[0].rec_name, '05/01/2022|1.00 usd|Text 1 [Cat1]')
self.assertEqual(book.lines[1].rec_name, '06/05/2022|1.00 usd|Text 2 [Cat1]')
self.assertEqual(book.lines[0].rec_name, '05/01/2022|Rev|1.00 usd|Text 1 [Cat1]')
self.assertEqual(book.lines[1].rec_name, '06/05/2022|Rev|1.00 usd|Text 2 [Cat1]')
Lines.wfcheck([book.lines[0]])
Reconciliation.wfcheck([book.reconciliations[0]])
self.assertEqual(len(book.reconciliations[0].lines), 1)
self.assertEqual(book.reconciliations[0].lines[0].rec_name, '05/01/2022|1.00 usd|Text 1 [Cat1]')
self.assertEqual(book.reconciliations[0].lines[0].rec_name, '05/01/2022|Rev|1.00 usd|Text 1 [Cat1]')
Lines.write(*[
[book.lines[1]],
@ -539,6 +548,7 @@ class ReconTestCase(ModuleTestCase):
types = self.prep_type()
category = self.prep_category(cattype='in')
company = self.prep_company()
party = self.prep_party()
book, = Book.create([{
'name': 'Book 1',
'btype': types.id,
@ -550,6 +560,7 @@ class ReconTestCase(ModuleTestCase):
'category': category.id,
'bookingtype': 'in',
'amount': Decimal('1.0'),
'party': party.id,
}])],
'reconciliations': [('create', [{
'date': date(2022, 5, 28),
@ -599,6 +610,7 @@ class ReconTestCase(ModuleTestCase):
types = self.prep_type()
category = self.prep_category(cattype='in')
company = self.prep_company()
party = self.prep_party()
book, = Book.create([{
'name': 'Book 1',
'btype': types.id,
@ -610,12 +622,14 @@ class ReconTestCase(ModuleTestCase):
'category': category.id,
'bookingtype': 'in',
'amount': Decimal('1.0'),
'party': party.id,
}, {
'date': date(2022, 5, 5),
'description': 'Text 2',
'category': category.id,
'bookingtype': 'in',
'amount': Decimal('1.0'),
'party': party.id,
}])],
'reconciliations': [('create', [{
'date': date(2022, 5, 28),
@ -626,8 +640,8 @@ class ReconTestCase(ModuleTestCase):
self.assertEqual(book.name, 'Book 1')
self.assertEqual(book.state, 'open')
self.assertEqual(len(book.lines), 2)
self.assertEqual(book.lines[0].rec_name, '05/01/2022|1.00 usd|Text 1 [Cat1]')
self.assertEqual(book.lines[1].rec_name, '05/05/2022|1.00 usd|Text 2 [Cat1]')
self.assertEqual(book.lines[0].rec_name, '05/01/2022|Rev|1.00 usd|Text 1 [Cat1]')
self.assertEqual(book.lines[1].rec_name, '05/05/2022|Rev|1.00 usd|Text 2 [Cat1]')
self.assertEqual(book.lines[0].reconciliation, None)
self.assertEqual(book.lines[1].reconciliation, None)
self.assertEqual(len(book.reconciliations), 1)

View file

@ -35,4 +35,13 @@ full copyright notices and license terms. -->
<group name="description" colspan="4" col="1" string="Description">
<field name="description"/>
</group>
<newline/>
<label name="reference"/>
<field name="reference"/>
<newline/>
<field name="references" colspan="4"/>
<newline/>
<field name="owner_cashbook"/>
</form>

View file

@ -5,8 +5,7 @@ full copyright notices and license terms. -->
<tree>
<field name="cashbook" tree_invisible="1"/>
<field name="date"/>
<field name="party"/>
<field name="booktransf"/>
<field name="payee"/>
<field name="category_view"/>
<field name="description" expand="1"/>
<field name="credit" sum="Credit"/>