Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exclusive Forms for Portal users (respecting Partner hierarchy) #124

Closed
wants to merge 8 commits into from
3 changes: 2 additions & 1 deletion formio/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
{
'name': 'Forms',
'summary': 'Form Builder & integration of professional and versatile Forms to collect any information you need for your business.',
'version': '8.17',
'version': '9.0',
'license': 'LGPL-3',
'author': 'Nova Code',
'website': 'https://www.novacode.nl',
Expand Down Expand Up @@ -42,6 +42,7 @@
'views/formio_version_github_tag_views.xml',
'views/formio_menu.xml',
'views/res_config_settings_views.xml',
'views/res_partner_views.xml',
'views/mail_activity_views.xml',
# formio templates
'views/formio_builder_templates.xml',
Expand Down
4 changes: 2 additions & 2 deletions formio/i18n/de.po
Original file line number Diff line number Diff line change
Expand Up @@ -1169,5 +1169,5 @@ msgstr "js"
#: code:addons/formio/formio/models/formio_builder.py:160
#: code:addons/formio/models/formio_builder.py:160
#, python-format
msgid "{title} (state: {state} - version: {version})"
msgstr "{title} (Status: {state} - Version: {version})"
msgid "{title} (state: {state}, version: {version})"
msgstr "{title} (Status: {state}, Version: {version})"
4 changes: 2 additions & 2 deletions formio/i18n/pt_BR.po
Original file line number Diff line number Diff line change
Expand Up @@ -2142,5 +2142,5 @@ msgstr ""
#. module: formio
#: code:addons/formio/models/formio_builder.py:247
#, python-format
msgid "{title} (state: {state} - version: {version})"
msgstr "{title} (state: {state} - versão: {version})"
msgid "{title} (state: {state}, version: {version})"
msgstr "{title} (state: {state}, versão: {version})"
4 changes: 2 additions & 2 deletions formio/i18n/zh_CN.po
Original file line number Diff line number Diff line change
Expand Up @@ -2265,5 +2265,5 @@ msgstr ""
#. module: formio
#: code:addons/formio/models/formio_builder.py:0
#, python-format
msgid "{title} (state: {state} - version: {version})"
msgstr "{title} (状态: {state} - 版本号: {version})"
msgid "{title} (state: {state}, version: {version})"
msgstr "{title} (状态: {state}, 版本号: {version})"
2 changes: 2 additions & 0 deletions formio/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from . import formio_builder_js_options
from . import formio_builder_translation
from . import formio_default_asset_css
from . import formio_builder_form_exclusive_partner
from . import formio_form
from . import formio_res_model
from . import formio_version
Expand All @@ -16,3 +17,4 @@
from . import ir_view
from . import res_config_settings
from . import res_lang
from . import res_partner
40 changes: 38 additions & 2 deletions formio/models/formio_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,17 @@ class Builder(models.Model):
- Current: Live and in use (publisehd).
- Obsolete: Was current but obsolete (unpublished)""")
display_state = fields.Char("Display State", compute='_compute_display_fields', store=False)
display_name_full = fields.Char("Display Name Full", compute='_compute_display_fields', store=False)
display_name_full = fields.Char("Display Name Full", compute='_compute_display_fields', search='_search_display_name_full', store=False)
parent_id = fields.Many2one('formio.builder', string='Parent Builder', readonly=True)
parent_version = fields.Integer(related='parent_id.version', string='Parent Version', readonly=True)
version = fields.Integer("Version", required=True, readonly=True, default=1)
version_comment = fields.Text("Version Comment")
user_id = fields.Many2one('res.users', string='Assigned user', track_visibility='onchange')
exclusive_partner_rel_ids = fields.One2many(
'formio.builder.form.exclusive.partner', 'builder_id',
string='Exclusive Partners',
help='Give access only to users related to this partner (either linked directly to the partner or to its children). If left empty, this restriction doesn\'t apply.')
exclusive_partner_ids = fields.Many2many('res.partner', compute='_compute_exclusive_partner_ids', search='_search_exclusive_partner_ids')
forms = fields.One2many('formio.form', 'builder_id', string='Forms')
portal = fields.Boolean("Portal", track_visibility='onchange', help="Form is accessible by assigned portal user")
portal_submit_done_url = fields.Char(
Expand Down Expand Up @@ -208,6 +213,14 @@ def _decode_schema(self, schema):
schema = ast.literal_eval(schema)
return schema

def _search_display_name_full(self, operator, value):
if value:
builders = self.search([('title', operator, value)])
if builders:
return [('id', 'in', builders.ids)]
else:
return [('id', '=', False)]

@api.onchange('formio_js_options_id')
def _onchange_formio_js_options_id(self):
if self.formio_js_options_id:
Expand Down Expand Up @@ -245,9 +258,32 @@ def _compute_display_fields(self):
if self._context.get('display_name_title'):
r.display_name_full = r.title
else:
r.display_name_full = _("{title} (state: {state} - version: {version})").format(
r.display_name_full = _("{title} (state: {state}, version: {version})").format(
title=r.title, state=r.display_state, version=r.version)

@api.depends('exclusive_partner_rel_ids')
def _compute_exclusive_partner_ids(self):
for r in self:
if r.exclusive_partner_rel_ids:
exclusive_partner_ids = (r.exclusive_partner_rel_ids.mapped('partner_id').mapped('child_ids') | r.exclusive_partner_rel_ids.mapped('partner_id')).ids
r.exclusive_partner_ids = [(6, 0, exclusive_partner_ids)]
else:
r.exclusive_user_ids = False

def _search_exclusive_partner_ids(self, operator, value):
"""
Search exclusive res.partner records

:param int value: id of res.partner
"""
if operator == '=' and value:
domain = [('exclusive_partner_rel_ids.partner_id.id', '=', value)]
elif operator == '=' and not value:
domain = [('exclusive_partner_rel_ids', '=', False)]
else:
domain = [('id', '!=', False)]
return domain

@api.depends('public')
def _compute_public_url(self):
for r in self:
Expand Down
32 changes: 32 additions & 0 deletions formio/models/formio_builder_form_exclusive_partner.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Copyright Nova Code (http://www.novacode.nl)
# See LICENSE file for full licensing details.

from odoo import api, fields, models, _
from odoo.exceptions import ValidationError


class BuilderFormExclusivePartner(models.Model):
_name = 'formio.builder.form.exclusive.partner'
_description = 'Form Builder Form Exclusive Partner'

builder_id = fields.Many2one('formio.builder', string='Form Builder', required=True)
builder_uuid = fields.Char(related='builder_id.uuid', string='Form Builder UUID')
builder_title = fields.Char(related='builder_id.title', string='Form Builder Title')
builder_name = fields.Char(related='builder_id.name', string='Form Builder Name')
builder_version = fields.Integer(related='builder_id.version', string='Form Builder Version')
builder_state = fields.Selection(related='builder_id.state', string='Form Builder State')
partner_id = fields.Many2one('res.partner', required=True)
partner_parent_id = fields.Many2one('res.partner', related='partner_id.parent_id')
#partner_child_ids = fields.One2many('res.partner', related='partner_id.child_ids')
partner_company_type = fields.Selection(related='partner_id.company_type')

@api.constrains('builder_id', 'partner_id')
def _constraint_unique_builder_and_partner(self):
for r in self:
res = self.search([
("builder_id", "=", r.builder_id.id),
("partner_id", "=", r.partner_id.id)
])
if len(res) > 1:
msg = _("A Form Builder can only be exclusively assigned to a Partner once. Affected Form Builder:\n%s") % r.builder_id.display_name_full
raise ValidationError(msg)
2 changes: 1 addition & 1 deletion formio/models/formio_form.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ def _compute_kanban_group_state(self):

def _compute_access(self):
user_groups = self.env.user.groups_id
for form in self:
for form in self.sudo():
# allow_unlink
unlink_form = self.get_form(form.uuid, 'unlink')
if unlink_form:
Expand Down
25 changes: 25 additions & 0 deletions formio/models/res_partner.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Copyright Nova Code (http://www.novacode.nl)
# See LICENSE file for full licensing details.

from odoo import fields, models


class ResPartner(models.Model):
_inherit = 'res.partner'

exclusive_formio_builder_form_rel_ids = fields.One2many(
'formio.builder.form.exclusive.partner', 'partner_id',
string='Exclusive Forms',
help='Give access only to Forms this partner (either linked directly to the partner or to its children). If left empty, this restriction doesn\'t apply.')
exclusive_formio_builder_form_ids = fields.One2many(
'formio.builder.form.exclusive.partner', compute='_compute_exclusive_formio_builder_form_ids', string='Exclusive Forms determined')

def _compute_exclusive_formio_builder_form_ids(self):
for r in self:
domain = ['|', ('partner_id', '=', r.id), ('partner_id', 'parent_of', r.id)]
res = self.env['formio.builder.form.exclusive.partner'].search(domain)

if res:
r.exclusive_formio_builder_form_ids = [(6, 0, res.ids)]
else:
r.exclusive_formio_builder_form_ids = False
11 changes: 11 additions & 0 deletions formio/security/ir_model_access.xml
Original file line number Diff line number Diff line change
Expand Up @@ -384,5 +384,16 @@ See LICENSE file for full copyright and licensing details. -->
<field name="perm_write" eval="1"/>
<field name="perm_unlink" eval="1"/>
</record>

<!-- Formio Exclusive Partner Model -->
<record id="access_formio_builder_form_exclusive_partner_admin" model="ir.model.access">
<field name="name">formio.builder.form.exclusive.partner: Admin</field>
<field name="model_id" ref="formio.model_formio_builder_form_exclusive_partner"/>
<field name="group_id" ref="formio.group_formio_admin"/>
<field name="perm_read" eval="1"/>
<field name="perm_create" eval="1"/>
<field name="perm_write" eval="1"/>
<field name="perm_unlink" eval="1"/>
</record>
</data>
</odoo>
51 changes: 39 additions & 12 deletions formio/security/ir_rule.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ See LICENSE file for full copyright and licensing details. -->

<odoo>
<data>
<!-- read, write, create -->
<record id="formio_form_user_all" model="ir.rule">
<field name="name">formio.form: User all forms</field>
<field name="model_id" ref="model_formio_form"/>
Expand All @@ -26,6 +27,24 @@ See LICENSE file for full copyright and licensing details. -->
<field name="domain_force">[('user_id', '=', user.id)]</field>
</record>

<record id="formio_form_portal_user" model="ir.rule">
<field name="name">formio.form: Portal user forms</field>
<field name="model_id" ref="model_formio_form"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="False"/>
<field name="perm_unlink" eval="False"/>
<field name="groups" eval="[(4, ref('base.group_portal'))]"/>
<field name="domain_force">
[
'&amp;',
('portal_share', '=', True),
'|', ('create_uid', '=', user.id), ('submission_partner_id', '=', user.partner_id.id)
]
</field>
</record>

<!-- unlink (delete) -->
<record id="formio_form_unlink_user_assigned" model="ir.rule">
<field name="name">formio.form unlink: User assigned forms</field>
<field name="model_id" ref="model_formio_form"/>
Expand All @@ -39,17 +58,6 @@ See LICENSE file for full copyright and licensing details. -->
</field>
</record>

<record id="formio_form_portal_user" model="ir.rule">
<field name="name">formio.form read, write: Portal User</field>
<field name="model_id" ref="model_formio_form"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="False"/>
<field name="perm_unlink" eval="False"/>
<field name="groups" eval="[(4, ref('base.group_portal'))]"/>
<field name="domain_force">[('builder_id.portal', '=', True), ('user_id', '=', user.id)]</field>
</record>

<record id="formio_form_unlink_portal_user" model="ir.rule">
<field name="name">formio.form unlink: Portal User</field>
<field name="model_id" ref="model_formio_form"/>
Expand All @@ -63,7 +71,26 @@ See LICENSE file for full copyright and licensing details. -->
'&amp;',
'&amp;',
'&amp;',
('builder_id.portal', '=', True), ('create_uid', '=', user.id), ('user_id', '=', user.id), ('state', '!=', 'COMPLETE')]
('portal_share', '=', True), ('create_uid', '=', user.id), ('user_id', '=', user.id), ('state', '!=', 'COMPLETE')]
</field>
</record>

<!-- exclusive forms (portal) -->
<record id="formio_builder_read_exclusive_user_portal_user" model="ir.rule">
<field name="name">formio.builder read: Exclusive Users Portal User</field>
<field name="model_id" ref="model_formio_builder"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_unlink" eval="False"/>
<field name="groups" eval="[(4, ref('base.group_portal'))]"/>
<field name="domain_force">
[
'|', '|',
'&amp;', ('portal', '=', True), ('exclusive_partner_ids', '=', False),
'&amp;', ('portal', '=', True), ('exclusive_partner_ids', '=', user.partner_id.id),
'&amp;', ('portal', '=', True), ('exclusive_partner_ids', '=', user.partner_id.parent_id.id)
]
</field>
</record>
</data>
Expand Down
16 changes: 16 additions & 0 deletions formio/static/description/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,22 @@ <h4 class="oe_mb16 text-center">Download &amp; Install Available (Form.io GUI) V
<section class="oe_container">
<div class="oe_row oe_spaced">
<h2 class="oe_slogan" style="color:#875A7B;">Releases</h2>
<h4 class="oe_mb16">9.0</h4>
<ul>
<li>
New feature: Exclusive Forms for Portal users (respecting Partner hierarchy).<br/>
Configuration can be done per Form Builder, with respecting the Partner hierarchy.<br/>
Forms (builders) assigned to Partners are available to all Child Partners.
</li>
</ul>
<h4 class="oe_mb16">8.18</h4>
<ul>
<li>
Fix: Issue in Form (form-view) searching Builder(s) really didn't worked properly.<br/>
Technical details:<br/>
This change addresses the <code>formio.builder</code>, adding the <code>search</code> method for the computed field <code>display_name_full</code> which is used as <code>_rec_name</code>.
</li>
</ul>
<h4 class="oe_mb16">8.17</h4>
<ul>
<li>
Expand Down
20 changes: 20 additions & 0 deletions formio/views/formio_builder_views.xml
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,20 @@ See LICENSE file for full licensing details. -->
</page>
<page string="Resource" name="res_model_settings" attrs="{'invisible': [('formio_res_model_id', '=', False)]}"/>
<page string="Portal" name="portal_settings">
<group name="exclusive_partners" string="Exclusive Forms" attrs="{'invisible': [('formio_res_model_id', '!=', False)]}">
<div class="mb-3 text-muted" colspan="2">
<i class="fa fa-info-circle" title="info"/> Give access only to Users related to the Partners below, either linked directly to the Partner or to its children.<br/>
If left empty, this restriction doesn't apply and Forms are available by obtaining other configuration.
</div>
<field name="exclusive_partner_rel_ids" string="Partners">
<tree editable="bottom" default_order="partner_id asc">
<field name="builder_id" invisible="1"/>
<field name="partner_id"/>
<field name="partner_company_type"/>
<field name="partner_parent_id"/>
</tree>
</field>
</group>
<group>
<group string="Redirect After Submit">
<field name="portal_submit_done_url" groups="formio.group_formio_admin" string="Redirect URL" readonly="0"/>
Expand Down Expand Up @@ -261,6 +275,7 @@ See LICENSE file for full licensing details. -->
<search string="Form Builders">
<field name="title"/>
<field name="name"/>
<field name="exclusive_partner_ids" filter_domain="[('exclusive_partner_ids.partner_id', 'ilike', self)]"/>
<field name="user_id"/>
<field name="formio_version_id"/>
<separator/>
Expand All @@ -279,6 +294,11 @@ See LICENSE file for full licensing details. -->
<filter string="Not Portal" name="not_portal"
domain="[('portal', '=', False)]"/>
<separator/>
<filter string="Exclusive assigned to Partners (in Portal)" name="exclusive_partners"
domain="[('exclusive_partner_rel_ids', '!=', False)]"/>
<filter string="Not Exclusive assigned to Partners (in Portal)" name="not_exclusive_partners"
domain="[('exclusive_partner_rel_ids', '=', False)]"/>
<separator/>
<filter string="Wizard" name="wizard"
domain="[('wizard', '=', True)]"/>
<filter string="Not Wizard" name="not_portal"
Expand Down
Loading