Metadata-Version: 2.1
Name: odoo-addon-web_form_banner
Version: 16.0.1.1.0.2
Summary: Web Form Banner
Home-page: https://github.com/OCA/web
Author: Quartile, Odoo Community Association (OCA)
Author-email: support@odoo-community.org
License: AGPL-3
Classifier: Programming Language :: Python
Classifier: Framework :: Odoo
Classifier: Framework :: Odoo :: 16.0
Classifier: License :: OSI Approved :: GNU Affero General Public License v3
Requires-Python: >=3.10
Requires-Dist: odoo<16.1dev,>=16.0a

.. image:: https://odoo-community.org/readme-banner-image
   :target: https://odoo-community.org/get-involved?utm_source=readme
   :alt: Odoo Community Association

===============
Web Form Banner
===============

.. 
   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
   !! This file is generated by oca-gen-addon-readme !!
   !! changes will be overwritten.                   !!
   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
   !! source digest: sha256:b4fea38806c7f0f523049e82f07071663141d13e2de757fb402c94969f637e8d
   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

.. |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
    :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
    :alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fweb-lightgray.png?logo=github
    :target: https://github.com/OCA/web/tree/16.0/web_form_banner
    :alt: OCA/web
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
    :target: https://translation.odoo-community.org/projects/web-16-0/web-16-0-web_form_banner
    :alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
    :target: https://runboat.odoo-community.org/builds?repo=OCA/web&target_branch=16.0
    :alt: Try me on Runboat

|badge1| |badge2| |badge3| |badge4| |badge5|

The module adds configurable banners for backend **form** views. Define rules per model
(and optionally per view) to show context-aware alerts with a chosen severity (info/warning/danger).

Messages can be plain text with ${placeholders} or fully custom HTML; visibility,
severity, and values are computed server-side via a safe Python expression.

Banners are injected just before or after a target node (default: //sheet) and refresh
on form load/save/reload.

**Table of contents**

.. contents::
   :local:

Usage
=====

#. Go to *Settings > Technical > User Interface > Form Banner Rules* and create a rule.
#. Choose Model, select Trigger Fields (optional), set Default Severity, select Views
   (optional), update Target XPath (insertion point) and Position, and configure the
   message.
#. Save. Open any matching form record—the banner will appear and auto-refresh after
   load/save/reload.

Usage of message fields:
~~~~~~~~~~~~~~~~~~~~~~~~

* **Message** (message): Text shown in the banner. Supports `${placeholders}` filled
  from values returned by message_value_code. Ignored if message_value_code returns an
  `html` value.
* **HTML** (message_is_html): If enabled, the message string is rendered as HTML;
  otherwise it's treated as plain text.
* **Message Value Code** (message_value_code): Safe Python expression evaluated per
  record. Return a dict such as `{"visible": True, "severity": "warning", "values": {"name": record.name}}`.
  Use either message or `html` (from this code), not both. Several evaluation context
  variables are available.

Evaluation context variables available in Message Value Code:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

* `env`: Odoo environment for ORM access.
* `user`: Current user (`env.user`).
* `ctx`: Copy of the current context (`dict(env.context)`).
* `record`: Current record (the form's record).
* `draft`: The persisted field values of the ORM record (before applying the current
  form's unsaved changes) + the current unsaved changes on trigger fields.
  Should be used instead of `record` when your rule is triggered dynamically by an
  update to a trigger field. It doesn't include any values from complex fields
  (one2many/reference, etc).
* `record_id`: Integer id of the record being edited, or `False` if the form
  is creating a new record.
* `model`: Shortcut to the current model (`env[record._name]`).
* `url_for(obj)`: Helper that returns a backend form URL for `obj`.
* `context_today(ts=None)`: User-timezone “today” (date) for reliable date comparisons.
* `time`, `datetime`: Standard Python time/datetime modules.
* `dateutil`: `{ "parser": dateutil.parser, "relativedelta": dateutil.relativedelta }`
* `timezone`: `pytz.timezone` for TZ handling.
* `float_compare`, `float_is_zero`, `float_round`: Odoo float utils for precision-safe
  comparisons/rounding.

All of the above are injected by the module to the safe_eval locals.

Trigger Fields
~~~~~~~~~~~~~~

*Trigger Fields* is an optional list of model fields that, when changed in the open
form, cause the banner to **recompute live**. If left empty, the banner does **not**
auto-refresh as the user edits the form.

When a trigger fires, the module sends the current draft values to the server, sanitizes
them, builds an evaluation record, and re-runs your `message_value_code`.

You should use `draft` instead of `record` to access the current form values if your
rule is triggered based on an update to a trigger field.

Message setting examples:
~~~~~~~~~~~~~~~~~~~~~~~~~

**A) Missing email on contact (warning)**

* Model: `res.partner`
* Message: `This contact has no email.`
* Message Value Code:

.. code-block:: python

  {"visible": not bool(record.email)}

**B) Show partner comment if available**

* Model: `purchase.order`
* Message: `Vendor Comments: ${comment}`
* Message Value Code (single expression):

.. code-block:: python

  {
    "visible": bool(record.partner_id.comment),
    "values": {"comment": record.partner_id.comment},
  }

It is also possible to use "convenience placeholders" without an explicit `values` key:

.. code-block:: python

  {
    "visible": bool(record.partner_id.comment),
    "comment": record.partner_id.comment,
  }

**C) High-value sale order (dynamic severity)**

