mirror of
https://github.com/OCA/contract.git
synced 2025-02-13 17:57:24 +02:00
[IMP] contract: add section and notes in contract line
This commit is contained in:
committed by
Pedro M. Baeza
parent
f86bb0de30
commit
9291305c48
@@ -74,7 +74,8 @@ Known issues / Roadmap
|
||||
======================
|
||||
|
||||
* Recover states and others functional fields in Contracts.
|
||||
|
||||
* Depending on the contract lines, some sections of contract
|
||||
line have no meaning that they are propagated to certain invoices
|
||||
|
||||
Bug Tracker
|
||||
===========
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
'wizards/contract_manually_create_invoice.xml',
|
||||
'wizards/contract_contract_terminate.xml',
|
||||
'views/contract_tag.xml',
|
||||
'views/assets.xml',
|
||||
'views/abstract_contract_line.xml',
|
||||
'views/contract.xml',
|
||||
'views/contract_line.xml',
|
||||
|
||||
@@ -17,13 +17,13 @@ class ContractAbstractContractLine(models.AbstractModel):
|
||||
_description = 'Abstract Recurring Contract Line'
|
||||
|
||||
product_id = fields.Many2one(
|
||||
'product.product', string='Product', required=True
|
||||
'product.product', string='Product'
|
||||
)
|
||||
|
||||
name = fields.Text(string='Description', required=True)
|
||||
quantity = fields.Float(default=1.0, required=True)
|
||||
uom_id = fields.Many2one(
|
||||
'uom.uom', string='Unit of Measure', required=True
|
||||
'uom.uom', string='Unit of Measure'
|
||||
)
|
||||
automatic_price = fields.Boolean(
|
||||
string="Auto-price?",
|
||||
@@ -125,6 +125,9 @@ class ContractAbstractContractLine(models.AbstractModel):
|
||||
required=True,
|
||||
ondelete='cascade',
|
||||
)
|
||||
display_type = fields.Selection([
|
||||
('line_section', "Section"),
|
||||
('line_note', "Note")], default=False, help="Technical field for UX purpose.")
|
||||
|
||||
@api.model
|
||||
def _get_default_recurring_invoicing_offset(
|
||||
|
||||
@@ -146,6 +146,9 @@ class ContractLine(models.Model):
|
||||
def _compute_state(self):
|
||||
today = fields.Date.context_today(self)
|
||||
for rec in self:
|
||||
if rec.display_type:
|
||||
rec.state = False
|
||||
continue
|
||||
if rec.is_canceled:
|
||||
rec.state = 'canceled'
|
||||
continue
|
||||
@@ -648,15 +651,15 @@ class ContractLine(models.Model):
|
||||
|
||||
@api.depends('recurring_next_date', 'date_start', 'date_end')
|
||||
def _compute_create_invoice_visibility(self):
|
||||
# TODO: depending on the lines, and their order, some sections
|
||||
# have no meaning in certain invoices
|
||||
today = fields.Date.context_today(self)
|
||||
for rec in self:
|
||||
if rec.date_start:
|
||||
if today < rec.date_start:
|
||||
rec.create_invoice_visibility = False
|
||||
if (not rec.display_type and
|
||||
rec.date_start and today >= rec.date_start):
|
||||
rec.create_invoice_visibility = bool(rec.recurring_next_date)
|
||||
else:
|
||||
rec.create_invoice_visibility = bool(
|
||||
rec.recurring_next_date
|
||||
)
|
||||
rec.create_invoice_visibility = False
|
||||
|
||||
@api.multi
|
||||
def _prepare_invoice_line(self, invoice_id=False, invoice_values=False):
|
||||
@@ -665,6 +668,7 @@ class ContractLine(models.Model):
|
||||
self.last_date_invoiced, self.recurring_next_date
|
||||
)
|
||||
invoice_line_vals = {
|
||||
'display_type': self.display_type,
|
||||
'product_id': self.product_id.id,
|
||||
'quantity': self._get_quantity_to_invoice(*dates),
|
||||
'uom_id': self.uom_id.id,
|
||||
@@ -1299,7 +1303,8 @@ class ContractLine(models.Model):
|
||||
@api.multi
|
||||
def unlink(self):
|
||||
"""stop unlink uncnacled lines"""
|
||||
if not all(self.mapped('is_canceled')):
|
||||
for record in self:
|
||||
if not (record.is_canceled or record.display_type):
|
||||
raise ValidationError(
|
||||
_("Contract line must be canceled before delete")
|
||||
)
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
* Recover states and others functional fields in Contracts.
|
||||
|
||||
* Depending on the contract lines, some sections of contract
|
||||
line have no meaning that they are propagated to certain invoices
|
||||
|
||||
@@ -5,27 +5,27 @@
|
||||
<t t-call="web.html_container">
|
||||
<t t-foreach="docs" t-as="o">
|
||||
<t t-call="web.external_layout">
|
||||
<t t-set="o" t-value="o.with_context(lang=o.partner_id.lang)" />
|
||||
<t t-set="address">
|
||||
<p id="partner_info"><strong>Partner:</strong></p>
|
||||
<div t-field="o.partner_id"
|
||||
t-options='{"widget": "contact", "fields": ["address", "name", "phone", "mobile", "fax", "email"], "no_marker": true, "phone_icons": true}'/>
|
||||
<p t-if="o.partner_id.vat">VAT: <span t-field="o.partner_id.vat"/></p>
|
||||
</t>
|
||||
<div class="page">
|
||||
<div class="oe_structure"/>
|
||||
<div class="row" id="partner_info">
|
||||
<div class="col-xs-5 col-xs-offset-7">
|
||||
<p id="partner_info"><strong>Partner:</strong></p>
|
||||
<div t-field="o.partner_id" t-field-options='{"widget": "contact", "fields": ["address", "name", "phone", "mobile", "fax", "email"], "no_marker": true, "phone_icons": true}'/>
|
||||
<p t-if="o.partner_id.vat">VAT: <span t-field="o.partner_id.vat"/></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" id="header_info">
|
||||
<div class="col-xs-3">
|
||||
<div class="col-3">
|
||||
<strong>Responsible: </strong><p t-field="o.user_id"/>
|
||||
<strong>Contract: </strong><p t-field="o.code"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" id="invoice_info">
|
||||
<t t-set="total" t-value="0"/>
|
||||
<div class="col-xs-12">
|
||||
<div class="col-12">
|
||||
<t t-set="total" t-value="0"/>
|
||||
<p id="services_info"><strong>Recurring Items</strong></p>
|
||||
<table class="table table-condensed">
|
||||
<table class="table table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><strong>Description</strong></th>
|
||||
@@ -36,7 +36,11 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr t-foreach="o.contract_line_ids" t-as="l">
|
||||
<t t-set="current_subtotal" t-value="0"/>
|
||||
<t t-foreach="o.contract_line_ids" t-as="l">
|
||||
<t t-set="current_subtotal" t-value="current_subtotal + l.price_subtotal"/>
|
||||
<tr t-att-class="'bg-200 font-weight-bold o_line_section' if l.display_type == 'line_section' else 'font-italic o_line_note' if l.display_type == 'line_note' else ''">
|
||||
<t t-if="not l.display_type">
|
||||
<td>
|
||||
<span t-field="l.name"/>
|
||||
</td>
|
||||
@@ -49,17 +53,44 @@
|
||||
<td class="text-right">
|
||||
<span t-field="l.price_subtotal" t-options='{"widget": "monetary", "display_currency": o.currency_id}'/>
|
||||
</td>
|
||||
<td>
|
||||
<td class="text-right">
|
||||
<span t-field="l.date_start"/>
|
||||
</td>
|
||||
<t t-set="total" t-value="total + l.price_subtotal"/>
|
||||
</t>
|
||||
<t t-if="l.display_type == 'line_section'">
|
||||
<td colspan="99">
|
||||
<span t-field="l.name"/>
|
||||
</td>
|
||||
<t t-set="current_section" t-value="l"/>
|
||||
<t t-set="current_subtotal" t-value="0"/>
|
||||
</t>
|
||||
<t t-if="l.display_type == 'line_note'">
|
||||
<td colspan="99">
|
||||
<span t-field="l.name"/>
|
||||
</td>
|
||||
</t>
|
||||
</tr>
|
||||
<t t-if="current_section and (l_last or o.contract_line_ids[l_index+1].display_type == 'line_section')">
|
||||
<tr class="is-subtotal text-right">
|
||||
<td colspan="99">
|
||||
<strong class="mr16">Subtotal</strong>
|
||||
<span
|
||||
t-esc="current_subtotal"
|
||||
t-options='{"widget": "monetary", "display_currency": o.currency_id}'
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
</t>
|
||||
</t>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="col-xs-4 pull-right">
|
||||
<table class="table table-condensed">
|
||||
<tr class="border-black">
|
||||
</div>
|
||||
<div id="total" class="row" name="total">
|
||||
<div class="col-4 ml-auto">
|
||||
<table class="table table-sm">
|
||||
<tr class="border-black o_subtotal" style="">
|
||||
<td><strong>Total</strong></td>
|
||||
<td class="text-right">
|
||||
<span t-esc="total" t-options='{"widget": "monetary", "display_currency": o.currency_id}'/>
|
||||
@@ -68,12 +99,15 @@
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" id="note">
|
||||
<strong>Notes: </strong>
|
||||
<br></br>
|
||||
<div>
|
||||
<div class="row mt-4" id="note">
|
||||
<div><strong>Notes: </strong></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<p t-field="o.note"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
@@ -425,6 +425,8 @@ To use it, just select the template on the contract and fields will be filled au
|
||||
<h1><a class="toc-backref" href="#id3">Known issues / Roadmap</a></h1>
|
||||
<ul class="simple">
|
||||
<li>Recover states and others functional fields in Contracts.</li>
|
||||
<li>Depending on the contract lines, some sections of contract
|
||||
line have no meaning that they are propagated to certain invoices</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="bug-tracker">
|
||||
|
||||
38
contract/static/src/js/section_and_note_fields_backend.js
Normal file
38
contract/static/src/js/section_and_note_fields_backend.js
Normal file
@@ -0,0 +1,38 @@
|
||||
/* Copyright 2020 Tecnativa - Ernesto Tejeda
|
||||
* License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
*/
|
||||
/*
|
||||
If in the sub-tree view where the sections and notes are to be used
|
||||
there are fields that have defined in the XML attrs = {'invisible': ....}
|
||||
and this condition is met, then an extra space appears in the rows
|
||||
corresponding to the sections and lines.
|
||||
This js was written to deal with that problem, but a solution based on
|
||||
this can be applied directly to Odoo*/
|
||||
odoo.define('contract.section_and_note_backend', function (require) {
|
||||
"use strict";
|
||||
|
||||
var fieldRegistry = require('web.field_registry');
|
||||
var section_and_note_one2many = fieldRegistry.get('section_and_note_one2many');
|
||||
|
||||
section_and_note_one2many.include({
|
||||
_getRenderer: function () {
|
||||
var result = this._super.apply(this, arguments);
|
||||
if (this.view.arch.tag === 'tree') {
|
||||
result.include({
|
||||
_renderBodyCell: function (record, node, index, options) {
|
||||
var $cell = this._super.apply(this, arguments);
|
||||
|
||||
var isSection = record.data.display_type === 'line_section';
|
||||
var isNote = record.data.display_type === 'line_note';
|
||||
|
||||
if (isSection || isNote) {
|
||||
$cell.removeClass('o_invisible_modifier');
|
||||
}
|
||||
return $cell;
|
||||
}
|
||||
})
|
||||
}
|
||||
return result
|
||||
},
|
||||
});
|
||||
});
|
||||
@@ -7,24 +7,38 @@
|
||||
<field name="model">contract.abstract.contract.line</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<header/>
|
||||
<field name="display_type" invisible="1"/>
|
||||
<header attrs="{'invisible': [('display_type', '!=', False)]}"/>
|
||||
<sheet>
|
||||
<group col="4">
|
||||
<field colspan="4" name="product_id"/>
|
||||
<field colspan="4" name="name"/>
|
||||
<field colspan="2" name="quantity"/>
|
||||
<field colspan="2" name="uom_id"/>
|
||||
<field colspan="2" name="automatic_price"/>
|
||||
<field name="specific_price" invisible="1"/>
|
||||
<group col="4" attrs="{'invisible': [('display_type', '!=', False)]}">
|
||||
<field colspan="4"
|
||||
name="product_id"
|
||||
attrs="{'required': [('display_type', '=', False)]}"/>
|
||||
<label for="quantity"/>
|
||||
<div class="o_row">
|
||||
<field name="quantity" class="oe_inline"/>
|
||||
<field name="uom_id"
|
||||
class="oe_inline"
|
||||
groups="uom.group_uom"
|
||||
attrs="{'required': [('display_type', '=', False)]}"/>
|
||||
</div>
|
||||
<field colspan="2" name="automatic_price"/>
|
||||
<field colspan="2" name="price_unit"
|
||||
attrs="{'readonly': [('automatic_price', '=', True)]}"/>
|
||||
<field colspan="2" name="discount" groups="base.group_no_one"/>
|
||||
</group>
|
||||
<group col="4">
|
||||
|
||||
<label for="name" string="Description" attrs="{'invisible': [('display_type', '!=', False)]}"/>
|
||||
<label for="name" string="Section" attrs="{'invisible': [('display_type', '!=', 'line_section')]}"/>
|
||||
<label for="name" string="Note" attrs="{'invisible': [('display_type', '!=', 'line_note')]}"/>
|
||||
<field name="name" nolabel="1"/>
|
||||
|
||||
<group col="4" attrs="{'invisible': [('display_type', '!=', False)]}">
|
||||
<field colspan="2" name="is_auto_renew"/>
|
||||
<field colspan="2" name="is_canceled" invisible="1"/>
|
||||
</group>
|
||||
<group attrs="{'invisible':[('is_auto_renew', '=', False)]}">
|
||||
<group attrs="{'invisible':['|', ('is_auto_renew', '=', False), ('display_type', '!=', False)]}">
|
||||
<group>
|
||||
<label for="auto_renew_interval"/>
|
||||
<div>
|
||||
@@ -48,10 +62,10 @@
|
||||
</div>
|
||||
</group>
|
||||
</group>
|
||||
<group name="recurrence_info">
|
||||
<group name="recurrence_info" attrs="{'invisible': [('display_type', '!=', False)]}">
|
||||
<group>
|
||||
<label for="recurring_interval"/>
|
||||
<div>
|
||||
<div class="o_row">
|
||||
<field name="recurring_interval"
|
||||
class="oe_inline" nolabel="1"/>
|
||||
<field name="recurring_rule_type"
|
||||
|
||||
10
contract/views/assets.xml
Normal file
10
contract/views/assets.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright 2020 Tecnativa - Ernesto Tejeda
|
||||
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -->
|
||||
<odoo>
|
||||
<template id="assets_backend" name="contract assets" inherit_id="web.assets_backend">
|
||||
<xpath expr="." position="inside">
|
||||
<script type="text/javascript" src="/contract/static/src/js/section_and_note_fields_backend.js"></script>
|
||||
</xpath>
|
||||
</template>
|
||||
</odoo>
|
||||
@@ -96,8 +96,75 @@
|
||||
<notebook>
|
||||
<page name="recurring_invoice_line"
|
||||
string="Recurring Invoices">
|
||||
<field name="contract_line_ids" attrs="{'readonly': [('is_terminated','=',True)]}"
|
||||
context="{'default_contract_type': contract_type}"/>
|
||||
<field name="contract_line_ids"
|
||||
attrs="{'readonly': [('is_terminated','=',True)]}"
|
||||
widget="section_and_note_one2many"
|
||||
context="{'default_contract_type': contract_type}">
|
||||
<tree decoration-muted="is_canceled"
|
||||
decoration-info="create_invoice_visibility and not is_canceled">
|
||||
<control>
|
||||
<create string="Add a line"/>
|
||||
<create string="Add a section" context="{'default_display_type': 'line_section'}"/>
|
||||
<create string="Add a note" context="{'default_display_type': 'line_note'}"/>
|
||||
</control>
|
||||
<field name="display_type" invisible="1"/>
|
||||
<field name="sequence" widget="handle"/>
|
||||
<field name="product_id"/>
|
||||
<field name="name" widget="section_and_note_text"/>
|
||||
<field name="analytic_account_id" groups="analytic.group_analytic_accounting"/>
|
||||
<field name="analytic_tag_ids" widget="many2many_tags" groups="analytic.group_analytic_tags"/>
|
||||
<field name="quantity"/>
|
||||
<field name="uom_id"/>
|
||||
<field name="automatic_price" attrs="{'column_invisible': [('parent.contract_type', '=', 'purchase')]}"/>
|
||||
<field name="price_unit"
|
||||
attrs="{'readonly': [('automatic_price', '=', True)]}"/>
|
||||
<field name="specific_price" invisible="1"/>
|
||||
<field name="discount" groups="base.group_no_one"/>
|
||||
<field name="price_subtotal"/>
|
||||
<field name="recurring_interval" invisible="1"/>
|
||||
<field name="recurring_rule_type" invisible="1"/>
|
||||
<field name="recurring_invoicing_type" invisible="1"/>
|
||||
<field name="date_start" required="1"/>
|
||||
<field name="date_end"/>
|
||||
<field name="recurring_next_date" required="1"/>
|
||||
<field name="last_date_invoiced" groups="base.group_no_one"/>
|
||||
<field name="create_invoice_visibility" invisible="1"/>
|
||||
<field name="is_plan_successor_allowed" invisible="1"/>
|
||||
<field name="is_stop_plan_successor_allowed" invisible="1"/>
|
||||
<field name="is_stop_allowed" invisible="1"/>
|
||||
<field name="is_cancel_allowed" invisible="1"/>
|
||||
<field name="is_un_cancel_allowed" invisible="1"/>
|
||||
<field name="is_auto_renew" invisible="1"/>
|
||||
<field name="is_canceled" invisible="1"/>
|
||||
<button name="action_plan_successor"
|
||||
string="Plan Start" type="object"
|
||||
icon="fa-calendar text-success"
|
||||
attrs="{'invisible': [('is_plan_successor_allowed', '=', False)]}"/>
|
||||
<button name="action_stop_plan_successor"
|
||||
string="Stop Plan Successor"
|
||||
type="object"
|
||||
icon="fa-pause text-muted"
|
||||
attrs="{'invisible': [('is_stop_plan_successor_allowed', '=', False)]}"/>
|
||||
<button name="action_stop" string="Stop"
|
||||
type="object"
|
||||
icon="fa-stop text-danger"
|
||||
attrs="{'invisible': [('is_stop_allowed', '=', False)]}"/>
|
||||
<button name="cancel" string="Cancel"
|
||||
type="object"
|
||||
icon="fa-ban text-danger"
|
||||
confirm="Are you sure you want to cancel this line"
|
||||
attrs="{'invisible': [('is_cancel_allowed', '=', False)]}"/>
|
||||
<button name="action_uncancel"
|
||||
string="Un-cancel" type="object"
|
||||
icon="fa-ban text-success"
|
||||
attrs="{'invisible': [('is_un_cancel_allowed', '=', False)]}"/>
|
||||
<button name="renew" string="Renew"
|
||||
type="object"
|
||||
icon="fa-fast-forward text-success"
|
||||
groups="base.group_no_one"
|
||||
attrs="{'invisible': [('is_auto_renew', '=', False)]}"/>
|
||||
</tree>
|
||||
</field>
|
||||
<field name="note"/>
|
||||
</page>
|
||||
<page name="info" string="Other Information">
|
||||
|
||||
@@ -38,7 +38,9 @@
|
||||
</group>
|
||||
</group>
|
||||
<group name="recurrence_info" position="after">
|
||||
<group name="analytic" groups="analytic.group_analytic_accounting,analytic.group_analytic_tags">
|
||||
<group name="analytic"
|
||||
groups="analytic.group_analytic_accounting,analytic.group_analytic_tags"
|
||||
attrs="{'invisible': [('display_type', '!=', False)]}">
|
||||
<field name="analytic_account_id" groups="analytic.group_analytic_accounting"/>
|
||||
<field name="analytic_tag_ids" widget="many2many_tags" groups="analytic.group_analytic_tags"/>
|
||||
</group>
|
||||
@@ -77,6 +79,7 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- TODO: Delete this view in migration to v13 or further migrations -->
|
||||
<!--TREE view-->
|
||||
<record id="contract_line_tree_view" model="ir.ui.view">
|
||||
<field name="name">contract.line tree view (in contract)</field>
|
||||
|
||||
@@ -19,11 +19,19 @@
|
||||
</group>
|
||||
</group>
|
||||
<group name="group_invoice_lines" string="Contract Template Lines">
|
||||
<field name="contract_line_ids" nolabel="1">
|
||||
<field name="contract_line_ids"
|
||||
widget="section_and_note_one2many"
|
||||
nolabel="1">
|
||||
<tree>
|
||||
<control>
|
||||
<create string="Add a line"/>
|
||||
<create string="Add a section" context="{'default_display_type': 'line_section'}"/>
|
||||
<create string="Add a note" context="{'default_display_type': 'line_note'}"/>
|
||||
</control>
|
||||
<field name="display_type" invisible="1"/>
|
||||
<field name="sequence" widget="handle" />
|
||||
<field name="product_id" />
|
||||
<field name="name" />
|
||||
<field name="name" widget="section_and_note_text"/>
|
||||
<field name="quantity" />
|
||||
<field name="uom_id" />
|
||||
<field name="automatic_price" attrs="{'column_invisible': [('parent.contract_type','=','purchase')]}"/>
|
||||
|
||||
@@ -9,4 +9,14 @@
|
||||
groups="sales_team.group_sale_salesman"
|
||||
/>
|
||||
|
||||
<record id="contract_contract_form_view" model="ir.ui.view">
|
||||
<field name="name">contract.contract.form.contract.sale</field>
|
||||
<field name="model">contract.contract</field>
|
||||
<field name="inherit_id" ref="contract.contract_contract_form_view"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='contract_line_ids']/tree/field[@name='discount']" position="attributes">
|
||||
<attribute name="groups" add="sale.group_discount_per_so_line" separator=","/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<field name="model">contract.abstract.contract.line</field>
|
||||
<field name="inherit_id" ref="contract.contract_abstract_contract_line_form_view"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='quantity']" position="before">
|
||||
<xpath expr="//label[@for='quantity']" position="before">
|
||||
<field name="qty_type"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='quantity']" position="after">
|
||||
|
||||
@@ -8,6 +8,16 @@
|
||||
<xpath expr="//field[@name='code']" position="after">
|
||||
<field name="skip_zero_qty"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='contract_line_ids']/tree/field[@name='quantity']" position="before">
|
||||
<field name="qty_type"/>
|
||||
<field
|
||||
name="qty_formula_id"
|
||||
attrs="{'invisible': [('qty_type', '!=', 'variable')]}"
|
||||
/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='contract_line_ids']/tree/field[@name='quantity']" position="attributes">
|
||||
<attribute name="attrs">{'invisible': [('qty_type', '!=', 'fixed')]}</attribute>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user