From 0b3f82f6c718a15d1cc6189199e1e53177c186b3 Mon Sep 17 00:00:00 2001 From: Frederik Jaeckel Date: Thu, 18 Aug 2022 13:05:16 +0200 Subject: [PATCH] reconciliation: check_overlap_dates() in validate() verschoben + tests --- reconciliation.py | 45 +++--- tests/test_reconciliation.py | 270 ++++++++++++++++++++--------------- 2 files changed, 174 insertions(+), 141 deletions(-) diff --git a/reconciliation.py b/reconciliation.py index 59a548d..72040ee 100644 --- a/reconciliation.py +++ b/reconciliation.py @@ -117,35 +117,31 @@ class Reconciliation(Workflow, ModelSQL, ModelView): }, }) - @classmethod - def check_overlap_dates(cls, date_from, date_to, id_cashbook, record=None): + def check_overlap_dates(self): """ deny overlap of date_from/date_to between records of same cashbook allow: date_to=date_from """ Recon = Pool().get('cashbook.recon') query = [ - ('cashbook.id', '=', id_cashbook), + ('cashbook.id', '=', self.cashbook.id), + ('id', '!=', self.id), ['OR', [ # 'start' is inside of other record - ('date_from', '<=', date_from), - ('date_to', '>', date_from), + ('date_from', '<=', self.date_from), + ('date_to', '>', self.date_from), ], [ # 'end' is inside of other record - ('date_from', '<', date_to), - ('date_to', '>=', date_to), + ('date_from', '<', self.date_to), + ('date_to', '>=', self.date_to), ], [ # enclose other record - ('date_from', '>=', date_from), - ('date_to', '<=', date_to), + ('date_from', '>=', self.date_from), + ('date_to', '<=', self.date_to), ], ], ] - # avoid finding ourselves - if record: - query.append(('id', '!=', record.id)) - if Recon.search_count(query) > 0: raise UserError(gettext('cashbook.msg_recon_err_overlap')) @@ -373,6 +369,15 @@ class Reconciliation(Workflow, ModelSQL, ModelView): if self.cashbook: 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 def create(cls, vlist): """ add debit/credit @@ -403,10 +408,6 @@ class Reconciliation(Workflow, ModelSQL, ModelView): if len(lines) > 0: 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) @classmethod @@ -418,22 +419,12 @@ class Reconciliation(Workflow, ModelSQL, ModelView): for reconciliations, values in zip(actions, actions): # deny write if chashbook is not open 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': raise UserError(gettext( 'cashbook.msg_book_deny_write', bookname = reconciliation.cashbook.rec_name, state_txt = reconciliation.cashbook.state_string, )) - super(Reconciliation, cls).write(*args) @classmethod diff --git a/tests/test_reconciliation.py b/tests/test_reconciliation.py index caa3636..10eacdb 100644 --- a/tests/test_reconciliation.py +++ b/tests/test_reconciliation.py @@ -16,8 +16,8 @@ class ReconTestCase(ModuleTestCase): module = 'cashbook' @with_transaction() - def test_recon_check_overlap(self): - """ create, check deny of overlap date + def test_recon_check_overlap_start(self): + """ create, check deny of overlap date - date_from """ pool = Pool() Book = pool.get('cashbook.book') @@ -33,136 +33,178 @@ class ReconTestCase(ModuleTestCase): '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), + }])], }]) - recon1, = Reconciliation.create([{ - 'date': date(2022, 5, 1), - 'date_from': date(2022, 5, 1), - 'date_to': date(2022, 5, 31), - 'cashbook': book.id, + Book.write(*[ + [book], + { + 'reconciliations': [('create', [{ + '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, 'The date range overlaps with another reconciliation.', 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' inside of other record - self.assertRaisesRegex(UserError, - 'The date range overlaps with another reconciliation.', - Reconciliation.write, - *[ - [recon2], - { - 'date_from': date(2022, 5, 2), - }, - ]) + @with_transaction() + def test_recon_check_overlap_inside(self): + """ create, check deny of overlap date - inside of period + """ + pool = Pool() + Book = pool.get('cashbook.book') + Reconciliation = pool.get('cashbook.recon') - # 'date_from' same date_from like other record - self.assertRaisesRegex(UserError, - 'The date range overlaps with another reconciliation.', - Reconciliation.write, - *[ - [recon2], - { - 'date_from': date(2022, 5, 1), - }, - ]) - - # 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, - [{ + 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, 4, 1), - 'date_to': date(2022, 4, 16), - 'cashbook': book.id, + 'date_from': date(2022, 5, 1), + 'date_to': date(2022, 5, 31), + }])], }]) - recon3, = Reconciliation.create([{ - 'date': date(2022, 4, 17), - 'date_from': date(2022, 6, 1), - 'date_to': date(2022, 6, 15), - 'cashbook': book.id, + Book.write(*[ + [book], + { + 'reconciliations': [('create', [{ + '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(recon2.rec_name, '04/15/2022 - 05/01/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.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, 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() def test_recon_set_start_amount_by_cashbook(self):