[IMP] product_contract: Set description under product name instead of description

Using the feature extraLines of Many2one field Component we can add the info under the product and avoid noice on the product description.

You can show this info on the description by using the system parameters:
    - product_contract.show_recurrency
    - product_contract.show_invoicing_type
    - product_contract.show_date
This commit is contained in:
Carlos Roca
2025-01-24 15:26:43 +01:00
parent 891236ab5f
commit f006353aa4
8 changed files with 212 additions and 144 deletions

View File

@@ -42,6 +42,16 @@ invoice directly.
.. contents:: .. contents::
:local: :local:
Configuration
=============
You can include the contract details on the sales order description by
using the following system parameters:
1. **Recurrency** -> product_contract.show_recurrency
2. **Invoicing Type** -> product_contract.show_invoicing_type
3. **Date** -> product_contract.show_date
Usage Usage
===== =====

View File

@@ -9,8 +9,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Odoo Server 10.0\n" "Project-Id-Version: Odoo Server 10.0\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-08-30 12:54+0000\n" "POT-Creation-Date: 2025-01-24 14:18+0000\n"
"PO-Revision-Date: 2024-08-30 15:06+0200\n" "PO-Revision-Date: 2025-01-24 15:19+0100\n"
"Last-Translator: Pedro M. Baeza <pedro.baeza@gmail.com>\n" "Last-Translator: Pedro M. Baeza <pedro.baeza@gmail.com>\n"
"Language-Team: Spanish (https://www.transifex.com/oca/teams/23907/es/)\n" "Language-Team: Spanish (https://www.transifex.com/oca/teams/23907/es/)\n"
"Language: es\n" "Language: es\n"
@@ -20,6 +20,27 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=n != 1;\n" "Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Poedit 3.0.1\n" "X-Generator: Poedit 3.0.1\n"
#. module: product_contract
#. odoo-python
#: code:addons/product_contract/models/sale_order_line.py:0
#, python-format
msgid "- Date: {}"
msgstr "- Fecha: {}"
#. module: product_contract
#. odoo-python
#: code:addons/product_contract/models/sale_order_line.py:0
#, python-format
msgid "- Invoicing Type: {}"
msgstr "- Tipo de facturación: {}"
#. module: product_contract
#. odoo-python
#: code:addons/product_contract/models/sale_order_line.py:0
#, python-format
msgid "- Recurrency: {}"
msgstr "- Recurrencia: {}"
#. module: product_contract #. module: product_contract
#: model_terms:ir.ui.view,arch_db:product_contract.contract_contract_customer_form_view #: model_terms:ir.ui.view,arch_db:product_contract.contract_contract_customer_form_view
msgid "<span class=\"o_stat_text\">Sale Orders</span>" msgid "<span class=\"o_stat_text\">Sale Orders</span>"
@@ -361,6 +382,11 @@ msgstr "Producto"
msgid "Product Contract Configurator Wizard" msgid "Product Contract Configurator Wizard"
msgstr "" msgstr ""
#. module: product_contract
#: model:ir.model.fields,field_description:product_contract.field_sale_order_line__product_contract_description
msgid "Product Contract Description"
msgstr ""
#. module: product_contract #. module: product_contract
#: model:ir.model.fields,field_description:product_contract.field_product_contract_configurator__product_uom_qty #: model:ir.model.fields,field_description:product_contract.field_product_contract_configurator__product_uom_qty
msgid "Quantity" msgid "Quantity"
@@ -616,53 +642,3 @@ msgstr "Años"
#, python-format #, python-format
msgid "You can't upsell or downsell a terminated contract" msgid "You can't upsell or downsell a terminated contract"
msgstr "No puede vender o vender un contrato terminado" msgstr "No puede vender o vender un contrato terminado"
#. module: product_contract
#. odoo-python
#: code:addons/product_contract/models/sale_order.py:0
#, python-format
msgid ""
"You must specify a contract template for '%(product_name)s' product in "
"'%(company_name)s' company."
msgstr ""
"Debes especificar una plantilla de contrato para el producto "
"'%(product_name)s' en la empresa '%(company_name)s'."
#. module: product_contract
#. odoo-python
#: code:addons/product_contract/models/sale_order_line.py:0
#, python-format
msgid ""
"{product}:\n"
" - Recurrency: {recurring_rule}\n"
" - Invoicing Type: {invoicing_type}\n"
" - Date: {date_text}\n"
" "
msgstr ""
#, python-format
#~ msgid ""
#~ "{product}\n"
#~ " - Recurrency: {recurring_rule}\n"
#~ " - Invoicing Type: {invoicing_type}\n"
#~ " - Date: {date_text}\n"
#~ " "
#~ msgstr ""
#~ "{product}\n"
#~ " - Periodicidad: {recurring_rule}\n"
#~ " - Tipo de facturación: {invoicing_type}\n"
#~ " - Fecha: {date_text}\n"
#~ " "
#~ msgid "Product Template"
#~ msgstr "Plantilla de producto"
#~ msgid "Sale Order"
#~ msgstr "Pedido de Venta"
#, python-format
#~ msgid ""
#~ "You must specify a contract template for '{}' product in '{}' company."
#~ msgstr ""
#~ "Debe especificar una plantilla de contrato para el producto '{}' en la "
#~ "compañía '{}'."

