line: datumsbereich prüfen + test,
abstimmung: vorgänger beachten + test line: party/transfer-book + test muß noch
This commit is contained in:
parent
7a07da852d
commit
30b91cf518
8 changed files with 465 additions and 28 deletions
48
line.py
48
line.py
|
@ -77,6 +77,23 @@ class Line(Workflow, ModelSQL, ModelView):
|
||||||
required=True, readonly=True, depends=['currency_digits'])
|
required=True, readonly=True, depends=['currency_digits'])
|
||||||
credit = fields.Numeric(string='Credit', digits=(16, Eval('currency_digits', 2)),
|
credit = fields.Numeric(string='Credit', digits=(16, Eval('currency_digits', 2)),
|
||||||
required=True, readonly=True, depends=['currency_digits'])
|
required=True, readonly=True, depends=['currency_digits'])
|
||||||
|
|
||||||
|
booktransf = fields.Many2One(string='Transfer Cashbook',
|
||||||
|
ondelete='RESTRICT', model_name='cashbook.book',
|
||||||
|
domain=[('cashbook.owner.id', '=', Eval('context',{}).get('user', -1))],
|
||||||
|
states={
|
||||||
|
'readonly': STATES['readonly'],
|
||||||
|
'invisible': ~Eval('bookingtype', '').in_(['mvin', 'mvout']),
|
||||||
|
'required': Eval('bookingtype', '').in_(['mvin', 'mvout']),
|
||||||
|
}, depends=DEPENDS+['bookingtype'])
|
||||||
|
party = fields.Many2One(string='Party', model_name='party.party',
|
||||||
|
ondelete='RESTRICT',
|
||||||
|
states={
|
||||||
|
'readonly': STATES['readonly'],
|
||||||
|
'invisible': ~Eval('bookingtype', '').in_(['in', 'out']),
|
||||||
|
'required': Eval('bookingtype', '').in_(['in', 'out']),
|
||||||
|
}, depends=DEPENDS+['bookingtype'])
|
||||||
|
|
||||||
reconciliation = fields.Many2One(string='Reconciliation', readonly=True,
|
reconciliation = fields.Many2One(string='Reconciliation', readonly=True,
|
||||||
model_name='cashbook.recon', ondelete='SET NULL',
|
model_name='cashbook.recon', ondelete='SET NULL',
|
||||||
domain=[('cashbook.id', '=', Eval('cashbook'))],
|
domain=[('cashbook.id', '=', Eval('cashbook'))],
|
||||||
|
@ -147,7 +164,36 @@ class Line(Workflow, ModelSQL, ModelView):
|
||||||
def wfcheck(cls, lines):
|
def wfcheck(cls, lines):
|
||||||
""" line is checked
|
""" line is checked
|
||||||
"""
|
"""
|
||||||
pass
|
pool = Pool()
|
||||||
|
Recon = pool.get('cashbook.recon')
|
||||||
|
|
||||||
|
for line in lines:
|
||||||
|
# deny if date is in range of existing reconciliation
|
||||||
|
# allow cashbook-line at range-limits
|
||||||
|
if Recon.search_count([
|
||||||
|
('state', 'in', ['check', 'done']),
|
||||||
|
('cashbook.id', '=', line.cashbook.id),
|
||||||
|
('date_from', '<', line.date),
|
||||||
|
('date_to', '>', line.date),
|
||||||
|
]) > 0:
|
||||||
|
raise UserError(gettext(
|
||||||
|
'cashbook.msg_line_err_write_to_reconciled',
|
||||||
|
datetxt = Report.format_date(line.date),
|
||||||
|
))
|
||||||
|
# deny if date is at reconciliation limits and two
|
||||||
|
# reconciliations exist
|
||||||
|
if Recon.search_count([
|
||||||
|
('state', 'in', ['check', 'done']),
|
||||||
|
('cashbook.id', '=', line.cashbook.id),
|
||||||
|
['OR',
|
||||||
|
('date_from', '=', line.date),
|
||||||
|
('date_to', '=', line.date),
|
||||||
|
]
|
||||||
|
]) > 1:
|
||||||
|
raise UserError(gettext(
|
||||||
|
'cashbook.msg_line_err_write_to_reconciled',
|
||||||
|
datetxt = Report.format_date(line.date),
|
||||||
|
))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ModelView.button
|
@ModelView.button
|
||||||
|
|
28
locale/de.po
28
locale/de.po
|
@ -39,8 +39,8 @@ msgid "The cashbook line '%(linetxt)s' cannot be deleted, its in state '%(linest
|
||||||
msgstr "Die Kassenbuchzeile '%(linetxt)s' kann nicht gelöscht werden, da sie im Status '%(linestate)s' ist."
|
msgstr "Die Kassenbuchzeile '%(linetxt)s' kann nicht gelöscht werden, da sie im Status '%(linestate)s' ist."
|
||||||
|
|
||||||
msgctxt "model:ir.message,text:msg_line_deny_stateedit_with_recon"
|
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."
|
msgid "The status cannot be changed to 'Edit' while the line '%(recname)s' is associated with a reconciliation."
|
||||||
msgstr "Der Status kann nicht in 'Bearbeiten' geändert werden, solange die Zeile '%(recname)s' mit einer Abstimmung verbunden ist."
|
msgstr "Der Status kann nicht in 'Bearbeiten' geändert werden, während die Zeile '%(recname)s' mit einer Abstimmung verbunden ist."
|
||||||
|
|
||||||
msgctxt "model:ir.message,text:msg_line_deny_write"
|
msgctxt "model:ir.message,text:msg_line_deny_write"
|
||||||
msgid "The cashbook line '%(recname)s' is '%(state_txt)s' and cannot be changed."
|
msgid "The cashbook line '%(recname)s' is '%(state_txt)s' and cannot be changed."
|
||||||
|
@ -86,6 +86,22 @@ msgctxt "model:ir.message,text:msg_recon_err_overlap"
|
||||||
msgid "The date range overlaps with another reconciliation."
|
msgid "The date range overlaps with another reconciliation."
|
||||||
msgstr "Der Datumsbereich überschneidet sich mit einer anderen Abstimmung."
|
msgstr "Der Datumsbereich überschneidet sich mit einer anderen Abstimmung."
|
||||||
|
|
||||||
|
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 "Für das Datum '%(datetxt)s' gibt es bereits eine abgeschlossene Abstimmung. Verwenden Sie ein anderes Datum."
|
||||||
|
|
||||||
|
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 "Im Datumsbereich von %(date_from)s bis %(date_to)s existieren noch Kassenbuchzeilen, die zu keiner Abstimmung gehören."
|
||||||
|
|
||||||
|
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 "Das Anfangsdatum '%(datefrom)s' der aktuellen Abstimmung '%(recname)s' muß dem Endedatum '%(dateto)s' des Vorgängers entsprechen."
|
||||||
|
|
||||||
|
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."
|
||||||
|
|
||||||
|
|
||||||
#############
|
#############
|
||||||
# res.group #
|
# res.group #
|
||||||
|
@ -474,6 +490,10 @@ msgctxt "field:cashbook.line,reconciliation:"
|
||||||
msgid "Reconciliation"
|
msgid "Reconciliation"
|
||||||
msgstr "Abstimmung"
|
msgstr "Abstimmung"
|
||||||
|
|
||||||
|
msgctxt "field:cashbook.line,party:"
|
||||||
|
msgid "Party"
|
||||||
|
msgstr "Partei"
|
||||||
|
|
||||||
|
|
||||||
#################
|
#################
|
||||||
# cashbook.type #
|
# cashbook.type #
|
||||||
|
@ -809,3 +829,7 @@ msgstr "Anfangsbetrag"
|
||||||
msgctxt "field:cashbook.recon,end_amount:"
|
msgctxt "field:cashbook.recon,end_amount:"
|
||||||
msgid "End Amount"
|
msgid "End Amount"
|
||||||
msgstr "Endbetrag"
|
msgstr "Endbetrag"
|
||||||
|
|
||||||
|
msgctxt "field:cashbook.recon,predecessor:"
|
||||||
|
msgid "Predecessor"
|
||||||
|
msgstr "Vorgänger"
|
||||||
|
|
14
message.xml
14
message.xml
|
@ -33,7 +33,7 @@ full copyright notices and license terms. -->
|
||||||
<field name="text">The cashbook line '%(recname)s' is '%(state_txt)s' and cannot be changed.</field>
|
<field name="text">The cashbook line '%(recname)s' is '%(state_txt)s' and cannot be changed.</field>
|
||||||
</record>
|
</record>
|
||||||
<record model="ir.message" id="msg_line_deny_stateedit_with_recon">
|
<record model="ir.message" id="msg_line_deny_stateedit_with_recon">
|
||||||
<field name="text">The status cannot be changed to 'Edit' as long as the line '%(recname)s' is associated with a reconciliation.</field>
|
<field name="text">The status cannot be changed to 'Edit' while the line '%(recname)s' is associated with a reconciliation.</field>
|
||||||
</record>
|
</record>
|
||||||
<record model="ir.message" id="msg_recon_deny_delete1">
|
<record model="ir.message" id="msg_recon_deny_delete1">
|
||||||
<field name="text">The reconciliation '%(recontxt)s' cannot be deleted because the Cashbook '%(bookname)s' is in state '%(bookstate)s'.</field>
|
<field name="text">The reconciliation '%(recontxt)s' cannot be deleted because the Cashbook '%(bookname)s' is in state '%(bookstate)s'.</field>
|
||||||
|
@ -65,6 +65,18 @@ full copyright notices and license terms. -->
|
||||||
<record model="ir.message" id="msg_recon_err_overlap">
|
<record model="ir.message" id="msg_recon_err_overlap">
|
||||||
<field name="text">The date range overlaps with another reconciliation.</field>
|
<field name="text">The date range overlaps with another reconciliation.</field>
|
||||||
</record>
|
</record>
|
||||||
|
<record model="ir.message" id="msg_line_err_write_to_reconciled">
|
||||||
|
<field name="text">For the date '%(datetxt)s' there is already a completed reconciliation. Use a different date.</field>
|
||||||
|
</record>
|
||||||
|
<record model="ir.message" id="msg_recon_lines_no_linked">
|
||||||
|
<field name="text">In the date range from %(date_from)s to %(date_to)s, there are still cashbook lines that do not belong to any reconciliation.</field>
|
||||||
|
</record>
|
||||||
|
<record model="ir.message" id="msg_recon_date_from_to_mismatch">
|
||||||
|
<field name="text">The start date '%(datefrom)s' of the current reconciliation '%(recname)s' must correspond to the end date '%(dateto)s' of the predecessor.</field>
|
||||||
|
</record>
|
||||||
|
<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>
|
||||||
|
|
||||||
</data>
|
</data>
|
||||||
</tryton>
|
</tryton>
|
||||||
|
|
|
@ -81,6 +81,9 @@ class Reconciliation(Workflow, ModelSQL, ModelView):
|
||||||
string="Currency"), 'on_change_with_currency')
|
string="Currency"), 'on_change_with_currency')
|
||||||
currency_digits = fields.Function(fields.Integer(string='Currency Digits'),
|
currency_digits = fields.Function(fields.Integer(string='Currency Digits'),
|
||||||
'on_change_with_currency_digits')
|
'on_change_with_currency_digits')
|
||||||
|
predecessor = fields.Function(fields.Many2One(string='Predecessor', readonly=True,
|
||||||
|
model_name='cashbook.recon'),
|
||||||
|
'on_change_with_predecessor')
|
||||||
|
|
||||||
state = fields.Selection(string='State', required=True, readonly=True,
|
state = fields.Selection(string='State', required=True, readonly=True,
|
||||||
select=True, selection=sel_reconstate)
|
select=True, selection=sel_reconstate)
|
||||||
|
@ -207,16 +210,25 @@ class Reconciliation(Workflow, ModelSQL, ModelView):
|
||||||
for reconciliation in reconciliations:
|
for reconciliation in reconciliations:
|
||||||
values = {}
|
values = {}
|
||||||
|
|
||||||
# get start_amount: end_amount of predecessor
|
if reconciliation.predecessor:
|
||||||
pre_recon = Recon.search([
|
# predecessor must be 'done'
|
||||||
('cashbook.id', '=', reconciliation.cashbook.id),
|
if reconciliation.predecessor.state != 'done':
|
||||||
('date_to', '<=', reconciliation.date_from),
|
raise UserError(gettext(
|
||||||
('state', 'in', ['check', 'done']),
|
'cashbook.msg_recon_predecessor_not_done',
|
||||||
], order=[('date_to', 'DESC')], limit=1)
|
recname_p = reconciliation.predecessor.rec_name,
|
||||||
if len(pre_recon) > 0:
|
recname_c = reconciliation.rec_name,
|
||||||
values['start_amount'] = pre_recon[0].end_amount
|
))
|
||||||
|
|
||||||
|
# check if current.date_from == predecessor.date_to
|
||||||
|
if reconciliation.predecessor.date_to != reconciliation.date_from:
|
||||||
|
raise UserError(gettext(
|
||||||
|
'cashbook.msg_recon_date_from_to_mismatch',
|
||||||
|
datefrom = Report.format_date(reconciliation.date_from),
|
||||||
|
dateto = Report.format_date(reconciliation.predecessor.date_to),
|
||||||
|
recname = reconciliation.rec_name,
|
||||||
|
))
|
||||||
|
values['start_amount'] = reconciliation.predecessor.end_amount
|
||||||
else :
|
else :
|
||||||
# not found, use 'start_balance' of cashbook
|
|
||||||
values['start_amount'] = reconciliation.cashbook.start_balance
|
values['start_amount'] = reconciliation.cashbook.start_balance
|
||||||
values['end_amount'] = values['start_amount']
|
values['end_amount'] = values['start_amount']
|
||||||
|
|
||||||
|
@ -253,13 +265,32 @@ class Reconciliation(Workflow, ModelSQL, ModelView):
|
||||||
for reconciliation in reconciliations:
|
for reconciliation in reconciliations:
|
||||||
to_wfdone_line.extend(list(reconciliation.lines))
|
to_wfdone_line.extend(list(reconciliation.lines))
|
||||||
|
|
||||||
|
# deny if there are lines not linked to reconciliation
|
||||||
|
if Line.search_count([
|
||||||
|
('cashbook.id', '=', reconciliation.cashbook.id),
|
||||||
|
('reconciliation', '=', None),
|
||||||
|
['OR',
|
||||||
|
[ # lines inside of date-range
|
||||||
|
('date', '>', reconciliation.date_from),
|
||||||
|
('date', '<', reconciliation.date_to),
|
||||||
|
],
|
||||||
|
# lines at from-date must relate to a reconciliation
|
||||||
|
('date', '=', reconciliation.date_from),
|
||||||
|
],
|
||||||
|
]) > 0:
|
||||||
|
raise UserError(gettext(
|
||||||
|
'cashbook.msg_recon_lines_no_linked',
|
||||||
|
date_from = Report.format_date(reconciliation.date_from),
|
||||||
|
date_to = Report.format_date(reconciliation.date_to),
|
||||||
|
))
|
||||||
|
|
||||||
if len(to_wfdone_line) > 0:
|
if len(to_wfdone_line) > 0:
|
||||||
Line.wfdone(to_wfdone_line)
|
Line.wfdone(to_wfdone_line)
|
||||||
|
|
||||||
def get_rec_name(self, name):
|
def get_rec_name(self, name):
|
||||||
""" short + name
|
""" short + name
|
||||||
"""
|
"""
|
||||||
return '%(from)s - %(to)s | %(start_amount)s %(symbol)s - %(start_amount)s %(symbol)s [%(num)s]' % {
|
return '%(from)s - %(to)s | %(start_amount)s %(symbol)s - %(end_amount)s %(symbol)s [%(num)s]' % {
|
||||||
'from': Report.format_date(self.date_from, None) if self.date_from is not None else '-',
|
'from': Report.format_date(self.date_from, None) if self.date_from is not None else '-',
|
||||||
'to': Report.format_date(self.date_to, None) if self.date_to is not None else '-',
|
'to': Report.format_date(self.date_to, None) if self.date_to is not None else '-',
|
||||||
'start_amount': Report.format_number(self.start_amount or 0.0, None),
|
'start_amount': Report.format_number(self.start_amount or 0.0, None),
|
||||||
|
@ -287,6 +318,21 @@ class Reconciliation(Workflow, ModelSQL, ModelView):
|
||||||
IrDate = Pool().get('ir.date')
|
IrDate = Pool().get('ir.date')
|
||||||
return IrDate.today()
|
return IrDate.today()
|
||||||
|
|
||||||
|
@fields.depends('cashbook', '_parent_cashbook.id', 'date_from')
|
||||||
|
def on_change_with_predecessor(self, name=None):
|
||||||
|
""" get predecessor
|
||||||
|
"""
|
||||||
|
Recon = Pool().get('cashbook.recon')
|
||||||
|
|
||||||
|
if self.cashbook:
|
||||||
|
if self.date_from is not None:
|
||||||
|
reconciliations = Recon.search([
|
||||||
|
('cashbook.id', '=', self.cashbook.id),
|
||||||
|
('date_from', '<', self.date_from),
|
||||||
|
], order=[('date_from', 'DESC')], limit=1)
|
||||||
|
if len(reconciliations) > 0:
|
||||||
|
return reconciliations[0].id
|
||||||
|
|
||||||
@fields.depends('cashbook', '_parent_cashbook.currency')
|
@fields.depends('cashbook', '_parent_cashbook.currency')
|
||||||
def on_change_with_currency(self, name=None):
|
def on_change_with_currency(self, name=None):
|
||||||
""" currency of cashbook
|
""" currency of cashbook
|
||||||
|
@ -314,7 +360,16 @@ class Reconciliation(Workflow, ModelSQL, ModelView):
|
||||||
def create(cls, vlist):
|
def create(cls, vlist):
|
||||||
""" add debit/credit
|
""" add debit/credit
|
||||||
"""
|
"""
|
||||||
|
Recon = Pool().get('cashbook.recon')
|
||||||
|
|
||||||
for values in vlist:
|
for values in vlist:
|
||||||
|
# set date_from date_to of predecessor
|
||||||
|
recons = Recon.search([
|
||||||
|
('cashbook.id', '=', values.get('cashbook', -1)),
|
||||||
|
], order=[('date_to', 'DESC')], limit=1)
|
||||||
|
if len(recons) > 0:
|
||||||
|
values['date_from'] = recons[0].date_to
|
||||||
|
|
||||||
cls.check_overlap_dates(
|
cls.check_overlap_dates(
|
||||||
values.get('date_from', None),
|
values.get('date_from', None),
|
||||||
values.get('date_to', None),
|
values.get('date_to', None),
|
||||||
|
|
|
@ -47,15 +47,10 @@ class ReconTestCase(ModuleTestCase):
|
||||||
'date_to': date(2022, 6, 30),
|
'date_to': date(2022, 6, 30),
|
||||||
'cashbook': book.id,
|
'cashbook': book.id,
|
||||||
}])
|
}])
|
||||||
self.assertEqual(recon2.rec_name, '06/01/2022 - 06/30/2022 | 0.00 usd - 0.00 usd [0]')
|
# updated by create to date_to of predecessor
|
||||||
|
self.assertEqual(recon2.rec_name, '05/31/2022 - 06/30/2022 | 0.00 usd - 0.00 usd [0]')
|
||||||
|
|
||||||
# same day for end of '0' and start of '1'
|
# same day for end of '0' and start of '1'
|
||||||
Reconciliation.write(*[
|
|
||||||
[recon2],
|
|
||||||
{
|
|
||||||
'date_from': date(2022, 5, 31),
|
|
||||||
},
|
|
||||||
])
|
|
||||||
self.assertEqual(recon1.rec_name, '05/01/2022 - 05/31/2022 | 0.00 usd - 0.00 usd [0]')
|
self.assertEqual(recon1.rec_name, '05/01/2022 - 05/31/2022 | 0.00 usd - 0.00 usd [0]')
|
||||||
self.assertEqual(recon2.rec_name, '05/31/2022 - 06/30/2022 | 0.00 usd - 0.00 usd [0]')
|
self.assertEqual(recon2.rec_name, '05/31/2022 - 06/30/2022 | 0.00 usd - 0.00 usd [0]')
|
||||||
|
|
||||||
|
@ -146,7 +141,7 @@ class ReconTestCase(ModuleTestCase):
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
|
|
||||||
# overlap at create
|
# overlap at .create()
|
||||||
self.assertRaisesRegex(UserError,
|
self.assertRaisesRegex(UserError,
|
||||||
'The date range overlaps with another reconciliation.',
|
'The date range overlaps with another reconciliation.',
|
||||||
Reconciliation.create,
|
Reconciliation.create,
|
||||||
|
@ -159,13 +154,183 @@ class ReconTestCase(ModuleTestCase):
|
||||||
|
|
||||||
recon3, = Reconciliation.create([{
|
recon3, = Reconciliation.create([{
|
||||||
'date': date(2022, 4, 17),
|
'date': date(2022, 4, 17),
|
||||||
'date_from': date(2022, 4, 1),
|
'date_from': date(2022, 6, 1),
|
||||||
'date_to': date(2022, 4, 15),
|
'date_to': date(2022, 6, 15),
|
||||||
'cashbook': book.id,
|
'cashbook': book.id,
|
||||||
}])
|
}])
|
||||||
self.assertEqual(recon1.rec_name, '05/01/2022 - 05/31/2022 | 0.00 usd - 0.00 usd [0]')
|
self.assertEqual(recon1.rec_name, '05/01/2022 - 05/31/2022 | 0.00 usd - 0.00 usd [0]')
|
||||||
self.assertEqual(recon2.rec_name, '04/15/2022 - 05/01/2022 | 0.00 usd - 0.00 usd [0]')
|
self.assertEqual(recon2.rec_name, '04/15/2022 - 05/01/2022 | 0.00 usd - 0.00 usd [0]')
|
||||||
self.assertEqual(recon3.rec_name, '04/01/2022 - 04/15/2022 | 0.00 usd - 0.00 usd [0]')
|
self.assertEqual(recon3.rec_name, '05/31/2022 - 06/15/2022 | 0.00 usd - 0.00 usd [0]')
|
||||||
|
|
||||||
|
@with_transaction()
|
||||||
|
def test_recon_set_start_amount_by_cashbook(self):
|
||||||
|
""" set stat-amount from cashbook-setting
|
||||||
|
"""
|
||||||
|
pool = Pool()
|
||||||
|
Book = pool.get('cashbook.book')
|
||||||
|
Reconciliation = pool.get('cashbook.recon')
|
||||||
|
|
||||||
|
types = self.prep_type()
|
||||||
|
company = self.prep_company()
|
||||||
|
book, = Book.create([{
|
||||||
|
'name': 'Book 1',
|
||||||
|
'btype': types.id,
|
||||||
|
'company': company.id,
|
||||||
|
'currency': company.currency.id,
|
||||||
|
'start_balance': Decimal('12.50'),
|
||||||
|
'reconciliations': [('create', [{
|
||||||
|
'date': date(2022, 5, 28),
|
||||||
|
'date_from': date(2022, 5, 1),
|
||||||
|
'date_to': date(2022, 5, 31),
|
||||||
|
}])],
|
||||||
|
}])
|
||||||
|
self.assertEqual(book.name, 'Book 1')
|
||||||
|
self.assertEqual(book.reconciliations[0].rec_name, '05/01/2022 - 05/31/2022 | 0.00 usd - 0.00 usd [0]')
|
||||||
|
|
||||||
|
Reconciliation.wfcheck(list(book.reconciliations))
|
||||||
|
self.assertEqual(book.reconciliations[0].rec_name, '05/01/2022 - 05/31/2022 | 12.50 usd - 12.50 usd [0]')
|
||||||
|
|
||||||
|
@with_transaction()
|
||||||
|
def test_recon_set_start_amount_by_predecessor(self):
|
||||||
|
""" set stat-amount from end_amount of predecessor
|
||||||
|
"""
|
||||||
|
pool = Pool()
|
||||||
|
Book = pool.get('cashbook.book')
|
||||||
|
Lines = pool.get('cashbook.line')
|
||||||
|
Reconciliation = pool.get('cashbook.recon')
|
||||||
|
|
||||||
|
types = self.prep_type()
|
||||||
|
company = self.prep_company()
|
||||||
|
category = self.prep_category(cattype='in')
|
||||||
|
book, = Book.create([{
|
||||||
|
'name': 'Book 1',
|
||||||
|
'btype': types.id,
|
||||||
|
'company': company.id,
|
||||||
|
'currency': company.currency.id,
|
||||||
|
'start_balance': Decimal('12.50'),
|
||||||
|
'reconciliations': [('create', [{
|
||||||
|
'date': date(2022, 5, 28),
|
||||||
|
'date_from': date(2022, 5, 1),
|
||||||
|
'date_to': date(2022, 5, 31),
|
||||||
|
}])],
|
||||||
|
'lines': [('create', [{
|
||||||
|
'date': date(2022, 5, 5),
|
||||||
|
'bookingtype': 'in',
|
||||||
|
'category': category.id,
|
||||||
|
'description': 'Line 1',
|
||||||
|
'amount': Decimal('5.0'),
|
||||||
|
}, {
|
||||||
|
'date': date(2022, 5, 5),
|
||||||
|
'bookingtype': 'in',
|
||||||
|
'category': category.id,
|
||||||
|
'description': 'Line 2',
|
||||||
|
'amount': Decimal('7.0'),
|
||||||
|
},])],
|
||||||
|
}])
|
||||||
|
self.assertEqual(book.name, 'Book 1')
|
||||||
|
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)
|
||||||
|
|
||||||
|
Lines.wfcheck(list(book.lines))
|
||||||
|
Reconciliation.wfcheck(list(book.reconciliations))
|
||||||
|
|
||||||
|
self.assertEqual(book.reconciliations[0].state, 'check')
|
||||||
|
self.assertEqual(book.reconciliations[0].rec_name, '05/01/2022 - 05/31/2022 | 12.50 usd - 24.50 usd [2]')
|
||||||
|
Reconciliation.wfdone(list(book.reconciliations))
|
||||||
|
self.assertEqual(book.reconciliations[0].state, 'done')
|
||||||
|
|
||||||
|
recons = Reconciliation.create([{
|
||||||
|
'cashbook': book.id,
|
||||||
|
'date_from': date(2022, 5, 31),
|
||||||
|
'date_to': date(2022, 6, 30),
|
||||||
|
}])
|
||||||
|
self.assertEqual(recons[0].rec_name, '05/31/2022 - 06/30/2022 | 0.00 usd - 0.00 usd [0]')
|
||||||
|
Reconciliation.wfcheck(recons)
|
||||||
|
self.assertEqual(recons[0].rec_name, '05/31/2022 - 06/30/2022 | 24.50 usd - 24.50 usd [0]')
|
||||||
|
|
||||||
|
@with_transaction()
|
||||||
|
def test_recon_predecessor_done(self):
|
||||||
|
""" predecessor must be done
|
||||||
|
"""
|
||||||
|
pool = Pool()
|
||||||
|
Book = pool.get('cashbook.book')
|
||||||
|
Reconciliation = pool.get('cashbook.recon')
|
||||||
|
|
||||||
|
types = self.prep_type()
|
||||||
|
company = self.prep_company()
|
||||||
|
book, = Book.create([{
|
||||||
|
'name': 'Book 1',
|
||||||
|
'btype': types.id,
|
||||||
|
'company': company.id,
|
||||||
|
'currency': company.currency.id,
|
||||||
|
'reconciliations': [('create', [{
|
||||||
|
'date': date(2022, 5, 28),
|
||||||
|
'date_from': date(2022, 5, 1),
|
||||||
|
'date_to': date(2022, 5, 31),
|
||||||
|
}])],
|
||||||
|
}])
|
||||||
|
self.assertEqual(book.name, 'Book 1')
|
||||||
|
self.assertEqual(book.state, 'open')
|
||||||
|
Reconciliation.wfcheck(list(book.reconciliations))
|
||||||
|
self.assertEqual(book.reconciliations[0].rec_name, '05/01/2022 - 05/31/2022 | 0.00 usd - 0.00 usd [0]')
|
||||||
|
self.assertEqual(book.reconciliations[0].state, 'check')
|
||||||
|
|
||||||
|
recons = Reconciliation.create([{
|
||||||
|
'cashbook': book.id,
|
||||||
|
'date_from': date(2022, 5, 31),
|
||||||
|
'date_to': date(2022, 6, 30),
|
||||||
|
}])
|
||||||
|
self.assertRaisesRegex(UserError,
|
||||||
|
"The predecessor '05/01/2022 - 05/31/2022 | 0.00 usd - 0.00 usd [0]' must be in the 'Done' state before you can check the current reconciliation '05/31/2022 - 06/30/2022 | 0.00 usd - 0.00 usd [0]'.",
|
||||||
|
Reconciliation.wfcheck,
|
||||||
|
recons)
|
||||||
|
|
||||||
|
@with_transaction()
|
||||||
|
def test_recon_autoset_date_from(self):
|
||||||
|
""" create reconciliation, check: set date_from to end of predecessor
|
||||||
|
"""
|
||||||
|
pool = Pool()
|
||||||
|
Book = pool.get('cashbook.book')
|
||||||
|
Reconciliation = pool.get('cashbook.recon')
|
||||||
|
|
||||||
|
types = self.prep_type()
|
||||||
|
company = self.prep_company()
|
||||||
|
book, = Book.create([{
|
||||||
|
'name': 'Book 1',
|
||||||
|
'btype': types.id,
|
||||||
|
'company': company.id,
|
||||||
|
'currency': company.currency.id,
|
||||||
|
'reconciliations': [('create', [{
|
||||||
|
'date': date(2022, 5, 28),
|
||||||
|
'date_from': date(2022, 5, 1),
|
||||||
|
'date_to': date(2022, 5, 31),
|
||||||
|
}])],
|
||||||
|
}])
|
||||||
|
self.assertEqual(book.name, 'Book 1')
|
||||||
|
self.assertEqual(book.state, 'open')
|
||||||
|
Reconciliation.wfcheck([book.reconciliations[0]])
|
||||||
|
Reconciliation.wfdone([book.reconciliations[0]])
|
||||||
|
|
||||||
|
r2, = Reconciliation.create([{
|
||||||
|
'cashbook': book.id,
|
||||||
|
'date_from': date(2022, 6, 10),
|
||||||
|
'date_to': date(2022, 6, 30),
|
||||||
|
}])
|
||||||
|
self.assertEqual(r2.rec_name, '05/31/2022 - 06/30/2022 | 0.00 usd - 0.00 usd [0]')
|
||||||
|
|
||||||
|
# update 'date_from' to wrong value
|
||||||
|
Reconciliation.write(*[
|
||||||
|
[r2],
|
||||||
|
{
|
||||||
|
'date_from': date(2022, 6, 1),
|
||||||
|
}])
|
||||||
|
self.assertEqual(r2.rec_name, '06/01/2022 - 06/30/2022 | 0.00 usd - 0.00 usd [0]')
|
||||||
|
|
||||||
|
self.assertRaisesRegex(UserError,
|
||||||
|
"The start date '06/01/2022' of the current reconciliation '06/01/2022 - 06/30/2022 | 0.00 usd - 0.00 usd [0]' must correspond to the end date '05/31/2022' of the predecessor.",
|
||||||
|
Reconciliation.wfcheck,
|
||||||
|
[r2])
|
||||||
|
|
||||||
@with_transaction()
|
@with_transaction()
|
||||||
def test_recon_create_check_line_add_to_recon(self):
|
def test_recon_create_check_line_add_to_recon(self):
|
||||||
|
@ -235,6 +400,133 @@ class ReconTestCase(ModuleTestCase):
|
||||||
Lines.wfedit,
|
Lines.wfedit,
|
||||||
[book.lines[0]])
|
[book.lines[0]])
|
||||||
|
|
||||||
|
# unlink lines from reconciliation
|
||||||
|
self.assertEqual(book.reconciliations[0].state, 'edit')
|
||||||
|
self.assertEqual(len(book.reconciliations[0].lines), 2)
|
||||||
|
Reconciliation.wfcheck(list(book.reconciliations))
|
||||||
|
Reconciliation.wfedit(list(book.reconciliations))
|
||||||
|
self.assertEqual(book.reconciliations[0].state, 'edit')
|
||||||
|
self.assertEqual(len(book.reconciliations[0].lines), 0)
|
||||||
|
|
||||||
|
# move date of 2nd line to june 1
|
||||||
|
# set reconciliation to 'check'
|
||||||
|
Lines.wfedit([book.lines[1]])
|
||||||
|
Lines.write(*[
|
||||||
|
[book.lines[1]],
|
||||||
|
{
|
||||||
|
'date': date(2022, 6, 1),
|
||||||
|
}])
|
||||||
|
# check reconciliation, this linkes the 1st line by date
|
||||||
|
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]')
|
||||||
|
|
||||||
|
# move 2nd line into date-range of checked-reconciliation, wf-check
|
||||||
|
Lines.write(*[
|
||||||
|
[book.lines[1]],
|
||||||
|
{
|
||||||
|
'date': date(2022, 5, 20),
|
||||||
|
}])
|
||||||
|
self.assertRaisesRegex(UserError,
|
||||||
|
"For the date '05/20/2022' there is already a completed reconciliation. Use a different date.",
|
||||||
|
Lines.wfcheck,
|
||||||
|
[book.lines[1]])
|
||||||
|
|
||||||
|
# set date to end of date-range of reconciliation
|
||||||
|
# should work
|
||||||
|
Lines.write(*[
|
||||||
|
[book.lines[1]],
|
||||||
|
{
|
||||||
|
'date': date(2022, 5, 31),
|
||||||
|
}])
|
||||||
|
Lines.wfcheck([book.lines[1]]) # ok
|
||||||
|
Lines.wfedit([book.lines[1]])
|
||||||
|
Lines.write(*[
|
||||||
|
[book.lines[1]],
|
||||||
|
{
|
||||||
|
'date': date(2022, 7, 1),
|
||||||
|
}])
|
||||||
|
|
||||||
|
# add 2nd reconciliation
|
||||||
|
recon2, = Reconciliation.create([{
|
||||||
|
'cashbook': book.id,
|
||||||
|
'date_from': date(2022, 5, 31),
|
||||||
|
'date_to': date(2022, 6, 30),
|
||||||
|
}])
|
||||||
|
Reconciliation.wfdone([book.reconciliations[0]])
|
||||||
|
Reconciliation.wfcheck([recon2])
|
||||||
|
|
||||||
|
Lines.write(*[
|
||||||
|
[book.lines[1]],
|
||||||
|
{
|
||||||
|
'date': date(2022, 5, 31),
|
||||||
|
}])
|
||||||
|
self.assertRaisesRegex(UserError,
|
||||||
|
"For the date '05/31/2022' there is already a completed reconciliation. Use a different date.",
|
||||||
|
Lines.wfcheck,
|
||||||
|
[book.lines[1]])
|
||||||
|
|
||||||
|
@with_transaction()
|
||||||
|
def test_recon_check_wfcheck_missing_lines(self):
|
||||||
|
""" create, booklines, check missing line at wfcheck
|
||||||
|
"""
|
||||||
|
pool = Pool()
|
||||||
|
Book = pool.get('cashbook.book')
|
||||||
|
Lines = pool.get('cashbook.line')
|
||||||
|
Reconciliation = pool.get('cashbook.recon')
|
||||||
|
|
||||||
|
types = self.prep_type()
|
||||||
|
category = self.prep_category(cattype='in')
|
||||||
|
company = self.prep_company()
|
||||||
|
book, = Book.create([{
|
||||||
|
'name': 'Book 1',
|
||||||
|
'btype': types.id,
|
||||||
|
'company': company.id,
|
||||||
|
'currency': company.currency.id,
|
||||||
|
'lines': [('create', [{
|
||||||
|
'date': date(2022, 5, 1),
|
||||||
|
'description': 'Text 1',
|
||||||
|
'category': category.id,
|
||||||
|
'bookingtype': 'in',
|
||||||
|
'amount': Decimal('1.0'),
|
||||||
|
}, {
|
||||||
|
'date': date(2022, 6, 5),
|
||||||
|
'description': 'Text 2',
|
||||||
|
'category': category.id,
|
||||||
|
'bookingtype': 'in',
|
||||||
|
'amount': Decimal('1.0'),
|
||||||
|
}])],
|
||||||
|
'reconciliations': [('create', [{
|
||||||
|
'date': date(2022, 5, 28),
|
||||||
|
'date_from': date(2022, 5, 1),
|
||||||
|
'date_to': date(2022, 5, 31),
|
||||||
|
}])],
|
||||||
|
}])
|
||||||
|
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]')
|
||||||
|
|
||||||
|
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]')
|
||||||
|
|
||||||
|
Lines.write(*[
|
||||||
|
[book.lines[1]],
|
||||||
|
{
|
||||||
|
'date': date(2022, 5, 15),
|
||||||
|
}])
|
||||||
|
|
||||||
|
self.assertRaisesRegex(UserError,
|
||||||
|
"In the date range from 05/01/2022 to 05/31/2022, there are still cashbook lines that do not belong to any reconciliation.",
|
||||||
|
Reconciliation.wfdone,
|
||||||
|
[book.reconciliations[0]])
|
||||||
|
|
||||||
@with_transaction()
|
@with_transaction()
|
||||||
def test_recon_check_deny_delete(self):
|
def test_recon_check_deny_delete(self):
|
||||||
""" create, booklines, reconciliation, try delete
|
""" create, booklines, reconciliation, try delete
|
||||||
|
@ -353,8 +645,8 @@ class ReconTestCase(ModuleTestCase):
|
||||||
Lines.wfcheck(book.lines)
|
Lines.wfcheck(book.lines)
|
||||||
Reconciliation.wfcheck(list(book.reconciliations))
|
Reconciliation.wfcheck(list(book.reconciliations))
|
||||||
self.assertEqual(len(book.reconciliations[0].lines), 2)
|
self.assertEqual(len(book.reconciliations[0].lines), 2)
|
||||||
self.assertEqual(book.lines[0].reconciliation.rec_name, '05/01/2022 - 05/31/2022 | 0.00 usd - 0.00 usd [2]')
|
self.assertEqual(book.lines[0].reconciliation.rec_name, '05/01/2022 - 05/31/2022 | 0.00 usd - 2.00 usd [2]')
|
||||||
self.assertEqual(book.lines[1].reconciliation.rec_name, '05/01/2022 - 05/31/2022 | 0.00 usd - 0.00 usd [2]')
|
self.assertEqual(book.lines[1].reconciliation.rec_name, '05/01/2022 - 05/31/2022 | 0.00 usd - 2.00 usd [2]')
|
||||||
|
|
||||||
# check --> edit
|
# check --> edit
|
||||||
Reconciliation.wfedit(list(book.reconciliations))
|
Reconciliation.wfedit(list(book.reconciliations))
|
||||||
|
|
|
@ -3,6 +3,7 @@ version=6.0.0
|
||||||
depends:
|
depends:
|
||||||
res
|
res
|
||||||
currency
|
currency
|
||||||
|
party
|
||||||
company
|
company
|
||||||
xml:
|
xml:
|
||||||
icon.xml
|
icon.xml
|
||||||
|
|
|
@ -7,7 +7,12 @@ full copyright notices and license terms. -->
|
||||||
<separator name="state" colspan="2" string="State"/>
|
<separator name="state" colspan="2" string="State"/>
|
||||||
|
|
||||||
<field name="cashbook" colspan="2"/>
|
<field name="cashbook" colspan="2"/>
|
||||||
<label id="lab1" string=" " colspan="2"/>
|
<group id="grpparty" colspan="2" col="4">
|
||||||
|
<label name="party"/>
|
||||||
|
<field name="party"/>
|
||||||
|
<label name="booktransf"/>
|
||||||
|
<field name="booktransf"/>
|
||||||
|
</group>
|
||||||
|
|
||||||
<field name="state"/>
|
<field name="state"/>
|
||||||
<group id="grpstate" col="2">
|
<group id="grpstate" col="2">
|
||||||
|
|
|
@ -5,6 +5,8 @@ full copyright notices and license terms. -->
|
||||||
<tree>
|
<tree>
|
||||||
<field name="cashbook" tree_invisible="1"/>
|
<field name="cashbook" tree_invisible="1"/>
|
||||||
<field name="date"/>
|
<field name="date"/>
|
||||||
|
<field name="party"/>
|
||||||
|
<field name="booktransf"/>
|
||||||
<field name="category_view"/>
|
<field name="category_view"/>
|
||||||
<field name="description" expand="1"/>
|
<field name="description" expand="1"/>
|
||||||
<field name="credit" sum="Credit"/>
|
<field name="credit" sum="Credit"/>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue