Browse Source

[ADD] agreement_sale_condition_base

pull/396/head
Alexandre Fayolle 5 years ago
parent
commit
563c0c360e
  1. 102
      agreement_sale_condition_base/README.rst
  2. 2
      agreement_sale_condition_base/__init__.py
  3. 38
      agreement_sale_condition_base/__manifest__.py
  4. 14
      agreement_sale_condition_base/data/agreement.xml
  5. 8
      agreement_sale_condition_base/data/agreement_type.xml
  6. 5
      agreement_sale_condition_base/demo/agreement.csv
  7. 25
      agreement_sale_condition_base/demo/agreement_type.xml
  8. 7
      agreement_sale_condition_base/models/__init__.py
  9. 9
      agreement_sale_condition_base/models/account_invoice.py
  10. 135
      agreement_sale_condition_base/models/agreement.py
  11. 51
      agreement_sale_condition_base/models/agreement_parameter_value.py
  12. 30
      agreement_sale_condition_base/models/agreement_type.py
  13. 20
      agreement_sale_condition_base/models/procurement_group.py
  14. 21
      agreement_sale_condition_base/models/res_partner.py
  15. 123
      agreement_sale_condition_base/models/sale_order.py
  16. 1
      agreement_sale_condition_base/readme/CONTRIBUTORS.rst
  17. 24
      agreement_sale_condition_base/readme/DESCRIPTION.rst
  18. 3
      agreement_sale_condition_base/security/ir.model.access.csv
  19. 440
      agreement_sale_condition_base/static/description/index.html
  20. 1
      agreement_sale_condition_base/tests/__init__.py
  21. 75
      agreement_sale_condition_base/tests/test_agreement_propagation.py
  22. 10
      agreement_sale_condition_base/tools.py
  23. 216
      agreement_sale_condition_base/views/agreement.xml
  24. 44
      agreement_sale_condition_base/views/agreement_parameter_value.xml
  25. 52
      agreement_sale_condition_base/views/agreement_type.xml
  26. 13
      agreement_sale_condition_base/views/procurement_group.xml
  27. 21
      agreement_sale_condition_base/views/res_partner.xml
  28. 17
      agreement_sale_condition_base/views/sale_order.xml

102
agreement_sale_condition_base/README.rst

@ -0,0 +1,102 @@
=========================
Agreement Sale Conditions
=========================
.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| image:: https://img.shields.io/badge/maturity-Alpha-red.png
:target: https://odoo-community.org/page/development-status
:alt: Alpha
.. |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%2Fcontract-lightgray.png?logo=github
:target: https://github.com/OCA/contract/tree/12.0/agreement_sale_condition
:alt: OCA/contract
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/contract-12-0/contract-12-0-agreement_sale_condition
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png
:target: https://runbot.odoo-community.org/runbot/110/12.0
:alt: Try me on Runbot
|badge1| |badge2| |badge3| |badge4| |badge5|
This module builds on the agreement and agreement_sale modules. It defines a
model for agreement parameter values. The intent is that additional modules can
add fields on an agreement which are m2o on to parameter values, and possibly
the allowed values for a given field could depend on the value of another one.
An agreement type can be linked to a template agreement. When the agreement
type is set on a sale order, a new agreement record is created using the
template agreement as a basis. This agreement specific to the sale order can be
customized by the sales man.
When the sale order is confirmed, the agreement of the sale order is propagated
to the procurement group of the sale order. This can be used by extension
modules to customize the generation of the stock moves and pickings to match
the agreement.
In a similar fashion, when an invoice is created from the sale order, the
agreement of the sale order, the agreement is propagated to the invoice.
.. IMPORTANT::
This is an alpha version, the data model and design can change at any time without warning.
Only for development or testing purpose, do not use in production.
`More details on development status <https://odoo-community.org/page/development-status>`_
**Table of contents**
.. contents::
:local:
Bug Tracker
===========
Bugs are tracked on `GitHub Issues <https://github.com/OCA/contract/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed
`feedback <https://github.com/OCA/contract/issues/new?body=module:%20agreement_sale_condition%0Aversion:%2012.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
~~~~~~~
* Camptocamp
Contributors
~~~~~~~~~~~~
* Alexandre Fayolle <alexandre.fayolle@camptocamp.com>
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.
.. |maintainer-gurneyalex| image:: https://github.com/gurneyalex.png?size=40px
:target: https://github.com/gurneyalex
:alt: gurneyalex
Current `maintainer <https://odoo-community.org/page/maintainer-role>`__:
|maintainer-gurneyalex|
This module is part of the `OCA/contract <https://github.com/OCA/contract/tree/12.0/agreement_sale_condition>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

2
agreement_sale_condition_base/__init__.py

@ -0,0 +1,2 @@
from . import tools
from . import models

38
agreement_sale_condition_base/__manifest__.py

@ -0,0 +1,38 @@
# Copyright 2019 Camptocamp
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
{
"name": "Agreement Sale Conditions and Partner Preferences (base module)",
"summary": "Base module to manage sale conditions "
"and partner preferences in agreements",
"version": "12.0.1.0.0",
# see https://odoo-community.org/page/development-status
"development_status": "Alpha",
"category": "Sale",
"author": "Camptocamp, Odoo Community Association (OCA)",
"maintainers": ["gurneyalex"],
"license": "AGPL-3",
"application": False,
"installable": True,
"preloadable": True,
"depends": [
"agreement_sale",
"stock",
"delivery",
],
"data": [
# "security/sale_service_definition_security.xml",
"security/ir.model.access.csv",
"views/agreement.xml",
"views/agreement_type.xml",
"views/agreement_parameter_value.xml",
"views/sale_order.xml",
"views/procurement_group.xml",
"views/res_partner.xml",
"data/agreement_type.xml",
"data/agreement.xml",
],
'demo': [
"demo/agreement_type.xml",
"demo/agreement.csv",
],
}

14
agreement_sale_condition_base/data/agreement.xml

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record model="agreement" id="agreement_standard">
<field name="name">Standard Template</field>
<field name="code">standard_tmpl</field>
<field name="agreement_type_id" ref="agreement_type_standard"/>
<field name="is_template" eval="True"/>
</record>
<!-- data loaded from xml does not call write, so the override is not called -> force it-->
<function model="agreement"
name="write"
eval="(ref('agreement_standard'), {'agreement_type_id': ref('agreement_type_standard')})"/>
</odoo>

8
agreement_sale_condition_base/data/agreement_type.xml

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="agreement_type_standard" model="agreement.type">
<field name="sequence" eval="10"/>
<field name="code">standard</field>
<field name="name">Standard</field>
</record>
</odoo>

5
agreement_sale_condition_base/demo/agreement.csv

@ -0,0 +1,5 @@
id,code,name,partner_id/id,agreement_type_id/id,is_template
agreement_sale_condition_base.agreement_next_day,next_day_tmpl,Template Standard Next Day,base.main_company,agreement_sale_condition_base.agreement_type_next_day,True
agreement_sale_condition_base.agreement_weekly_routine,weekly_routine_tmpl,Template Standard Weekly Routine,base.main_company,agreement_sale_condition_base.agreement_type_weekly_routine,True
agreement_sale_condition_base.agreement_agreed_date,agreed_date_tmpl,Template Standard Agreed Date,base.main_company,agreement_sale_condition_base.agreement_type_agreed_date,True
agreement_sale_condition_base.agreement_pick_up,pickup_tmpl,Template Pick Up,base.main_company,agreement_sale_condition_base.agreement_type_pick_up,True

25
agreement_sale_condition_base/demo/agreement_type.xml

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="agreement_type_next_day" model="agreement.type">
<field name="sequence" eval="10"/>
<field name="code">next_day</field>
<field name="name">Next Day</field>
</record>
<record id="agreement_type_weekly_routine" model="agreement.type">
<field name="sequence" eval="20"/>
<field name="code">weekly_routine</field>
<field name="name">Weekly Routine</field>
</record>
<record id="agreement_type_agreed_date" model="agreement.type">
<field name="sequence" eval="30"/>
<field name="code">agreed_date</field>
<field name="name">Agreed Date</field>
</record>
<record id="agreement_type_pick_up" model="agreement.type">
<field name="sequence" eval="40"/>
<field name="code">pick_up</field>
<field name="name">Pick Up</field>
</record>
</odoo>

7
agreement_sale_condition_base/models/__init__.py

@ -0,0 +1,7 @@
from . import agreement
from . import agreement_type
from . import agreement_parameter_value
from . import res_partner
from . import sale_order
from . import account_invoice
from . import procurement_group

9
agreement_sale_condition_base/models/account_invoice.py

@ -0,0 +1,9 @@
# Copyright 2019 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import fields, models
class AccountInvoice(models.Model):
_inherit = 'account.invoice'
agreement_id = fields.Many2one('agreement', readonly=True)

135
agreement_sale_condition_base/models/agreement.py

@ -0,0 +1,135 @@
# Copyright 2019 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import _, api, exceptions, fields, models
class Agreement(models.Model):
_inherit = 'agreement'
code = fields.Char(required=False)
sale_ids = fields.One2many(
'sale.order', 'agreement_id', string="Sale Orders"
)
is_sale_agreement = fields.Boolean(
'Sale Agreement?', compute='_compute_is_sale_agreement', store=True
)
is_customer_requirement = fields.Boolean('Customer requirement?')
@api.depends('sale_ids')
def _compute_is_sale_agreement(self):
for rec in self:
rec.is_sale_agreement = bool(rec.sale_ids)
@api.model
def _get_customer_agreement_fields(self):
"""return a list of field names which are related to customer preferences"""
# extend the list in modules implementing specific conditions
return []
@api.model
def _get_sale_agreement_fields(self):
"""return a list of field names which are related to sale conditions"""
# extend the list in modules implementing specific conditions
return []
def _get_agreement_fields(self):
return self._get_sale_agreement_fields() + \
self._get_customer_agreement_fields()
def template_prepare_agreement_values(self, sale_order):
self.ensure_one()
assert self.is_template, \
(
'Programming error: '
'this method must only be called on a template agreement'
)
fields = ['agreement_type_id'] + self._get_sale_agreement_fields()
tmpl_values = self.read(fields, load='_classic_write')[0]
del tmpl_values['id']
tmpl_values.update(
{
'name': self.agreement_type_id.name,
'is_template': False,
'is_customer_requirement': False
}
)
partner = sale_order.partner_id
customer_settings = partner.customer_agreement_settings_id
assert not customer_settings or \
customer_settings.is_customer_requirement, \
'customer_settings must be a customer requirement agreement'
if customer_settings:
fields = self._get_customer_agreement_fields()
cust_vals = customer_settings.read(
fields, load='_classic_write'
)[0]
del cust_vals['id']
tmpl_values.update(cust_vals)
tmpl_values['name'] = self.agreement_type.name
return tmpl_values
@api.multi
def write(self, values):
res = super().write(values)
if values.get('agreement_type_id'):
self._check_agreement_type_default_agreement()
return res
@api.model_create_multi
@api.returns('self', lambda value: value.id)
def create(self, vals_list):
res = super().create(vals_list)
res._check_agreement_type_default_agreement()
return res
def _check_agreement_type_default_agreement(self):
# if we are setting an agreement type on a template agreement then the
# template agreement becomes the default agreement of the agreement
# type
template_agreements = self.filtered('is_template')
for template in template_agreements:
agreement_type = template.agreement_type_id
if not agreement_type.default_agreement_id:
agreement_type.default_agreement_id = template
elif agreement_type.default_agreement_id == template:
continue
else:
raise exceptions.UserError(
_('It is forbidden to have 2 templates in the '
'same agreement type.')
)
def _values_for_clear_defaults(self):
values = {}
for field in self._get_customer_agreement_fields():
values[field] = False
return values
@api.onchange('is_template')
def onchange_is_template(self):
if self.is_template:
self.unset_customer_defaults()
self.partner_id = False
def unset_customer_defaults(self):
values = self._values_for_clear_defaults()
for rec in self:
rec.update(values)
@api.onchange('is_customer_requirement')
def onchange_is_customer(self):
if self.is_customer_requirement:
self.is_template = False
self.set_customer_defaults()
def _get_customer_defaults_values(self):
ParameterValue = self.env['agreement.parameter.value']
values = {}
for field in self._get_customer_agreement_fields():
values[field] = ParameterValue.get_default(field)
return values
def set_customer_defaults(self):
values = self._get_customer_defaults_values()
for rec in self:
rec.update(values)

51
agreement_sale_condition_base/models/agreement_parameter_value.py

@ -0,0 +1,51 @@
# Copyright 2019 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, fields, models
from ..tools import _default_sequence
class AgreementParameterValue(models.Model):
_name = 'agreement.parameter.value'
_description = 'Possible values for agreement m2o parameters'
_order = "parameter, sequence"
name = fields.Char(required=True, translate=True)
code = fields.Char(
required=True,
index=True,
help="code of the value, can be used to search for it "
"in a language neutral way",
)
sequence = fields.Integer(
required=True,
default=_default_sequence,
help="order the values for a given parameter",
)
parameter = fields.Char(
required=True,
help='set to the name of the agreement field which '
'can have this value (not strictly required but it helps)',
)
is_default = fields.Boolean(
string="Is the default value?",
help="Set this on 1 record for a given parameter to flag the value as "
"the default value. If a parameter has no default value, then its "
"default is False",
)
@api.model
def get(self, parameter, code):
res = self.search(
[('parameter', '=', parameter), ('code', '=', code)], limit=1
)
if res:
return res
else:
raise ValueError((parameter, code))
@api.model
def get_default(self, parameter):
res = self.search(
[('parameter', '=', parameter), ('is_default', '=', True)], limit=1
)
return res or False

30
agreement_sale_condition_base/models/agreement_type.py

@ -0,0 +1,30 @@
# Copyright 2019 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import _, api, exceptions, fields, models
from ..tools import _default_sequence
class AgreementType(models.Model):
_inherit = 'agreement.type'
_description = 'Types of sale agreement policies'
_order = 'sequence, code'
code = fields.Char(index=True)
sequence = fields.Integer(index=True, default=_default_sequence)
active = fields.Boolean(default=True)
default_agreement_id = fields.Many2one(
'agreement',
string="Default Agreement",
domain=[('is_template', '=', True)],
)
@api.constrains('default_agreement_id')
def _check_code_agreement(self):
for rec in self:
if rec.default_agreement_id.agreement_type_id != rec:
msg = _(
'The type of the default agreement must be %s, not %s'
) % (rec.name, rec.default_agreement_id.agreement_type_id.name)
raise exceptions.ValidationError(msg)

20
agreement_sale_condition_base/models/procurement_group.py

@ -0,0 +1,20 @@
# Copyright 2019 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, fields, models
class ProcurementGroup(models.Model):
_inherit = "procurement.group"
agreement_id = fields.Many2one('agreement', readonly=True)
@api.model_create_multi
@api.returns('self', lambda value: value.id)
def create(self, vals_list):
for values in vals_list:
so_id = values.get('sale_id')
if so_id:
agreement = self.env['sale.order'].browse(so_id).agreement_id
values['agreement_id'] = agreement.id
res = super().create(vals_list)
return res

21
agreement_sale_condition_base/models/res_partner.py

@ -0,0 +1,21 @@
# Copyright 2019 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import fields, models
class ResPartner(models.Model):
_inherit = "res.partner"
default_agreement_type_id = fields.Many2one(
comodel_name='agreement.type',
string='Default Agreement Type'
)
customer_agreement_settings_id = fields.Many2one(
comodel_name='agreement',
domain=[('is_customer_requirement', '=', True)],
string="Agreed customer preferences"
)
customer_agreements = fields.One2many(
comodel_name='agreement', inverse_name='partner_id',
string="All agreements"
)

123
agreement_sale_condition_base/models/sale_order.py

@ -0,0 +1,123 @@
# Copyright 2019 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
import logging
from odoo import api, fields, models
_logger = logging.getLogger(__name__)
class SaleOrder(models.Model):
_inherit = "sale.order"
agreement_type_id = fields.Many2one(
'agreement.type',
string='Agreement Type',
required=True,
copy=True,
default=lambda s: s.env['agreement.type'].search([], limit=1),
)
agreement_id = fields.Many2one(
domain=[
('is_template', '=', False),
('is_customer_requirement', '=', False),
],
readonly=True,
)
@api.onchange('agreement_type_id')
def onchange_agreement_type(self):
self._update_agreement()
@api.onchange('partner_id')
def onchange_partner_for_agreement(self):
if self.partner_id.default_agreement_type_id:
partner_agreement_type = self.partner_id.default_agreement_type_id
if self.agreement_type_id != partner_agreement_type:
self.agreement_type_id = partner_agreement_type
self._update_agreement()
def _prepare_sale_agreement_values(self):
return {
'name': self.agreement_type_id.name,
'partner_id': self.partner_id.id,
'agreement_type_id': self.agreement_type_id.id,
'is_template': False,
'is_customer_requirement': False,
}
def _update_agreement(self):
if not self.partner_id:
return
if not self.agreement_id and self.partner_id:
self.agreement_id = self.env['agreement'].create(
self._prepare_sale_agreement_values()
)
agreement_template = self.agreement_type_id.default_agreement_id
agreement_values = {}
if agreement_template:
if not agreement_template.is_template:
_logger.warn(
'The default agreement of the agreement type %s '
'is not a template agreement',
self.agreement_type_id)
else:
agreement_values = \
agreement_template.template_prepare_agreement_values(
self
)
self.agreement_id.write(agreement_values)
@api.model
def create(self, vals):
rec = super().create(vals)
if rec.agreement_id and not rec.agreement_id.code:
rec.agreement_id.code = rec.name
return rec
@api.multi
def unlink(self):
agreements = self.mapped('agreement_id')
res = super().unlink()
agreements.sudo().unlink()
return res
@api.multi
def _action_confirm(self):
self.filtered(lambda r: not r.agreement_id)._update_agreement()
result = super()._action_confirm()
self._apply_agreement()
return result
@api.multi
def copy_data(self, default=None):
if default is None:
default = {}
if 'agreement_id' not in default and self.agreement_id:
new_agreement = self.agreement_id.copy()
default['agreement_id'] = new_agreement.id
return super().copy_data(default=default)
def _apply_agreement(self):
# Nothing to do for now on the SO itself
return
@api.multi
def _prepare_invoice(self):
values = super()._prepare_invoice()
values['agreement_id'] = self.agreement_id.id
return values
class SaleOrderLine(models.Model):
_inherit = 'sale.order.line'
def _prepare_procurement_values(self, group_id=False):
agreement = self.order_id.agreement_id
values = super()._prepare_procurement_values(group_id=group_id)
values['agreement_id'] = agreement.id
# if agreement.delivery_date:
# values['date_planned'] = agreement.delivery_date - timedelta(
# days=self.order_id.company_id.security_lead
# )
return values

1
agreement_sale_condition_base/readme/CONTRIBUTORS.rst

@ -0,0 +1 @@
* Alexandre Fayolle <alexandre.fayolle@camptocamp.com>

24
agreement_sale_condition_base/readme/DESCRIPTION.rst

@ -0,0 +1,24 @@
This module builds on the agreement and agreement_sale modules. It defines a
model for agreement parameter values. The intent is that additional modules can
add fields on an agreement which are m2o on to parameter values, and possibly
the allowed values for a given field could depend on the value of another one.
An agreement type can be linked to a template agreement. When the agreement
type is set on a sale order, a new agreement record is created using the
template agreement as a basis. This agreement specific to the sale order can be
customized by the sales man.
A preferred agreement type can be set on on a customer, and some preferences on the
partner. These preferences are defined in a special type of agreement. The
intent is that additional modules can add fields on an agreement which are m2o
on agreement parameter values. The values of customer preferences are meant to
be used in combination of the value of the template agreement of the agreement
type when the sale order is confirmed.
When the sale order is confirmed, the agreement of the sale order is propagated
to the procurement group of the sale order. This can be used by extension
modules to customize the generation of the stock moves and pickings to match
the agreement.
In a similar fashion, when an invoice is created from the sale order, the
agreement of the sale order, the agreement is propagated to the invoice.

3
agreement_sale_condition_base/security/ir.model.access.csv

@ -0,0 +1,3 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_agreement_type,agrrement.type,model_agreement_type,,1,0,0,0
access_agreement_parameter_value,agreement.parameter.value,model_agreement_parameter_value,,1,0,0,0

440
agreement_sale_condition_base/static/description/index.html

@ -0,0 +1,440 @@
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils 0.15.1: http://docutils.sourceforge.net/" />
<title>Agreement Sale Conditions</title>
<style type="text/css">
/*
:Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 7952 2016-07-26 18:15:59Z milde $
:Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils.
See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
customize this style sheet.
*/
/* used to remove borders from tables and images */
.borderless, table.borderless td, table.borderless th {
border: 0 }
table.borderless td, table.borderless th {
/* Override padding for "table.docutils td" with "! important".
The right padding separates the table cells. */
padding: 0 0.5em 0 0 ! important }
.first {
/* Override more specific margin styles with "! important". */
margin-top: 0 ! important }
.last, .with-subtitle {
margin-bottom: 0 ! important }
.hidden {
display: none }
.subscript {
vertical-align: sub;
font-size: smaller }
.superscript {
vertical-align: super;
font-size: smaller }
a.toc-backref {
text-decoration: none ;
color: black }
blockquote.epigraph {
margin: 2em 5em ; }
dl.docutils dd {
margin-bottom: 0.5em }
object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
overflow: hidden;
}
/* Uncomment (and remove this text!) to get bold-faced definition list terms
dl.docutils dt {
font-weight: bold }
*/
div.abstract {
margin: 2em 5em }
div.abstract p.topic-title {
font-weight: bold ;
text-align: center }
div.admonition, div.attention, div.caution, div.danger, div.error,
div.hint, div.important, div.note, div.tip, div.warning {
margin: 2em ;
border: medium outset ;
padding: 1em }
div.admonition p.admonition-title, div.hint p.admonition-title,
div.important p.admonition-title, div.note p.admonition-title,
div.tip p.admonition-title {
font-weight: bold ;
font-family: sans-serif }
div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title, .code .error {
color: red ;
font-weight: bold ;
font-family: sans-serif }
/* Uncomment (and remove this text!) to get reduced vertical space in
compound paragraphs.
div.compound .compound-first, div.compound .compound-middle {
margin-bottom: 0.5em }
div.compound .compound-last, div.compound .compound-middle {
margin-top: 0.5em }
*/
div.dedication {
margin: 2em 5em ;
text-align: center ;
font-style: italic }
div.dedication p.topic-title {
font-weight: bold ;
font-style: normal }
div.figure {
margin-left: 2em ;
margin-right: 2em }
div.footer, div.header {
clear: both;
font-size: smaller }
div.line-block {
display: block ;
margin-top: 1em ;
margin-bottom: 1em }
div.line-block div.line-block {
margin-top: 0 ;
margin-bottom: 0 ;
margin-left: 1.5em }
div.sidebar {
margin: 0 0 0.5em 1em ;
border: medium outset ;
padding: 1em ;
background-color: #ffffee ;
width: 40% ;
float: right ;
clear: right }
div.sidebar p.rubric {
font-family: sans-serif ;
font-size: medium }
div.system-messages {
margin: 5em }
div.system-messages h1 {
color: red }
div.system-message {
border: medium outset ;
padding: 1em }
div.system-message p.system-message-title {
color: red ;
font-weight: bold }
div.topic {
margin: 2em }
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
margin-top: 0.4em }
h1.title {
text-align: center }
h2.subtitle {
text-align: center }
hr.docutils {
width: 75% }
img.align-left, .figure.align-left, object.align-left, table.align-left {
clear: left ;
float: left ;
margin-right: 1em }
img.align-right, .figure.align-right, object.align-right, table.align-right {
clear: right ;
float: right ;
margin-left: 1em }
img.align-center, .figure.align-center, object.align-center {
display: block;
margin-left: auto;
margin-right: auto;
}
table.align-center {
margin-left: auto;
margin-right: auto;
}
.align-left {
text-align: left }
.align-center {
clear: both ;
text-align: center }
.align-right {
text-align: right }
/* reset inner alignment in figures */
div.align-right {
text-align: inherit }
/* div.align-center * { */
/* text-align: left } */
.align-top {
vertical-align: top }
.align-middle {
vertical-align: middle }
.align-bottom {
vertical-align: bottom }
ol.simple, ul.simple {
margin-bottom: 1em }
ol.arabic {
list-style: decimal }
ol.loweralpha {
list-style: lower-alpha }
ol.upperalpha {
list-style: upper-alpha }
ol.lowerroman {
list-style: lower-roman }
ol.upperroman {
list-style: upper-roman }
p.attribution {
text-align: right ;
margin-left: 50% }
p.caption {
font-style: italic }
p.credits {
font-style: italic ;
font-size: smaller }
p.label {
white-space: nowrap }
p.rubric {
font-weight: bold ;
font-size: larger ;
color: maroon ;
text-align: center }
p.sidebar-title {
font-family: sans-serif ;
font-weight: bold ;
font-size: larger }
p.sidebar-subtitle {
font-family: sans-serif ;
font-weight: bold }
p.topic-title {
font-weight: bold }
pre.address {
margin-bottom: 0 ;
margin-top: 0 ;
font: inherit }
pre.literal-block, pre.doctest-block, pre.math, pre.code {
margin-left: 2em ;
margin-right: 2em }
pre.code .ln { color: grey; } /* line numbers */
pre.code, code { background-color: #eeeeee }
pre.code .comment, code .comment { color: #5C6576 }
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
pre.code .literal.string, code .literal.string { color: #0C5404 }
pre.code .name.builtin, code .name.builtin { color: #352B84 }
pre.code .deleted, code .deleted { background-color: #DEB0A1}
pre.code .inserted, code .inserted { background-color: #A3D289}
span.classifier {
font-family: sans-serif ;
font-style: oblique }
span.classifier-delimiter {
font-family: sans-serif ;
font-weight: bold }
span.interpreted {
font-family: sans-serif }
span.option {
white-space: nowrap }
span.pre {
white-space: pre }
span.problematic {
color: red }
span.section-subtitle {
/* font-size relative to parent (h1..h6 element) */
font-size: 80% }
table.citation {
border-left: solid 1px gray;
margin-left: 1px }
table.docinfo {
margin: 2em 4em }
table.docutils {
margin-top: 0.5em ;
margin-bottom: 0.5em }
table.footnote {
border-left: solid 1px black;
margin-left: 1px }
table.docutils td, table.docutils th,
table.docinfo td, table.docinfo th {
padding-left: 0.5em ;
padding-right: 0.5em ;
vertical-align: top }
table.docutils th.field-name, table.docinfo th.docinfo-name {
font-weight: bold ;
text-align: left ;
white-space: nowrap ;
padding-left: 0 }
/* "booktabs" style (no vertical lines) */
table.docutils.booktabs {
border: 0px;
border-top: 2px solid;
border-bottom: 2px solid;
border-collapse: collapse;
}
table.docutils.booktabs * {
border: 0px;
}
table.docutils.booktabs th {
border-bottom: thin solid;
text-align: left;
}
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
font-size: 100% }
ul.auto-toc {
list-style-type: none }
</style>
</head>
<body>
<div class="document" id="agreement-sale-conditions">
<h1 class="title">Agreement Sale Conditions</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external" href="https://odoo-community.org/page/development-status"><img alt="Alpha" src="https://img.shields.io/badge/maturity-Alpha-red.png" /></a> <a class="reference external" 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" href="https://github.com/OCA/contract/tree/12.0/agreement_sale_condition"><img alt="OCA/contract" src="https://img.shields.io/badge/github-OCA%2Fcontract-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/contract-12-0/contract-12-0-agreement_sale_condition"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runbot.odoo-community.org/runbot/110/12.0"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p>
<p>This module builds on the agreement and agreement_sale modules. It defines a
model for agreement parameter values. The intent is that additional modules can
add fields on an agreement which are m2o on to parameter values, and possibly
the allowed values for a given field could depend on the value of another one.</p>
<p>An agreement type can be linked to a template agreement. When the agreement
type is set on a sale order, a new agreement record is created using the
template agreement as a basis. This agreement specific to the sale order can be
customized by the sales man.</p>
<p>When the sale order is confirmed, the agreement of the sale order is propagated
to the procurement group of the sale order. This can be used by extension
modules to customize the generation of the stock moves and pickings to match
the agreement.</p>
<p>In a similar fashion, when an invoice is created from the sale order, the
agreement of the sale order, the agreement is propagated to the invoice.</p>
<div class="admonition important">
<p class="first admonition-title">Important</p>
<p class="last">This is an alpha version, the data model and design can change at any time without warning.
Only for development or testing purpose, do not use in production.
<a class="reference external" href="https://odoo-community.org/page/development-status">More details on development status</a></p>
</div>
<p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#bug-tracker" id="id1">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="id2">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="id3">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="id4">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="id5">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#id1">Bug Tracker</a></h1>
<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.
If you spotted it first, help us smashing it by providing a detailed and welcomed
<a class="reference external" href="https://github.com/OCA/contract/issues/new?body=module:%20agreement_sale_condition%0Aversion:%2012.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">
<h1><a class="toc-backref" href="#id2">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#id3">Authors</a></h2>
<ul class="simple">
<li>Camptocamp</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#id4">Contributors</a></h2>
<ul class="simple">
<li>Alexandre Fayolle &lt;<a class="reference external" href="mailto:alexandre.fayolle&#64;camptocamp.com">alexandre.fayolle&#64;camptocamp.com</a>&gt;</li>
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#id5">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" /></a>
<p>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.</p>
<p>Current <a class="reference external" href="https://odoo-community.org/page/maintainer-role">maintainer</a>:</p>
<p><a class="reference external" href="https://github.com/gurneyalex"><img alt="gurneyalex" src="https://github.com/gurneyalex.png?size=40px" /></a></p>
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/contract/tree/12.0/agreement_sale_condition">OCA/contract</a> project on GitHub.</p>
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
</div>
</div>
</div>
</body>
</html>

1
agreement_sale_condition_base/tests/__init__.py

@ -0,0 +1 @@
from . import test_agreement_propagation

75
agreement_sale_condition_base/tests/test_agreement_propagation.py

@ -0,0 +1,75 @@
# Copyright 2019 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo.tests import common
class TestAgreementPropagation(common.SavepointCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.agreement_type = cls.env['agreement.type'].create(
{'code': 'TST', 'name': 'test'}
)
cls.agreement = cls.env['agreement'].create(
{'name': 'Test Agreement Template',
'code': 'TST',
'is_template': 1,
'agreement_type_id': cls.agreement_type.id,
}
)
cls.product = cls.env['product.product'].create(
{'name': 'test product',
'type': 'consu',
'uom_id': 1,
}
)
cls.partner = cls.env['res.partner'].create(
{
'name': 'Test Customer',
'customer': True,
}
)
cls.sale = cls.env['sale.order'].create(
{
'partner_id': cls.partner.id,
'agreement_type_id': cls.agreement_type.id,
'order_line': [
(0, 0, {
'product_id': cls.product.id,
'product_uom': cls.product.uom_id.id,
'product_uom_qty': 1,
'price_unit': 10,
}
)
],
}
)
def test_default_agreement(self):
self.assertEqual(self.agreement_type.default_agreement_id,
self.agreement)
def test_sale_order_confirm(self):
sale = self.sale
sale.onchange_agreement_type()
self.assertEqual(
sale.agreement_id.agreement_type_id,
sale.agreement_type_id
)
self.assertNotEqual(
sale.agreement_id,
sale.agreement_type_id.default_agreement_id
)
self.assertEqual(
sale.agreement_id.partner_id,
sale.partner_id
)
self.assertTrue(sale.agreement_id.is_sale_agreement)
def test_agreement_propagation_to_procurement_group(self):
sale = self.sale
sale.action_confirm()
self.assertEqual(
sale.agreement_id,
sale.procurement_group_id.agreement_id
)

10
agreement_sale_condition_base/tools.py

@ -0,0 +1,10 @@
# Copyright 2019 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
def _default_sequence(self):
maxrec = self.search([], order='sequence desc', limit=1)
if maxrec:
return maxrec.sequence + 10
else:
return 0

216
agreement_sale_condition_base/views/agreement.xml

@ -0,0 +1,216 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="template_agreement_tree" model="ir.ui.view">
<field name="name">agreement.tree (template version)</field>
<field name="model">agreement</field>
<field name="priority" eval="30"/>
<field name="arch" type="xml">
<tree string="Agreement Templates">
<field name="code"/>
<field name="name"/>
<field name="agreement_type_id"/>
</tree>
</field>
</record>
<record id="template_agreement_form" model="ir.ui.view">
<field name="name">agreement.form (template version)</field>
<field name="model">agreement</field>
<field name="priority" eval="30"/>
<field name="arch" type="xml">
<form string="Agreement Template">
<div class="oe_button_box" name="button_box">
<button name="toggle_active" type="object"
class="oe_stat_button" icon="fa-archive">
<field name="active" widget="boolean_button"
options='{"terminology": "archive"}'/>
</button>
</div>
<group name="main">
<group name="left">
<field name="name"/>
<field name="partner_id" invisible='1'/>
</group>
<group name="right">
<field name="code"/>
<field name="company_id" groups="base.group_multi_company"/>
<field name="is_template" invisible='1'/>
<field name="is_customer_requirement" invisible='1'/>
<field name="is_sale_agreement" invisible="1"/>
</group>
</group>
<notebook name="agreement_condition">
<!-- put the condition fields in pages here -->
<page string="Sales Conditions" name="sale_condition">
</page>
</notebook>
</form>
</field>
</record>
<record id="customer_agreement_tree" model="ir.ui.view">
<field name="name">agreement.tree (customer preferences)</field>
<field name="model">agreement</field>
<field name="priority" eval="30"/>
<field name="arch" type="xml">
<tree string="Customer Preferences">
<field name="code"/>
<field name="name"/>
<field name="partner_id"/>
</tree>
</field>
</record>
<record id="customer_agreement_form" model="ir.ui.view">
<field name="name">agreement.form (customer preferences)</field>
<field name="model">agreement</field>
<field name="priority" eval="30"/>
<field name="arch" type="xml">
<form string="Customer Preferences">
<div class="oe_button_box" name="button_box">
<button name="toggle_active" type="object"
class="oe_stat_button" icon="fa-archive">
<field name="active" widget="boolean_button"
options='{"terminology": "archive"}'/>
</button>
</div>
<group name="main">
<group name="left">
<field name="name"/>
<field name="partner_id"/>
</group>
<group name="right">
<field name="code"/>
<field name="company_id" groups="base.group_multi_company"/>
<field name="is_customer_requirement" invisible='1'/>
</group>
</group>
<notebook name="customer_preferences">
<!-- display the fields in there -->
<page string="Customer Preferences" name="page1">
</page>
</notebook>
</form>
</field>
</record>
<!-- FIXME: needs merging with the template version -->
<record id="agreement_form" model="ir.ui.view">
<field name="name">agreement.form (sale order version)</field>
<field name="model">agreement</field>
<field name="inherit_id" ref="agreement.agreement_form"/>
<field name="arch" type="xml">
<field name="signature_date" position="attributes">
<attribute name="invisible">1</attribute>
</field>
<field name="end_date" position="attributes">
<attribute name="invisible">1</attribute>
</field>
<field name="start_date" position="attributes">
<attribute name="invisible">1</attribute>
</field>
<xpath expr="//group[@name='main']" position="after">
<group name="metadata">
<group groups="base.group_no_one">
<field name="is_template" invisible='1'/>
<field name="is_sale_agreement" invisible="1"/>
<field name="is_customer_requirement" invisible='1'/>
</group>
</group>
</xpath>
<field name="code" position="after">
<field name="agreement_type_id" readonly="1"/>
</field>
<field name="code" position="attributes">
<attribute name="invisible">1</attribute>
</field>
<field name="name" position="attributes">
<attribute name="readonly">1</attribute>
</field>
<xpath expr="//notebook/page[@name='config']" position="before">
<page string="Sales Conditions">
</page>
</xpath>
</field>
</record>
<record id="agreement_tree" model="ir.ui.view">
<field name="name">agreement.tree (sale order version)</field>
<field name="model">agreement</field>
<field name="inherit_id" ref="agreement.agreement_tree"/>
<field name="arch" type="xml">
<field name="signature_date" position="attributes">
<attribute name="invisible">1</attribute>
</field>
<field name="end_date" position="attributes">
<attribute name="invisible">1</attribute>
</field>
<field name="start_date" position="attributes">
<attribute name="invisible">1</attribute>
</field>
</field>
</record>
<record id="agreement.agreement_action" model="ir.actions.act_window">
<field name="name">Agreement Templates</field>
<field name="res_model">agreement</field>
<field name="view_mode">tree,form</field>
<field name="domain">[('is_template', '=', 1)]</field>
<field name="context">{"default_is_template": 1}</field>
</record>
<record model="ir.actions.act_window.view" id="agreement_action_form">
<field name="sequence" eval="10"/>
<field name="view_mode">form</field>
<field name="view_id" ref="template_agreement_form"/>
<field name="act_window_id" ref="agreement.agreement_action"/>
</record>
<record model="ir.actions.act_window.view" id="agreement_action_tree">
<field name="sequence" eval="1"/>
<field name="view_mode">tree</field>
<field name="view_id" ref="template_agreement_tree"/>
<field name="act_window_id" ref="agreement.agreement_action"/>
</record>
<record id="customer_agreement_action" model="ir.actions.act_window">
<field name="name">Customer Requirements</field>
<field name="res_model">agreement</field>
<field name="view_mode">tree,form</field>
<field name="domain">[("is_customer_requirement", "=", 1)]</field>
<field name="context">{"default_is_customer_requirement": 1}</field>
</record>
<record model="ir.actions.act_window.view" id="customer_agreement_action_form">
<field name="sequence" eval="10"/>
<field name="view_mode">form</field>
<field name="view_id" ref="customer_agreement_form"/>
<field name="act_window_id" ref="customer_agreement_action"/>
</record>
<record model="ir.actions.act_window.view" id="customer_agreement_action_tree">
<field name="sequence" eval="1"/>
<field name="view_mode">tree</field>
<field name="view_id" ref="customer_agreement_tree"/>
<field name="act_window_id" ref="customer_agreement_action"/>
</record>
<menuitem id="service_definition_menu"
string="Service Definition"
parent="sale.menu_sale_config"
sequence="100"
/>
<menuitem id="agreement.agreement_menu"
action="agreement.agreement_action"
parent="service_definition_menu"
sequence="10"/>
<menuitem id="customer_agreement_menu"
action="customer_agreement_action"
parent="service_definition_menu"
sequence="11"/>
</odoo>

44
agreement_sale_condition_base/views/agreement_parameter_value.xml

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="agreement_parameter_value_search" model="ir.ui.view">
<field name="name">agreement.parameter.value.search</field>
<field name="model">agreement.parameter.value</field>
<field name="arch" type="xml">
<search string="Agreement Parameter Values" >
<field name="code"/>
<field name="name"/>
<field name="parameter"/>
<group expand="0" string="Group By">
<filter string="Parameter" name="parameter" domain="[]" context="{'group_by': 'parameter'}"/>
</group>
</search>
</field>
</record>
<record id="agreement_parameter_value_tree" model="ir.ui.view">
<field name="name">agreement.parameter.value.tree</field>
<field name="model">agreement.parameter.value</field>
<field name="arch" type="xml">
<tree string="Agreement Parameter Values" >
<field name="sequence" widget="handle"/>
<field name="code"/>
<field name="name"/>
<field name="parameter"/>
</tree>
</field>
</record>
<record id="agreement_parameter_value_action" model="ir.actions.act_window">
<field name="name">Agreement Parameter Values</field>
<field name="res_model">agreement.parameter.value</field>
<field name="view_mode">tree</field>
</record>
<menuitem id="agreement_parameter_value_menu"
action="agreement_parameter_value_action"
parent="service_definition_menu"
sequence="13"/>
</odoo>

52
agreement_sale_condition_base/views/agreement_type.xml

@ -0,0 +1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="agreement_type_form" model="ir.ui.view">
<field name="name">agreement.type.form</field>
<field name="model">agreement.type</field>
<field name="inherit_id" ref="agreement.agreement_type_form_view"/>
<field name="arch" type="xml">
<xpath expr="//sheet/div[1]" position="after">
<group name="main">
<group name="left">
<field name="code"/>
</group>
<group name="right">
<field name="default_agreement_id"/>
</group>
</group>
</xpath>
</field>
</record>
<record id="agreement_type_tree" model="ir.ui.view">
<field name="name">agreement.type.tree</field>
<field name="model">agreement.type</field>
<field name="inherit_id" ref="agreement.agreement_type_list_view"/>
<field name="arch" type="xml">
<field name="name" position="before">
<field name="sequence" widget="handle"/>
</field>
<field name="name" position="after">
<field name="code"/>
</field>
</field>
</record>
<record id="agreement_type_search" model="ir.ui.view">
<field name="name">agreement.type.search</field>
<field name="model">agreement.type</field>
<field name="inherit_id" ref="agreement.agreement_type_search"/>
<field name="arch" type="xml">
<field name="name" position="after">
<field name="code" required="1"/>
</field>
</field>
</record>
<menuitem id="agreement_type_menu"
action="agreement.agreement_type_action"
parent="service_definition_menu"
sequence="12"/>
</odoo>

13
agreement_sale_condition_base/views/procurement_group.xml

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="procurement_group_form_view" model="ir.ui.view">
<field name="name">procurement.group.form</field>
<field name="model">procurement.group</field>
<field name="inherit_id" ref="stock.procurement_group_form_view"/>
<field name="arch" type="xml">
<field name="move_type" position="after">
<field name="agreement_id"/>
</field>
</field>
</record>
</odoo>

21
agreement_sale_condition_base/views/res_partner.xml

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record model="ir.ui.view" id="partner_form">
<field name="model">res.partner</field>
<field name="inherit_id" ref="base.view_partner_form"/>
<field name="arch" type="xml">
<xpath expr="//page[@name='internal_notes']" position="before">
<page name="agreement" string="Agreements">
<group>
<field name="default_agreement_type_id"/>
<field name="customer_agreement_settings_id"
context="{'default_partner_id': id, 'default_is_customer_requirement': 1, 'default_code': ref, 'form_view_ref': 'agreement_sale_condition_base.customer_agreement_form'}"/>
</group>
<group groups='base.group_no_one'>
<field name="customer_agreements" nolabel="1" />
</group>
</page>
</xpath>
</field>
</record>
</odoo>

17
agreement_sale_condition_base/views/sale_order.xml

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="sale_order_agreement_form_view" model="ir.ui.view">
<field name="name">sale.order.agreement.form.view</field>
<field name="model">sale.order</field>
<field name="inherit_id" ref="sale.view_order_form"/>
<field name="arch" type="xml">
<field name="client_order_ref" position="after">
<field name="agreement_id"/>
</field>
<field name="partner_id" position="after">
<field name="agreement_type_id"/>
</field>
</field>
</record>
</odoo>
Loading…
Cancel
Save