View File

@@ -6,6 +6,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Odoo Server 17.0\n" "Project-Id-Version: Odoo Server 17.0\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-01-24 14:18+0000\n"
"PO-Revision-Date: 2025-01-24 14:18+0000\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: \n" "Language-Team: \n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
@@ -13,6 +15,27 @@ msgstr ""
"Content-Transfer-Encoding: \n" "Content-Transfer-Encoding: \n"
"Plural-Forms: \n" "Plural-Forms: \n"
#. module: product_contract
#. odoo-python
#: code:addons/product_contract/models/sale_order_line.py:0
#, python-format
msgid "- Date: {}"
msgstr ""
#. module: product_contract
#. odoo-python
#: code:addons/product_contract/models/sale_order_line.py:0
#, python-format
msgid "- Invoicing Type: {}"
msgstr ""
#. module: product_contract
#. odoo-python
#: code:addons/product_contract/models/sale_order_line.py:0
#, python-format
msgid "- Recurrency: {}"
msgstr ""
#. module: product_contract #. module: product_contract
#: model_terms:ir.ui.view,arch_db:product_contract.contract_contract_customer_form_view #: model_terms:ir.ui.view,arch_db:product_contract.contract_contract_customer_form_view
msgid "<span class=\"o_stat_text\">Sale Orders</span>" msgid "<span class=\"o_stat_text\">Sale Orders</span>"
@@ -354,6 +377,11 @@ msgstr ""
msgid "Product Contract Configurator Wizard" msgid "Product Contract Configurator Wizard"
msgstr "" msgstr ""
#. module: product_contract
#: model:ir.model.fields,field_description:product_contract.field_sale_order_line__product_contract_description
msgid "Product Contract Description"
msgstr ""
#. module: product_contract #. module: product_contract
#: model:ir.model.fields,field_description:product_contract.field_product_contract_configurator__product_uom_qty #: model:ir.model.fields,field_description:product_contract.field_product_contract_configurator__product_uom_qty
msgid "Quantity" msgid "Quantity"
@@ -559,24 +587,3 @@ msgstr ""
#, python-format #, python-format
msgid "You can't upsell or downsell a terminated contract" msgid "You can't upsell or downsell a terminated contract"
msgstr "" msgstr ""
#. module: product_contract
#. odoo-python
#: code:addons/product_contract/models/sale_order.py:0
#, python-format
msgid ""
"You must specify a contract template for '%(product_name)s' product in "
"'%(company_name)s' company."
msgstr ""
#. module: product_contract
#. odoo-python
#: code:addons/product_contract/models/sale_order_line.py:0
#, python-format
msgid ""
"{product}:\n"
" - Recurrency: {recurring_rule}\n"
" - Invoicing Type: {invoicing_type}\n"
" - Date: {date_text}\n"
" "
msgstr ""

View File

