Skip to content
Snippets Groups Projects
Commit 5ea5153af7ec authored by Axel Prel's avatar Axel Prel
Browse files

expression-builder wizard

parent 12f80aca0e9e
No related branches found
No related tags found
1 merge request!67Implement caching and optimization for Redner template handling
......@@ -6,6 +6,8 @@
- Fix: ensure Redner instance reflects updated system parameters.
- Add python-magic as external dependency and fix print-paper-size metadata.
- Restriction Added: Disallow the deletion of a template if its source is Redner.
(Deletion is still allowed for templates created in Odoo but not for those originating from Redner.)
18.0.1.0.1
----------
......
......@@ -30,6 +30,7 @@
"data": [
"wizard/mail_compose_message_views.xml",
"wizard/template_list_view.xml",
"wizard/expression_builder_view.xml",
"security/ir.model.access.csv",
"views/redner_template.xml",
"views/mail_template.xml",
......
......@@ -248,7 +248,7 @@
logger.error("Failed to read extension from file:%s", e)
return
record.template_data = encoded
record.template_data_filename = "template" + ext
record.template_data_filename = f"{record.name}{ext}"
except Exception as e:
logger.error("Failed to read redner template :%s", e)
return
......@@ -453,7 +453,7 @@
# We do NOT depend on the API for consistency here
# So raised error should not result block template deletion
for record in self:
if record.redner_id:
if record.redner_id and record.allow_modification_from_odoo:
try:
self.redner.templates.account_template_delete(record.redner_id)
except Exception:
......
......@@ -3,3 +3,5 @@
access_redner_template,access_redner_template,model_redner_template,base.group_no_one,1,1,1,1
access_redner_substitution,access_redner_substitution,model_redner_substitution,base.group_no_one,1,1,1,1
access_redner_template_list,access_redner_template_list,model_template_list_wizard,base.group_no_one,1,1,1,1
access_redner_expression_builder,access_redner_expression_builder,model_expression_builder_wizard,base.group_no_one,1,1,1,1
access_redner_expression_builder_field,access_redner_expression_builder_field,model_expression_builder_field,base.group_no_one,1,1,1,1
from . import mail_compose_message, template_list
from . import (
expression_builder,
expression_builder_field,
mail_compose_message,
template_list,
)
from odoo import exceptions, fields, models
# ExpressionBuilder
class ExpressionBuilder(models.TransientModel):
_name = "expression.builder.wizard"
_description = "Expression Builder Wizard"
# the substitution the expression builder is working on
substitution_id = fields.Many2one(
comodel_name="redner.substitution",
string="Substitution",
help="The Redner Substitution on which we assign the value",
required=True,
)
# the expression field is concatened with the fields values
# when the wizard action is completed, this field is
# written in the substitution value
expression = fields.Char(
string="Substitution",
help=(
"Stores the substitution value the builder is working on."
" (example: 'partner_id.name')"
),
)
suggested_fields = fields.One2many(
comodel_name="expression.builder.field",
inverse_name="wizard_id",
string="Suggested Fields",
help="The suggested fields, based on the substitution converter value",
)
def get_fields(self, model, converter):
# Get all field records for the model
vals_list = self.env["ir.model.fields"].search([("model", "=", model._name)])
# Filter fields based on the converter type
if converter == "relation-to-many":
vals_list = [f for f in vals_list if f.ttype == "many2many"]
elif converter == "field":
vals_list = [f for f in vals_list if f.ttype != "many2many"]
else:
vals_list = []
return [
{
"field_name": f.field_description,
"field_technical_name": f.name,
"field_type": f.ttype,
"field_comodel_name": f.relation,
}
for f in vals_list
]
def action_cancel(self):
# custom cancel, unlinks the fields, the wizard itself
# and close window
self.unlink()
return {"type": "ir.actions.act_window_close"}
def action_save(self):
selected_count = 0
selected_field = False
for f in self.suggested_fields:
if f.selected:
selected_count += 1
selected_field = f
if selected_count > 1:
raise exceptions.UserError(
"You cannot select more than one field to build the expression"
)
elif selected_count == 0:
raise exceptions.UserError(
"You have to select one field to build the expression"
)
elif selected_field.field_type in ["many2one", "one2many"]:
# in this case we do not close the window.
# instead we refresh the wizard by showing the
# fields 1 field deeper
# and we update the expression field
if self.expression or self.expression != "":
self.expression += "." + selected_field.field_technical_name
else:
self.expression = selected_field.field_technical_name
# get comodel
comodel = self.env.get(selected_field.field_comodel_name)
if comodel is None:
return
vals_list = self.get_fields(comodel, self.substitution_id.converter)
for val in vals_list:
val["wizard_id"] = self.id
# remove previous fields
self.suggested_fields.unlink()
# add and create the next fields
fields_list = self.env["expression.builder.field"].create(vals_list)
self.suggested_fields = [(6, 0, fields_list.ids)]
# stay on updated wizard
return {
"type": "ir.actions.act_window",
"res_model": "expression.builder.wizard",
"view_mode": "form",
"res_id": self.id,
"target": "new",
}
# if the selected field is not relationnal:
if self.expression or self.expression != "":
# expression has already a value
self.substitution_id.write(
{
"value": self.expression
+ "."
+ selected_field.field_technical_name,
}
)
else:
# expression is empty
self.substitution_id.write(
{
"value": selected_field.field_technical_name,
}
)
# at the end, we unlink all of the temp data
# and close the window
return self.action_cancel()
from odoo import fields, models
class ExpressionBuilderField(models.TransientModel):
_name = "expression.builder.field"
_description = "Expression Builder Field"
wizard_id = fields.Many2one(
string="Expression builder",
comodel_name="expression.builder.wizard",
required=True,
ondelete="cascade",
)
field_name = fields.Char(
string="Field name",
help="The field's comprehensible name",
)
field_type = fields.Char(
string="Field Type",
help="The field's type (boolean, text, ...)",
)
field_comodel_name = fields.Char(
string="Comodel Name",
help="If the field is relational, store the comodel name here",
)
field_technical_name = fields.Char(
string="Field Technical Name",
help="The field's technical name",
)
selected = fields.Boolean(
string="Selected",
help="When selected, this field will be added to the substitution value",
readonly=False,
)
<odoo>
<record id="view_expression_builder_wizard_form" model="ir.ui.view">
<field name="name">expression.builder.wizard.form</field>
<field name="model">expression.builder.wizard</field>
<field name="arch" type="xml">
<form string="Build Expression">
<sheet>
<field name="substitution_id" invisible="1" />
<field name="suggested_fields" nolabel="1" colspan="2">
<list
no_open="true"
editable="top"
create="false"
delete="false"
default_order="field_name asc"
>
<field name="selected" />
<field name="field_name" readonly="1" />
<field name="field_technical_name" readonly="1" />
<field name="field_type" readonly="1" />
<field name="field_comodel_name" readonly="1" />
</list>
</field>
<footer>
<button
string="Save"
type="object"
name="action_save"
class="btn-primary"
/>
<button
string="Cancel"
type="object"
name="action_cancel"
class="btn-secondary"
/>
</footer>
</sheet>
</form>
</field>
</record>
</odoo>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment