diff --git a/modules/account/account.py b/modules/account/account.py
index 6964ef77f5..90907a9c52 100644
--- a/modules/account/account.py
+++ b/modules/account/account.py
@@ -421,6 +421,7 @@ class Type(
class OpenType(Wizard):
__name__ = 'account.account.open_type'
+ _readonly = True
start = StateTransition()
account = StateAction('account.act_account_balance_sheet')
ledger_account = StateAction('account.act_account_general_ledger')
@@ -2306,6 +2307,7 @@ class GeneralLedgerAccountParty(_GeneralLedgerAccount):
class OpenGeneralLedgerAccountParty(Wizard):
__name__ = 'account.general_ledger.account.party.open'
start_state = 'open'
+ _readonly = True
open = StateAction('account.act_general_ledger_line_form')
def do_open(self, action):
diff --git a/modules/account/account.xml b/modules/account/account.xml
index 8acbb57bc5..e760751024 100644
--- a/modules/account/account.xml
+++ b/modules/account/account.xml
@@ -462,10 +462,6 @@ this repository contains the full copyright notices and license terms. -->
account.account.type,-1
-
-
-
-
account.account
diff --git a/modules/account/move.py b/modules/account/move.py
index d35e3b065c..e4d074c8dc 100644
--- a/modules/account/move.py
+++ b/modules/account/move.py
@@ -1934,6 +1934,7 @@ class OpenJournalAsk(ModelView):
class OpenJournal(Wizard):
__name__ = 'account.move.open_journal'
+ _readonly = True
start = StateTransition()
ask = StateView('account.move.open_journal.ask',
'account.open_journal_ask_view_form', [
@@ -2003,6 +2004,7 @@ class OpenJournal(Wizard):
class OpenAccount(Wizard):
__name__ = 'account.move.open_account'
start_state = 'open_'
+ _readonly = True
open_ = StateAction('account.act_move_line_form')
def do_open_(self, action):
diff --git a/modules/account/tax.py b/modules/account/tax.py
index f016eed00c..787abbfbd6 100644
--- a/modules/account/tax.py
+++ b/modules/account/tax.py
@@ -1841,6 +1841,7 @@ class TaxRuleLine(sequence_ordered(), ModelSQL, ModelView, MatchMixin):
class OpenTaxCode(Wizard):
__name__ = 'account.tax.open_code'
start_state = 'open_'
+ _readonly = True
open_ = StateAction('account.act_tax_line_form')
def do_open_(self, action):
diff --git a/modules/account_move_line_grouping/account.py b/modules/account_move_line_grouping/account.py
index 9465a4c853..4f815f1432 100644
--- a/modules/account_move_line_grouping/account.py
+++ b/modules/account_move_line_grouping/account.py
@@ -250,6 +250,7 @@ class MoveLineGroup_MoveLine(ModelSQL):
class OpenAccount(metaclass=PoolMeta):
__name__ = 'account.move.open_account'
+ _readonly = True
def do_open_(self, action):
pool = Pool()
diff --git a/modules/analytic_account/line.py b/modules/analytic_account/line.py
index 942ccf880f..29e2617c5e 100644
--- a/modules/analytic_account/line.py
+++ b/modules/analytic_account/line.py
@@ -273,6 +273,7 @@ class MoveLine(metaclass=PoolMeta):
class OpenAccount(Wizard):
__name__ = 'analytic_account.line.open_account'
start_state = 'open_'
+ _readonly = True
open_ = StateAction('analytic_account.act_line_form')
def do_open_(self, action):
diff --git a/modules/production/bom.py b/modules/production/bom.py
index 07d2a5d2b5..6d25039c4e 100644
--- a/modules/production/bom.py
+++ b/modules/production/bom.py
@@ -318,6 +318,7 @@ class OpenBOMTreeTree(ModelView):
class OpenBOMTree(Wizard):
__name__ = 'production.bom.tree.open'
+ _readonly = True
start = StateView('production.bom.tree.open.start',
'production.bom_tree_open_start_view_form', [
diff --git a/modules/project_invoice/project.py b/modules/project_invoice/project.py
index eca2165fae..cca22943be 100644
--- a/modules/project_invoice/project.py
+++ b/modules/project_invoice/project.py
@@ -673,6 +673,7 @@ class WorkInvoicedProgress(ModelView, ModelSQL):
class OpenInvoice(Wizard):
__name__ = 'project.open_invoice'
start_state = 'open_'
+ _readonly = True
open_ = StateAction('account_invoice.act_invoice_form')
def do_open_(self, action):
diff --git a/modules/sale/sale.py b/modules/sale/sale.py
index fda1cafac0..bfcdcc1aa4 100644
--- a/modules/sale/sale.py
+++ b/modules/sale/sale.py
@@ -2564,6 +2564,7 @@ class ModifyHeader(Wizard):
class OpenProduct(Wizard):
__name__ = 'sale.open_product'
+ _readonly = True
start = StateAction('sale.act_product')
diff --git a/modules/sale/sale_reporting.py b/modules/sale/sale_reporting.py
index ff382f2bd2..1d0a640a8b 100644
--- a/modules/sale/sale_reporting.py
+++ b/modules/sale/sale_reporting.py
@@ -910,6 +910,7 @@ class RegionTree(ModelSQL, ModelView):
class OpenRegionTree(Wizard):
__name__ = 'sale.reporting.region.tree.open'
+ _readonly = True
start = StateAction('sale.act_reporting_country_tree')
@@ -1051,6 +1052,7 @@ class CountryTree(UnionMixin, Abstract, ModelView):
class OpenCountryTree(Wizard):
__name__ = 'sale.reporting.country.tree.open'
+ _readonly = True
start = StateTransition()
country = StateAction('sale.act_reporting_country_time_series')
diff --git a/modules/stock/product.py b/modules/stock/product.py
index a9869baa7a..37a7599e9d 100644
--- a/modules/stock/product.py
+++ b/modules/stock/product.py
@@ -576,6 +576,7 @@ class ProductByLocationContext(ModelView):
class OpenProductQuantitiesByWarehouse(Wizard):
__name__ = 'stock.product_quantities_warehouse.open'
start_state = 'open_'
+ _readonly = True
open_ = StateAction('stock.act_product_quantities_warehouse')
def do_open_(self, action):
@@ -869,6 +870,7 @@ class ProductQuantitiesByWarehouseContext(ModelView):
class OpenProductQuantitiesByWarehouseMove(Wizard):
__name__ = 'stock.product_quantities_warehouse.move.open'
start_state = 'open_'
+ _readonly = True
open_ = StateAction('stock.act_product_quantities_warehouse_move')
def do_open_(self, action):
diff --git a/trytond/CHANGELOG b/trytond/CHANGELOG
index 5193bfd39a..40cd3a2095 100644
--- a/trytond/CHANGELOG
+++ b/trytond/CHANGELOG
@@ -1,3 +1,4 @@
+* Manage readonly wizard
* Export Many2One and Reference using record name
* Support import of one2many as list of name
* Support export of xxx2many fields as list of name
diff --git a/trytond/doc/ref/wizard.rst b/trytond/doc/ref/wizard.rst
index 5bfd45ec18..3a21f49813 100644
--- a/trytond/doc/ref/wizard.rst
+++ b/trytond/doc/ref/wizard.rst
@@ -37,6 +37,13 @@ Class attributes are:
deletion of the wizard and it may return one of the :ref:`client side action
keywords `.
+.. attribute:: Wizard._readonly
+
+ A boolean to set :attr:`trytond.transaction.Transaction.readonly` when
+ executing the wizard.
+ When set to ``True``, ``write`` access on the ``active_model`` is not
+ needed.
+
.. attribute:: Wizard.__rpc__
Same as :attr:`trytond.model.Model.__rpc__`.
diff --git a/trytond/trytond/wizard/wizard.py b/trytond/trytond/wizard/wizard.py
index fc19ab8a3a..7cf830e1a5 100644
--- a/trytond/trytond/wizard/wizard.py
+++ b/trytond/trytond/wizard/wizard.py
@@ -198,6 +198,7 @@ class Wizard(URLMixin, PoolBase):
__no_slots__ = True # To allow setting State
start_state = 'start'
end_state = 'end'
+ _readonly = False
@classmethod
def __setup__(cls):
@@ -205,7 +206,7 @@ class Wizard(URLMixin, PoolBase):
cls.__rpc__ = {
'create': RPC(readonly=False),
'delete': RPC(readonly=False),
- 'execute': RPC(readonly=False, check_access=False),
+ 'execute': RPC(readonly=cls._readonly, check_access=False),
}
# Copy states
@@ -248,9 +249,10 @@ class Wizard(URLMixin, PoolBase):
ActionWizard = pool.get('ir.action.wizard')
User = pool.get('res.user')
Group = pool.get('res.group')
- context = Transaction().context
+ transaction = Transaction()
+ context = transaction.context
- if Transaction().user == 0:
+ if transaction.user == 0:
return
with check_access():
@@ -284,7 +286,7 @@ class Wizard(URLMixin, PoolBase):
gettext(
'ir.msg_context_groups',
groups=', '.join(g.rec_name for g in groups)))
- elif model and model != 'ir.ui.menu':
+ elif model and model != 'ir.ui.menu' and not transaction.readonly:
if (not callable(getattr(Model, 'table_query', None))
or Model.write.__func__ != ModelSQL.write.__func__):
ModelAccess.check(model, 'write')