reconciliation: check_overlap_dates() in validate() verschoben + tests

This commit is contained in:
Frederik Jaeckel 2022-08-18 13:05:16 +02:00
parent 91a34e216b
commit 0b3f82f6c7
2 changed files with 174 additions and 141 deletions

View file

@ -117,35 +117,31 @@ class Reconciliation(Workflow, ModelSQL, ModelView):
}, },
}) })
@classmethod def check_overlap_dates(self):
def check_overlap_dates(cls, date_from, date_to, id_cashbook, record=None):
""" deny overlap of date_from/date_to between records of same cashbook """ deny overlap of date_from/date_to between records of same cashbook
allow: date_to=date_from allow: date_to=date_from
""" """
Recon = Pool().get('cashbook.recon') Recon = Pool().get('cashbook.recon')
query = [ query = [
('cashbook.id', '=', id_cashbook), ('cashbook.id', '=', self.cashbook.id),
('id', '!=', self.id),
['OR', ['OR',
[ # 'start' is inside of other record [ # 'start' is inside of other record
('date_from', '<=', date_from), ('date_from', '<=', self.date_from),
('date_to', '>', date_from), ('date_to', '>', self.date_from),
], ],
[ # 'end' is inside of other record [ # 'end' is inside of other record
('date_from', '<', date_to), ('date_from', '<', self.date_to),
('date_to', '>=', date_to), ('date_to', '>=', self.date_to),
], ],
[ # enclose other record [ # enclose other record
('date_from', '>=', date_from), ('date_from', '>=', self.date_from),
('date_to', '<=', date_to), ('date_to', '<=', self.date_to),
], ],
], ],
] ]
# avoid finding ourselves
if record:
query.append(('id', '!=', record.id))
if Recon.search_count(query) > 0: if Recon.search_count(query) > 0:
raise UserError(gettext('cashbook.msg_recon_err_overlap')) raise UserError(gettext('cashbook.msg_recon_err_overlap'))
@ -373,6 +369,15 @@ class Reconciliation(Workflow, ModelSQL, ModelView):
if self.cashbook: if self.cashbook:
return self.cashbook.state return self.cashbook.state
@classmethod
def validate(cls, reconciliations):
""" deny overlap of dates
"""
super(Reconciliation, cls).validate(reconciliations)
for reconciliation in reconciliations:
reconciliation.check_overlap_dates()
@classmethod @classmethod
def create(cls, vlist): def create(cls, vlist):
""" add debit/credit """ add debit/credit
@ -403,10 +408,6 @@ class Reconciliation(Workflow, ModelSQL, ModelView):
if len(lines) > 0: if len(lines) > 0:
values['date_to'] = lines[0].date values['date_to'] = lines[0].date
cls.check_overlap_dates(
values.get('date_from', None),
values.get('date_to', None),
values.get('cashbook', None))
return super(Reconciliation, cls).create(vlist) return super(Reconciliation, cls).create(vlist)
@classmethod @classmethod
@ -418,22 +419,12 @@ class Reconciliation(Workflow, ModelSQL, ModelView):
for reconciliations, values in zip(actions, actions): for reconciliations, values in zip(actions, actions):
# deny write if chashbook is not open # deny write if chashbook is not open
for reconciliation in reconciliations: for reconciliation in reconciliations:
# deny overlap
if len(set({'date_from', 'date_to'}).intersection(set(values.keys()))) > 0:
cls.check_overlap_dates(
values.get('date_from', reconciliation.date_from),
values.get('date_to', reconciliation.date_to),
reconciliation.cashbook.id,
reconciliation)
if reconciliation.cashbook.state != 'open': if reconciliation.cashbook.state != 'open':
raise UserError(gettext( raise UserError(gettext(
'cashbook.msg_book_deny_write', 'cashbook.msg_book_deny_write',
bookname = reconciliation.cashbook.rec_name, bookname = reconciliation.cashbook.rec_name,
state_txt = reconciliation.cashbook.state_string, state_txt = reconciliation.cashbook.state_string,
)) ))
super(Reconciliation, cls).write(*args) super(Reconciliation, cls).write(*args)
@classmethod @classmethod

View file