@@ -6,6 +6,7 @@ from dateutil.relativedelta import relativedelta
from odoo import _, api, fields, models from odoo import _, api, fields, models
from odoo.exceptions import ValidationError from odoo.exceptions import ValidationError
from odoo.tools import str2bool
MONTH_NB_MAPPING = { MONTH_NB_MAPPING = {
"monthly": 1, "monthly": 1,
@@ -74,6 +75,9 @@ class SaleOrderLine(models.Model):
contract_start_date_method = fields.Selection( contract_start_date_method = fields.Selection(
related="product_id.contract_start_date_method" related="product_id.contract_start_date_method"
) )
product_contract_description = fields.Text(
compute="_compute_product_contract_description"
)
@api.constrains("contract_id") @api.constrains("contract_id")
def _check_contact_is_not_terminated(self): def _check_contact_is_not_terminated(self):
@@ -307,64 +311,103 @@ class SaleOrderLine(models.Model):
start_date = start_date + relativedelta(day=31) start_date = start_date + relativedelta(day=31)
line.date_start = start_date line.date_start = start_date
@api.depends("product_id") def _get_product_contract_date_text(self):
def _compute_name(self): self.ensure_one()
res = super()._compute_name() date_text = ""
if self.contract_start_date_method == "manual":
date_text = "%s" % self.date_start
if self.date_end:
date_text += " -> %s" % self.date_end
else:
field_info = dict(
self._fields["contract_start_date_method"].get_description(self.env)
)
field_selection = dict(field_info.get("selection"))
start_method_label = field_selection.get(self.contract_start_date_method)
date_text = start_method_label and "%s" % start_method_label
if (
self.recurring_rule_type != "monthly"
and self.product_id["force_month_%s" % self.recurring_rule_type]
):
field_info = dict(
self.env["product.template"]
._fields["force_month_%s" % self.recurring_rule_type]
.get_description(self.env)
)
field_selection = dict(field_info.get("selection"))
force_month_label = field_selection.get(
self.product_id["force_month_%s" % self.recurring_rule_type]
)
date_text += " (%s)" % force_month_label
return date_text and _("- Date: {}").format(date_text)
def _get_product_contract_recurring_rule_label(self):
self.ensure_one()
field_info = dict(self._fields["recurring_rule_type"].get_description(self.env))
field_selection = dict(field_info.get("selection"))
recurring_rule_label = field_selection.get(self.recurring_rule_type)
return recurring_rule_label and _("- Recurrency: {}").format(
recurring_rule_label
)
def _get_product_contract_invoicing_type_label(self):
field_info = dict(
self._fields["recurring_invoicing_type"].get_description(self.env)
)
field_selection = dict(field_info.get("selection"))
invoicing_type_label = field_selection.get(self.recurring_invoicing_type)
return invoicing_type_label and _("- Invoicing Type: {}").format(
invoicing_type_label
)
@api.depends(
"product_id",
"date_start",
"date_end",
"recurring_rule_type",
"recurring_invoicing_type",
)
def _compute_product_contract_description(self):
self.product_contract_description = False
for line in self: for line in self:
if line.is_contract: if line.is_contract:
date_text = "" description = ""
if line.contract_start_date_method == "manual": if (
date_text = "%s" % line.date_start recurring_rule_label
if line.date_end: := line._get_product_contract_recurring_rule_label()
date_text += " -> %s" % line.date_end ):
else: description += recurring_rule_label + "||"
field_info = dict( if (
line._fields["contract_start_date_method"].get_description( invoicing_type_label
self.env := line._get_product_contract_invoicing_type_label()
) ):
) description += invoicing_type_label + "||"
field_selection = dict(field_info.get("selection")) if date_text := line._get_product_contract_date_text():
start_method_label = field_selection.get( description += date_text + "||"
line.contract_start_date_method line.product_contract_description = description
)
date_text = "%s" % start_method_label
if (
line.recurring_rule_type != "monthly"
and line.product_id["force_month_%s" % line.recurring_rule_type]
):
field_info = dict(
self.env["product.template"]
._fields["force_month_%s" % line.recurring_rule_type]
.get_description(self.env)
)
field_selection = dict(field_info.get("selection"))
force_month_label = field_selection.get(
line.product_id["force_month_%s" % line.recurring_rule_type]
)
date_text += " (%s)" % force_month_label
field_info = dict(
self._fields["recurring_rule_type"].get_description(self.env)
)
field_selection = dict(field_info.get("selection"))
recurring_rule_label = field_selection.get(line.recurring_rule_type)
field_info = dict(
self._fields["recurring_invoicing_type"].get_description(self.env)
)
field_selection = dict(field_info.get("selection"))
invoicing_type_label = field_selection.get(
line.recurring_invoicing_type
)
line.name = _(
"""{product}:
- Recurrency: {recurring_rule}
- Invoicing Type: {invoicing_type}
- Date: {date_text}
"""
).format(
product=line.product_id.display_name,
recurring_rule=recurring_rule_label,
invoicing_type=invoicing_type_label,
date_text=date_text,
)
@api.depends(
"date_start", "date_end", "recurring_rule_type", "recurring_invoicing_type"
)
def _compute_name(self):
res = super()._compute_name()
ICP = self.env["ir.config_parameter"].sudo()
for line in self:
if line.is_contract:
description = ""
if str2bool(ICP.get_param("product_contract.show_recurrency")) and (
recurring_rule_label
:= line._get_product_contract_recurring_rule_label()
):
description += "\n\t" + recurring_rule_label
if str2bool(ICP.get_param("product_contract.show_invoicing_type")) and (
invoicing_type_label
:= line._get_product_contract_invoicing_type_label()
):
description += "\n\t" + invoicing_type_label
if str2bool(ICP.get_param("product_contract.show_date")) and (
date_text := line._get_product_contract_date_text()
):
description += "\n\t" + date_text
line.name = f"{line.product_id.display_name}{description}"
return res return res

View File

@@ -0,0 +1,5 @@
You can include the contract details on the sales order description by using the following system parameters:
1. **Recurrency** -\> product_contract.show_recurrency
2. **Invoicing Type** -\> product_contract.show_invoicing_type
3. **Date** -\> product_contract.show_date

View File

@@ -379,19 +379,30 @@ invoice directly.</p>
<p><strong>Table of contents</strong></p> <p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents"> <div class="contents local topic" id="contents">
<ul class="simple"> <ul class="simple">
<li><a class="reference internal" href="#usage" id="toc-entry-1">Usage</a></li> <li><a class="reference internal" href="#configuration" id="toc-entry-1">Configuration</a></li>
<li><a class="reference internal" href="#known-issues-roadmap" id="toc-entry-2">Known issues / Roadmap</a></li> <li><a class="reference internal" href="#usage" id="toc-entry-2">Usage</a></li>
<li><a class="reference internal" href="#bug-tracker" id="toc-entry-3">Bug Tracker</a></li> <li><a class="reference internal" href="#known-issues-roadmap" id="toc-entry-3">Known issues / Roadmap</a></li>
<li><a class="reference internal" href="#credits" id="toc-entry-4">Credits</a><ul> <li><a class="reference internal" href="#bug-tracker" id="toc-entry-4">Bug Tracker</a></li>
<li><a class="reference internal" href="#authors" id="toc-entry-5">Authors</a></li> <li><a class="reference internal" href="#credits" id="toc-entry-5">Credits</a><ul>
<li><a class="reference internal" href="#contributors" id="toc-entry-6">Contributors</a></li> <li><a class="reference internal" href="#authors" id="toc-entry-6">Authors</a></li>
<li><a class="reference internal" href="#maintainers" id="toc-entry-7">Maintainers</a></li> <li><a class="reference internal" href="#contributors" id="toc-entry-7">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="toc-entry-8">Maintainers</a></li>
</ul> </ul>
</li> </li>
</ul> </ul>
</div> </div>
<div class="section" id="configuration">
<h1><a class="toc-backref" href="#toc-entry-1">Configuration</a></h1>
<p>You can include the contract details on the sales order description by
using the following system parameters:</p>
<ol class="arabic simple">
<li><strong>Recurrency</strong> -&gt; product_contract.show_recurrency</li>
<li><strong>Invoicing Type</strong> -&gt; product_contract.show_invoicing_type</li>
<li><strong>Date</strong> -&gt; product_contract.show_date</li>
</ol>
</div>
<div class="section" id="usage"> <div class="section" id="usage">
<h1><a class="toc-backref" href="#toc-entry-1">Usage</a></h1> <h1><a class="toc-backref" href="#toc-entry-2">Usage</a></h1>
<p>To use this module, you need to:</p> <p>To use this module, you need to:</p>
<ol class="arabic simple"> <ol class="arabic simple">
<li>Go to Sales -&gt; Products and select or create a product.</li> <li>Go to Sales -&gt; Products and select or create a product.</li>
@@ -401,14 +412,14 @@ product</li>
</ol> </ol>
</div> </div>
<div class="section" id="known-issues-roadmap"> <div class="section" id="known-issues-roadmap">
<h1><a class="toc-backref" href="#toc-entry-2">Known issues / Roadmap</a></h1> <h1><a class="toc-backref" href="#toc-entry-3">Known issues / Roadmap</a></h1>
<ul class="simple"> <ul class="simple">
<li>Theres no support right now for computing the start date for the <li>Theres no support right now for computing the start date for the
following recurrent types: daily, weekly and monthlylastday.</li> following recurrent types: daily, weekly and monthlylastday.</li>
</ul> </ul>
</div> </div>
<div class="section" id="bug-tracker"> <div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#toc-entry-3">Bug Tracker</a></h1> <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/contract/issues">GitHub Issues</a>. <p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/contract/issues">GitHub Issues</a>.
In case of trouble, please check there if your issue has already been reported. 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 If you spotted it first, help us to smash it by providing a detailed and welcomed
@@ -416,16 +427,16 @@ If you spotted it first, help us to smash it by providing a detailed and welcome
<p>Do not contact contributors directly about support or help with technical issues.</p> <p>Do not contact contributors directly about support or help with technical issues.</p>
</div> </div>
<div class="section" id="credits"> <div class="section" id="credits">
<h1><a class="toc-backref" href="#toc-entry-4">Credits</a></h1> <h1><a class="toc-backref" href="#toc-entry-5">Credits</a></h1>
<div class="section" id="authors"> <div class="section" id="authors">
<h2><a class="toc-backref" href="#toc-entry-5">Authors</a></h2> <h2><a class="toc-backref" href="#toc-entry-6">Authors</a></h2>
<ul class="simple"> <ul class="simple">
<li>LasLabs</li> <li>LasLabs</li>
<li>ACSONE SA/NV</li> <li>ACSONE SA/NV</li>
</ul> </ul>
</div> </div>
<div class="section" id="contributors"> <div class="section" id="contributors">
<h2><a class="toc-backref" href="#toc-entry-6">Contributors</a></h2> <h2><a class="toc-backref" href="#toc-entry-7">Contributors</a></h2>
<ul class="simple"> <ul class="simple">
<li>Ted Salmon &lt;<a class="reference external" href="mailto:tsalmon&#64;laslabs.com">tsalmon&#64;laslabs.com</a>&gt;</li> <li>Ted Salmon &lt;<a class="reference external" href="mailto:tsalmon&#64;laslabs.com">tsalmon&#64;laslabs.com</a>&gt;</li>
<li>Souheil Bejaoui &lt;<a class="reference external" href="mailto:souheil.bejaoui&#64;acsone.eu">souheil.bejaoui&#64;acsone.eu</a>&gt;</li> <li>Souheil Bejaoui &lt;<a class="reference external" href="mailto:souheil.bejaoui&#64;acsone.eu">souheil.bejaoui&#64;acsone.eu</a>&gt;</li>
@@ -439,7 +450,7 @@ If you spotted it first, help us to smash it by providing a detailed and welcome
</ul> </ul>
</div> </div>
<div class="section" id="maintainers"> <div class="section" id="maintainers">
<h2><a class="toc-backref" href="#toc-entry-7">Maintainers</a></h2> <h2><a class="toc-backref" href="#toc-entry-8">Maintainers</a></h2>
<p>This module is maintained by the OCA.</p> <p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org"> <a class="reference external image-reference" href="https://odoo-community.org">
<img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" /> <img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" />

View File

@@ -4,6 +4,21 @@ import {SaleOrderLineProductField} from "@sale/js/sale_product_field";
import {patch} from "@web/core/utils/patch"; import {patch} from "@web/core/utils/patch";
patch(SaleOrderLineProductField.prototype, { patch(SaleOrderLineProductField.prototype, {
get extraLines() {
var res = super.extraLines;
if (
this.props.record.data.is_contract &&
this.props.record.data.product_contract_description
) {
for (var val of this.props.record.data.product_contract_description.split(
"||"
)) {
res.push(val);
}
}
return res;
},
async _onProductUpdate() { async _onProductUpdate() {
super._onProductUpdate(...arguments); super._onProductUpdate(...arguments);
if (this.props.record.data.is_contract) { if (this.props.record.data.is_contract) {

View File

@@ -100,6 +100,7 @@
> >
<field name="contract_template_id" column_invisible="1" /> <field name="contract_template_id" column_invisible="1" />
<field name="is_contract" column_invisible="1" /> <field name="is_contract" column_invisible="1" />
<field name="product_contract_description" column_invisible="1" />
<field <field
name="contract_id" name="contract_id"
options='{"no_create": True}' options='{"no_create": True}'