changeset d80510557e5e in modules/account:default
details: https://hg.tryton.org/modules/account?cmd=changeset&node=d80510557e5e
description:
        Add validate_fields to ModelStorage

        issue11303
        review386191002
diffstat:

 account.py    |   19 ++++++---
 fiscalyear.py |   77 ++++++++++++++++++++++------------------
 move.py       |   54 +++++++++++++++------------
 period.py     |  109 +++++++++++++++++++++++++++++++++------------------------
 tax.py        |   42 ++++++++++++---------
 5 files changed, 173 insertions(+), 128 deletions(-)

diffs (400 lines):

diff -r 4f9b64692892 -r d80510557e5e account.py
--- a/account.py        Mon Apr 11 22:23:58 2022 +0200
+++ b/account.py        Mon Apr 11 23:24:20 2022 +0200
@@ -952,10 +952,10 @@
         table_h.drop_column('kind')
 
     @classmethod
-    def validate(cls, accounts):
-        super(Account, cls).validate(accounts)
-        cls.check_second_currency(accounts)
-        cls.check_move_domain(accounts)
+    def validate_fields(cls, accounts, field_names):
+        super().validate_fields(accounts, field_names)
+        cls.check_second_currency(accounts, field_names)
+        cls.check_move_domain(accounts, field_names)
 
     @staticmethod
     def default_left():
@@ -1159,9 +1159,14 @@
                 setattr(self, field, getattr(self.parent, field))
 
     @classmethod
-    def check_second_currency(cls, accounts):
+    def check_second_currency(cls, accounts, field_names=None):
         pool = Pool()
         Line = pool.get('account.move.line')
+        if field_names and not (
+                field_names & (
+                    {'second_currency', 'type'}
+                    | set(cls.deferral.validation_depends))):
+            return
         for account in accounts:
             if not account.second_currency:
                 continue
@@ -1190,9 +1195,11 @@
                         account=account.rec_name))
 
     @classmethod
-    def check_move_domain(cls, accounts):
+    def check_move_domain(cls, accounts, field_names=None):
         pool = Pool()
         Line = pool.get('account.move.line')
+        if field_names and not (field_names & {'closed', 'type'}):
+            return
         accounts = [a for a in accounts if a.closed or not a.type]
         for sub_accounts in grouped_slice(accounts):
             sub_accounts = list(sub_accounts)
diff -r 4f9b64692892 -r d80510557e5e fiscalyear.py
--- a/fiscalyear.py     Mon Apr 11 22:23:58 2022 +0200
+++ b/fiscalyear.py     Mon Apr 11 23:24:20 2022 +0200
@@ -100,45 +100,54 @@
             }.get(self.state)
 
     @classmethod
-    def validate(cls, years):
-        super(FiscalYear, cls).validate(years)
-        for year in years:
-            year.check_dates()
-            year.check_post_move_sequence()
+    def validate_fields(cls, fiscalyears, field_names):
+        super().validate_fields(fiscalyears, field_names)
+        cls.check_dates(fiscalyears, field_names)
+        cls.check_post_move_sequence(fiscalyears, field_names)
 
-    def check_dates(self):
+    @classmethod
+    def check_dates(cls, fiscalyears, field_names=None):
+        if field_names and not (field_names & {
+                    'start_date', 'end_date', 'company'}):
+            return
         transaction = Transaction()
         connection = transaction.connection
-        self.__class__.lock()
+        cls.lock()
         cursor = connection.cursor()
-        table = self.__table__()
-        cursor.execute(*table.select(table.id,
-                where=(((table.start_date <= self.start_date)
-                        & (table.end_date >= self.start_date))
-                    | ((table.start_date <= self.end_date)
-                        & (table.end_date >= self.end_date))
-                    | ((table.start_date >= self.start_date)
-                        & (table.end_date <= self.end_date)))
-                & (table.company == self.company.id)
-                & (table.id != self.id)))
-        second_id = cursor.fetchone()
-        if second_id:
-            second = self.__class__(second_id[0])
-            raise FiscalYearDatesError(
-                gettext('account.msg_fiscalyear_overlap',
-                    first=self.rec_name,
-                    second=second.rec_name))
+        table = cls.__table__()
+        for year in fiscalyears:
+            cursor.execute(*table.select(table.id,
+                    where=(((table.start_date <= year.start_date)
+                            & (table.end_date >= year.start_date))
+                        | ((table.start_date <= year.end_date)
+                            & (table.end_date >= year.end_date))
+                        | ((table.start_date >= year.start_date)
+                            & (table.end_date <= year.end_date)))
+                    & (table.company == year.company.id)
+                    & (table.id != year.id)))
+            second_id = cursor.fetchone()
+            if second_id:
+                second = cls(second_id[0])
+                raise FiscalYearDatesError(
+                    gettext('account.msg_fiscalyear_overlap',
+                        first=year.rec_name,
+                        second=second.rec_name))
 
