details: https://code.tryton.org/tryton/commit/d1e1210f0021
branch: default
user: Cédric Krier <[email protected]>
date: Mon Oct 05 23:21:28 2026 +0200
description:
Ensure readonly fields are copied with the default value
Since 6c611c520744, the readonly of field is enforced so the copied
value of
readonly field must be the default value to skip the check.
diffstat:
modules/account/account.py | 2 +-
modules/account/move.py | 2 +-
modules/account_asset/asset.py | 6 +++---
modules/account_payment_stripe/payment.py | 16 ++--------------
modules/party/party.py | 6 +++++-
modules/sale_advance_payment/sale.py | 2 +-
modules/sale_project_task/sale.py | 6 +++++-
trytond/trytond/model/modelsingleton.py | 11 ++++++++---
trytond/trytond/tests/test_tryton.py | 8 ++++++++
9 files changed, 34 insertions(+), 25 deletions(-)
diffs (197 lines):
diff -r 08c5c82cd1e2 -r d1e1210f0021 modules/account/account.py
--- a/modules/account/account.py Mon Oct 05 18:21:13 2026 +0200
+++ b/modules/account/account.py Mon Oct 05 23:21:28 2026 +0200
@@ -1274,7 +1274,7 @@
else:
default = default.copy()
default.setdefault('template', None)
- default.setdefault('deferrals', [])
+ default.setdefault('deferrals')
new_accounts = super().copy(accounts, default=default)
cls._rebuild_tree('parent', None, 0)
return new_accounts
diff -r 08c5c82cd1e2 -r d1e1210f0021 modules/account/move.py
--- a/modules/account/move.py Mon Oct 05 18:21:13 2026 +0200
+++ b/modules/account/move.py Mon Oct 05 23:21:28 2026 +0200
@@ -1571,7 +1571,7 @@
default.setdefault('state', 'draft')
default.setdefault('move', None)
default.setdefault('reconciliation', None)
- default.setdefault('reconciliations_delegated', [])
+ default.setdefault('reconciliations_delegated')
return super().copy(lines, default=default)
@classmethod
diff -r 08c5c82cd1e2 -r d1e1210f0021 modules/account_asset/asset.py
--- a/modules/account_asset/asset.py Mon Oct 05 18:21:13 2026 +0200
+++ b/modules/account_asset/asset.py Mon Oct 05 23:21:28 2026 +0200
@@ -728,12 +728,12 @@
default = {}
else:
default = default.copy()
- default.setdefault('lines', [])
- default.setdefault('update_moves', [])
+ default.setdefault('lines')
+ default.setdefault('update_moves')
default.setdefault('number', None)
default.setdefault('supplier_invoice_line', None)
default.setdefault('move')
- default.setdefault('revisions', [])
+ default.setdefault('revisions')
return super().copy(assets, default=default)
@classmethod
diff -r 08c5c82cd1e2 -r d1e1210f0021 modules/account_payment_stripe/payment.py
--- a/modules/account_payment_stripe/payment.py Mon Oct 05 18:21:13 2026 +0200
+++ b/modules/account_payment_stripe/payment.py Mon Oct 05 23:21:28 2026 +0200
@@ -282,10 +282,6 @@
def default_stripe_capturable(cls):
return False
- @classmethod
- def default_stripe_idempotency_key(cls):
- return uuid.uuid4().hex
-
@fields.depends('process_method',
'stripe_token', 'stripe_payment_intent_id',
'stripe_customer_source', 'stripe_customer_source_selection',
@@ -349,9 +345,7 @@
if mode == 'create':
if 'stripe_idempotency_key' not in values:
# Ensure to get a different key for each record
- # default methods are called only once
- values['stripe_idempotency_key'] = (
- cls.default_stripe_idempotency_key())
+ values['stripe_idempotency_key'] = uuid.uuid4().hex
return values
@classmethod
@@ -843,10 +837,6 @@
def get_stripe_amount(self, name):
return int(self.amount * 10 ** self.currency.digits)
- @classmethod
- def default_stripe_idempotency_key(cls):
- return uuid.uuid4().hex
-
@fields.depends('payment', '_parent_payment.currency')
def on_change_with_currency(self, name=None):
return self.payment.currency if self.payment else None
@@ -865,9 +855,7 @@
if mode == 'create':
if 'stripe_idempotency_key' not in values:
# Ensure to get a different key for each record
- # default methods are called only once
- values['stripe_idempotency_key'] = (
- cls.default_stripe_idempotency_key())
+ values['stripe_idempotency_key'] = uuid.uuid4().hex
return values
@classmethod
diff -r 08c5c82cd1e2 -r d1e1210f0021 modules/party/party.py
--- a/modules/party/party.py Mon Oct 05 18:21:13 2026 +0200
+++ b/modules/party/party.py Mon Oct 05 23:21:28 2026 +0200
@@ -968,6 +968,10 @@
pass
return code
+ @classmethod
+ def default_eu_vat_valid(cls):
+ return False
+
def pre_validate(self):
super().pre_validate()
self.check_code()
@@ -1076,7 +1080,7 @@
@classmethod
def copy(cls, identifiers, default=None):
default = default.copy() if default is not None else {}
- default.setdefault('eu_vat_valid')
+ default.setdefault('eu_vat_valid', cls.default_eu_vat_valid())
default.setdefault('eu_vat_validated_at')
return super().copy(identifiers, default=default)
diff -r 08c5c82cd1e2 -r d1e1210f0021 modules/sale_advance_payment/sale.py
--- a/modules/sale_advance_payment/sale.py Mon Oct 05 18:21:13 2026 +0200
+++ b/modules/sale_advance_payment/sale.py Mon Oct 05 23:21:28 2026 +0200
@@ -223,7 +223,7 @@
default = {}
else:
default = default.copy()
- default.setdefault('invoice_lines', [])
+ default.setdefault('invoice_lines')
return super().copy(lines, default)
def create_invoice(self):
diff -r 08c5c82cd1e2 -r d1e1210f0021 modules/sale_project_task/sale.py
--- a/modules/sale_project_task/sale.py Mon Oct 05 18:21:13 2026 +0200
+++ b/modules/sale_project_task/sale.py Mon Oct 05 23:21:28 2026 +0200
@@ -129,6 +129,10 @@
'sale_task_creation_method', **pattern)
@classmethod
+ def default_tasks_to_create(cls):
+ return False
+
+ @classmethod
def check_method(cls, sales, field_names=None):
super().check_method(sales, field_names=field_names)
if field_names and not (field_names & {
@@ -148,7 +152,7 @@
def copy(cls, sales, default=None):
default = default.copy() if default is not None else {}
default.setdefault('tasks_state')
- default.setdefault('tasks_to_create')
+ default.setdefault('tasks_to_create', cls.default_tasks_to_create())
return super().copy(sales, default=default)
@classmethod
diff -r 08c5c82cd1e2 -r d1e1210f0021 trytond/trytond/model/modelsingleton.py
--- a/trytond/trytond/model/modelsingleton.py Mon Oct 05 18:21:13 2026 +0200
+++ b/trytond/trytond/model/modelsingleton.py Mon Oct 05 23:21:28 2026 +0200
@@ -114,12 +114,17 @@
return res
@classmethod
- def default_get(cls, fields_names, with_rec_name=True):
+ def default_get(
+ cls, fields_names=None, with_rec_name=True, with_default=True):
+ if fields_names is None:
+ fields_names = cls._fields.keys()
+
if '_timestamp' in fields_names:
fields_names = list(fields_names)
fields_names.remove('_timestamp')
- default = super().default_get(fields_names,
- with_rec_name=with_rec_name)
+ default = super().default_get(
+ fields_names,
+ with_rec_name=with_rec_name, with_default=with_default)
singleton = cls.get_singleton()
if singleton:
if with_rec_name:
diff -r 08c5c82cd1e2 -r d1e1210f0021 trytond/trytond/tests/test_tryton.py
--- a/trytond/trytond/tests/test_tryton.py Mon Oct 05 18:21:13 2026 +0200
+++ b/trytond/trytond/tests/test_tryton.py Mon Oct 05 23:21:28 2026 +0200
@@ -927,6 +927,7 @@
continue
if not issubclass(model, ModelStorage):
continue
+ default_values = model.default_get(with_rec_name=False)
with self.subTest(model=mname):
model.copy([])
if copy.call_args:
@@ -939,6 +940,13 @@
fields = {
k.split('.', 1)[0] for k in default.keys()}
self.assertLessEqual(fields, klass._fields.keys())
+ for field_name in fields:
+ field = getattr(klass, field_name)
+ if field.readonly:
+ with self.subTest(field=field_name):
+ self.assertEqual(
+ default[field_name],
+ default_values.get(field_name))
copy.reset_mock()
@with_transaction()