@ -16,8 +16,8 @@ class ReconTestCase(ModuleTestCase):
module = 'cashbook' module = 'cashbook'
@with_transaction() @with_transaction()
def test_recon_check_overlap(self): def test_recon_check_overlap_start(self):
""" create, check deny of overlap date """ create, check deny of overlap date - date_from
""" """
pool = Pool() pool = Pool()
Book = pool.get('cashbook.book') Book = pool.get('cashbook.book')
@ -33,136 +33,178 @@ class ReconTestCase(ModuleTestCase):
'currency': company.currency.id, 'currency': company.currency.id,
'number_sequ': self.prep_sequence().id, 'number_sequ': self.prep_sequence().id,
'start_date': date(2022, 5, 1), 'start_date': date(2022, 5, 1),
'reconciliations': [('create', [{
'date': date(2022, 5, 1),
'date_from': date(2022, 5, 1),
'date_to': date(2022, 5, 31),
}])],
}]) }])
recon1, = Reconciliation.create([{ Book.write(*[
'date': date(2022, 5, 1), [book],
'date_from': date(2022, 5, 1), {
'date_to': date(2022, 5, 31), 'reconciliations': [('create', [{
'cashbook': book.id, 'date': date(2022, 6, 1),
'date_from': date(2022, 6, 1),
'date_to': date(2022, 6, 30),
}])],
}]) }])
self.assertEqual(recon1.rec_name, '05/01/2022 - 05/31/2022 | 0.00 usd - 0.00 usd [0]') self.assertEqual(book.reconciliations[0].rec_name, '05/01/2022 - 05/31/2022 | 0.00 usd - 0.00 usd [0]')
self.assertEqual(book.reconciliations[1].rec_name, '05/31/2022 - 06/30/2022 | 0.00 usd - 0.00 usd [0]')
recon2, = Reconciliation.create([{
'date': date(2022, 6, 1),
'date_from': date(2022, 6, 1),
'date_to': date(2022, 6, 30),
'cashbook': book.id,
}])
# 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'
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]')
# 'date_from' inside of other record
self.assertRaisesRegex(UserError, self.assertRaisesRegex(UserError,
'The date range overlaps with another reconciliation.', 'The date range overlaps with another reconciliation.',
Reconciliation.write, Reconciliation.write,
*[ *[
[recon2], [book.reconciliations[1]],
{
'date_from': date(2022, 4, 15),
'date_to': date(2022, 5, 2),
},
])
@with_transaction()
def test_recon_check_overlap_end(self):
""" create, check deny of overlap date - date_to
"""
pool = Pool()
Book = pool.get('cashbook.book')
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,
'number_sequ': self.prep_sequence().id,
'start_date': date(2022, 5, 1),
'reconciliations': [('create', [{
'date': date(2022, 5, 1),
'date_from': date(2022, 5, 1),
'date_to': date(2022, 5, 31),
}])],
}])
Book.write(*[
[book],
{
'reconciliations': [('create', [{
'date': date(2022, 6, 1),
'date_from': date(2022, 6, 1),
'date_to': date(2022, 6, 30),
}])],
}])
self.assertEqual(book.reconciliations[0].rec_name, '05/01/2022 - 05/31/2022 | 0.00 usd - 0.00 usd [0]')
self.assertEqual(book.reconciliations[1].rec_name, '05/31/2022 - 06/30/2022 | 0.00 usd - 0.00 usd [0]')
self.assertRaisesRegex(UserError,
'The date range overlaps with another reconciliation.',
Reconciliation.write,
*[
[book.reconciliations[1]],
{ {
'date_from': date(2022, 5, 30), 'date_from': date(2022, 5, 30),
}, },
]) ])
# 'date_from' inside of other record @with_transaction()
self.assertRaisesRegex(UserError, def test_recon_check_overlap_inside(self):
'The date range overlaps with another reconciliation.', """ create, check deny of overlap date - inside of period
Reconciliation.write, """
*[ pool = Pool()
[recon2], Book = pool.get('cashbook.book')
{ Reconciliation = pool.get('cashbook.recon')
'date_from': date(2022, 5, 2),
},
])
# 'date_from' same date_from like other record types = self.prep_type()
self.assertRaisesRegex(UserError, category = self.prep_category(cattype='in')
'The date range overlaps with another reconciliation.', company = self.prep_company()
Reconciliation.write, book, = Book.create([{
*[ 'name': 'Book 1',
[recon2], 'btype': types.id,
{ 'company': company.id,
'date_from': date(2022, 5, 1), 'currency': company.currency.id,
}, 'number_sequ': self.prep_sequence().id,
]) 'start_date': date(2022, 5, 1),
'reconciliations': [('create', [{
# enclose other record
self.assertRaisesRegex(UserError,
'The date range overlaps with another reconciliation.',
Reconciliation.write,
*[
[recon2],
{
'date_from': date(2022, 4, 30),
},
])
# within other record
self.assertRaisesRegex(UserError,
'The date range overlaps with another reconciliation.',
Reconciliation.write,
*[
[recon2],
{
'date_from': date(2022, 5, 2),
'date_to': date(2022, 5, 12),
},
])
# from after to
self.assertRaisesRegex(UserError,
'The value for field "Start Date" in "Cashbook Reconciliation" is not valid according to its domain.',
Reconciliation.write,
*[
[recon2],
{
'date_from': date(2022, 4, 15),
'date_to': date(2022, 4, 10),
},
])
# 'date_to' at 'date_from' of other record - allowed
Reconciliation.write(*[
[recon2],
{
'date_from': date(2022, 4, 15),
'date_to': date(2022, 5, 1),
}])
# 'date_to' after other date_from
self.assertRaisesRegex(UserError,
'The date range overlaps with another reconciliation.',
Reconciliation.write,
*[
[recon2],
{
'date_to': date(2022, 5, 2),
},
])
# overlap at .create()
self.assertRaisesRegex(UserError,
'The date range overlaps with another reconciliation.',
Reconciliation.create,
[{
'date': date(2022, 5, 1), 'date': date(2022, 5, 1),
'date_from': date(2022, 4, 1), 'date_from': date(2022, 5, 1),
'date_to': date(2022, 4, 16), 'date_to': date(2022, 5, 31),
'cashbook': book.id, }])],
}]) }])
recon3, = Reconciliation.create([{ Book.write(*[
'date': date(2022, 4, 17), [book],
'date_from': date(2022, 6, 1), {
'date_to': date(2022, 6, 15), 'reconciliations': [('create', [{
'cashbook': book.id, 'date': date(2022, 6, 1),
'date_from': date(2022, 6, 1),
'date_to': date(2022, 6, 30),
}])],
}]) }])
self.assertEqual(recon1.rec_name, '05/01/2022 - 05/31/2022 | 0.00 usd - 0.00 usd [0]') self.assertEqual(book.reconciliations[0].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(book.reconciliations[1].rec_name, '05/31/2022 - 06/30/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]')
self.assertRaisesRegex(UserError,
'The date range overlaps with another reconciliation.',
Reconciliation.write,
*[
[book.reconciliations[1]],
{
'date_from': date(2022, 5, 5),
'date_to': date(2022, 5, 15),
},
])
@with_transaction()
def test_recon_check_overlap_enclose(self):
""" create, check deny of overlap date - enclose a period
"""
pool = Pool()
Book = pool.get('cashbook.book')
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,
'number_sequ': self.prep_sequence().id,
'start_date': date(2022, 5, 1),
'reconciliations': [('create', [{
'date': date(2022, 5, 1),
'date_from': date(2022, 5, 1),
'date_to': date(2022, 5, 31),
}])],
}])
Book.write(*[
[book],
{
'reconciliations': [('create', [{
'date': date(2022, 6, 1),
'date_from': date(2022, 6, 1),
'date_to': date(2022, 6, 30),
}])],
}])
self.assertEqual(book.reconciliations[0].rec_name, '05/01/2022 - 05/31/2022 | 0.00 usd - 0.00 usd [0]')
self.assertEqual(book.reconciliations[1].rec_name, '05/31/2022 - 06/30/2022 | 0.00 usd - 0.00 usd [0]')
self.assertRaisesRegex(UserError,
'The date range overlaps with another reconciliation.',
Reconciliation.write,
*[
[book.reconciliations[1]],
{
'date_from': date(2022, 4, 25),
'date_to': date(2022, 6, 10),
},
])
@with_transaction() @with_transaction()
def test_recon_set_start_amount_by_cashbook(self): def test_recon_set_start_amount_by_cashbook(self):