From 1e7dd3c351f4001e06d150c73484ca514b35dea8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 10 Oct 2024 00:34:19 +0200 Subject: [PATCH] Use SQL constraint to enforce unique usage of post move sequence --- modules/account/exceptions.py | 12 ------------ modules/account/fiscalyear.py | 25 +++++-------------------- modules/account/message.xml | 8 ++++---- modules/account/period.py | 30 +++++++----------------------- 4 files changed, 16 insertions(+), 59 deletions(-) diff --git a/modules/account/exceptions.py b/modules/account/exceptions.py index ec51d4526e..0be7e42aba 100644 --- a/modules/account/exceptions.py +++ b/modules/account/exceptions.py @@ -21,22 +21,10 @@ class PeriodDatesError(PeriodValidationError): pass -class PeriodSequenceError(PeriodValidationError): - pass - - class FiscalYearNotFoundError(UserError): pass -class FiscalYearValidationError(ValidationError): - pass - - -class FiscalYearSequenceError(FiscalYearValidationError): - pass - - class FiscalYearCloseError(UserError): pass diff --git a/modules/account/fiscalyear.py b/modules/account/fiscalyear.py index 6c948540b1..21c2393064 100644 --- a/modules/account/fiscalyear.py +++ b/modules/account/fiscalyear.py @@ -8,7 +8,8 @@ from sql.operators import Equal, NotEqual from trytond.cache import Cache from trytond.i18n import gettext -from trytond.model import Exclude, ModelSQL, ModelView, Workflow, fields +from trytond.model import ( + Exclude, ModelSQL, ModelView, Unique, Workflow, fields) from trytond.model.exceptions import AccessError from trytond.pool import Pool from trytond.pyson import Eval, Id @@ -20,8 +21,7 @@ from trytond.wizard import ( Button, StateAction, StateTransition, StateView, Wizard) from .exceptions import ( - FiscalYearCloseError, FiscalYearNotFoundError, FiscalYearReOpenError, - FiscalYearSequenceError) + FiscalYearCloseError, FiscalYearNotFoundError, FiscalYearReOpenError) STATES = { 'readonly': Eval('state') != 'open', @@ -79,6 +79,8 @@ class FiscalYear(Workflow, ModelSQL, ModelView): t.end_date), RangeOverlap), (Case((t.state == 'open', t.id), else_=-1), NotEqual)), 'account.msg_open_fiscalyear_earlier'), + ('post_move_sequence_unique', Unique(t, t.post_move_sequence), + 'account.msg_fiscalyear_post_move_unique'), ] cls._order.insert(0, ('start_date', 'DESC')) cls._transitions |= set(( @@ -136,25 +138,8 @@ class FiscalYear(Workflow, ModelSQL, ModelView): @classmethod def validate_fields(cls, fiscalyears, field_names): super().validate_fields(fiscalyears, field_names) - cls.check_post_move_sequence(fiscalyears, field_names) cls.check_period_dates(fiscalyears, field_names) - @classmethod - def check_post_move_sequence(cls, fiscalyears, field_names=None): - if field_names and 'post_move_sequence' not in field_names: - return - for fiscalyear in fiscalyears: - sequence = fiscalyear.post_move_sequence - years = cls.search([ - ('post_move_sequence', '=', sequence.id), - ('id', '!=', fiscalyear.id), - ], limit=1) - if years: - raise FiscalYearSequenceError(gettext( - 'account.msg_fiscalyear_different_post_move_sequence', - first=fiscalyear.rec_name, - second=years[0].rec_name)) - @classmethod def check_period_dates(cls, fiscalyears, field_names=None): pool = Pool() diff --git a/modules/account/message.xml b/modules/account/message.xml index cf80cc7926..0670a47893 100644 --- a/modules/account/message.xml +++ b/modules/account/message.xml @@ -24,8 +24,8 @@ this repository contains the full copyright notices and license terms. --> The dates of standard period of the same fiscal year can not overlap. - - You cannot use the same post move sequence for the periods "%(first)s" and "%(second)s" because they are from different fiscal years. + + A post move sequence can be reused only by periods in the same fiscal year. The dates for period "%(period)s" must be between the dates of its fiscal year "%(fiscalyear)s". @@ -69,8 +69,8 @@ this repository contains the full copyright notices and license terms. --> Open fiscal years can not be before closed fiscal years. - - The fiscal years "%(first)s" and "%(second)s" cannot have the same post move sequence, you must use different sequences. + + The post move sequence of fiscal years must be unique. To close the fiscal year, the balance of account "%(account)s" must be zero. diff --git a/modules/account/period.py b/modules/account/period.py index 95e10791bc..71068e1617 100644 --- a/modules/account/period.py +++ b/modules/account/period.py @@ -1,7 +1,7 @@ # This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. -from sql.operators import Equal +from sql.operators import Equal, NotEqual from trytond.cache import Cache from trytond.const import OPERATORS @@ -15,9 +15,7 @@ from trytond.sql.operators import RangeOverlap from trytond.tools import grouped_slice from trytond.transaction import Transaction -from .exceptions import ( - ClosePeriodError, PeriodDatesError, PeriodNotFoundError, - PeriodSequenceError) +from .exceptions import ClosePeriodError, PeriodDatesError, PeriodNotFoundError _STATES = { 'readonly': Eval('state') != 'open', @@ -70,6 +68,11 @@ class Period(Workflow, ModelSQL, ModelView): (DateRange(t.start_date, t.end_date, '[]'), RangeOverlap), where=t.type == 'standard'), 'account.msg_period_standard_overlap'), + ('post_move_sequence_unique', + Exclude(t, + (t.post_move_sequence, Equal), + (t.fiscalyear, NotEqual)), + 'account.msg_period_post_move_sequence_unique'), ] cls._sql_indexes.add( Index( @@ -135,7 +138,6 @@ class Period(Workflow, ModelSQL, ModelView): super().validate_fields(periods, field_names) cls.check_fiscalyear_dates(periods, field_names) cls.check_move_dates(periods, field_names) - cls.check_post_move_sequence(periods, field_names) @classmethod def check_fiscalyear_dates(cls, periods, field_names=None): @@ -180,24 +182,6 @@ class Period(Workflow, ModelSQL, ModelView): move=move.rec_name, move_date=lang.strftime(move.date))) - @classmethod - def check_post_move_sequence(cls, periods, field_names=None): - if field_names and not ( - field_names & {'post_move_sequence', 'fiscalyear'}): - return - for period in periods: - if not period.post_move_sequence: - continue - periods = cls.search([ - ('post_move_sequence', '=', period.post_move_sequence.id), - ('fiscalyear', '!=', period.fiscalyear.id), - ]) - if periods: - raise PeriodSequenceError( - gettext('account.msg_period_same_sequence', - first=period.rec_name, - second=periods[0].rec_name)) - @classmethod def find(cls, company, date=None, test_state=True): '''