Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 16 additions & 17 deletions report_qweb_field_option/README.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
.. image:: https://odoo-community.org/readme-banner-image
:target: https://odoo-community.org/get-involved?utm_source=readme
:alt: Odoo Community Association

========================
Report Qweb Field Option
========================
Expand All @@ -17,7 +13,7 @@ Report Qweb Field Option
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
:alt: Beta
.. |badge2| image:: https://img.shields.io/badge/license-AGPL--3-blue.png
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Freporting--engine-lightgray.png?logo=github
Expand Down Expand Up @@ -49,15 +45,18 @@ create records according to your needs.

For each record:

- Set **Model** and **Field** (required)
- Set **UoM** and **UoM Field**, or **Currency** and **Currency Field**
only for fields of float type (optional)
- Set **Company** (optional)
- Set **Options** as a string representation of a dictionary. E.g.,
``{"widget": "date"}``, ``{"widget": "monetary"}``, or
``{"widget": "contact", "fields": ["name", "phone"]}``
- Set **Digits** (only for float-type fields). The value is ignored if
Options is set
- Set **Model** and **Field** (required)
- Set **UoM** and **UoM Field**, or **Currency** and **Currency Field**
only for fields of float type (optional)
- Set **Domain** to specify a domain for more specific filtering (e.g.,
``[('secondary_uom_id', '=', 1)]`` to apply only when a specific
secondary UoM is used) (optional)
- Set **Company** (optional)
- Set **Options** as a string representation of a dictionary. E.g.,
``{"widget": "date"}``, ``{"widget": "monetary"}``, or
``{"widget": "contact", "fields": ["name", "phone"]}``
- Set **Digits** (only for float-type fields). The value is ignored if
Options is set

Usage
=====
Expand Down Expand Up @@ -115,10 +114,10 @@ Authors
Contributors
------------

- `Quartile <https://www.quartile.co>`__:
- `Quartile <https://www.quartile.co>`__:

- Yoshi Tashiro
- Aung Ko Ko Lin
- Yoshi Tashiro
- Aung Ko Ko Lin

Maintainers
-----------
Expand Down
50 changes: 49 additions & 1 deletion report_qweb_field_option/models/qweb_field_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
import ast
import logging

from odoo import _, api, fields, models
from odoo import _, api, fields, models, tools
from odoo.exceptions import ValidationError
from odoo.osv.expression import normalize_domain
from odoo.tools.safe_eval import safe_eval

_logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -52,6 +54,14 @@ class QwebFieldOptions(models.Model):
)
digits = fields.Integer()
company_id = fields.Many2one("res.company", string="Company")
domain = fields.Char(
help="Optional domain for additional filtering conditions.\n"
"This is evaluated in addition to UoM/Currency conditions.\n"
"Examples:\n"
"[('secondary_uom_id', '=', 1)]\n"
"[('secondary_uom_id.name', '=', 'Box')]\n"
"[('state', 'in', ['sale', 'done'])]",
)

@api.constrains("field_options")
def _check_field_options_format(self):
Expand All @@ -74,6 +84,28 @@ def _check_field_options_format(self):
_("Options must be a dictionary, but got %s") % type(field_options)
)

def _get_eval_context(self):
return {
"time": tools.safe_eval.time,
"datetime": tools.safe_eval.datetime,
"dateutil": tools.safe_eval.dateutil,
"timezone": tools.safe_eval.pytz.timezone,
"context_today": lambda: fields.Date.context_today(self),
}

@api.constrains("domain")
def _check_domain_format(self):
for rec in self:
if not rec.domain:
continue
try:
normalize_domain(safe_eval(rec.domain, rec._get_eval_context()))
except Exception as e:
raise ValidationError(
_("Invalid domain format: %(domain)s.\n" "Error: %(error)s")
% {"domain": rec.domain, "error": e}
) from e

def _get_score(self, record):
self.ensure_one()
score = 1
Expand All @@ -91,6 +123,22 @@ def _get_score(self, record):
score += 1
else:
return -1
if self.domain:
try:
domain = normalize_domain(
safe_eval(self.domain, self._get_eval_context())
)
if not record.filtered_domain(domain):
return -1
score += 1
except Exception as e:
_logger.warning(
"Failed to evaluate domain %s for record %s: %s",
self.domain,
record,
e,
)
return -1
return score