-    def check_post_move_sequence(self):
-        years = self.search([
-                ('post_move_sequence', '=', self.post_move_sequence.id),
-                ('id', '!=', self.id),
-                ])
-        if years:
-            raise FiscalYearSequenceError(
-                gettext('account.msg_fiscalyear_different_post_move_sequence',
-                    first=self.rec_name,
-                    second=years[0].rec_name))
+    @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 write(cls, *args):
diff -r 4f9b64692892 -r d80510557e5e move.py
--- a/move.py   Mon Apr 11 22:23:58 2022 +0200
+++ b/move.py   Mon Apr 11 23:24:20 2022 +0200
@@ -219,17 +219,20 @@
         return [(None, '')] + [(m, get_name(m)) for m in models]
 
     @classmethod
-    def validate(cls, moves):
-        super(Move, cls).validate(moves)
-        for move in moves:
-            move.check_date()
+    def validate_fields(cls, moves, field_names):
+        super().validate_fields(moves, field_names)
+        cls.check_date(moves, field_names)
 
-    def check_date(self):
-        if (self.date < self.period.start_date
-                or self.date > self.period.end_date):
-            raise MoveDatesError(
-                gettext('account.msg_move_date_outside_period',
-                    move=self.rec_name))
+    @classmethod
+    def check_date(cls, moves, field_names=None):
+        if field_names and not (field_names & {'date', 'period'}):
+            return
+        for move in moves:
+            if (move.date < move.period.start_date
+                    or move.date > move.period.end_date):
+                raise MoveDatesError(
+                    gettext('account.msg_move_date_outside_period',
+                        move=move.rec_name))
 
     @classmethod
     def check_modify(cls, moves):
@@ -1147,22 +1150,25 @@
         return list(set(l.id for line in lines for l in line.move.lines))
 
     @classmethod
-    def validate(cls, lines):
+    def validate_fields(cls, lines, field_names):
         super(Line, cls).validate(lines)
-        for line in lines:
-            line.check_account()
+        cls.check_account(lines, field_names)
 
-    def check_account(self):
-        if not self.account.type or self.account.closed:
-            raise AccessError(
-                gettext('account.msg_line_closed_account',
-                    account=self.account.rec_name))
-        if bool(self.party) != bool(self.account.party_required):
-            error = 'party_set' if self.party else 'party_required'
-            raise AccessError(
-                gettext('account.msg_line_%s' % error,
-                    account=self.account.rec_name,
-                    line=self.rec_name))
+    @classmethod
+    def check_account(cls, lines, field_names=None):
+        if field_names and not (field_names & {'account', 'party'}):
+            return
+        for line in lines:
+            if not line.account.type or line.account.closed:
+                raise AccessError(
+                    gettext('account.msg_line_closed_account',
+                        account=line.account.rec_name))
+            if bool(line.party) != bool(line.account.party_required):
+                error = 'party_set' if line.party else 'party_required'
+                raise AccessError(
+                    gettext('account.msg_line_%s' % error,
+                        account=line.account.rec_name,
+                        line=line.rec_name))
 
     @classmethod
     def check_journal_period_modify(cls, period, journal):
diff -r 4f9b64692892 -r d80510557e5e period.py
--- a/period.py Mon Apr 11 22:23:58 2022 +0200
+++ b/period.py Mon Apr 11 23:24:20 2022 +0200
@@ -103,59 +103,76 @@
             }.get(self.state)
 
     @classmethod
-    def validate(cls, periods):
-        super(Period, cls).validate(periods)
-        for period in periods:
-            period.check_dates()
-            period.check_fiscalyear_dates()
-            period.check_post_move_sequence()
+    def validate_fields(cls, periods, field_names):
+        super().validate_fields(periods, field_names)
+        cls.check_dates(periods, field_names)
+        cls.check_fiscalyear_dates(periods, field_names)
+        cls.check_post_move_sequence(periods, field_names)
 
-    def check_dates(self):
-        if self.type != 'standard':
-            return True
+    @classmethod
+    def check_dates(cls, periods, field_names=None):
+        if field_names and not (
+                field_names & {
+                    'start_date', 'end_date', 'fiscalyear', 'type'}):
+            return
         transaction = Transaction()
         connection = transaction.connection
-        self.__class__.lock()
-        table = self.__table__()
+        cls.lock()
+        table = cls.__table__()
         cursor = connection.cursor()