* Model: `sale.order`
* Message: `High-value order: ${amount_total}`
* Message Value Code:

.. code-block:: python

  {
    "visible": record.amount_total >= 30000,
    "severity": "danger" if record.amount_total >= 100000 else "warning",
    "values": {"amount_total": record.amount_total},
  }

**D) Quotation past validity date**

* Model: `sale.order`
* Message: `This quotation is past its validity date (${validity_date}).`
* Message Value Code:

.. code-block:: python

  {
    "visible": bool(record.validity_date and context_today() > record.validity_date and record.state in ["draft", "sent"]),
    "values": {"validity_date": record.validity_date},
  }

**E) Pending activities on a task (uses `env`)**

* Model: `project.task`
* Message: `There are ${cnt} pending activities.`
* Message Value Code (multi-line with `result`):

.. code-block:: python

  cnt = env["mail.activity"].search_count([("res_model","=",record._name),("res_id","=",record.id)])
  result = {"visible": cnt > 0, "values": {"cnt": cnt}}

**F) Product is missing internal reference (uses trigger fields)**

* Model: `product.template`
* Trigger Fields: `default_code`
* Message: `Make sure to set an internal reference!`
* Message Value Code:

.. code-block:: python

  {"visible": not bool(draft.default_code)}

**G) HTML banner linking to the customer's last sales order (uses trigger fields)**

* Model: `sale.order`
* Trigger Fields: `partner_id`
* Message: (leave blank; `html` provided by Message Value Code)
* Message Value Code (multi-line with `result`):

.. code-block:: python

  domain = [("partner_id", "=", draft.partner_id.id)]
  if record_id:
    domain += [("id", "<", record_id)]
  last = model.search(domain, order="date_order desc, id desc", limit=1)
  if last:
    html = "<strong>Previous order:</strong> <a href='%s'>%s</a>" % (url_for(last), last.name)
    result = {"visible": True, "html": html}
  else:
    result = {"visible": False}

Known issues / Roadmap
======================

Banner presentation inside `<group>`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Placing a full-width inline banner inside a `<group>` is only partially supported.
Depending on the target XPath (especially when targeting a `<field/>` rendered by
certain widgets), the banner or surrounding fields may render distorted.

Limitations of `draft` eval context variable
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

* `draft` is always available in the eval context, but for new records (`record_id` =
  `False`) it only contains the trigger fields from the banner rules.
* For existing records, `draft` overlays the trigger field values on top of the
  persisted record; all other fields come from `Model.new` defaults rather than the
  database.
* Only simple field types are included: `char`, `text`, `html`, `selection`, `boolean`,
  `integer`, `float`, `monetary`, `date`, `datetime`, `many2one`, and `many2many`.
  **one2many/reference/other types are omitted.**

Bug Tracker
===========

Bugs are tracked on `GitHub Issues <https://github.com/OCA/web/issues>`_.
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
`feedback <https://github.com/OCA/web/issues/new?body=module:%20web_form_banner%0Aversion:%2016.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.

Do not contact contributors directly about support or help with technical issues.

Credits
=======

Authors
~~~~~~~

* Quartile

Contributors
~~~~~~~~~~~~

* `Quartile <https://www.quartile.co>`_:

  * Yoshi Tashiro
  * Aung Ko Ko Lin

Maintainers
~~~~~~~~~~~

This module is maintained by the OCA.

.. image:: https://odoo-community.org/logo.png
   :alt: Odoo Community Association
   :target: https://odoo-community.org

OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.

This module is part of the `OCA/web <https://github.com/OCA/web/tree/16.0/web_form_banner>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