def _update_field_options(self, record, field_options):
Expand Down
3 changes: 3 additions & 0 deletions report_qweb_field_option/readme/CONFIGURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ For each record:
- Set **Model** and **Field** (required)
- Set **UoM** and **UoM Field**, or **Currency** and **Currency Field**
only for fields of float type (optional)
- Set **Domain** to specify a domain for more specific filtering
(e.g., `[('secondary_uom_id', '=', 1)]` to apply only when
a specific secondary UoM is used) (optional)
- Set **Company** (optional)
- Set **Options** as a string representation of a dictionary. E.g.,
`{"widget": "date"}`, `{"widget": "monetary"}`, or
Expand Down
33 changes: 15 additions & 18 deletions report_qweb_field_option/static/description/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils: https://docutils.sourceforge.io/" />
<title>README.rst</title>
<title>Report Qweb Field Option</title>
<style type="text/css">

/*
Expand Down Expand Up @@ -360,21 +360,16 @@
</style>
</head>
<body>
<div class="document">
<div class="document" id="report-qweb-field-option">
<h1 class="title">Report Qweb Field Option</h1>


<a class="reference external image-reference" href="https://odoo-community.org/get-involved?utm_source=readme">
<img alt="Odoo Community Association" src="https://odoo-community.org/readme-banner-image" />
</a>
<div class="section" id="report-qweb-field-option">
<h1>Report Qweb Field Option</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:6a839e0b8361541500cea7946ac9d7bfbcbe37ab2a102576061a2940c4343c5c
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/license-AGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/reporting-engine/tree/18.0/report_qweb_field_option"><img alt="OCA/reporting-engine" src="https://img.shields.io/badge/github-OCA%2Freporting--engine-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/reporting-engine-18-0/reporting-engine-18-0-report_qweb_field_option"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/reporting-engine&amp;target_branch=18.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/reporting-engine/tree/18.0/report_qweb_field_option"><img alt="OCA/reporting-engine" src="https://img.shields.io/badge/github-OCA%2Freporting--engine-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/reporting-engine-18-0/reporting-engine-18-0-report_qweb_field_option"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/reporting-engine&amp;target_branch=18.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
<p>This module allows administrators to define the decimal precision of
float fields and add option values to fields (e.g., adding a date widget
option to datetime fields) for QWeb report and view presentation.</p>
Expand All @@ -394,14 +389,17 @@ <h1>Report Qweb Field Option</h1>
</ul>
</div>
<div class="section" id="configuration">
<h2><a class="toc-backref" href="#toc-entry-1">Configuration</a></h2>
<h1><a class="toc-backref" href="#toc-entry-1">Configuration</a></h1>
<p>Go to <em>Settings &gt; Technical &gt; Reporting &gt; Qweb Field Options</em>, and
create records according to your needs.</p>
<p>For each record:</p>
<ul class="simple">
<li>Set <strong>Model</strong> and <strong>Field</strong> (required)</li>
<li>Set <strong>UoM</strong> and <strong>UoM Field</strong>, or <strong>Currency</strong> and <strong>Currency Field</strong>
only for fields of float type (optional)</li>
<li>Set <strong>Domain</strong> to specify a domain for more specific filtering (e.g.,
<tt class="docutils literal"><span class="pre">[('secondary_uom_id',</span> <span class="pre">'=',</span> 1)]</tt> to apply only when a specific
secondary UoM is used) (optional)</li>
<li>Set <strong>Company</strong> (optional)</li>
<li>Set <strong>Options</strong> as a string representation of a dictionary. E.g.,
<tt class="docutils literal">{&quot;widget&quot;: &quot;date&quot;}</tt>, <tt class="docutils literal">{&quot;widget&quot;: &quot;monetary&quot;}</tt>, or
Expand All @@ -411,15 +409,15 @@ <h2><a class="toc-backref" href="#toc-entry-1">Configuration</a></h2>
</ul>
</div>
<div class="section" id="usage">
<h2><a class="toc-backref" href="#toc-entry-2">Usage</a></h2>
<h1><a class="toc-backref" href="#toc-entry-2">Usage</a></h1>
<p>Print a QWeb report (quotation, invoice, purchase order, etc.), and the
value presentation for fields like line quantity, price unit and date
order are adjusted according to the Qweb Field Options configuration.</p>
<p>Note that among matching configuration records, the one with the
strictest condition will be applied.</p>
</div>
<div class="section" id="known-issues-roadmap">
<h2><a class="toc-backref" href="#toc-entry-3">Known issues / Roadmap</a></h2>
<h1><a class="toc-backref" href="#toc-entry-3">Known issues / Roadmap</a></h1>
<div class="line-block">
<div class="line">#. QWeb field option settings only apply to fields rendered with
<tt class="docutils literal"><span class="pre">t-field</span></tt>.</div>
Expand All @@ -441,23 +439,23 @@ <h2><a class="toc-backref" href="#toc-entry-3">Known issues / Roadmap</a></h2>
<a class="reference external" href="https://github.com/odoo/odoo/blob/5eec379/addons/purchase/views/portal_templates.xml#L101-L102">https://github.com/odoo/odoo/blob/5eec379/addons/purchase/views/portal_templates.xml#L101-L102</a></p>
</div>
<div class="section" id="bug-tracker">
<h2><a class="toc-backref" href="#toc-entry-4">Bug Tracker</a></h2>
<h1><a class="toc-backref" href="#toc-entry-4">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/reporting-engine/issues">GitHub Issues</a>.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
<a class="reference external" href="https://github.com/OCA/reporting-engine/issues/new?body=module:%20report_qweb_field_option%0Aversion:%2018.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p>
</div>
<div class="section" id="credits">
<h2><a class="toc-backref" href="#toc-entry-5">Credits</a></h2>
<h1><a class="toc-backref" href="#toc-entry-5">Credits</a></h1>
<div class="section" id="authors">
<h3><a class="toc-backref" href="#toc-entry-6">Authors</a></h3>
<h2><a class="toc-backref" href="#toc-entry-6">Authors</a></h2>
<ul class="simple">
<li>Quartile</li>
</ul>
</div>
<div class="section" id="contributors">
<h3><a class="toc-backref" href="#toc-entry-7">Contributors</a></h3>
<h2><a class="toc-backref" href="#toc-entry-7">Contributors</a></h2>
<ul class="simple">
<li><a class="reference external" href="https://www.quartile.co">Quartile</a>:<ul>
<li>Yoshi Tashiro</li>
Expand All @@ -467,7 +465,7 @@ <h3><a class="toc-backref" href="#toc-entry-7">Contributors</a></h3>
</ul>
</div>
<div class="section" id="maintainers">
<h3><a class="toc-backref" href="#toc-entry-8">Maintainers</a></h3>
<h2><a class="toc-backref" href="#toc-entry-8">Maintainers</a></h2>
<p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org">
<img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" />
Expand All @@ -480,6 +478,5 @@ <h3><a class="toc-backref" href="#toc-entry-8">Maintainers</a></h3>
</div>
</div>
</div>
</div>
</body>
</html>
36 changes: 36 additions & 0 deletions report_qweb_field_option/tests/test_report_qweb_field_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,3 +153,39 @@ def test_qweb_field_option_with_uom(self):
self.test_record, "quantity", False, False, {}, values
)
self.assertEqual(content, "1.0")

def test_domain_validation(self):
"""Test that invalid domain raises validation error"""
with self.assertRaises(ValidationError):
self.env["qweb.field.options"].create(
{
"res_model_id": self.test_model.id,
"field_id": self.value_field.id,
"domain": "invalid domain",
"digits": 2,
}
)

def test_qweb_field_option_with_domain(self):
values = {"report_type": "pdf"}
jpy_currency = self.env.ref("base.JPY")
jpy_currency.active = True
self.qweb_options_rec.digits = 2
self.env["qweb.field.options"].create(
{
"res_model_id": self.test_model.id,
"field_id": self.value_field.id,
"domain": f"[('currency_id', '=', {jpy_currency.id})]",
"digits": 0,
}
)
_, content, _ = self.IrQweb._get_field(
self.test_record, "value", False, False, {}, values
)
self.assertEqual(content, "1.00")
# Test with JPY: domain matches, uses JPY-specific option (0 digits)
self.test_record.currency_id = jpy_currency.id
_, content, _ = self.IrQweb._get_field(
self.test_record, "value", False, False, {}, values
)
self.assertEqual(content, "1")
7 changes: 7 additions & 0 deletions report_qweb_field_option/views/qweb_field_options_views.xml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@
readonly="currency_id == False"
required="currency_id != False"
/>
<field name="res_model_name" column_invisible="1" />
<field
name="domain"
widget="domain"
options="{'model': 'res_model_name'}"
optional="hide"
/>
<field
name="company_id"
groups="base.group_multi_company"
Expand Down
Loading