-        cursor.execute(*table.select(table.id,
-                where=(((table.start_date <= self.start_date)
-                        & (table.end_date >= self.start_date))
-                    | ((table.start_date <= self.end_date)
-                        & (table.end_date >= self.end_date))
-                    | ((table.start_date >= self.start_date)
-                        & (table.end_date <= self.end_date)))
-                & (table.fiscalyear == self.fiscalyear.id)
-                & (table.type == 'standard')
-                & (table.id != self.id)))
-        period_id = cursor.fetchone()
-        if period_id:
-            overlapping_period = self.__class__(period_id[0])
-            raise PeriodDatesError(
-                gettext('account.msg_period_overlap',
-                    first=self.rec_name,
-                    second=overlapping_period.rec_name))
+        for period in periods:
+            if period.type != 'standard':
+                continue
+            cursor.execute(*table.select(table.id,
+                    where=(((table.start_date <= period.start_date)
+                            & (table.end_date >= period.start_date))
+                        | ((table.start_date <= period.end_date)
+                            & (table.end_date >= period.end_date))
+                        | ((table.start_date >= period.start_date)
+                            & (table.end_date <= period.end_date)))
+                    & (table.fiscalyear == period.fiscalyear.id)
+                    & (table.type == 'standard')
+                    & (table.id != period.id)))
+            period_id = cursor.fetchone()
+            if period_id:
+                overlapping_period = cls(period_id[0])
+                raise PeriodDatesError(
+                    gettext('account.msg_period_overlap',
+                        first=period.rec_name,
+                        second=overlapping_period.rec_name))
 
-    def check_fiscalyear_dates(self):
-        if (self.start_date < self.fiscalyear.start_date
-                or self.end_date > self.fiscalyear.end_date):
-            raise PeriodDatesError(
-                gettext('account.msg_period_fiscalyear_dates',
-                    period=self.rec_name,
-                    fiscalyear=self.fiscalyear.rec_name))
+    @classmethod
+    def check_fiscalyear_dates(cls, periods, field_names=None):
+        if field_names and not (
+                field_names & {
+                    'start_date', 'end_date', 'fiscalyear'}):
+            return
+        for period in periods:
+            fiscalyear = period.fiscalyear
+            if (period.start_date < fiscalyear.start_date
+                    or period.end_date > fiscalyear.end_date):
+                raise PeriodDatesError(
+                    gettext('account.msg_period_fiscalyear_dates',
+                        period=period.rec_name,
+                        fiscalyear=fiscalyear.rec_name))
 
-    def check_post_move_sequence(self):
-        if not self.post_move_sequence:
+    @classmethod
+    def check_post_move_sequence(cls, periods, field_names=None):
+        if field_names and not (
+                field_names & {'post_move_sequence', 'fiscalyear'}):
             return
-        periods = self.search([
-                ('post_move_sequence', '=', self.post_move_sequence.id),
-                ('fiscalyear', '!=', self.fiscalyear.id),
-                ])
-        if periods:
-            raise PeriodSequenceError(
-                gettext('account.msg_period_same_sequence',
-                    first=self.rec_name,
-                    second=periods[0].rec_name))
+        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_id, date=None, exception=True, test_state=True):
diff -r 4f9b64692892 -r d80510557e5e tax.py
--- a/tax.py    Mon Apr 11 22:23:58 2022 +0200
+++ b/tax.py    Mon Apr 11 23:24:20 2022 +0200
@@ -578,16 +578,19 @@
         cls._order.insert(0, ('account', 'ASC'))
 
     @classmethod
-    def validate(cls, tax_templates):
-        super(TaxTemplate, cls).validate(tax_templates)
-        for tax_template in tax_templates:
-            tax_template.check_update_unit_price()
+    def validate_fields(cls, tax_templates, field_names):
+        super().validate_fields(tax_templates, field_names)
+        cls.check_update_unit_price(tax_templates, field_names)
 
-    def check_update_unit_price(self):
-        if self.update_unit_price and self.parent:
-            raise AccessError(
-                gettext('account.msg_tax_update_unit_price_with_parent',
-                    tax=self.rec_name))
+    @classmethod
+    def check_update_unit_price(cls, tax_templates, field_names=None):
+        if field_names and not (field_names & {'update_unit_price', 'parent'}):
+            return
+        for tax in tax_templates:
+            if tax.update_unit_price and tax.parent:
+                raise AccessError(gettext(
+                        'account.msg_tax_update_unit_price_with_parent',
+                        tax=tax.rec_name))
 
     @staticmethod
     def default_type():
@@ -778,16 +781,19 @@
     del _states
 
     @classmethod
-    def validate(cls, taxes):
-        super(Tax, cls).validate(taxes)
-        for tax in taxes:
-            tax.check_update_unit_price()
+    def validate_fields(cls, taxes, field_names):
+        super().validate_fields(taxes, field_names)
+        cls.check_update_unit_price(taxes, field_names)
 
-    def check_update_unit_price(self):
-        if self.parent and self.update_unit_price:
-            raise AccessError(
-                gettext('account.msg_tax_update_unit_price_with_parent',
-                    tax=self.rec_name))
+    @classmethod
+    def check_update_unit_price(cls, taxes, field_names=None):
+        if field_names and not (field_names & {'parent', 'update_unit_price'}):
+            return
+        for tax in taxes:
+            if tax.parent and tax.update_unit_price:
+                raise AccessError(gettext(
+                        'account.msg_tax_update_unit_price_with_parent',
+                        tax=tax.rec_name))
 
     @staticmethod
     def default_type():

Reply via email to