Skip to content

Commit 1b75477

Browse files
[IMP] web_form_banner: pre-commit auto fixes
1 parent cdf3ef6 commit 1b75477

File tree

11 files changed

+457
-422
lines changed

11 files changed

+457
-422
lines changed

web_form_banner/README.rst

Lines changed: 155 additions & 143 deletions
Large diffs are not rendered by default.

web_form_banner/pyproject.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[build-system]
2+
requires = ["whool"]
3+
build-backend = "whool.buildapi"
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
- [Quartile](https://www.quartile.co):
2+
- Yoshi Tashiro
3+
- Aung Ko Ko Lin

web_form_banner/readme/CONTRIBUTORS.rst

Lines changed: 0 additions & 4 deletions
This file was deleted.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
The module adds configurable banners for backend **form** views. Define
2+
rules per model (and optionally per view) to show context-aware alerts
3+
with a chosen severity (info/warning/danger).
4+
5+
Messages can be plain text with \${placeholders} or fully custom HTML;
6+
visibility, severity, and values are computed server-side via a safe
7+
Python expression.
8+
9+
Banners are injected just before or after a target node (default:
10+
//sheet) and refresh on form load/save/reload.

web_form_banner/readme/DESCRIPTION.rst

Lines changed: 0 additions & 8 deletions
This file was deleted.

web_form_banner/readme/ROADMAP.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
## Banner presentation inside \<group\>
2+
3+
Placing a full-width inline banner inside a \<group\> is only partially
4+
supported. Depending on the target XPath (especially when targeting a
5+
\<field/\> rendered by certain widgets), the banner or surrounding
6+
fields may render distorted.
7+
8+
## Limitations of draft eval context variable
9+
10+
- draft is always available in the eval context, but for new records
11+
(record_id = False) it only contains the trigger fields from the
12+
banner rules.
13+
- For existing records, draft overlays the trigger field values on top
14+
of the persisted record; all other fields come from Model.new defaults
15+
rather than the database.
16+
- Only simple field types are included: char, text, html, selection,
17+
boolean, integer, float, monetary, date, datetime, many2one, and
18+
many2many. **one2many/reference/other types are omitted.**

web_form_banner/readme/ROADMAP.rst

Lines changed: 0 additions & 18 deletions
This file was deleted.

web_form_banner/readme/USAGE.md

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
1. Go to *Settings \> Technical \> User Interface \> Form Banner Rules*
2+
and create a rule.
3+
2. Choose Model, select Trigger Fields (optional), set Default
4+
Severity, select Views (optional), update Target XPath (insertion
5+
point) and Position, and configure the message.
6+
3. Save. Open any matching form record—the banner will appear and
7+
auto-refresh after load/save/reload.
8+
9+
## Usage of message fields:
10+
11+
- **Message** (message): Text shown in the banner. Supports
12+
\${placeholders} filled from values returned by message_value_code.
13+
Ignored if message_value_code returns an html value.
14+
- **HTML** (message_is_html): If enabled, the message string is rendered
15+
as HTML; otherwise it's treated as plain text.
16+
- **Message Value Code** (message_value_code): Safe Python expression
17+
evaluated per record. Return a dict such as {"visible": True,
18+
"severity": "warning", "values": {"name": record.name}}. Use either
19+
message or html (from this code), not both. Several evaluation context
20+
variables are available.
21+
22+
## Evaluation context variables available in Message Value Code:
23+
24+
- \`env\`: Odoo environment for ORM access.
25+
- \`user\`: Current user (env.user).
26+
- \`ctx\`: Copy of the current context (dict(env.context)).
27+
- \`record\`: Current record (the form's record).
28+
- \`draft\`: The persisted field values of the ORM record (before
29+
applying the current form's unsaved changes) + the current unsaved
30+
changes on trigger fields. Should be used instead of record when your
31+
rule is triggered dynamically by an update to a trigger field. It
32+
doesn't include any values from complex fields (one2many/reference,
33+
etc).
34+
- \`record_id\`: Integer id of the record being edited, or False if the
35+
form is creating a new record.
36+
- \`model\`: Shortcut to the current model (env\[record.\_name\]).
37+
- \`url_for(obj): Helper that returns a backend form URL for \`obj.
38+
- \`context_today(ts=None)\`: User-timezone “today” (date) for reliable
39+
date comparisons.
40+
- time, \`datetime\`: Standard Python time/datetime modules.
41+
- \`dateutil\`: { "parser": dateutil.parser, "relativedelta":
42+
dateutil.relativedelta }
43+
- \`timezone\`: pytz.timezone for TZ handling.
44+
- float_compare, float_is_zero, \`float_round\`: Odoo float utils for
45+
precision-safe comparisons/rounding.
46+
47+
All of the above are injected by the module to the safe_eval locals.
48+
49+
## Trigger Fields
50+
51+
*Trigger Fields* is an optional list of model fields that, when changed
52+
in the open form, cause the banner to **recompute live**. If left empty,
53+
the banner does **not** auto-refresh as the user edits the form.
54+
55+
When a trigger fires, the module sends the current draft values to the
56+
server, sanitizes them, builds an evaluation record, and re-runs your
57+
message_value_code.
58+
59+
You should use draft instead of record to access the current form values
60+
if your rule is triggered based on an update to a trigger field.
61+
62+
## Message setting examples:
63+
64+
**A) Missing email on contact (warning)**
65+
66+
- Model: res.partner
67+
- Message: This contact has no email.
68+
- Message Value Code:
69+
70+
``` python
71+
{"visible": not bool(record.email)}
72+
```
73+
74+
**B) Show partner comment if available**
75+
76+
- Model: purchase.order
77+
- Message: Vendor Comments: \${comment}
78+
- Message Value Code (single expression):
79+
80+
``` python
81+
{
82+
"visible": bool(record.partner_id.comment),
83+
"values": {"comment": record.partner_id.comment},
84+
}
85+
```
86+
87+
It is also possible to use "convenience placeholders" without an
88+
explicit values key:
89+
90+
``` python
91+
{
92+
"visible": bool(record.partner_id.comment),
93+
"comment": record.partner_id.comment,
94+
}
95+
```
96+
97+
**C) High-value sale order (dynamic severity)**
98+
99+
- Model: sale.order
100+
- Message: High-value order: \${amount_total}
101+
- Message Value Code:
102+
103+
``` python
104+
{
105+
"visible": record.amount_total >= 30000,
106+
"severity": "danger" if record.amount_total >= 100000 else "warning",
107+
"values": {"amount_total": record.amount_total},
108+
}
109+
```
110+
111+
**D) Quotation past validity date**
112+
113+
- Model: sale.order
114+
- Message: This quotation is past its validity date (\${validity_date}).
115+
- Message Value Code:
116+
117+
``` python
118+
{
119+
"visible": bool(record.validity_date and context_today() > record.validity_date and record.state in ["draft", "sent"]),
120+
"values": {"validity_date": record.validity_date},
121+
}
122+
```
123+
124+
**E) Pending activities on a task (uses \`env\`)**
125+
126+
- Model: project.task
127+
- Message: There are \${cnt} pending activities.
128+
- Message Value Code (multi-line with result):
129+
130+
``` python
131+
cnt = env["mail.activity"].search_count([("res_model","=",record._name),("res_id","=",record.id)])
132+
result = {"visible": cnt > 0, "values": {"cnt": cnt}}
133+
```
134+
135+
**F) Product is missing internal reference (uses trigger fields)**
136+
137+
- Model: product.template
138+
- Trigger Fields: default_code
139+
- Message: Make sure to set an internal reference!
140+
- Message Value Code:
141+
142+
``` python
143+
{"visible": not bool(draft.default_code)}
144+
```
145+
146+
**G) HTML banner linking to the customer's last sales order (uses
147+
trigger fields)**
148+
149+
- Model: sale.order
150+
- Trigger Fields: partner_id
151+
- Message: (leave blank; html provided by Message Value Code)
152+
- Message Value Code (multi-line with result):
153+
154+
``` python
155+
domain = [("partner_id", "=", draft.partner_id.id)]
156+
if record_id:
157+
domain += [("id", "<", record_id)]
158+
last = model.search(domain, order="date_order desc, id desc", limit=1)
159+
if last:
160+
html = "<strong>Previous order:</strong> <a href='%s'>%s</a>" % (url_for(last), last.name)
161+
result = {"visible": True, "html": html}
162+
else:
163+
result = {"visible": False}
164+
```

web_form_banner/readme/USAGE.rst

Lines changed: 0 additions & 160 deletions
This file was deleted.

0 commit comments

Comments
 (0)