[ADD] base: direct support for binding an action to a model

This commit is contained in:
Raphael Collet
2017-08-28 09:53:23 +02:00
parent 60d9f6fef9
commit 55549f1e61
38 changed files with 181 additions and 450 deletions
@@ -328,19 +328,11 @@
<field name="type">ir.actions.server</field>
<field name="state">code</field>
<field name="model_id" ref="account.model_account_payment"/>
<field name="binding_model_id" ref="account.model_account_payment"/>
<field name="code">
records.post()
</field>
</record>
<record id="account_confirm_payments" model="ir.values">
<field name="model_id" ref="account.model_account_payment"/>
<field name="name">Confirm Payments</field>
<field name="key2">client_action_multi</field>
<field name="value" eval="'ir.actions.server,' +str(ref('action_account_confirm_payments'))" />
<field name="key">action</field>
<field name="model">account.payment</field>
</record>
</data>
</odoo>
@@ -26,15 +26,7 @@
<field name="view_mode">tree,form</field>
<field name="view_id" ref="view_account_move_reversal"/>
<field name="target">new</field>
</record>
<record model="ir.values" id="action_account_move_reversal">
<field name="model_id" ref="account.model_account_move" />
<field name="name">Reverse Moves</field>
<field name="key2">client_action_multi</field>
<field name="value" eval="'ir.actions.act_window,' +str(ref('action_view_account_move_reversal'))" />
<field name="key">action</field>
<field name="model">account.move</field>
<field name="binding_model_id" ref="account.model_account_move" />
</record>
</data>
</odoo>
@@ -33,15 +33,7 @@
<field name="view_mode">form</field>
<field name="view_id" ref="view_account_move_line_reconcile_full"/>
<field name="target">new</field>
</record>
<record model="ir.values" id="action_account_move_line_reconcile_prompt_values">
<field name="model_id" ref="account.model_account_move_line" />
<field name="name">Reconcile Entries</field>
<field name="key2">client_action_multi</field>
<field name="value" eval="'ir.actions.act_window,' +str(ref('action_view_account_move_line_reconcile'))" />
<field name="key">action</field>
<field name="model">account.move.line</field>
<field name="binding_model_id" ref="account.model_account_move_line" />
</record>
<record id="account_move_line_reconcile_writeoff" model="ir.ui.view">
@@ -25,15 +25,8 @@
<field name="view_mode">form</field>
<field name="view_id" ref="account_report_general_ledger_view"/>
<field name="target">new</field>
</record>
<record id="action_account_general_ledger_values" model="ir.values">
<field name="model_id" ref="account.model_account_account" />
<field name="name">General Ledger</field>
<field name="key2">client_print_multi</field>
<field name="value" eval="'ir.actions.act_window,' +str(ref('action_account_general_ledger_menu'))" />
<field name="key">action</field>
<field name="model">account.account</field>
<field name="binding_model_id" ref="account.model_account_account" />
<field name="binding_type">report</field>
</record>
<menuitem
@@ -26,15 +26,8 @@
<field name="view_mode">form</field>
<field name="view_id" ref="account_report_partner_ledger_view"/>
<field name="target">new</field>
</record>
<record id="action_account_partner_ledger_values" model="ir.values">
<field name="model_id" ref="account.model_account_account" />
<field name="name">Partner Ledger</field>
<field name="key2">client_print_multi</field>
<field name="value" eval="'ir.actions.act_window,' +str(ref('action_account_partner_ledger_menu'))" />
<field name="key">action</field>
<field name="model">account.account</field>
<field name="binding_model_id" ref="account.model_account_account" />
<field name="binding_type">report</field>
</record>
<menuitem
@@ -25,6 +25,8 @@
<field name="view_mode">form</field>
<field name="view_id" ref="account_report_balance_view"/>
<field name="target">new</field>
<field name="binding_model_id" ref="account.model_account_account" />
<field name="binding_type">report</field>
</record>
<menuitem id="menu_general_Balance_report"
@@ -33,13 +35,4 @@
action="action_account_balance_menu"
groups="account.group_account_user"/>
<record id="action_account_balance_report_values1" model="ir.values">
<field name="model_id" ref="account.model_account_account" />
<field name="name">Trial Balance</field>
<field name="key2">client_print_multi</field>
<field name="value" eval="'ir.actions.act_window,' +str(ref('action_account_balance_menu'))" />
<field name="key">action</field>
<field name="model">account.account</field>
</record>
</odoo>
@@ -22,17 +22,9 @@
<field name="res_model">account.unreconcile</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="view_id" ref="account_unreconcile_view"/>
<field name="target">new</field>
</record>
<record model="ir.values" id="account_unreconcile_values">
<field name="model_id" ref="account.model_account_move_line" />
<field name="name">Unreconcile Entries</field>
<field name="key2">client_action_multi</field>
<field name="value" eval="'ir.actions.act_window,' + str(ref('action_account_unreconcile'))" />
<field name="key">action</field>
<field name="model">account.move.line</field>
<field name="view_id" ref="account_unreconcile_view"/>
<field name="target">new</field>
<field name="binding_model_id" ref="account.model_account_move_line" />
</record>
</data>
@@ -27,15 +27,7 @@
<field name="context">{}</field>
<field name="target">new</field>
<field name="help">This wizard will validate all journal entries selected. Once journal entries are validated, you can not update them anymore.</field>
</record>
<record model="ir.values" id="validate_account_move_values">
<field name="model_id" ref="account.model_account_move" />
<field name="name">Post Journal Entries</field>
<field name="key2">client_action_multi</field>
<field name="value" eval="'ir.actions.act_window,' + str(ref('action_validate_account_move'))" />
<field name="key">action</field>
<field name="model">account.move</field>
<field name="binding_model_id" ref="account.model_account_move" />
</record>
</data>
@@ -14,20 +14,12 @@
<record model="ir.actions.server" id="action_account_print_checks">
<field name="name">Print Checks</field>
<field name="model_id" ref="account.model_account_payment"/>
<field name="binding_model_id" ref="account.model_account_payment" />
<field name="code">
if records:
action = records.print_checks()
</field>
</record>
<record model="ir.values" id="account_print_checks">
<field name="model_id" ref="account.model_account_payment" />
<field name="name">Print Checks</field>
<field name="key2">client_action_multi</field>
<field name="value" eval="'ir.actions.server,' +str(ref('action_account_print_checks'))" />
<field name="key">action</field>
<field name="model">account.payment</field>
</record>
</data>
</odoo>
@@ -12,7 +12,7 @@
</xpath>
<xpath expr="//button[@name='unlink_action']" position="replace">
<button name="unlink_action_for_menu" string="Remove Action" type="object"
attrs="{'invisible':[('menu_ir_values_id','=',False)]}"
attrs="{'invisible':[('binding_model_id','=',False)]}"
help="Remove the contextual action related to this server action"/>
</xpath>
<div class="oe_title" position="before">
+2 -8
View File
@@ -715,8 +715,9 @@
'Mark as Lost' in action dropdown
-->
<record id="action_mark_as_lost" model="ir.actions.server">
<field name="name">Crm: Mark Leads as lost</field>
<field name="name">Mark as lost</field>
<field name="model_id" ref="model_crm_lead"/>
<field name="binding_model_id" ref="crm.model_crm_lead"/>
<field name="state">code</field>
<field name="code">
if record:
@@ -726,13 +727,6 @@ if record:
</field>
</record>
<record id="ir_mark_as_lost" model="ir.values">
<field eval="'client_action_multi'" name="key2"/>
<field eval="'crm.lead'" name="model"/>
<field name="name">Mark as lost</field>
<field eval="'ir.actions.server,%d'%action_mark_as_lost" name="value"/>
</record>
<!--
Menu Actions
-->
+1 -9
View File
@@ -292,15 +292,7 @@
<field name="domain">[('id','in',active_ids)]</field>
<field name="view_type">tree</field>
<field name="view_id" ref="view_partner_tree2"/>
</record>
<record id="hr_employee_action_subordinate_hierachy_mutli" model="ir.values">
<field name="name">Subordinate Hierarchy</field>
<field name="model_id" ref="base.model_res_partner"/>
<field name="value" eval="'ir.actions.act_window,' + str(ref('hr_employee_action_subordinate_hierachy'))"/>
<field name="key">action</field>
<field name="key2">client_action_multi</field>
<field name="model">hr.employee</field>
<field name="binding_model_id" ref="base.model_res_partner"/>
</record>
<!-- Employee Category -->
+1 -8
View File
@@ -736,6 +736,7 @@
<field name="name">Expense: Submit To Manager</field>
<field name="type">ir.actions.server</field>
<field name="model_id" ref="model_hr_expense"/>
<field name="binding_model_id" ref="model_hr_expense"/>
<field name="state">code</field>
<field name="code">
if records:
@@ -743,14 +744,6 @@ if records:
</field>
</record>
<record id="action_hr_expense_submit" model="ir.values">
<field name="name">Submit To Manager</field>
<field name="model_id" ref="model_hr_expense"/>
<field name="model">hr.expense</field>
<field name="key2">client_action_multi</field>
<field eval="'ir.actions.server,%d'%hr_expense_submit_action_server" name="value"/>
</record>
<menuitem id="menu_hr_expense_root" name="Expenses" sequence="100" web_icon="hr_expense,static/description/icon.png"/>
<menuitem id="menu_hr_expense_my_expenses" name="My Expenses" sequence="1" parent="menu_hr_expense_root" groups="base.group_user"/>
@@ -28,15 +28,8 @@
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
<record id="hr_holidays_summary_employee_value" model="ir.values">
<field name="model_id" ref="hr.model_hr_employee" />
<field name="name">Leaves Summary</field>
<field name="key2">client_print_multi</field>
<field name="value" eval="'ir.actions.act_window,' + str(ref('action_hr_holidays_summary_employee'))" />
<field name="key">action</field>
<field name="model">hr.employee</field>
<field name="binding_model_id" ref="hr.model_hr_employee" />
<field name="binding_type">report</field>
</record>
</odoo>
@@ -26,15 +26,8 @@
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
<record model="ir.values" id="payslip_lines_contribution_register_value">
<field name="model_id" ref="model_hr_contribution_register" />
<field name="name">PaySlip Lines</field>
<field name="key2">client_print_multi</field>
<field name="value" eval="'ir.actions.act_window,' + str(ref('action_payslip_lines_contribution_register'))" />
<field name="key">action</field>
<field name="model">hr.contribution.register</field>
<field name="binding_model_id" ref="model_hr_contribution_register" />
<field name="binding_type">report</field>
</record>
</odoo>
+3 -27
View File
@@ -3,6 +3,7 @@
<record id="lunch_order_line_action_order" model="ir.actions.server">
<field name="name">Lunch: Order meals</field>
<field name="model_id" ref="model_lunch_order_line"/>
<field name="binding_model_id" ref="model_lunch_order_line"/>
<field name="state">code</field>
<field name="code">
if records:
@@ -10,45 +11,20 @@ if records:
</field>
</record>
<record id="ir_lunch_order_line_action_order" model="ir.values">
<field name="model_id" ref="model_lunch_order_line" />
<field name="name">Order meals</field>
<field name="key2">client_action_multi</field>
<field eval="'ir.actions.server,%d'%lunch_order_line_action_order" name="value"/>
<field name="key">action</field>
<field name="model">lunch.order.line</field>
</record>
<record id="lunch_order_line_action_confirm" model="ir.actions.server">
<field name="name">Lunch: Receive meals</field>
<field name="model_id" ref="model_lunch_order_line"/>
<field name="binding_model_id" ref="model_lunch_order_line"/>
<field name="state">code</field>
<field name="code">records.confirm()</field>
</record>
<record id="ir_lunch_order_line_action_confirm" model="ir.values">
<field name="model_id" ref="model_lunch_order_line" />
<field name="name">Receive meals</field>
<field name="key2">client_action_multi</field>
<field eval="'ir.actions.server,%d'%lunch_order_line_action_confirm" name="value"/>
<field name="key">action</field>
<field name="model">lunch.order.line</field>
</record>
<record id="lunch_order_line_action_cancel" model="ir.actions.server">
<field name="name">Lunch: Cancel meals</field>
<field name="model_id" ref="model_lunch_order_line"/>
<field name="binding_model_id" ref="model_lunch_order_line"/>
<field name="state">code</field>
<field name="code">records.cancel()</field>
</record>
<record id="ir_lunch_order_line_action_cancel" model="ir.values">
<field name="model_id" ref="model_lunch_order_line" />
<field name="name">Cancel meals</field>
<field name="key2">client_action_multi</field>
<field eval="'ir.actions.server,%d'%lunch_order_line_action_cancel" name="value"/>
<field name="key">action</field>
<field name="model">lunch.order.line</field>
</record>
</odoo>
+1 -10
View File
@@ -548,20 +548,11 @@
<field name="name">Lunch: Archive/Restore products</field>
<field name="type">ir.actions.server</field>
<field name="model_id" ref="model_lunch_product" />
<field name="binding_model_id" ref="model_lunch_product" />
<field name="state">code</field>
<field name="code">records.toggle_active()</field>
</record>
<record id="ir_values_lunch_archive_product" model="ir.values">
<field name="name">action_lunch_archive_product</field>
<field name="action_id" ref="action_server_lunch_archive_product" />
<field name="value" eval="'ir.actions.server,' + str(ref('action_server_lunch_archive_product'))"/>
<field name="key">action</field>
<field name="model_id" ref="model_lunch_product" />
<field name="model">lunch.product</field>
<field name="key2">client_action_multi</field>
</record>
<!-- Search for product -->
<record id="lunch_product_view_search" model="ir.ui.view">
<field name="name">lunch.product.search</field>
+3 -17
View File
@@ -171,8 +171,6 @@ class MailTemplate(models.Model):
ref_ir_act_window = fields.Many2one('ir.actions.act_window', 'Sidebar action', readonly=True, copy=False,
help="Sidebar action to make this template available on records "
"of the related document model")
ref_ir_value = fields.Many2one('ir.values', 'Sidebar Button', readonly=True, copy=False,
help="Sidebar button to open the sidebar action")
attachment_ids = fields.Many2many('ir.attachment', 'email_template_attachment_rel', 'email_template_id',
'attachment_id', 'Attachments',
help="You may attach files to this template, to be added to all "
@@ -255,40 +253,28 @@ class MailTemplate(models.Model):
for template in self:
if template.ref_ir_act_window:
template.ref_ir_act_window.sudo().unlink()
if template.ref_ir_value:
template.ref_ir_value.sudo().unlink()
return True
@api.multi
def create_action(self):
ActWindowSudo = self.env['ir.actions.act_window'].sudo()
IrValuesSudo = self.env['ir.values'].sudo()
view = self.env.ref('mail.email_compose_message_wizard_form')
for template in self:
src_obj = template.model_id.model
button_name = _('Send Mail (%s)') % template.name
action = ActWindowSudo.create({
'name': button_name,
'type': 'ir.actions.act_window',
'res_model': 'mail.compose.message',
'src_model': src_obj,
'src_model': template.model_id.model,
'view_type': 'form',
'context': "{'default_composition_mode': 'mass_mail', 'default_template_id' : %d, 'default_use_template': True}" % (template.id),
'view_mode': 'form,tree',
'view_id': view.id,
'target': 'new',
'binding_model_id': template.model_id.id,
})
ir_value = IrValuesSudo.create({
'name': button_name,
'model': src_obj,
'key2': 'client_action_multi',
'value': "ir.actions.act_window,%s" % action.id})
template.write({
'ref_ir_act_window': action.id,
'ref_ir_value': ir_value.id,
})
template.write({'ref_ir_act_window': action.id})
return True
+2 -4
View File
@@ -129,15 +129,13 @@ class TestMailTemplate(TestMail):
def test_add_context_action(self):
self.email_template.create_action()
# check template act_window and ir_values has been updated
# check template act_window has been updated
self.assertTrue(bool(self.email_template.ref_ir_act_window))
self.assertTrue(bool(self.email_template.ref_ir_value))
# check those records
action = self.email_template.ref_ir_act_window
self.assertEqual(action.name, 'Send Mail (%s)' % self.email_template.name)
value = self.email_template.ref_ir_value
self.assertEqual(value.name, 'Send Mail (%s)' % self.email_template.name)
self.assertEqual(action.binding_model_id.model, 'mail.test')
def test_set_scheduled_date_on_a_template(self):
self.email_template_in_2_days = self.email_template.copy()
+1 -6
View File
@@ -239,12 +239,7 @@
<field name="view_type">tree</field>
<field name="view_id" ref="mrp_bom_line_tree_view"/>
<field name="view_type">tree</field>
</record>
<record id="ir_BOM_structure" model="ir.values">
<field eval="'client_action_multi'" name="key2"/>
<field eval="'mrp.bom'" name="model"/>
<field name="name">Bill of Materials Structure</field>
<field eval="'ir.actions.act_window,'+str(mrp_bom_line_action_from_bom)" name="value"/>
<field name="binding_model_id" ref="mrp.model_mrp_bom"/>
</record>
<record id="template_open_bom" model="ir.actions.act_window">
+1 -9
View File
@@ -24,19 +24,11 @@
<record id="production_order_server_action" model="ir.actions.server">
<field name="name">Mrp: Plan Production Orders</field>
<field name="model_id" ref="mrp.model_mrp_production"/>
<field name="binding_model_id" ref="mrp.model_mrp_production"/>
<field name="state">code</field>
<field name="code">records.button_plan()</field>
</record>
<record id="run_procurement_order_action" model="ir.values">
<field name="model_id" ref="mrp.model_mrp_production" />
<field name="name">Plan Orders</field>
<field name="key2">client_action_multi</field>
<field name="key">action</field>
<field name="model">mrp.production</field>
<field name="value" eval="'ir.actions.server,' + str(ref('production_order_server_action'))" />
</record>
<record id="mrp_production_form_view" model="ir.ui.view">
<field name="name">mrp.production.form</field>
<field name="model">mrp.production</field>
+2 -10
View File
@@ -337,8 +337,9 @@
</record>
<record id="procurement_order_server_action" model="ir.actions.server">
<field name="name">Procurement: Run Procurements</field>
<field name="name">Run Procurements</field>
<field name="model_id" ref="model_procurement_order"/>
<field name="binding_model_id" ref="model_procurement_order"/>
<field name="state">code</field>
<field name="code">
if records:
@@ -346,14 +347,5 @@ if records:
</field>
</record>
<record id="run_procurement_order_action" model="ir.values">
<field name="model_id" ref="procurement.model_procurement_order" />
<field name="name">Run Procurements</field>
<field name="key2">client_action_multi</field>
<field name="key">action</field>
<field name="model">procurement.order</field>
<field name="value" eval="'ir.actions.server,' + str(ref('procurement_order_server_action'))" />
</record>
</data>
</odoo>
-7
View File
@@ -696,13 +696,6 @@ action = model.activate_sample_project()
<field name="context">{'project_id':active_id}</field>
</record>
<record id="ir_project_task_open" model="ir.values">
<field eval="'tree_but_open'" name="key2"/>
<field eval="'project.project'" name="model"/>
<field name="name">View project's tasks</field>
<field eval="'ir.actions.act_window,'+str(dblc_proj)" name="value"/>
</record>
<!-- Task types -->
<record id="task_type_search" model="ir.ui.view">
<field name="name">project.task.type.search</field>
@@ -48,16 +48,8 @@
<field name="view_mode">form</field>
<field name="target">new</field>
<field name="groups_id" eval="[(4,ref('sales_team.group_sale_salesman'))]"/>
</record>
<!-- TODO: check if we need this -->
<record model="ir.values" id="sale_order_line_make_invoice">
<field name="model_id" ref="sale.model_sale_order_line" />
<field name="name">Invoice Orders</field>
<field name="key2">client_action_multi</field>
<field name="value" eval="'ir.actions.act_window,' + str(ref('action_view_sale_advance_payment_inv'))" />
<field name="key">action</field>
<field name="model">sale.order</field>
<!-- TODO: check if we need this -->
<field name="binding_model_id" ref="sale.model_sale_order_line" />
</record>
</odoo>
+1 -10
View File
@@ -682,6 +682,7 @@
<field name="name">Survey: Clean test answers</field>
<field name="type">ir.actions.server</field>
<field name="model_id" ref="model_survey_survey" />
<field name="binding_model_id" ref="model_survey_survey" />
<field name="state">code</field>
<field name="code">
if records:
@@ -689,16 +690,6 @@ if records:
</field>
</record>
<record id="survey_values_action_clean_test_answers" model="ir.values">
<field name="name">Survey clean test answers</field>
<field name="action_id" ref="survey_action_server_clean_test_answers" />
<field name="value" eval="'ir.actions.server,' + str(ref('survey_action_server_clean_test_answers'))"/>
<field name="key">action</field>
<field name="model_id" ref="model_survey_survey" />
<field name="model">survey.survey</field>
<field name="key2">client_action_multi</field>
</record>
<!-- MENU ELEMENTS -->
<!-- Left menu categories-->
@@ -122,8 +122,9 @@
</record>
<record id="action_assign_salesman_according_assigned_partner" model="ir.actions.server">
<field name="name">Crm Assignation: Assign salesman of assigned partner</field>
<field name="name">Assign salesman of assigned partner</field>
<field name="model_id" ref="model_crm_lead"/>
<field name="binding_model_id" ref="model_crm_lead"/>
<field name="state">code</field>
<field name="code">
if env.context.get('active_domain'):
@@ -132,13 +133,4 @@ records.assign_salesman_of_assigned_partner()
</field>
</record>
<record model="ir.values" id="ir_assign_salesman_according_assigned_partner">
<field name="model_id" ref="model_crm_lead" />
<field name="name">Assign salesman of assigned partner</field>
<field name="key2">client_action_multi</field>
<field eval="'ir.actions.server,%d'%action_assign_salesman_according_assigned_partner" name="value"/>
<field name="key">action</field>
<field name="model">crm.lead</field>
</record>
</odoo>
+47 -16
View File
@@ -8,6 +8,7 @@ from odoo.tools.safe_eval import safe_eval, test_python_expr
from odoo.tools import pycompat
from odoo.http import request
from collections import defaultdict
import datetime
import dateutil
import logging
@@ -29,6 +30,11 @@ class IrActions(models.Model):
help = fields.Html(string='Action Description',
help='Optional help text for the users with a description of the target view, such as its usage and purpose.',
translate=True)
binding_model_id = fields.Many2one('ir.model', ondelete='cascade',
help="Setting a value makes this action available in the sidebar for the given model.")
binding_type = fields.Selection([('action', 'Action'),
('report', 'Report')],
required=True, default='action')
def _compute_xml_id(self):
res = self.get_external_id()
@@ -38,6 +44,8 @@ class IrActions(models.Model):
@api.model
def create(self, vals):
res = super(IrActions, self).create(vals)
# self.get_bindings() depends on action records
self.clear_caches()
# ir_values.get_actions() depends on action records
self.env['ir.values'].clear_caches()
return res
@@ -45,6 +53,8 @@ class IrActions(models.Model):
@api.multi
def write(self, vals):
res = super(IrActions, self).write(vals)
# self.get_bindings() depends on action records
self.clear_caches()
# ir_values.get_actions() depends on action records
self.env['ir.values'].clear_caches()
return res
@@ -56,6 +66,8 @@ class IrActions(models.Model):
todos = self.env['ir.actions.todo'].search([('action_id', 'in', self.ids)])
todos.unlink()
res = super(IrActions, self).unlink()
# self.get_bindings() depends on action records
self.clear_caches()
# ir_values.get_actions() depends on action records
self.env['ir.values'].clear_caches()
return res
@@ -72,6 +84,38 @@ class IrActions(models.Model):
'timezone': timezone,
}
@api.model
@tools.ormcache('frozenset(self.env.user.groups_id.ids)', 'model_name')
def get_bindings(self, model_name):
""" Retrieve the list of actions bound to the given model.
:return: a dict mapping binding types to a list of dict describing
actions, where the latter is given by calling the method
``read`` on the action record.
"""
cr = self.env.cr
query = """ SELECT a.id, a.type, a.binding_type
FROM ir_actions a, ir_model m
WHERE a.binding_model_id=m.id AND m.model=%s
ORDER BY a.id """
cr.execute(query, [model_name])
# discard unauthorized actions, and read action definitions
result = defaultdict(list)
user_groups = self.env.user.groups_id
for action_id, action_model, binding_type in cr.fetchall():
try:
action = self.env[action_model].browse(action_id)
action_groups = getattr(action, 'groups_id', ())
if action_groups and not action_groups & user_groups:
# the user may not perform this action
continue
result[binding_type].append(action.read()[0])
except (AccessError, MissingError):
continue
return result
class IrActionsActWindow(models.Model):
_name = 'ir.actions.act_window'
@@ -320,9 +364,6 @@ class IrActionsServer(models.Model):
model_id = fields.Many2one('ir.model', string='Model', required=True, ondelete='cascade',
help="Model on which the server action runs.")
model_name = fields.Char(related='model_id.model', readonly=True, store=True)
menu_ir_values_id = fields.Many2one('ir.values', string='Action on Object',
copy=False, readonly=True,
help='IrValues entry of the related more menu entry action')
# Python code
code = fields.Text(string='Python Code', groups='base.group_system',
default=DEFAULT_PYTHON_CODE,
@@ -365,25 +406,15 @@ class IrActionsServer(models.Model):
def create_action(self):
""" Create a contextual action for each server action. """
for action in self:
ir_values = self.env['ir.values'].sudo().create({
'name': _('Run %s') % action.name,
'model': action.model_id.model,
'key2': 'client_action_multi',
'value': "ir.actions.server,%s" % action.id,
})
action.write({'menu_ir_values_id': ir_values.id})
action.write({'binding_model_id': action.model_id.id,
'binding_type': 'action'})
return True
@api.multi
def unlink_action(self):
""" Remove the contextual actions created for the server actions. """
self.check_access_rights('write', raise_exception=True)
for action in self:
if action.menu_ir_values_id:
try:
action.menu_ir_values_id.sudo().unlink()
except Exception:
raise UserError(_('Deletion of the action record failed.'))
self.filtered('binding_model_id').write({'binding_model_id': False})
return True
@api.model
+6 -6
View File
@@ -52,14 +52,14 @@
<field name="model">ir.actions.report</field>
<field name="arch" type="xml">
<form string="Report">
<field name="ir_values_id" invisible="1"/>
<field name="binding_model_id" invisible="1"/>
<sheet>
<div class="oe_button_box" name="button_box">
<button name="create_action" string="Add in the 'Print' menu" type="object"
attrs="{'invisible':[('ir_values_id','!=',False)]}" icon="fa-plus-square"
attrs="{'invisible':[('binding_model_id','!=',False)]}" icon="fa-plus-square"
help="Display an option on related documents to print this report" class="oe_stat_button"/>
<button name="unlink_action" string="Remove from the 'Print' menu" type="object"
attrs="{'invisible':[('ir_values_id','=',False)]}" icon="fa-minus-square"
attrs="{'invisible':[('binding_model_id','=',False)]}" icon="fa-minus-square"
help="Remove the contextual action related this report" class="oe_stat_button"/>
<button name="associated_view" string="QWeb views" type="object"
attrs="{'invisible':[('report_type', 'not in', ['qweb-pdf', 'qweb-html'])]}" icon='fa-code'
@@ -254,13 +254,13 @@
<field name="arch" type="xml">
<form string="Server Action">
<header>
<field name="menu_ir_values_id" invisible="1"/>
<field name="binding_model_id" invisible="1"/>
<button name="create_action" string="Create Contextual Action" type="object"
class="btn-primary"
attrs="{'invisible':[('menu_ir_values_id','!=',False)]}"
attrs="{'invisible':[('binding_model_id','!=',False)]}"
help="Display an option in the 'More' top-menu in order to run this action."/>
<button name="unlink_action" string="Remove Contextual Action" type="object"
attrs="{'invisible':[('menu_ir_values_id','=',False)]}"
attrs="{'invisible':[('binding_model_id','=',False)]}"
help="Remove 'More' top-menu contextual action related to this action"/>
</header>
<sheet>
+4 -15
View File
@@ -79,6 +79,7 @@ class IrActionsReport(models.Model):
name = fields.Char(translate=True)
type = fields.Char(default='ir.actions.report')
binding_type = fields.Selection(default='report')
model = fields.Char(required=True)
report_type = fields.Selection([('qweb-html', 'HTML'), ('qweb-pdf', 'PDF')], required=True, default='qweb-pdf',
@@ -90,8 +91,6 @@ class IrActionsReport(models.Model):
report_file = fields.Char(string='Report File', required=False, readonly=False, store=True,
help="The path to the main report file (depending on Report Type) or empty if the content is in another field")
groups_id = fields.Many2many('res.groups', 'res_groups_report_rel', 'uid', 'gid', string='Groups')
ir_values_id = fields.Many2one('ir.values', string='More Menu entry', readonly=True,
help='More menu entry.', copy=False)
multi = fields.Boolean(string='On Multiple Doc.', help="If set to true, the action will not be displayed on the right toolbar of a form view.")
paperformat_id = fields.Many2one('report.paperformat', 'Paper format')
@@ -119,25 +118,15 @@ class IrActionsReport(models.Model):
def create_action(self):
""" Create a contextual action for each report. """
for report in self:
ir_values = self.env['ir.values'].sudo().create({
'name': report.name,
'model': report.model,
'key2': 'client_print_multi',
'value': "ir.actions.report,%s" % report.id,
})
report.write({'ir_values_id': ir_values.id})
model = self.env['ir.model']._get(report.model)
report.write({'binding_model_id': model.id, 'binding_type': 'report'})
return True
@api.multi
def unlink_action(self):
""" Remove the contextual actions created for the reports. """
self.check_access_rights('write', raise_exception=True)
for report in self:
if report.ir_values_id:
try:
report.ir_values_id.sudo().unlink()
except Exception:
raise UserError(_('Deletion of the action record failed.'))
self.filtered('binding_model_id').write({'binding_model_id': False})
return True
#--------------------------------------------------------------------------
-14
View File
@@ -50,20 +50,6 @@
</search>
</field>
</record>
<record id="action_module_open_categ" model="ir.actions.act_window">
<field name="name">Apps</field>
<field name="res_model">ir.module.module</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form,kanban</field>
<field name="domain">[('category_id','=',active_id)]</field>
</record>
<record id="ir_action_module_category" model="ir.values">
<field eval="'tree_but_open'" name="key2"/>
<field eval="'ir.module.category'" name="model"/>
<field name="name">Categorized Apps</field>
<field eval="'ir.actions.act_window,%d'%action_module_open_categ" name="value"/>
</record>
<!-- Modules -->
<record id="module_form" model="ir.ui.view">
@@ -5,18 +5,9 @@
<field name="name">Base: Module Immediate Install</field>
<field name="type">ir.actions.server</field>
<field name="model_id" ref="model_ir_module_module" />
<field name="binding_model_id" ref="model_ir_module_module" />
<field name="state">code</field>
<field name="code">records.button_immediate_install()</field>
</record>
<record model="ir.values" id="action_module_immediate_install">
<field name="name">action_module_immediate_install</field>
<field name="action_id" ref="action_server_module_immediate_install" />
<field name="value" eval="'ir.actions.server,' + str(ref('action_server_module_immediate_install'))" />
<field name="key">action</field>
<field name="model_id" ref="model_ir_module_module" />
<field name="model">ir.module.module</field>
<field name="key2">client_action_multi</field>
</record>
</data>
</odoo>
@@ -113,13 +113,6 @@
</record>
<menuitem action="action_res_company_form" id="menu_action_res_company_form" parent="base.menu_users"/>
<record id="ir_open_company" model="ir.values">
<field eval="'tree_but_open'" name="key2"/>
<field eval="'res.company'" name="model"/>
<field name="name">Companies</field>
<field eval="'ir.actions.act_window,%d'%company_normal_action_tree" name="value"/>
</record>
<record id="view_company_report_form" model="ir.ui.view">
<field name="name">res.company.report.form</field>
<field name="model">res.company</field>
+6
View File
@@ -681,6 +681,8 @@ class GroupsView(models.Model):
def create(self, values):
user = super(GroupsView, self).create(values)
self._update_user_groups_view()
# actions.get_bindings() depends on action records
self.env['ir.actions.actions'].clear_caches()
# ir_values.get_actions() depends on action records
self.env['ir.values'].clear_caches()
return user
@@ -689,6 +691,8 @@ class GroupsView(models.Model):
def write(self, values):
res = super(GroupsView, self).write(values)
self._update_user_groups_view()
# actions.get_bindings() depends on action records
self.env['ir.actions.actions'].clear_caches()
# ir_values.get_actions() depends on action records
self.env['ir.values'].clear_caches()
return res
@@ -697,6 +701,8 @@ class GroupsView(models.Model):
def unlink(self):
res = super(GroupsView, self).unlink()
self._update_user_groups_view()
# actions.get_bindings() depends on action records
self.env['ir.actions.actions'].clear_caches()
# ir_values.get_actions() depends on action records
self.env['ir.values'].clear_caches()
return res
+51 -10
View File
@@ -60,19 +60,11 @@ class TestServerActions(TestServerActionsBase):
# Do: create contextual action
self.action.create_action()
# Test: ir_values created
ir_values = self.env['ir.values'].search([('name', '=', 'Run TestAction')])
self.assertEqual(len(ir_values), 1, 'ir_actions_server: create_action should have created an entry in ir_values')
self.assertEqual(ir_values.value, b'ir.actions.server,%d' % self.action.id, 'ir_actions_server: created ir_values should reference the server action')
self.assertEqual(ir_values.model, 'res.partner', 'ir_actions_server: created ir_values should be linked to the action base model')
self.assertEqual(self.action.binding_model_id.model, 'res.partner')
# Do: remove contextual action
self.action.unlink_action()
# Test: ir_values removed
ir_values = self.env['ir.values'].search([('name', '=', 'Run TestAction')])
self.assertEqual(len(ir_values), 0, 'ir_actions_server: unlink_action should remove the ir_values record')
self.assertFalse(self.action.binding_model_id)
def test_10_code(self):
self.action.write({
@@ -186,6 +178,55 @@ class TestServerActions(TestServerActionsBase):
})
class TestActionBindings(common.TransactionCase):
def test_bindings(self):
""" check the action bindings on models """
Actions = self.env['ir.actions.actions']
# first make sure there is no bound action
bindings = Actions.get_bindings('res.partner')
self.assertFalse(bindings['action'])
self.assertFalse(bindings['report'])
# create action bindings, and check the returned bindings
action1 = self.env.ref('base.action_attachment')
action2 = self.env.ref('base.ir_default_menu_action')
action3 = self.env['ir.actions.report'].search([('groups_id', '=', False)], limit=1)
action1.binding_model_id = action2.binding_model_id \
= action3.binding_model_id \
= self.env['ir.model']._get('res.partner')
bindings = Actions.get_bindings('res.partner')
self.assertItemsEqual(
bindings['action'],
(action1 + action2).read(),
"Wrong action bindings",
)
self.assertItemsEqual(
bindings['report'],
action3.read(),
"Wrong action bindings",
)
# add a group on an action, and check that it is not returned
group = self.env.ref('base.group_user')
action2.groups_id += group
self.env.user.groups_id -= group
bindings = Actions.get_bindings('res.partner')
self.assertItemsEqual(
bindings['action'],
action1.read(),
"Wrong action bindings",
)
self.assertItemsEqual(
bindings['report'],
action3.read(),
"Wrong action bindings",
)
class TestCustomFields(common.TransactionCase):
MODEL = 'res.partner'
+10 -18
View File
@@ -1302,28 +1302,20 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
# Add related action information if aksed
if toolbar:
IrValues = self.env['ir.values']
resprint = IrValues.get_actions('client_print_multi', self._name)
resaction = IrValues.get_actions('client_action_multi', self._name)
resrelate = IrValues.get_actions('client_action_relate', self._name)
resprint = [print_[2]
for print_ in resprint
if view_type == 'tree' or not print_[2].get('multi')]
resaction = [action[2]
for action in resaction
if view_type == 'tree' or not action[2].get('multi')]
#When multi="True" set it will display only in More of the list view
resrelate = [action[2]
for action in resrelate
if (action[2].get('multi') and view_type == 'tree') or (not action[2].get('multi') and view_type == 'form')]
bindings = self.env['ir.actions.actions'].get_bindings(self._name)
resreport = [action
for action in bindings['report']
if view_type == 'tree' or not action.get('multi')]
resaction = [action
for action in bindings['action']
if view_type == 'tree' or not action.get('multi')]
for x in itertools.chain(resprint, resaction, resrelate):
x['string'] = x['name']
for res in itertools.chain(resreport, resaction):
res['string'] = res['name']
result['toolbar'] = {
'print': resprint,
'print': resreport,
'action': resaction,
'relate': resrelate,
}
return result
+7 -50
View File
@@ -276,13 +276,6 @@ form: module.record_id""" % (xml_id,)
if records:
records.unlink()
def _remove_ir_values(self, name, value, model):
domain = [('name', '=', name), ('value', '=', value), ('model', '=', model)]
ir_values = self.env['ir.values'].search(domain)
if ir_values:
ir_values.unlink()
return True
def _tag_report(self, rec, data_node=None, mode=None):
res = {}
for dest,f in (('name','string'),('model','model'),('report_name','name')):
@@ -328,15 +321,12 @@ form: module.record_id""" % (xml_id,)
self.idref[xml_id] = int(id)
if not rec.get('menu') or safe_eval(rec.get('menu','False')):
keyword = str(rec.get('keyword', 'client_print_multi'))
value = 'ir.actions.report,'+str(id)
action = self.env['ir.values'].set_action(res['name'], keyword, res['model'], value)
self.env['ir.actions.report'].browse(id).write({'ir_values_id': action.id})
report = self.env['ir.actions.report'].browse(id)
report.create_action()
elif self.mode=='update' and safe_eval(rec.get('menu','False'))==False:
# Special check for report having attribute menu=False on update
value = 'ir.actions.report,'+str(id)
self._remove_ir_values(res['name'], value, res['model'])
self.env['ir.actions.report'].browse(id).write({'ir_values_id': False})
report = self.env['ir.actions.report'].browse(id)
report.unlink_action()
return id
def _tag_function(self, rec, data_node=None, mode=None):
@@ -437,46 +427,14 @@ form: module.record_id""" % (xml_id,)
if rec.get('target'):
res['target'] = rec.get('target','')
if src_model:
res['binding_model_id'] = self.env['ir.model']._get(src_model).id
res['binding_type'] = 'report' if rec.get('key2') == 'client_print_multi' else 'action'
if rec.get('multi'):
res['multi'] = safe_eval(rec.get('multi', 'False'))
id = self.env['ir.model.data']._update('ir.actions.act_window', self.module, res, xml_id, noupdate=self.isnoupdate(data_node), mode=self.mode)
self.idref[xml_id] = int(id)
if src_model:
#keyword = 'client_action_relate'
res_id = False
model = src_model
if isinstance(model, (list, tuple)):
model, res_id = model
keyword = rec.get('key2') or 'client_action_relate'
value = 'ir.actions.act_window,%s' % id
replace = rec.get('replace') or True
self.env['ir.values'].set_action(xml_id, action_slot=keyword, model=model, action=value, res_id=res_id)
# TODO add remove ir.model.data
def _tag_ir_set(self, rec, data_node=None, mode=None):
"""
.. deprecated:: 9.0
Use the <record> notation with ``ir.values`` as model instead.
"""
if self.mode != 'init':
return
res = {}
for field in rec.findall('./field'):
f_name = field.get("name")
f_val = _eval_xml(self, field, self.env)
res[f_name] = f_val
ir_values = self.env['ir.values']
for model in res['models']:
res_id = False
if isinstance(model, (list, tuple)):
model, res_id = model
if res['key'] == 'default':
ir_values.set_default(model, field_name=res['name'], value=res['value'], condition=res['key2'])
elif res['key'] == 'action':
ir_values.set_action(res['name'], action_slot=res['key2'], model=model, action=res['value'], res_id=res_id)
def _tag_menuitem(self, rec, data_node=None, mode=None):
rec_id = rec.get("id")
self._test_xml_id(rec_id)
@@ -812,7 +770,6 @@ form: module.record_id""" % (xml_id,)
'menuitem': self._tag_menuitem,
'template': self._tag_template,
'report': self._tag_report,
'ir_set': self._tag_ir_set, # deprecated:: 9.0
'act_window': self._tag_act_window,
'assert': self._tag_assert,
}
+8 -48
View File
@@ -79,9 +79,6 @@ def is_ref(node):
return isinstance(node, yaml_tag.Ref) \
or _is_yaml_mapping(node, yaml_tag.Ref)
def is_ir_set(node):
return _is_yaml_mapping(node, yaml_tag.IrSet)
def is_string(node):
return isinstance(node, pycompat.string_types)
@@ -728,17 +725,12 @@ class YamlInterpreter(object):
if node.target:
values['target'] = node.target
if node.src_model and isinstance(node.src_model, basestring):
values['binding_model_id'] = self.env['ir.model']._get(node.src_model).id
id = self.sudo_env['ir.model.data']._update('ir.actions.act_window', self.module, values, node.id, mode=self.mode)
self.id_map[node.id] = int(id)
if node.src_model:
keyword = 'client_action_relate'
value = 'ir.actions.act_window,%s' % id
res_id = False
model = node.src_model
if isinstance(model, (list, tuple)):
model, res_id = model
self.env['ir.values'].sudo().set_action(node.id, action_slot=keyword, model=model, action=value, res_id=res_id)
# TODO add remove ir.model.data
def process_delete(self, node):
@@ -755,37 +747,13 @@ class YamlInterpreter(object):
def process_url(self, node):
self.validate_xml_id(node.id)
res = {'name': node.name, 'url': node.url, 'target': node.target}
id = self.sudo_env['ir.model.data']._update("ir.actions.act_url", self.module, res, node.id, mode=self.mode)
self.id_map[node.id] = int(id)
# ir_set
if (not node.menu or safe_eval(node.menu)) and id:
keyword = node.keyword or 'client_action_multi'
value = 'ir.actions.act_url,%s' % id
self.env['ir.values'].sudo().set_action(node.url, action_slot=keyword, model="ir.actions.act_url", action=value, res_id=False)
def process_ir_set(self, node):
if not self.mode == 'init':
return False
_, fields = list(node.items())[0]
res = {}
for fieldname, expression in fields.items():
if is_eval(expression):
value = safe_eval(expression.expression, self.eval_context)
else:
value = expression
res[fieldname] = value
ir_values = self.env['ir.values']
for model in res['models']:
res_id = False
if isinstance(model, (list, tuple)):
model, res_id = model
if res['key'] == 'default':
ir_values.sudo().set_default(model, field_name=res['name'], value=res['value'], condition=res['key2'])
elif res['key'] == 'action':
ir_values.sudo().set_action(res['name'], action_slot=res['key2'], model=model, action=res['value'], res_id=res_id)
action = self.env['ir.actions.actions'].browse(int(id))
action.binding_model_id = self.env['ir.model']._get('ir.actions.act_url')
def process_report(self, node):
values = {}
@@ -806,14 +774,8 @@ class YamlInterpreter(object):
self.id_map[xml_id] = int(id)
if not node.menu or safe_eval(node.menu):
keyword = node.keyword or 'client_print_multi'
value = 'ir.actions.report,%s' % id
ir_values = self.env['ir.values']
res_id = False
model = values['model']
if isinstance(model, (list, tuple)):
model, res_id = model
ir_values.sudo().set_action(values['name'], action_slot=keyword, model=model, action=value, res_id=res_id)
report = self.env['ir.actions.report'].browse(id)
report.create_action()
def process_none(self):
"""
@@ -854,8 +816,6 @@ class YamlInterpreter(object):
self.process_url(node)
elif is_context(node):
self.process_context(node)
elif is_ir_set(node):
self.process_ir_set(node)
elif is_act_window(node):
self.process_act_window(node)
elif is_report(node):
-9
View File
@@ -91,10 +91,6 @@ class Ref(YamlTag):
def __str__(self):
return 'ref(%s)' % repr(self.expr)
class IrSet(YamlTag):
def __init__(self):
super(IrSet, self).__init__()
def assert_constructor(loader, node):
kwargs = loader.construct_mapping(node)
return Assert(**kwargs)
@@ -149,10 +145,6 @@ def ref_constructor(loader, tag_suffix, node):
kwargs = loader.construct_mapping(node)
return Ref(**kwargs)
def ir_set_constructor(loader, node):
kwargs = loader.construct_mapping(node)
return IrSet(**kwargs)
# Registers constructors for custom tags.
# Constructors are actually defined globally: do not redefined them in another
# class/file/package. This means that module recorder need import this file.
@@ -169,5 +161,4 @@ def add_constructors():
yaml.add_constructor(u"!url", url_constructor)
yaml.add_constructor(u"!eval", eval_constructor)
yaml.add_multi_constructor(u"!ref", ref_constructor)
yaml.add_constructor(u"!ir_set", ir_set_constructor)
add_constructors()