Add validate_fields to ModelStorage
issue11303 review386191002
This commit is contained in:
+13
-6
@@ -952,10 +952,10 @@ class Account(AccountMixin(), ActivePeriodMixin, tree(), ModelSQL, ModelView):
|
||||
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 @@ class Account(AccountMixin(), ActivePeriodMixin, tree(), ModelSQL, ModelView):
|
||||
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 @@ class Account(AccountMixin(), ActivePeriodMixin, tree(), ModelSQL, ModelView):
|
||||
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)
|
||||
|
||||
+43
-34
@@ -100,45 +100,54 @@ class FiscalYear(Workflow, ModelSQL, ModelView):
|
||||
}.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):
|
||||
|
||||
@@ -219,17 +219,20 @@ class Move(ModelSQL, ModelView):
|
||||
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 @@ class Line(MoveLineMixin, ModelSQL, ModelView):
|
||||
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):
|
||||
|
||||
@@ -103,59 +103,76 @@ class Period(Workflow, ModelSQL, ModelView):
|
||||
}.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))
|
||||
|
||||
def check_post_move_sequence(self):
|
||||
if not self.post_move_sequence:
|
||||
@classmethod
|
||||
def check_fiscalyear_dates(cls, periods, field_names=None):
|
||||
if field_names and not (
|
||||
field_names & {
|
||||
'start_date', 'end_date', '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:
|
||||
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))
|
||||
|
||||
@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_id, date=None, exception=True, test_state=True):
|
||||
|
||||
@@ -578,16 +578,19 @@ class TaxTemplate(sequence_ordered(), ModelSQL, ModelView, DeactivableMixin):
|
||||
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 @@ class Tax(sequence_ordered(), ModelSQL, ModelView, DeactivableMixin):
|
||||
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():
|
||||
|
||||
Reference in New Issue
Block a user