mirror of
https://github.com/OCA/contract.git
synced 2025-02-13 17:57:24 +02:00
142
agreement_legal/README.rst
Normal file
142
agreement_legal/README.rst
Normal file
@@ -0,0 +1,142 @@
|
||||
================
|
||||
Agreements Legal
|
||||
================
|
||||
|
||||
.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
!! This file is generated by oca-gen-addon-readme !!
|
||||
!! changes will be overwritten. !!
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
|
||||
:target: https://odoo-community.org/page/development-status
|
||||
:alt: Beta
|
||||
.. |badge2| image:: https://img.shields.io/badge/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_legal
|
||||
: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_legal
|
||||
: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 allows you to manage agreements, letter of intent and contract content.
|
||||
The module is meant to be used by the legal team of a company and to allow them
|
||||
to define sections, clauses and templates with their respective content that can
|
||||
be dynamic.
|
||||
|
||||
Based on the template, an agreement can be created and the pdf document generated.
|
||||
|
||||
The agreement would go through a workflow to finally become a contract with the
|
||||
customer signature.
|
||||
|
||||
**Table of contents**
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
|
||||
Configuration
|
||||
=============
|
||||
|
||||
To configure this module:
|
||||
|
||||
* Go to Agreement > Configuration > Templates
|
||||
* Create a new template with sections and clauses and their respective content
|
||||
* Go to Agreement > Configuration > Stages
|
||||
* Create and reorder stages to match your process
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
To use this module:
|
||||
|
||||
* Go to Agreement > Agreements
|
||||
* Create a new agreement
|
||||
* Select a template
|
||||
* Follow the process to get the required approval
|
||||
* Send the invitation to the customer to review and sign the agreement
|
||||
|
||||
* Define Field using widget domain but having partial_use option true:
|
||||
* For Ex:
|
||||
* <field name="field_domain" widget="domain" nolabel="1"
|
||||
* options="{'model': 'agreement.recital',
|
||||
* 'partial_use': True}"/>
|
||||
|
||||
Known issues / Roadmap
|
||||
======================
|
||||
|
||||
* Split the module to remove the dependencies on sale and account and provide
|
||||
the same feature in extra modules (agreement_sale, agreement_account,
|
||||
agreement_purchase)
|
||||
|
||||
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_legal%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
|
||||
~~~~~~~
|
||||
|
||||
* Pavlov Media
|
||||
* Open Source Integrators
|
||||
* Yves Goldberg (Ygol Internetwork)
|
||||
|
||||
Contributors
|
||||
~~~~~~~~~~~~
|
||||
|
||||
* Patrick Wilson <pwilson@pavlovmedia.com>
|
||||
* Bhavesh Odedra <bodedra@opensourceintegrators.com>
|
||||
* Wolfgang Hall <whall@opensourceintegrators.com>
|
||||
* Maxime Chambreuil <mchambreuil@opensourceintegrators.com>
|
||||
* Sandip Mangukiya <smangukiya@opensourceintegrators.com>
|
||||
* Yves Goldberg <yves@ygol.com>
|
||||
|
||||
Other credits
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
The development of this module has been financially supported by:
|
||||
|
||||
* Pavlov Media
|
||||
* Open Source Integrators
|
||||
* Yves Goldberg
|
||||
|
||||
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-max3903| image:: https://github.com/max3903.png?size=40px
|
||||
:target: https://github.com/max3903
|
||||
:alt: max3903
|
||||
.. |maintainer-ygol| image:: https://github.com/ygol.png?size=40px
|
||||
:target: https://github.com/ygol
|
||||
:alt: ygol
|
||||
|
||||
Current `maintainers <https://odoo-community.org/page/maintainer-role>`__:
|
||||
|
||||
|maintainer-max3903| |maintainer-ygol|
|
||||
|
||||
This module is part of the `OCA/contract <https://github.com/OCA/contract/tree/12.0/agreement_legal>`_ project on GitHub.
|
||||
|
||||
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
|
||||
4
agreement_legal/__init__.py
Normal file
4
agreement_legal/__init__.py
Normal file
@@ -0,0 +1,4 @@
|
||||
# Copyright (C) 2018 - TODAY, Pavlov Media
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from . import models
|
||||
43
agreement_legal/__manifest__.py
Normal file
43
agreement_legal/__manifest__.py
Normal file
@@ -0,0 +1,43 @@
|
||||
# Copyright (C) 2018 - TODAY, Pavlov Media
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
{
|
||||
"name": "Agreements Legal",
|
||||
"summary": "Manage Agreements, LOI and Contracts",
|
||||
"author": "Pavlov Media, "
|
||||
"Open Source Integrators, "
|
||||
"Yves Goldberg (Ygol Internetwork), "
|
||||
"Odoo Community Association (OCA)",
|
||||
"website": "https://github.com/OCA/contract",
|
||||
"category": "Partner",
|
||||
"license": "AGPL-3",
|
||||
"version": "14.0.1.0.0",
|
||||
"depends": ["contacts", "agreement", "product"],
|
||||
"data": [
|
||||
"data/ir_sequence.xml",
|
||||
"data/module_category.xml",
|
||||
"data/agreement_stage.xml",
|
||||
"data/agreement_type.xml",
|
||||
"data/demo.xml",
|
||||
"security/res_groups.xml",
|
||||
"security/ir.model.access.csv",
|
||||
"report/agreement.xml",
|
||||
"views/res_config_settings.xml",
|
||||
"views/agreement_appendix.xml",
|
||||
"views/agreement_clause.xml",
|
||||
"views/agreement_recital.xml",
|
||||
"views/agreement_section.xml",
|
||||
"views/agreement_stages.xml",
|
||||
"views/agreement_type.xml",
|
||||
"views/agreement_subtype.xml",
|
||||
"views/agreement_renewaltype.xml",
|
||||
"views/agreement_increasetype.xml",
|
||||
"views/res_partner.xml",
|
||||
"views/agreement.xml",
|
||||
"views/menu.xml",
|
||||
],
|
||||
"demo": ["demo/demo.xml"],
|
||||
"application": True,
|
||||
"development_status": "Beta",
|
||||
"maintainers": ["max3903", "ygol"],
|
||||
}
|
||||
57
agreement_legal/data/agreement_stage.xml
Normal file
57
agreement_legal/data/agreement_stage.xml
Normal file
@@ -0,0 +1,57 @@
|
||||
<odoo>
|
||||
|
||||
<record id="agreement_stage_new" model="agreement.stage">
|
||||
<field name="name">New</field>
|
||||
<field name="sequence">10</field>
|
||||
<field name="stage_type">agreement</field>
|
||||
</record>
|
||||
|
||||
<record id="agreement_stage_draft" model="agreement.stage">
|
||||
<field name="name">Draft</field>
|
||||
<field name="sequence">20</field>
|
||||
<field name="stage_type">agreement</field>
|
||||
</record>
|
||||
|
||||
<record id="agreement_stage_reviewed" model="agreement.stage">
|
||||
<field name="name">Reviewed</field>
|
||||
<field name="sequence">30</field>
|
||||
<field name="stage_type">agreement</field>
|
||||
</record>
|
||||
|
||||
<record id="agreement_stage_negotiation" model="agreement.stage">
|
||||
<field name="name">Negotiation</field>
|
||||
<field name="sequence">40</field>
|
||||
<field name="stage_type">agreement</field>
|
||||
</record>
|
||||
|
||||
<record id="agreement_stage_out" model="agreement.stage">
|
||||
<field name="name">Out for Customer Signature</field>
|
||||
<field name="sequence">50</field>
|
||||
<field name="stage_type">agreement</field>
|
||||
</record>
|
||||
|
||||
<record id="agreement_stage_internal" model="agreement.stage">
|
||||
<field name="name">Waiting Internal Signature</field>
|
||||
<field name="sequence">60</field>
|
||||
<field name="stage_type">agreement</field>
|
||||
</record>
|
||||
|
||||
<record id="agreement_stage_active" model="agreement.stage">
|
||||
<field name="name">Active</field>
|
||||
<field name="sequence">70</field>
|
||||
<field name="stage_type">agreement</field>
|
||||
</record>
|
||||
|
||||
<record id="agreement_stage_expired" model="agreement.stage">
|
||||
<field name="name">Expired</field>
|
||||
<field name="sequence">80</field>
|
||||
<field name="stage_type">agreement</field>
|
||||
</record>
|
||||
|
||||
<record id="agreement_stage_cancelled" model="agreement.stage">
|
||||
<field name="name">Cancelled</field>
|
||||
<field name="sequence">100</field>
|
||||
<field name="fold">True</field>
|
||||
<field name="stage_type">agreement</field>
|
||||
</record>
|
||||
</odoo>
|
||||
15
agreement_legal/data/agreement_type.xml
Normal file
15
agreement_legal/data/agreement_type.xml
Normal file
@@ -0,0 +1,15 @@
|
||||
<odoo>
|
||||
|
||||
<record id="agreement_type_agreement" model="agreement.type">
|
||||
<field name="name">Agreement</field>
|
||||
</record>
|
||||
|
||||
<record id="agreement_type_contract" model="agreement.type">
|
||||
<field name="name">Contract</field>
|
||||
</record>
|
||||
|
||||
<record id="agreement_type_loi" model="agreement.type">
|
||||
<field name="name">Letter of Intent</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
123
agreement_legal/data/demo.xml
Normal file
123
agreement_legal/data/demo.xml
Normal file
@@ -0,0 +1,123 @@
|
||||
<!--
|
||||
© 2019 Ygol Internetwork (yves@ygol.com)
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
-->
|
||||
<odoo noupdate="1">
|
||||
|
||||
<function name="write" model="ir.model.data">
|
||||
<function name="search" model="ir.model.data">
|
||||
<value eval="[('module', '=', 'agreement'), ('name', '=', 'market1')]" />
|
||||
</function>
|
||||
<value eval="{'noupdate': False}" />
|
||||
</function>
|
||||
|
||||
<record id="agreement.market1" model="agreement">
|
||||
<field name="description">Hardware IT (C2C-IT0042)</field>
|
||||
<field name="agreement_type_id" ref="agreement_type_agreement" />
|
||||
</record>
|
||||
|
||||
<function name="write" model="ir.model.data">
|
||||
<function name="search" model="ir.model.data">
|
||||
<value eval="[('module', '=', 'agreement'), ('name', '=', 'market1')]" />
|
||||
</function>
|
||||
<value eval="{'noupdate': True}" />
|
||||
</function>
|
||||
|
||||
<function name="write" model="ir.model.data">
|
||||
<function name="search" model="ir.model.data">
|
||||
<value eval="[('module', '=', 'agreement'), ('name', '=', 'market2')]" />
|
||||
</function>
|
||||
<value eval="{'noupdate': False}" />
|
||||
</function>
|
||||
|
||||
<record id="agreement.market2" model="agreement">
|
||||
<field name="description">Fiber access office Lausanne (C2C-IT0043)</field>
|
||||
<field name="agreement_type_id" ref="agreement_type_contract" />
|
||||
</record>
|
||||
|
||||
<function name="write" model="ir.model.data">
|
||||
<function name="search" model="ir.model.data">
|
||||
<value eval="[('module', '=', 'agreement'), ('name', '=', 'market2')]" />
|
||||
</function>
|
||||
<value eval="{'noupdate': True}" />
|
||||
</function>
|
||||
|
||||
<function name="write" model="ir.model.data">
|
||||
<function name="search" model="ir.model.data">
|
||||
<value eval="[('module', '=', 'agreement'), ('name', '=', 'market3')]" />
|
||||
</function>
|
||||
<value eval="{'noupdate': False}" />
|
||||
</function>
|
||||
|
||||
<record id="agreement.market3" model="agreement">
|
||||
<field name="description">Vétérinaire (AGR-VETO001)</field>
|
||||
<field name="agreement_type_id" ref="agreement_type_loi" />
|
||||
</record>
|
||||
|
||||
<function name="write" model="ir.model.data">
|
||||
<function name="search" model="ir.model.data">
|
||||
<value eval="[('module', '=', 'agreement'), ('name', '=', 'market3')]" />
|
||||
</function>
|
||||
<value eval="{'noupdate': True}" />
|
||||
</function>
|
||||
|
||||
<function name="write" model="ir.model.data">
|
||||
<function name="search" model="ir.model.data">
|
||||
<value eval="[('module', '=', 'agreement'), ('name', '=', 'market4')]" />
|
||||
</function>
|
||||
<value eval="{'noupdate': False}" />
|
||||
</function>
|
||||
|
||||
<record id="agreement.market4" model="agreement">
|
||||
<field
|
||||
name="description"
|
||||
>Wazo IPBX deployment and maintenance (AGR-TEL001)</field>
|
||||
<field name="agreement_type_id" ref="agreement_type_loi" />
|
||||
</record>
|
||||
|
||||
<function name="write" model="ir.model.data">
|
||||
<function name="search" model="ir.model.data">
|
||||
<value eval="[('module', '=', 'agreement'), ('name', '=', 'market4')]" />
|
||||
</function>
|
||||
<value eval="{'noupdate': True}" />
|
||||
</function>
|
||||
|
||||
<function name="write" model="ir.model.data">
|
||||
<function name="search" model="ir.model.data">
|
||||
<value eval="[('module', '=', 'agreement'), ('name', '=', 'market5')]" />
|
||||
</function>
|
||||
<value eval="{'noupdate': False}" />
|
||||
</function>
|
||||
|
||||
<record id="agreement.market5" model="agreement">
|
||||
<field name="description">SIP Phones supply (BUY-VOIP012)</field>
|
||||
<field name="agreement_type_id" ref="agreement_type_loi" />
|
||||
</record>
|
||||
|
||||
<function name="write" model="ir.model.data">
|
||||
<function name="search" model="ir.model.data">
|
||||
<value eval="[('module', '=', 'agreement'), ('name', '=', 'market5')]" />
|
||||
</function>
|
||||
<value eval="{'noupdate': True}" />
|
||||
</function>
|
||||
|
||||
<function name="write" model="ir.model.data">
|
||||
<function name="search" model="ir.model.data">
|
||||
<value eval="[('module', '=', 'agreement'), ('name', '=', 'market6')]" />
|
||||
</function>
|
||||
<value eval="{'noupdate': False}" />
|
||||
</function>
|
||||
|
||||
<record id="agreement.market6" model="agreement">
|
||||
<field name="description">SIP-ISDN gateways (BUY-VOIP013)</field>
|
||||
<field name="agreement_type_id" ref="agreement_type_contract" />
|
||||
</record>
|
||||
|
||||
<function name="write" model="ir.model.data">
|
||||
<function name="search" model="ir.model.data">
|
||||
<value eval="[('module', '=', 'agreement'), ('name', '=', 'market6')]" />
|
||||
</function>
|
||||
<value eval="{'noupdate': True}" />
|
||||
</function>
|
||||
|
||||
</odoo>
|
||||
12
agreement_legal/data/ir_sequence.xml
Normal file
12
agreement_legal/data/ir_sequence.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<odoo noupdate="1">
|
||||
|
||||
<!-- Sequence for agreement -->
|
||||
<record id="seq_agreement" model="ir.sequence">
|
||||
<field name="name">Agreements</field>
|
||||
<field name="code">agreement</field>
|
||||
<field name="prefix">AG</field>
|
||||
<field name="padding">3</field>
|
||||
<field name="company_id" eval="False" />
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
8
agreement_legal/data/module_category.xml
Normal file
8
agreement_legal/data/module_category.xml
Normal file
@@ -0,0 +1,8 @@
|
||||
<odoo>
|
||||
|
||||
<record id="agreement" model="ir.module.category">
|
||||
<field name="name">Agreement</field>
|
||||
<field name="sequence">80</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
40
agreement_legal/demo/demo.xml
Normal file
40
agreement_legal/demo/demo.xml
Normal file
@@ -0,0 +1,40 @@
|
||||
<!--
|
||||
© 2019 Ygol Internetwork (yves@ygol.com)
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
-->
|
||||
<odoo noupdate="1">
|
||||
|
||||
<record id="agreement.market1" model="agreement">
|
||||
<field name="description">Hardware IT (C2C-IT0042)</field>
|
||||
<field name="agreement_type_id" ref="agreement_type_agreement" />
|
||||
</record>
|
||||
|
||||
<record id="agreement.market2" model="agreement">
|
||||
<field name="description">Fiber access office Lausanne (C2C-IT0043)</field>
|
||||
<field name="agreement_type_id" ref="agreement_type_contract" />
|
||||
</record>
|
||||
|
||||
<record id="agreement.market3" model="agreement">
|
||||
<field name="description">Vétérinaire (AGR-VETO001)</field>
|
||||
<field name="agreement_type_id" ref="agreement_type_loi" />
|
||||
</record>
|
||||
|
||||
<record id="agreement.market4" model="agreement">
|
||||
<field
|
||||
name="description"
|
||||
>Wazo IPBX deployment and maintenance (AGR-TEL001)</field>
|
||||
<field name="agreement_type_id" ref="agreement_type_loi" />
|
||||
</record>
|
||||
|
||||
<record id="agreement.market5" model="agreement">
|
||||
<field name="description">SIP Phones supply (BUY-VOIP012)</field>
|
||||
<field name="agreement_type_id" ref="agreement_type_agreement" />
|
||||
</record>
|
||||
|
||||
<record id="agreement.market6" model="agreement">
|
||||
<field name="is_template">True</field>
|
||||
<field name="description">SIP-ISDN gateways (BUY-VOIP013)</field>
|
||||
<field name="agreement_type_id" ref="agreement_legal.agreement_type_contract" />
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
1710
agreement_legal/i18n/agreement_legal.pot
Normal file
1710
agreement_legal/i18n/agreement_legal.pot
Normal file
File diff suppressed because it is too large
Load Diff
1768
agreement_legal/i18n/es.po
Normal file
1768
agreement_legal/i18n/es.po
Normal file
File diff suppressed because it is too large
Load Diff
2004
agreement_legal/i18n/fr.po
Normal file
2004
agreement_legal/i18n/fr.po
Normal file
File diff suppressed because it is too large
Load Diff
1772
agreement_legal/i18n/pt.po
Normal file
1772
agreement_legal/i18n/pt.po
Normal file
File diff suppressed because it is too large
Load Diff
1771
agreement_legal/i18n/pt_BR.po
Normal file
1771
agreement_legal/i18n/pt_BR.po
Normal file
File diff suppressed because it is too large
Load Diff
1764
agreement_legal/i18n/pt_PT.po
Normal file
1764
agreement_legal/i18n/pt_PT.po
Normal file
File diff suppressed because it is too large
Load Diff
1761
agreement_legal/i18n/zh_CN.po
Normal file
1761
agreement_legal/i18n/zh_CN.po
Normal file
File diff suppressed because it is too large
Load Diff
18
agreement_legal/models/__init__.py
Normal file
18
agreement_legal/models/__init__.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from . import (
|
||||
res_config_settings,
|
||||
agreement_stage,
|
||||
agreement,
|
||||
agreement_appendix,
|
||||
agreement_clause,
|
||||
agreement_line,
|
||||
agreement_recital,
|
||||
agreement_section,
|
||||
agreement_type,
|
||||
agreement_subtype,
|
||||
res_partner,
|
||||
product_template,
|
||||
agreement_renewaltype,
|
||||
agreement_increasetype,
|
||||
)
|
||||
416
agreement_legal/models/agreement.py
Normal file
416
agreement_legal/models/agreement.py
Normal file
@@ -0,0 +1,416 @@
|
||||
# Copyright (C) 2018 - TODAY, Pavlov Media
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
|
||||
|
||||
class Agreement(models.Model):
|
||||
_inherit = "agreement"
|
||||
|
||||
name = fields.Char(string="Title", required=True)
|
||||
version = fields.Integer(
|
||||
string="Version",
|
||||
default=1,
|
||||
copy=False,
|
||||
help="The versions are used to keep track of document history and "
|
||||
"previous versions can be referenced.",
|
||||
)
|
||||
revision = fields.Integer(
|
||||
string="Revision",
|
||||
default=0,
|
||||
copy=False,
|
||||
help="The revision will increase with every save event.",
|
||||
)
|
||||
description = fields.Text(
|
||||
string="Description", tracking=True, help="Description of the agreement"
|
||||
)
|
||||
dynamic_description = fields.Text(
|
||||
compute="_compute_dynamic_description",
|
||||
string="Dynamic Description",
|
||||
help="Compute dynamic description",
|
||||
)
|
||||
start_date = fields.Date(
|
||||
string="Start Date", tracking=True, help="When the agreement starts."
|
||||
)
|
||||
end_date = fields.Date(
|
||||
string="End Date", tracking=True, help="When the agreement ends."
|
||||
)
|
||||
color = fields.Integer(string="Color")
|
||||
active = fields.Boolean(
|
||||
string="Active",
|
||||
default=True,
|
||||
help="If unchecked, it will allow you to hide the agreement without "
|
||||
"removing it.",
|
||||
)
|
||||
company_signed_date = fields.Date(
|
||||
string="Signed on",
|
||||
tracking=True,
|
||||
help="Date the contract was signed by Company.",
|
||||
)
|
||||
partner_signed_date = fields.Date(
|
||||
string="Signed on (Partner)",
|
||||
tracking=True,
|
||||
help="Date the contract was signed by the Partner.",
|
||||
)
|
||||
term = fields.Integer(
|
||||
string="Term (Months)",
|
||||
tracking=True,
|
||||
help="Number of months this agreement/contract is in effect with the "
|
||||
"partner.",
|
||||
)
|
||||
expiration_notice = fields.Integer(
|
||||
string="Exp. Notice (Days)",
|
||||
tracking=True,
|
||||
help="Number of Days before expiration to be notified.",
|
||||
)
|
||||
change_notice = fields.Integer(
|
||||
string="Change Notice (Days)",
|
||||
tracking=True,
|
||||
help="Number of Days to be notified before changes.",
|
||||
)
|
||||
special_terms = fields.Text(
|
||||
string="Special Terms",
|
||||
tracking=True,
|
||||
help="Any terms that you have agreed to and want to track on the "
|
||||
"agreement/contract.",
|
||||
)
|
||||
dynamic_special_terms = fields.Text(
|
||||
compute="_compute_dynamic_special_terms",
|
||||
string="Dynamic Special Terms",
|
||||
help="Compute dynamic special terms",
|
||||
)
|
||||
code = fields.Char(
|
||||
string="Reference",
|
||||
required=True,
|
||||
default=lambda self: _("New"),
|
||||
tracking=True,
|
||||
copy=False,
|
||||
help="ID used for internal contract tracking.",
|
||||
)
|
||||
increase_type_id = fields.Many2one(
|
||||
"agreement.increasetype",
|
||||
string="Increase Type",
|
||||
tracking=True,
|
||||
help="The amount that certain rates may increase.",
|
||||
)
|
||||
termination_requested = fields.Date(
|
||||
string="Termination Requested Date",
|
||||
tracking=True,
|
||||
help="Date that a request for termination was received.",
|
||||
)
|
||||
termination_date = fields.Date(
|
||||
string="Termination Date",
|
||||
tracking=True,
|
||||
help="Date that the contract was terminated.",
|
||||
)
|
||||
reviewed_date = fields.Date(string="Reviewed Date", tracking=True)
|
||||
reviewed_user_id = fields.Many2one("res.users", string="Reviewed By", tracking=True)
|
||||
approved_date = fields.Date(string="Approved Date", tracking=True)
|
||||
approved_user_id = fields.Many2one("res.users", string="Approved By", tracking=True)
|
||||
currency_id = fields.Many2one("res.currency", string="Currency")
|
||||
partner_id = fields.Many2one(
|
||||
"res.partner",
|
||||
string="Partner",
|
||||
required=False,
|
||||
copy=True,
|
||||
help="The customer or vendor this agreement is related to.",
|
||||
)
|
||||
partner_contact_id = fields.Many2one(
|
||||
"res.partner",
|
||||
string="Partner Contact",
|
||||
copy=True,
|
||||
help="The primary partner contact (If Applicable).",
|
||||
)
|
||||
partner_contact_phone = fields.Char(
|
||||
related="partner_contact_id.phone", string="Partner Phone"
|
||||
)
|
||||
partner_contact_email = fields.Char(
|
||||
related="partner_contact_id.email", string="Partner Email"
|
||||
)
|
||||
company_contact_id = fields.Many2one(
|
||||
"res.partner",
|
||||
string="Company Contact",
|
||||
copy=True,
|
||||
help="The primary contact in the company.",
|
||||
)
|
||||
company_contact_phone = fields.Char(
|
||||
related="company_contact_id.phone", string="Phone"
|
||||
)
|
||||
company_contact_email = fields.Char(
|
||||
related="company_contact_id.email", string="Email"
|
||||
)
|
||||
use_parties_content = fields.Boolean(
|
||||
string="Use parties content", help="Use custom content for parties"
|
||||
)
|
||||
company_partner_id = fields.Many2one(
|
||||
related="company_id.partner_id", string="Company's Partner"
|
||||
)
|
||||
|
||||
def _get_default_parties(self):
|
||||
deftext = """
|
||||
<h3>Company Information</h3>
|
||||
<p>
|
||||
${object.company_id.partner_id.name or ''}.<br>
|
||||
${object.company_id.partner_id.street or ''} <br>
|
||||
${object.company_id.partner_id.state_id.code or ''}
|
||||
${object.company_id.partner_id.zip or ''}
|
||||
${object.company_id.partner_id.city or ''}<br>
|
||||
${object.company_id.partner_id.country_id.name or ''}.<br><br>
|
||||
Represented by <b>${object.company_contact_id.name or ''}.</b>
|
||||
</p>
|
||||
<p></p>
|
||||
<h3>Partner Information</h3>
|
||||
<p>
|
||||
${object.partner_id.name or ''}.<br>
|
||||
${object.partner_id.street or ''} <br>
|
||||
${object.partner_id.state_id.code or ''}
|
||||
${object.partner_id.zip or ''} ${object.partner_id.city or ''}<br>
|
||||
${object.partner_id.country_id.name or ''}.<br><br>
|
||||
Represented by <b>${object.partner_contact_id.name or ''}.</b>
|
||||
</p>
|
||||
"""
|
||||
return deftext
|
||||
|
||||
parties = fields.Html(
|
||||
string="Parties",
|
||||
tracking=True,
|
||||
default=_get_default_parties,
|
||||
help="Parties of the agreement",
|
||||
)
|
||||
dynamic_parties = fields.Html(
|
||||
compute="_compute_dynamic_parties",
|
||||
string="Dynamic Parties",
|
||||
help="Compute dynamic parties",
|
||||
)
|
||||
agreement_type_id = fields.Many2one(
|
||||
tracking=True,
|
||||
)
|
||||
agreement_subtype_id = fields.Many2one(
|
||||
"agreement.subtype",
|
||||
string="Agreement Sub-type",
|
||||
tracking=True,
|
||||
help="Select the sub-type of this agreement. Sub-Types are related to "
|
||||
"agreement types.",
|
||||
)
|
||||
product_ids = fields.Many2many("product.template", string="Products & Services")
|
||||
assigned_user_id = fields.Many2one(
|
||||
"res.users",
|
||||
string="Assigned To",
|
||||
tracking=True,
|
||||
help="Select the user who manages this agreement.",
|
||||
)
|
||||
company_signed_user_id = fields.Many2one(
|
||||
"res.users",
|
||||
string="Signed By",
|
||||
tracking=True,
|
||||
help="The user at our company who authorized/signed the agreement or "
|
||||
"contract.",
|
||||
)
|
||||
partner_signed_user_id = fields.Many2one(
|
||||
"res.partner",
|
||||
string="Signed By (Partner)",
|
||||
tracking=True,
|
||||
help="Contact on the account that signed the agreement/contract.",
|
||||
)
|
||||
parent_agreement_id = fields.Many2one(
|
||||
"agreement",
|
||||
string="Parent Agreement",
|
||||
help="Link this agreement to a parent agreement. For example if this "
|
||||
"agreement is an amendment to another agreement. This list will "
|
||||
"only show other agreements related to the same account.",
|
||||
)
|
||||
renewal_type_id = fields.Many2one(
|
||||
"agreement.renewaltype",
|
||||
string="Renewal Type",
|
||||
tracking=True,
|
||||
help="Describes what happens after the contract expires.",
|
||||
)
|
||||
recital_ids = fields.One2many(
|
||||
"agreement.recital", "agreement_id", string="Recitals", copy=True
|
||||
)
|
||||
sections_ids = fields.One2many(
|
||||
"agreement.section", "agreement_id", string="Sections", copy=True
|
||||
)
|
||||
clauses_ids = fields.One2many("agreement.clause", "agreement_id", string="Clauses")
|
||||
appendix_ids = fields.One2many(
|
||||
"agreement.appendix", "agreement_id", string="Appendices", copy=True
|
||||
)
|
||||
previous_version_agreements_ids = fields.One2many(
|
||||
"agreement",
|
||||
"parent_agreement_id",
|
||||
string="Previous Versions",
|
||||
copy=False,
|
||||
domain=[("active", "=", False)],
|
||||
)
|
||||
child_agreements_ids = fields.One2many(
|
||||
"agreement",
|
||||
"parent_agreement_id",
|
||||
string="Child Agreements",
|
||||
copy=False,
|
||||
domain=[("active", "=", True)],
|
||||
)
|
||||
line_ids = fields.One2many(
|
||||
"agreement.line", "agreement_id", string="Products/Services", copy=False
|
||||
)
|
||||
state = fields.Selection(
|
||||
[("draft", "Draft"), ("active", "Active"), ("inactive", "Inactive")],
|
||||
default="draft",
|
||||
tracking=True,
|
||||
)
|
||||
notification_address_id = fields.Many2one(
|
||||
"res.partner",
|
||||
string="Notification Address",
|
||||
help="The address to send notificaitons to, if different from "
|
||||
"customer address.(Address Type = Other)",
|
||||
)
|
||||
signed_contract_filename = fields.Char(string="Filename")
|
||||
signed_contract = fields.Binary(string="Signed Document", tracking=True)
|
||||
field_id = fields.Many2one(
|
||||
"ir.model.fields",
|
||||
string="Field",
|
||||
help="""Select target field from the related document model. If it is a
|
||||
relationship field you will be able to select a target field at the
|
||||
destination of the relationship.""",
|
||||
)
|
||||
sub_object_id = fields.Many2one(
|
||||
"ir.model",
|
||||
string="Sub-model",
|
||||
help="""When a relationship field is selected as first field, this
|
||||
field shows the document model the relationship goes to.""",
|
||||
)
|
||||
sub_model_object_field_id = fields.Many2one(
|
||||
"ir.model.fields",
|
||||
string="Sub-field",
|
||||
help="""When a relationship field is selected as first field, this
|
||||
field lets you select the target field within the destination document
|
||||
model (sub-model).""",
|
||||
)
|
||||
default_value = fields.Char(
|
||||
string="Default Value",
|
||||
help="Optional value to use if the target field is empty.",
|
||||
)
|
||||
copyvalue = fields.Char(
|
||||
string="Placeholder Expression",
|
||||
help="""Final placeholder expression, to be copy-pasted in the desired
|
||||
template field.""",
|
||||
)
|
||||
|
||||
# compute the dynamic content for mako expression
|
||||
def _compute_dynamic_description(self):
|
||||
MailTemplates = self.env["mail.template"]
|
||||
for agreement in self:
|
||||
lang = agreement.partner_id.lang or "en_US"
|
||||
description = MailTemplates.with_context(lang=lang)._render_template(
|
||||
agreement.description, "agreement", [agreement.id]
|
||||
)
|
||||
des = ""
|
||||
for i in description:
|
||||
des += description[i]
|
||||
agreement.dynamic_description = des
|
||||
|
||||
def _compute_dynamic_parties(self):
|
||||
MailTemplates = self.env["mail.template"]
|
||||
for agreement in self:
|
||||
lang = agreement.partner_id.lang or "en_US"
|
||||
parties = MailTemplates.with_context(lang=lang)._render_template(
|
||||
agreement.parties, "agreement", [agreement.id]
|
||||
)
|
||||
agreement.dynamic_parties = parties
|
||||
|
||||
def _compute_dynamic_special_terms(self):
|
||||
MailTemplates = self.env["mail.template"]
|
||||
for agreement in self:
|
||||
lang = agreement.partner_id.lang or "en_US"
|
||||
special_terms = MailTemplates.with_context(lang=lang)._render_template(
|
||||
agreement.special_terms, "agreement", [agreement.id]
|
||||
)
|
||||
agreement.dynamic_special_terms = special_terms
|
||||
|
||||
@api.onchange("field_id", "sub_model_object_field_id", "default_value")
|
||||
def onchange_copyvalue(self):
|
||||
self.sub_object_id = False
|
||||
self.copyvalue = False
|
||||
self.sub_object_id = False
|
||||
if self.field_id and not self.field_id.relation:
|
||||
self.copyvalue = "${{object.{} or {}}}".format(
|
||||
self.field_id.name, self.default_value or "''"
|
||||
)
|
||||
self.sub_model_object_field_id = False
|
||||
if self.field_id and self.field_id.relation:
|
||||
self.sub_object_id = self.env["ir.model"].search(
|
||||
[("model", "=", self.field_id.relation)]
|
||||
)[0]
|
||||
if self.sub_model_object_field_id:
|
||||
self.copyvalue = "${{object.{}.{} or {}}}".format(
|
||||
self.field_id.name,
|
||||
self.sub_model_object_field_id.name,
|
||||
self.default_value or "''",
|
||||
)
|
||||
|
||||
# Used for Kanban grouped_by view
|
||||
@api.model
|
||||
def _read_group_stage_ids(self, stages, domain, order):
|
||||
stage_ids = self.env["agreement.stage"].search(
|
||||
[("stage_type", "=", "agreement")]
|
||||
)
|
||||
return stage_ids
|
||||
|
||||
stage_id = fields.Many2one(
|
||||
"agreement.stage",
|
||||
string="Stage",
|
||||
group_expand="_read_group_stage_ids",
|
||||
help="Select the current stage of the agreement.",
|
||||
tracking=True,
|
||||
index=True,
|
||||
)
|
||||
|
||||
# Create New Version Button
|
||||
def create_new_version(self):
|
||||
for rec in self:
|
||||
if not rec.state == "draft":
|
||||
# Make sure status is draft
|
||||
rec.state = "draft"
|
||||
default_vals = {
|
||||
"name": "{} - OLD VERSION".format(rec.name),
|
||||
"active": False,
|
||||
"parent_agreement_id": rec.id,
|
||||
"version": rec.version,
|
||||
"code": rec.code + "-V" + str(rec.version),
|
||||
}
|
||||
# Make a current copy and mark it as old
|
||||
rec.copy(default=default_vals)
|
||||
# Increment the Version
|
||||
rec.version = rec.version + 1
|
||||
|
||||
def create_new_agreement(self):
|
||||
self.ensure_one()
|
||||
default_vals = {
|
||||
"name": "New",
|
||||
"active": True,
|
||||
"version": 1,
|
||||
"revision": 0,
|
||||
"state": "draft",
|
||||
"stage_id": self.env.ref("agreement_legal.agreement_stage_new").id,
|
||||
}
|
||||
res = self.copy(default=default_vals)
|
||||
res.sections_ids.mapped("clauses_ids").write({"agreement_id": res.id})
|
||||
return {
|
||||
"res_model": "agreement",
|
||||
"type": "ir.actions.act_window",
|
||||
"view_mode": "form",
|
||||
"view_type": "form",
|
||||
"res_id": res.id,
|
||||
}
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
if vals.get("code", _("New")) == _("New"):
|
||||
vals["code"] = self.env["ir.sequence"].next_by_code("agreement") or _("New")
|
||||
if not vals.get("stage_id"):
|
||||
vals["stage_id"] = self.env.ref("agreement_legal.agreement_stage_new").id
|
||||
return super().create(vals)
|
||||
|
||||
# Increments the revision on each save action
|
||||
def write(self, vals):
|
||||
vals["revision"] = self.revision + 1
|
||||
return super().write(vals)
|
||||
98
agreement_legal/models/agreement_appendix.py
Normal file
98
agreement_legal/models/agreement_appendix.py
Normal file
@@ -0,0 +1,98 @@
|
||||
# Copyright (C) 2018 - TODAY, Pavlov Media
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class AgreementAppendix(models.Model):
|
||||
_name = "agreement.appendix"
|
||||
_description = "Agreement Appendices"
|
||||
_order = "sequence"
|
||||
|
||||
name = fields.Char(string="Name", required=True)
|
||||
title = fields.Char(
|
||||
string="Title",
|
||||
required=True,
|
||||
help="The title is displayed on the PDF. The name is not.",
|
||||
)
|
||||
sequence = fields.Integer(string="Sequence", default=10)
|
||||
content = fields.Html(string="Content")
|
||||
dynamic_content = fields.Html(
|
||||
compute="_compute_dynamic_content",
|
||||
string="Dynamic Content",
|
||||
help="compute dynamic Content",
|
||||
)
|
||||
agreement_id = fields.Many2one("agreement", string="Agreement", ondelete="cascade")
|
||||
active = fields.Boolean(
|
||||
string="Active",
|
||||
default=True,
|
||||
help="If unchecked, it will allow you to hide this appendix without "
|
||||
"removing it.",
|
||||
)
|
||||
|
||||
# Dynamic field editor
|
||||
field_id = fields.Many2one(
|
||||
"ir.model.fields",
|
||||
string="Field",
|
||||
help="""Select target field from the related document model. If it is a
|
||||
relationship field you will be able to select a target field at the
|
||||
destination of the relationship.""",
|
||||
)
|
||||
sub_object_id = fields.Many2one(
|
||||
"ir.model",
|
||||
string="Sub-model",
|
||||
help="""When a relationship field is selected as first field, this
|
||||
field shows the document model the relationship goes to.""",
|
||||
)
|
||||
sub_model_object_field_id = fields.Many2one(
|
||||
"ir.model.fields",
|
||||
string="Sub-field",
|
||||
help="""When a relationship field is selected as first field, this
|
||||
field lets you select the target field within the destination document
|
||||
model (sub-model).""",
|
||||
)
|
||||
default_value = fields.Char(
|
||||
string="Default Value",
|
||||
help="Optional value to use if the target field is empty.",
|
||||
)
|
||||
copyvalue = fields.Char(
|
||||
string="Placeholder Expression",
|
||||
help="""Final placeholder expression, to be copy-pasted in the desired
|
||||
template field.""",
|
||||
)
|
||||
|
||||
@api.onchange("field_id", "sub_model_object_field_id", "default_value")
|
||||
def onchange_copyvalue(self):
|
||||
self.sub_object_id = False
|
||||
self.copyvalue = False
|
||||
self.sub_object_id = False
|
||||
if self.field_id and not self.field_id.relation:
|
||||
self.copyvalue = "${{object.{} or {}}}".format(
|
||||
self.field_id.name,
|
||||
self.default_value or "''",
|
||||
)
|
||||
self.sub_model_object_field_id = False
|
||||
if self.field_id and self.field_id.relation:
|
||||
self.sub_object_id = self.env["ir.model"].search(
|
||||
[("model", "=", self.field_id.relation)]
|
||||
)[0]
|
||||
if self.sub_model_object_field_id:
|
||||
self.copyvalue = "${{object.{}.{} or {}}}".format(
|
||||
self.field_id.name,
|
||||
self.sub_model_object_field_id.name,
|
||||
self.default_value or "''",
|
||||
)
|
||||
|
||||
# compute the dynamic content for mako expression
|
||||
def _compute_dynamic_content(self):
|
||||
MailTemplates = self.env["mail.template"]
|
||||
for appendix in self:
|
||||
lang = (
|
||||
appendix.agreement_id
|
||||
and appendix.agreement_id.partner_id.lang
|
||||
or "en_US"
|
||||
)
|
||||
content = MailTemplates.with_context(lang=lang)._render_template(
|
||||
appendix.content, "agreement.appendix", [appendix.id]
|
||||
)
|
||||
appendix.dynamic_content = content
|
||||
97
agreement_legal/models/agreement_clause.py
Normal file
97
agreement_legal/models/agreement_clause.py
Normal file
@@ -0,0 +1,97 @@
|
||||
# Copyright (C) 2018 - TODAY, Pavlov Media
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class AgreementClause(models.Model):
|
||||
_name = "agreement.clause"
|
||||
_description = "Agreement Clauses"
|
||||
_order = "sequence"
|
||||
|
||||
name = fields.Char(string="Name", required=True)
|
||||
title = fields.Char(
|
||||
string="Title", help="The title is displayed on the PDF. The name is not."
|
||||
)
|
||||
sequence = fields.Integer(string="Sequence")
|
||||
agreement_id = fields.Many2one("agreement", string="Agreement", ondelete="cascade")
|
||||
section_id = fields.Many2one(
|
||||
"agreement.section", string="Section", ondelete="cascade"
|
||||
)
|
||||
content = fields.Html(string="Clause Content")
|
||||
dynamic_content = fields.Html(
|
||||
compute="_compute_dynamic_content",
|
||||
string="Dynamic Content",
|
||||
help="compute dynamic Content",
|
||||
)
|
||||
active = fields.Boolean(
|
||||
string="Active",
|
||||
default=True,
|
||||
help="If unchecked, it will allow you to hide the agreement without "
|
||||
"removing it.",
|
||||
)
|
||||
|
||||
# Dynamic field editor
|
||||
field_id = fields.Many2one(
|
||||
"ir.model.fields",
|
||||
string="Field",
|
||||
help="""Select target field from the related document model. If it is a
|
||||
relationship field you will be able to select a target field at the
|
||||
destination of the relationship.""",
|
||||
)
|
||||
sub_object_id = fields.Many2one(
|
||||
"ir.model",
|
||||
string="Sub-model",
|
||||
help="""When a relationship field is selected as first field, this
|
||||
field shows the document model the relationship goes to.""",
|
||||
)
|
||||
sub_model_object_field_id = fields.Many2one(
|
||||
"ir.model.fields",
|
||||
string="Sub-field",
|
||||
help="""When a relationship field is selected as first field, this
|
||||
field lets you select the target field within the destination document
|
||||
model (sub-model).""",
|
||||
)
|
||||
default_value = fields.Char(
|
||||
string="Default Value",
|
||||
help="Optional value to use if the target field is empty.",
|
||||
)
|
||||
copyvalue = fields.Char(
|
||||
string="Placeholder Expression",
|
||||
help="""Final placeholder expression, to be copy-pasted in the desired
|
||||
template field.""",
|
||||
)
|
||||
|
||||
@api.onchange("field_id", "sub_model_object_field_id", "default_value")
|
||||
def onchange_copyvalue(self):
|
||||
self.sub_object_id = False
|
||||
self.copyvalue = False
|
||||
self.sub_object_id = False
|
||||
if self.field_id and not self.field_id.relation:
|
||||
self.copyvalue = "${{object.{} or {}}}".format(
|
||||
self.field_id.name,
|
||||
self.default_value or "''",
|
||||
)
|
||||
self.sub_model_object_field_id = False
|
||||
if self.field_id and self.field_id.relation:
|
||||
self.sub_object_id = self.env["ir.model"].search(
|
||||
[("model", "=", self.field_id.relation)]
|
||||
)[0]
|
||||
if self.sub_model_object_field_id:
|
||||
self.copyvalue = "${{object.{}.{} or {}}}".format(
|
||||
self.field_id.name,
|
||||
self.sub_model_object_field_id.name,
|
||||
self.default_value or "''",
|
||||
)
|
||||
|
||||
# compute the dynamic content for mako expression
|
||||
def _compute_dynamic_content(self):
|
||||
MailTemplates = self.env["mail.template"]
|
||||
for clause in self:
|
||||
lang = (
|
||||
clause.agreement_id and clause.agreement_id.partner_id.lang or "en_US"
|
||||
)
|
||||
content = MailTemplates.with_context(lang=lang)._render_template(
|
||||
clause.content, "agreement.clause", [clause.id]
|
||||
)
|
||||
clause.dynamic_content = content
|
||||
24
agreement_legal/models/agreement_increasetype.py
Normal file
24
agreement_legal/models/agreement_increasetype.py
Normal file
@@ -0,0 +1,24 @@
|
||||
# Copyright (C) 2018 - TODAY, Pavlov Media
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
# Main Agreement Increase Type Records Model
|
||||
class AgreementIncreaseType(models.Model):
|
||||
_name = "agreement.increasetype"
|
||||
_description = "Agreement Increase Type"
|
||||
|
||||
# General
|
||||
name = fields.Char(
|
||||
string="Title",
|
||||
required=True,
|
||||
help="Increase types describe any increases that may happen during "
|
||||
"the contract.",
|
||||
)
|
||||
description = fields.Text(
|
||||
string="Description", required=True, help="Description of the renewal type."
|
||||
)
|
||||
increase_percent = fields.Integer(
|
||||
string="Increase Percentage", help="Percentage that the amount will increase."
|
||||
)
|
||||
20
agreement_legal/models/agreement_line.py
Normal file
20
agreement_legal/models/agreement_line.py
Normal file
@@ -0,0 +1,20 @@
|
||||
# Copyright (C) 2018 - TODAY, Pavlov Media
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class AgreementLine(models.Model):
|
||||
_name = "agreement.line"
|
||||
_description = "Agreement Lines"
|
||||
|
||||
product_id = fields.Many2one("product.product", string="Product")
|
||||
name = fields.Char(string="Description", required=True)
|
||||
agreement_id = fields.Many2one("agreement", string="Agreement", ondelete="cascade")
|
||||
qty = fields.Float(string="Quantity")
|
||||
uom_id = fields.Many2one("uom.uom", string="Unit of Measure", required=True)
|
||||
|
||||
@api.onchange("product_id")
|
||||
def _onchange_product_id(self):
|
||||
self.name = self.product_id.name
|
||||
self.uom_id = self.product_id.uom_id.id
|
||||
94
agreement_legal/models/agreement_recital.py
Normal file
94
agreement_legal/models/agreement_recital.py
Normal file
@@ -0,0 +1,94 @@
|
||||
# Copyright (C) 2018 - TODAY, Pavlov Media
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class AgreementRecital(models.Model):
|
||||
_name = "agreement.recital"
|
||||
_description = "Agreement Recitals"
|
||||
_order = "sequence"
|
||||
|
||||
name = fields.Char(string="Name", required=True)
|
||||
title = fields.Char(
|
||||
string="Title",
|
||||
help="The title is displayed on the PDF." "The name is not.",
|
||||
)
|
||||
sequence = fields.Integer(string="Sequence", default=10)
|
||||
content = fields.Html(string="Content")
|
||||
dynamic_content = fields.Html(
|
||||
compute="_compute_dynamic_content",
|
||||
string="Dynamic Content",
|
||||
help="compute dynamic Content",
|
||||
)
|
||||
agreement_id = fields.Many2one("agreement", string="Agreement", ondelete="cascade")
|
||||
active = fields.Boolean(
|
||||
string="Active",
|
||||
default=True,
|
||||
help="If unchecked, it will allow you to hide this recital without "
|
||||
"removing it.",
|
||||
)
|
||||
|
||||
# Dynamic field editor
|
||||
field_id = fields.Many2one(
|
||||
"ir.model.fields",
|
||||
string="Field",
|
||||
help="""Select target field from the related document model. If it is a
|
||||
relationship field you will be able to select a target field at the
|
||||
destination of the relationship.""",
|
||||
)
|
||||
sub_object_id = fields.Many2one(
|
||||
"ir.model",
|
||||
string="Sub-model",
|
||||
help="""When a relationship field is selected as first field, this
|
||||
field shows the document model the relationship goes to.""",
|
||||
)
|
||||
sub_model_object_field_id = fields.Many2one(
|
||||
"ir.model.fields",
|
||||
string="Sub-field",
|
||||
help="""When a relationship field is selected as first field, this
|
||||
field lets you select the target field within the destination document
|
||||
model (sub-model).""",
|
||||
)
|
||||
default_value = fields.Char(
|
||||
string="Default Value",
|
||||
help="Optional value to use if the target field is empty.",
|
||||
)
|
||||
copyvalue = fields.Char(
|
||||
string="Placeholder Expression",
|
||||
help="""Final placeholder expression, to be copy-pasted in the desired
|
||||
template field.""",
|
||||
)
|
||||
|
||||
@api.onchange("field_id", "sub_model_object_field_id", "default_value")
|
||||
def onchange_copyvalue(self):
|
||||
self.sub_object_id = False
|
||||
self.copyvalue = False
|
||||
self.sub_object_id = False
|
||||
if self.field_id and not self.field_id.relation:
|
||||
self.copyvalue = "${{object.{} or {}}}".format(
|
||||
self.field_id.name, self.default_value or "''"
|
||||
)
|
||||
self.sub_model_object_field_id = False
|
||||
if self.field_id and self.field_id.relation:
|
||||
self.sub_object_id = self.env["ir.model"].search(
|
||||
[("model", "=", self.field_id.relation)]
|
||||
)[0]
|
||||
if self.sub_model_object_field_id:
|
||||
self.copyvalue = "${{object.{}.{} or {}}}".format(
|
||||
self.field_id.name,
|
||||
self.sub_model_object_field_id.name,
|
||||
self.default_value or "''",
|
||||
)
|
||||
|
||||
# compute the dynamic content for mako expression
|
||||
def _compute_dynamic_content(self):
|
||||
MailTemplates = self.env["mail.template"]
|
||||
for recital in self:
|
||||
lang = (
|
||||
recital.agreement_id and recital.agreement_id.partner_id.lang or "en_US"
|
||||
)
|
||||
content = MailTemplates.with_context(lang=lang)._render_template(
|
||||
recital.content, "agreement.recital", [recital.id]
|
||||
)
|
||||
recital.dynamic_content = content
|
||||
21
agreement_legal/models/agreement_renewaltype.py
Normal file
21
agreement_legal/models/agreement_renewaltype.py
Normal file
@@ -0,0 +1,21 @@
|
||||
# Copyright (C) 2018 - TODAY, Pavlov Media
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
# Main Agreement Section Records Model
|
||||
class AgreementRenewalType(models.Model):
|
||||
_name = "agreement.renewaltype"
|
||||
_description = "Agreement Renewal Type"
|
||||
|
||||
# General
|
||||
name = fields.Char(
|
||||
string="Title",
|
||||
required=True,
|
||||
help="Renewal types describe what happens after the "
|
||||
"agreement/contract expires.",
|
||||
)
|
||||
description = fields.Text(
|
||||
string="Description", required=True, help="Description of the renewal type."
|
||||
)
|
||||
96
agreement_legal/models/agreement_section.py
Normal file
96
agreement_legal/models/agreement_section.py
Normal file
@@ -0,0 +1,96 @@
|
||||
# Copyright (C) 2018 - TODAY, Pavlov Media
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class AgreementSection(models.Model):
|
||||
_name = "agreement.section"
|
||||
_description = "Agreement Sections"
|
||||
_order = "sequence"
|
||||
|
||||
name = fields.Char(string="Name", required=True)
|
||||
title = fields.Char(
|
||||
string="Title", help="The title is displayed on the PDF. The name is not."
|
||||
)
|
||||
sequence = fields.Integer(string="Sequence")
|
||||
agreement_id = fields.Many2one("agreement", string="Agreement", ondelete="cascade")
|
||||
clauses_ids = fields.One2many(
|
||||
"agreement.clause", "section_id", string="Clauses", copy=True
|
||||
)
|
||||
content = fields.Html(string="Section Content")
|
||||
dynamic_content = fields.Html(
|
||||
compute="_compute_dynamic_content",
|
||||
string="Dynamic Content",
|
||||
help="compute dynamic Content",
|
||||
)
|
||||
active = fields.Boolean(
|
||||
string="Active",
|
||||
default=True,
|
||||
help="If unchecked, it will allow you to hide the agreement without "
|
||||
"removing it.",
|
||||
)
|
||||
|
||||
# Dynamic field editor
|
||||
field_id = fields.Many2one(
|
||||
"ir.model.fields",
|
||||
string="Field",
|
||||
help="""Select target field from the related document model. If it is a
|
||||
relationship field you will be able to select a target field at the
|
||||
destination of the relationship.""",
|
||||
)
|
||||
sub_object_id = fields.Many2one(
|
||||
"ir.model",
|
||||
string="Sub-model",
|
||||
help="""When a relationship field is selected as first field, this
|
||||
field shows the document model the relationship goes to.""",
|
||||
)
|
||||
sub_model_object_field_id = fields.Many2one(
|
||||
"ir.model.fields",
|
||||
string="Sub-field",
|
||||
help="""When a relationship field is selected as first field, this
|
||||
field lets you select the target field within the destination document
|
||||
model (sub-model).""",
|
||||
)
|
||||
default_value = fields.Char(
|
||||
string="Default Value",
|
||||
help="Optional value to use if the target field is empty.",
|
||||
)
|
||||
copyvalue = fields.Char(
|
||||
string="Placeholder Expression",
|
||||
help="""Final placeholder expression, to be copy-pasted in the desired
|
||||
template field.""",
|
||||
)
|
||||
|
||||
@api.onchange("field_id", "sub_model_object_field_id", "default_value")
|
||||
def onchange_copyvalue(self):
|
||||
self.sub_object_id = False
|
||||
self.copyvalue = False
|
||||
self.sub_object_id = False
|
||||
if self.field_id and not self.field_id.relation:
|
||||
self.copyvalue = "${{object.{} or {}}}".format(
|
||||
self.field_id.name, self.default_value or "''"
|
||||
)
|
||||
self.sub_model_object_field_id = False
|
||||
if self.field_id and self.field_id.relation:
|
||||
self.sub_object_id = self.env["ir.model"].search(
|
||||
[("model", "=", self.field_id.relation)]
|
||||
)[0]
|
||||
if self.sub_model_object_field_id:
|
||||
self.copyvalue = "${{object.{}.{} or {}}}".format(
|
||||
self.field_id.name,
|
||||
self.sub_model_object_field_id.name,
|
||||
self.default_value or "''",
|
||||
)
|
||||
|
||||
# compute the dynamic content for mako expression
|
||||
def _compute_dynamic_content(self):
|
||||
MailTemplates = self.env["mail.template"]
|
||||
for section in self:
|
||||
lang = (
|
||||
section.agreement_id and section.agreement_id.partner_id.lang or "en_US"
|
||||
)
|
||||
content = MailTemplates.with_context(lang=lang)._render_template(
|
||||
section.content, "agreement.section", [section.id]
|
||||
)
|
||||
section.dynamic_content = content
|
||||
24
agreement_legal/models/agreement_stage.py
Normal file
24
agreement_legal/models/agreement_stage.py
Normal file
@@ -0,0 +1,24 @@
|
||||
# Copyright (C) 2018 - TODAY, Pavlov Media
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
# Main Agreement Section Records Model
|
||||
class AgreementStage(models.Model):
|
||||
_name = "agreement.stage"
|
||||
_description = "Agreement Stages"
|
||||
_order = "sequence"
|
||||
|
||||
# General
|
||||
name = fields.Char(string="Stage Name", required=True)
|
||||
description = fields.Text(string="Description", required=False)
|
||||
sequence = fields.Integer(string="Sequence", default="1", required=False)
|
||||
fold = fields.Boolean(
|
||||
string="Is Folded",
|
||||
required=False,
|
||||
help="This stage is folded in the kanban view by default.",
|
||||
)
|
||||
stage_type = fields.Selection(
|
||||
[("agreement", "Agreement")], string="Type", required=True
|
||||
)
|
||||
12
agreement_legal/models/agreement_status.py
Normal file
12
agreement_legal/models/agreement_status.py
Normal file
@@ -0,0 +1,12 @@
|
||||
# Copyright (C) 2018 - TODAY, Pavlov Media
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
# Main Agreement Status Records Model
|
||||
class AgreementStatus(models.Model):
|
||||
_name = "agreement.type"
|
||||
|
||||
# General
|
||||
name = fields.Char(string="Title", required=True)
|
||||
12
agreement_legal/models/agreement_subtype.py
Normal file
12
agreement_legal/models/agreement_subtype.py
Normal file
@@ -0,0 +1,12 @@
|
||||
# Copyright (C) 2018 - TODAY, Pavlov Media
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class AgreementSubtype(models.Model):
|
||||
_name = "agreement.subtype"
|
||||
_description = "Agreement Subtypes"
|
||||
|
||||
name = fields.Char(string="Name", required=True)
|
||||
agreement_type_id = fields.Many2one("agreement.type", string="Agreement Type")
|
||||
13
agreement_legal/models/agreement_type.py
Normal file
13
agreement_legal/models/agreement_type.py
Normal file
@@ -0,0 +1,13 @@
|
||||
# Copyright (C) 2018 - TODAY, Pavlov Media
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class AgreementType(models.Model):
|
||||
_inherit = "agreement.type"
|
||||
_description = "Agreement Types"
|
||||
|
||||
agreement_subtypes_ids = fields.One2many(
|
||||
"agreement.subtype", "agreement_type_id", string="Subtypes"
|
||||
)
|
||||
10
agreement_legal/models/product_template.py
Normal file
10
agreement_legal/models/product_template.py
Normal file
@@ -0,0 +1,10 @@
|
||||
# Copyright (C) 2018 - TODAY, Pavlov Media
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class Product(models.Model):
|
||||
_inherit = "product.template"
|
||||
|
||||
agreements_ids = fields.Many2many("agreement", string="Agreements")
|
||||
37
agreement_legal/models/res_config_settings.py
Normal file
37
agreement_legal/models/res_config_settings.py
Normal file
@@ -0,0 +1,37 @@
|
||||
# Copyright (C) 2018 - TODAY, Open Source Integrators
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class ResConfigSettings(models.TransientModel):
|
||||
_inherit = "res.config.settings"
|
||||
|
||||
module_agreement_maintenance = fields.Boolean(
|
||||
string="Manage maintenance agreements and contracts."
|
||||
)
|
||||
module_agreement_mrp = fields.Boolean(
|
||||
string="Link your manufacturing orders to an agreement."
|
||||
)
|
||||
module_agreement_project = fields.Boolean(
|
||||
string="Link your projects and tasks to an agreement."
|
||||
)
|
||||
module_agreement_repair = fields.Boolean(
|
||||
string="Link your repair orders to an agreement."
|
||||
)
|
||||
module_agreement_rma = fields.Boolean(string="Link your RMAs to an agreement.")
|
||||
module_agreement_sale = fields.Boolean(
|
||||
string="Create an agreement when the sale order is confirmed."
|
||||
)
|
||||
module_agreement_sale_subscription = fields.Boolean(
|
||||
string="Link your subscriptions to an agreement."
|
||||
)
|
||||
module_agreement_stock = fields.Boolean(
|
||||
string="Link your pickings to an agreement."
|
||||
)
|
||||
module_fieldservice_agreement = fields.Boolean(
|
||||
string="Link your Field Service orders and equipments to an agreement."
|
||||
)
|
||||
module_agreement_helpdesk = fields.Boolean(
|
||||
string="Link your Helpdesk tickets to an agreement."
|
||||
)
|
||||
10
agreement_legal/models/res_partner.py
Normal file
10
agreement_legal/models/res_partner.py
Normal file
@@ -0,0 +1,10 @@
|
||||
# Copyright (C) 2018 - TODAY, Pavlov Media
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class Partner(models.Model):
|
||||
_inherit = "res.partner"
|
||||
|
||||
agreement_ids = fields.One2many("agreement", "partner_id", string="Agreements")
|
||||
6
agreement_legal/readme/CONFIGURE.rst
Normal file
6
agreement_legal/readme/CONFIGURE.rst
Normal file
@@ -0,0 +1,6 @@
|
||||
To configure this module:
|
||||
|
||||
* Go to Agreement > Configuration > Templates
|
||||
* Create a new template with sections and clauses and their respective content
|
||||
* Go to Agreement > Configuration > Stages
|
||||
* Create and reorder stages to match your process
|
||||
6
agreement_legal/readme/CONTRIBUTORS.rst
Normal file
6
agreement_legal/readme/CONTRIBUTORS.rst
Normal file
@@ -0,0 +1,6 @@
|
||||
* Patrick Wilson <pwilson@pavlovmedia.com>
|
||||
* Bhavesh Odedra <bodedra@opensourceintegrators.com>
|
||||
* Wolfgang Hall <whall@opensourceintegrators.com>
|
||||
* Maxime Chambreuil <mchambreuil@opensourceintegrators.com>
|
||||
* Sandip Mangukiya <smangukiya@opensourceintegrators.com>
|
||||
* Yves Goldberg <yves@ygol.com>
|
||||
5
agreement_legal/readme/CREDITS.rst
Normal file
5
agreement_legal/readme/CREDITS.rst
Normal file
@@ -0,0 +1,5 @@
|
||||
The development of this module has been financially supported by:
|
||||
|
||||
* Pavlov Media
|
||||
* Open Source Integrators
|
||||
* Yves Goldberg
|
||||
9
agreement_legal/readme/DESCRIPTION.rst
Normal file
9
agreement_legal/readme/DESCRIPTION.rst
Normal file
@@ -0,0 +1,9 @@
|
||||
This module allows you to manage agreements, letter of intent and contract content.
|
||||
The module is meant to be used by the legal team of a company and to allow them
|
||||
to define sections, clauses and templates with their respective content that can
|
||||
be dynamic.
|
||||
|
||||
Based on the template, an agreement can be created and the pdf document generated.
|
||||
|
||||
The agreement would go through a workflow to finally become a contract with the
|
||||
customer signature.
|
||||
3
agreement_legal/readme/ROADMAP.rst
Normal file
3
agreement_legal/readme/ROADMAP.rst
Normal file
@@ -0,0 +1,3 @@
|
||||
* Split the module to remove the dependencies on sale and account and provide
|
||||
the same feature in extra modules (agreement_sale, agreement_account,
|
||||
agreement_purchase)
|
||||
7
agreement_legal/readme/USAGE.rst
Normal file
7
agreement_legal/readme/USAGE.rst
Normal file
@@ -0,0 +1,7 @@
|
||||
To use this module:
|
||||
|
||||
* Go to Agreement > Agreements
|
||||
* Create a new agreement
|
||||
* Select a template
|
||||
* Follow the process to get the required approval
|
||||
* Send the invitation to the customer to review and sign the agreement
|
||||
179
agreement_legal/report/agreement.xml
Normal file
179
agreement_legal/report/agreement.xml
Normal file
@@ -0,0 +1,179 @@
|
||||
<odoo>
|
||||
|
||||
<record id="partner_agreement_contract_document" model="ir.actions.report">
|
||||
<field name="name">Agreement</field>
|
||||
<field name="model">agreement</field>
|
||||
<field name="report_type">qweb-pdf</field>
|
||||
<field name="report_name">agreement_legal.report_agreement_document</field>
|
||||
<field name="report_file">agreement_legal.report_agreement_document</field>
|
||||
</record>
|
||||
|
||||
<record id="partner_agreement_contract_document_preview" model="ir.actions.report">
|
||||
<field name="name">Agreement Preview</field>
|
||||
<field name="model">agreement</field>
|
||||
<field name="report_type">qweb-html</field>
|
||||
<field name="report_name">agreement_legal.report_agreement_document</field>
|
||||
<field name="report_file">agreement_legal.report_agreement_document</field>
|
||||
</record>
|
||||
|
||||
<template id="report_agreement_document">
|
||||
<t t-name="agreement.report_agreement_document">
|
||||
<t t-call="web.html_container">
|
||||
<t t-foreach="docs" t-as="doc">
|
||||
<t t-call="web.external_layout">
|
||||
<div class="page">
|
||||
<h1 t-field="doc.name" />
|
||||
<div name="description">
|
||||
<span t-field="doc.dynamic_description" />
|
||||
</div>
|
||||
<h2>Parties</h2>
|
||||
<div name="parties">
|
||||
<t t-if="doc.use_parties_content">
|
||||
<p t-field="doc.dynamic_parties" />
|
||||
</t>
|
||||
</div>
|
||||
<t t-if="not doc.use_parties_content">
|
||||
<h3>Company Information</h3>
|
||||
<div name="company_address">
|
||||
<address
|
||||
t-field="doc.company_id.partner_id"
|
||||
t-options='{"widget": "contact", "fields": ["address", "name"], "no_marker": True}'
|
||||
/>
|
||||
</div>
|
||||
<div name="company_contact">
|
||||
Represented by <span
|
||||
t-field="doc.company_contact_id.name"
|
||||
/>.
|
||||
</div>
|
||||
<h3>Partner Information</h3>
|
||||
<div name="partner_address">
|
||||
<address
|
||||
t-field="doc.partner_id"
|
||||
t-options='{"widget": "contact", "fields": ["address", "name"], "no_marker": True}'
|
||||
/>
|
||||
</div>
|
||||
<div name="partner_contact">
|
||||
Represented by <span
|
||||
t-field="doc.partner_contact_id.name"
|
||||
/>.
|
||||
</div>
|
||||
</t>
|
||||
<h2>Agreement</h2>
|
||||
<h3>Recitals</h3>
|
||||
<table class="table table-condensed">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<ol>
|
||||
<li
|
||||
t-foreach="doc.recital_ids"
|
||||
t-as="r"
|
||||
>
|
||||
<t t-if="r.title">
|
||||
<h3 t-field="r.title" />
|
||||
</t>
|
||||
<p t-field="r.dynamic_content" />
|
||||
</li>
|
||||
</ol>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table class="table table-condensed">
|
||||
<tbody class="section_tbody">
|
||||
<tr>
|
||||
<td>
|
||||
<ol>
|
||||
<li
|
||||
t-foreach="doc.sections_ids"
|
||||
t-as="s"
|
||||
>
|
||||
<t t-if="s.title">
|
||||
<h3 t-field="s.title" />
|
||||
</t>
|
||||
<p t-field="s.dynamic_content" />
|
||||
<ol>
|
||||
<li
|
||||
t-foreach="s.clauses_ids"
|
||||
t-as="c"
|
||||
>
|
||||
<t t-if="c.title">
|
||||
<h4 t-field="c.title" />
|
||||
</t>
|
||||
<p
|
||||
t-field="c.dynamic_content"
|
||||
/>
|
||||
</li>
|
||||
</ol>
|
||||
</li>
|
||||
</ol>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<t t-if="special_term">
|
||||
<h2>Special Terms</h2>
|
||||
<div name="special_term">
|
||||
<p t-field="doc.dynamic_special_terms" />
|
||||
</div>
|
||||
</t>
|
||||
<h2>Signatures</h2>
|
||||
<table class="table table-condensed">
|
||||
<theader>
|
||||
<tr>
|
||||
<th>Partner</th>
|
||||
<th>Company</th>
|
||||
</tr>
|
||||
</theader>
|
||||
<tbody class="section_tbody">
|
||||
<tr>
|
||||
<td>
|
||||
<p t-field="doc.partner_id" />
|
||||
<p>By: </p>
|
||||
<p>
|
||||
Name: <span
|
||||
t-field="doc.partner_contact_id.name"
|
||||
/>
|
||||
</p>
|
||||
<p>
|
||||
Title: <span
|
||||
t-field="doc.partner_contact_id.function"
|
||||
/>
|
||||
</p>
|
||||
<p>Date: </p>
|
||||
</td>
|
||||
<td>
|
||||
<p t-field="doc.company_id.partner_id" />
|
||||
<p>By: </p>
|
||||
<p>
|
||||
Name: <span
|
||||
t-field="doc.company_contact_id.name"
|
||||
/>
|
||||
</p>
|
||||
<p>
|
||||
Title: <span
|
||||
t-field="doc.company_contact_id.function"
|
||||
/>
|
||||
</p>
|
||||
<p>Date: </p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div t-foreach="doc.appendix_ids" t-as="a">
|
||||
<div class="page">
|
||||
<h1
|
||||
t-field="a.title"
|
||||
style="page-break-before: always;"
|
||||
/>
|
||||
<p t-field="a.dynamic_content" />
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
</odoo>
|
||||
29
agreement_legal/security/ir.model.access.csv
Normal file
29
agreement_legal/security/ir.model.access.csv
Normal file
@@ -0,0 +1,29 @@
|
||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_agreement_readonly,agreement readonly,model_agreement,group_agreement_readonly,1,0,0,0
|
||||
access_agreement_allusers,agreement all users,model_agreement,group_agreement_user,1,1,1,0
|
||||
access_agreement_manager,agreement manager,model_agreement,group_agreement_manager,1,1,1,1
|
||||
access_agreement_recital_readonly,recital readonly,model_agreement_recital,group_agreement_readonly,1,0,0,0
|
||||
access_agreement_recital_allusers,recital all users,model_agreement_recital,group_agreement_user,1,1,1,0
|
||||
access_agreement_recital_manager,recital manager,model_agreement_recital,group_agreement_manager,1,1,1,1
|
||||
access_agreement_section_readonly,section readonly,model_agreement_section,group_agreement_readonly,1,0,0,0
|
||||
access_agreement_section_allusers,section all users,model_agreement_section,group_agreement_user,1,1,1,0
|
||||
access_agreement_section_manager,section manager,model_agreement_section,group_agreement_manager,1,1,1,1
|
||||
access_agreement_clause_readonly,clause readonly,model_agreement_clause,group_agreement_readonly,1,0,0,0
|
||||
access_agreement_clause_allusers,clause all users,model_agreement_clause,group_agreement_user,1,1,1,0
|
||||
access_agreement_clause_manager,clause manager,model_agreement_clause,group_agreement_manager,1,1,1,1
|
||||
access_agreement_appendix_readonly,appendix readonly,model_agreement_appendix,group_agreement_readonly,1,0,0,0
|
||||
access_agreement_appendix_allusers,appendix all users,model_agreement_appendix,group_agreement_user,1,1,1,0
|
||||
access_agreement_appendix_manager,appendix manager,model_agreement_appendix,group_agreement_manager,1,1,1,1
|
||||
access_agreement_line_readonly,agreement line readonly,model_agreement_line,group_agreement_readonly,1,0,0,0
|
||||
access_agreement_line_allusers,agreement line all users,model_agreement_line,group_agreement_user,1,1,1,0
|
||||
access_agreement_line_manager,agreement line manager,model_agreement_line,group_agreement_manager,1,1,1,1
|
||||
access_agreement_stage_readonly,stage readonly,model_agreement_stage,group_agreement_readonly,1,0,0,0
|
||||
access_agreement_stage_manager,stage manager,model_agreement_stage,group_agreement_manager,1,1,1,1
|
||||
access_agreement_type_readonly,type readonly,model_agreement_type,group_agreement_readonly,1,0,0,0
|
||||
access_agreement_type_manager,type manager,model_agreement_type,group_agreement_manager,1,1,1,1
|
||||
access_agreement_subtype_readonly,subtype readonly,model_agreement_subtype,group_agreement_readonly,1,0,0,0
|
||||
access_agreement_subtype_manager,subtype manager,model_agreement_subtype,group_agreement_manager,1,1,1,1
|
||||
access_agreement_renewaltype_readonly,renewaltype readonly,model_agreement_renewaltype,group_agreement_readonly,1,0,0,0
|
||||
access_agreement_renewaltype_manager,renewaltype manager,model_agreement_renewaltype,group_agreement_manager,1,1,1,1
|
||||
access_agreement_increasetype_readonly,increasetype readonly,model_agreement_increasetype,group_agreement_readonly,1,0,0,0
|
||||
access_agreement_increasetype_manager,increasetype manager,model_agreement_increasetype,group_agreement_manager,1,1,1,1
|
||||
|
36
agreement_legal/security/res_groups.xml
Normal file
36
agreement_legal/security/res_groups.xml
Normal file
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<record id="module_agreement_legal_category" model="ir.module.category">
|
||||
<field name="name">Agreement</field>
|
||||
<field name="sequence">17</field>
|
||||
</record>
|
||||
|
||||
<!-- Readonly group -->
|
||||
<record id="group_agreement_readonly" model="res.groups">
|
||||
<field name="name">Read-Only Users</field>
|
||||
<field name="category_id" ref="module_agreement_legal_category" />
|
||||
<field
|
||||
name="implied_ids"
|
||||
eval="[(4, ref('base.group_user')), (4, ref('agreement.group_use_agreement_type')), (4, ref('agreement.group_use_agreement_template'))]"
|
||||
/>
|
||||
</record>
|
||||
|
||||
<!-- User group -->
|
||||
<record id="group_agreement_user" model="res.groups">
|
||||
<field name="name">User</field>
|
||||
<field name="category_id" ref="module_agreement_legal_category" />
|
||||
<field name="implied_ids" eval="[(4, ref('group_agreement_readonly'))]" />
|
||||
</record>
|
||||
|
||||
<!-- Manager group -->
|
||||
<record id="group_agreement_manager" model="res.groups">
|
||||
<field name="name">Manager</field>
|
||||
<field name="category_id" ref="module_agreement_legal_category" />
|
||||
<field name="implied_ids" eval="[(4, ref('group_agreement_user'))]" />
|
||||
<field
|
||||
name="users"
|
||||
eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"
|
||||
/>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
BIN
agreement_legal/static/description/icon.png
Normal file
BIN
agreement_legal/static/description/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
237
agreement_legal/static/description/icon.svg
Normal file
237
agreement_legal/static/description/icon.svg
Normal file
@@ -0,0 +1,237 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="100mm"
|
||||
height="100mm"
|
||||
viewBox="0 0 100 100"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
sodipodi:docname="icon.svg"
|
||||
inkscape:version="0.92.2 5c3e80d, 2017-08-06"
|
||||
inkscape:export-filename="/Users/marcelsavegnago/Documents/id42/LOGOS/icon.png"
|
||||
inkscape:export-xdpi="91.867622"
|
||||
inkscape:export-ydpi="91.867622">
|
||||
<defs
|
||||
id="defs2">
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath4562">
|
||||
<rect
|
||||
ry="4.1577382"
|
||||
y="13.040181"
|
||||
x="-124.92113"
|
||||
height="98.866074"
|
||||
width="99.811012"
|
||||
id="rect4564"
|
||||
style="fill:#aa0000;stroke-width:0.26458332"
|
||||
clip-path="none" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath4578">
|
||||
<rect
|
||||
ry="4.1577382"
|
||||
y="1.5119057"
|
||||
x="-120.00744"
|
||||
height="97.930626"
|
||||
width="99.811012"
|
||||
id="rect4580"
|
||||
style="fill:#aa0000;stroke-width:0.26458332" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.7"
|
||||
inkscape:cx="404.85241"
|
||||
inkscape:cy="231.79398"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:current-layer="layer2"
|
||||
showgrid="false"
|
||||
inkscape:snap-page="true"
|
||||
showguides="true"
|
||||
inkscape:guide-bbox="true"
|
||||
inkscape:window-width="1280"
|
||||
inkscape:window-height="702"
|
||||
inkscape:window-x="12"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:snap-global="false"
|
||||
inkscape:measure-start="187.143,62.8571"
|
||||
inkscape:measure-end="188.571,-1.42857">
|
||||
<sodipodi:guide
|
||||
position="27.285156,77.130766"
|
||||
orientation="-0.70710678,0.70710678"
|
||||
id="guide4619"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
position="65.956845,10.583333"
|
||||
orientation="-0.70710678,0.70710678"
|
||||
id="guide4621"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
position="67.704985,78.09933"
|
||||
orientation="-0.70710678,0.70710678"
|
||||
id="guide4623"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
position="62.407434,24.722431"
|
||||
orientation="-0.70710678,0.70710678"
|
||||
id="guide4625"
|
||||
inkscape:locked="false" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-197)"
|
||||
style="display:inline" />
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer2"
|
||||
inkscape:label="Layer 2"
|
||||
style="display:inline">
|
||||
<rect
|
||||
y="0"
|
||||
x="0"
|
||||
height="25.164532"
|
||||
width="100"
|
||||
id="rect4535"
|
||||
style="fill:#2483c5;stroke-width:0.13272627;fill-opacity:0.80149812"
|
||||
ry="4.9136906"
|
||||
inkscape:export-xdpi="91.327972"
|
||||
inkscape:export-ydpi="91.327972" />
|
||||
<rect
|
||||
ry="4.9136906"
|
||||
style="fill:#24245c;stroke-width:0.13272627;fill-opacity:1"
|
||||
id="rect4566"
|
||||
width="100"
|
||||
height="25.164532"
|
||||
x="0.18899068"
|
||||
y="74.958138"
|
||||
inkscape:export-xdpi="91.327972"
|
||||
inkscape:export-ydpi="91.327972" />
|
||||
<rect
|
||||
style="fill:#2483c5;stroke-width:0.26458332;fill-opacity:1"
|
||||
id="rect914"
|
||||
width="99.811012"
|
||||
height="97.930626"
|
||||
x="0.18898809"
|
||||
y="1.1339295"
|
||||
ry="4.1577382"
|
||||
inkscape:export-xdpi="91.327972"
|
||||
inkscape:export-ydpi="91.327972" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m -94.801154,22.164916 -27.663136,26.566584 2.26786,51.64648 h 37.697532 17.674503 l 18.256764,-17.499341 -0.357726,-12.039111 0.103556,-35.709692 -12.367577,-11.943386 -13.921757,0.298048 -13.752518,-1.096522"
|
||||
style="display:inline;opacity:0.47600002;fill:#550000;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
id="path4576"
|
||||
clip-path="url(#clipPath4578)"
|
||||
transform="matrix(1,0,0,1.0477127,120.21264,-5.0610747)"
|
||||
inkscape:export-xdpi="91.327972"
|
||||
inkscape:export-ydpi="91.327972"
|
||||
sodipodi:nodetypes="ccccccccccc" />
|
||||
<g
|
||||
id="g1099"
|
||||
transform="matrix(0.15694819,0,0,0.15694819,22.442357,17.453291)">
|
||||
<g
|
||||
id="g1034">
|
||||
<g
|
||||
id="g1032">
|
||||
<g
|
||||
id="g1030">
|
||||
<path
|
||||
id="path1014"
|
||||
d="m 249.5054,92.823 h 53.791 l 0.005,62.757 27.271,-42.343 V 77.743 c 0,-2.168 -0.863,-4.247 -2.396,-5.787 L 258.6124,2.395 C 257.0794,0.863 254.9994,0 252.8274,0 H 37.741399 c -13.534,0 -24.547,11.008 -24.547,24.543 v 370.914 c 0,13.534 11.012,24.543 24.547,24.543 H 306.0244 c 13.533,0 24.545,-11.009 24.545,-24.543 V 290.15 l -27.264,41.721 0.004,60.854 H 40.468399 V 27.274 H 239.3744 v 55.417 c 0,5.599 4.535,10.132 10.131,10.132 z"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#ffffff" />
|
||||
<path
|
||||
id="path1016"
|
||||
d="m 348.90644,221.22282 -9.86485,-9.16236 c -1.61064,-1.4946 -4.12524,-1.40313 -5.62182,0.20718 l -75.50518,81.27788 -10.21401,-9.48701 75.50535,-81.27888 c 1.49674,-1.61128 1.40428,-4.12606 -0.20619,-5.62165 l -9.86467,-9.16334 c -1.61047,-1.49559 -4.12721,-1.40346 -5.62182,0.20718 L 194.4577,309.90372 c -0.4803,0.5173 -0.81352,1.15314 -0.96811,1.84192 l -10.49398,47.16303 c -0.30606,1.3771 0.13989,2.81815 1.17596,3.77596 1.0354,0.96175 2.50407,1.30178 3.85321,0.89486 l 46.26272,-13.93733 c 0.67777,-0.20139 1.28716,-0.58393 1.7696,-1.10186 L 349.11051,226.83903 c 1.49852,-1.60388 1.40425,-4.11998 -0.20407,-5.61621 z"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#ffffff" />
|
||||
<path
|
||||
id="path1018"
|
||||
d="m 395.23055,171.35435 -35.76922,-33.22883 c -1.60867,-1.49426 -4.1264,-1.4023 -5.62182,0.20718 l -34.29286,36.91594 c -1.49459,1.61064 -1.40363,4.12821 0.20685,5.62379 l 35.76956,33.22685 c 1.6085,1.49526 4.12721,1.40347 5.62182,-0.20717 l 34.2917,-36.91513 c 1.49756,-1.61013 1.40444,-4.12705 -0.20603,-5.62263 z"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#ffffff" />
|
||||
<path
|
||||
id="path1020"
|
||||
d="m 83.563,109.13658 h 78 c 5.523,0 10,-4.478 10,-10.000003 0,-5.522 -4.477,-10 -10,-10 h -78 c -5.523,0 -10,4.478 -10,10 0,5.522003 4.479,10.000003 10,10.000003 z"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#ffffff" />
|
||||
<path
|
||||
id="path1022"
|
||||
d="m 231.563,149.13658 c 0,-5.522 -4.479,-10 -10,-10 h -138 c -5.523,0 -10,4.478 -10,10 0,5.522 4.477,10 10,10 h 138 c 5.523,0 10,-4.478 10,-10 z"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#ffffff" />
|
||||
<path
|
||||
id="path1024"
|
||||
d="m 83.563,209.13658 h 78 c 5.523,0 10,-4.478 10,-10 0,-5.522 -4.477,-10 -10,-10 h -78 c -5.523,0 -10,4.478 -10,10 0,5.522 4.479,10 10,10 z"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#ffffff" />
|
||||
<path
|
||||
id="path1026"
|
||||
d="m 83.563,259.13658 h 78 c 5.523,0 10,-4.478 10,-10 0,-5.521 -4.477,-10 -10,-10 h -78 c -5.523,0 -10,4.479 -10,10 0,5.522 4.479,10 10,10 z"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#ffffff" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="g1036" />
|
||||
<g
|
||||
id="g1038" />
|
||||
<g
|
||||
id="g1040" />
|
||||
<g
|
||||
id="g1042" />
|
||||
<g
|
||||
id="g1044" />
|
||||
<g
|
||||
id="g1046" />
|
||||
<g
|
||||
id="g1048" />
|
||||
<g
|
||||
id="g1050" />
|
||||
<g
|
||||
id="g1052" />
|
||||
<g
|
||||
id="g1054" />
|
||||
<g
|
||||
id="g1056" />
|
||||
<g
|
||||
id="g1058" />
|
||||
<g
|
||||
id="g1060" />
|
||||
<g
|
||||
id="g1062" />
|
||||
<g
|
||||
id="g1064" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 8.5 KiB |
481
agreement_legal/static/description/index.html
Normal file
481
agreement_legal/static/description/index.html
Normal file
@@ -0,0 +1,481 @@
|
||||
<?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>Agreements Legal</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="agreements-legal">
|
||||
<h1 class="title">Agreements Legal</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="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.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_legal"><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_legal"><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 allows you to manage agreements, letter of intent and contract content.
|
||||
The module is meant to be used by the legal team of a company and to allow them
|
||||
to define sections, clauses and templates with their respective content that can
|
||||
be dynamic.</p>
|
||||
<p>Based on the template, an agreement can be created and the pdf document generated.</p>
|
||||
<p>The agreement would go through a workflow to finally become a contract with the
|
||||
customer signature.</p>
|
||||
<p><strong>Table of contents</strong></p>
|
||||
<div class="contents local topic" id="contents">
|
||||
<ul class="simple">
|
||||
<li><a class="reference internal" href="#configuration" id="id1">Configuration</a></li>
|
||||
<li><a class="reference internal" href="#usage" id="id2">Usage</a></li>
|
||||
<li><a class="reference internal" href="#known-issues-roadmap" id="id3">Known issues / Roadmap</a></li>
|
||||
<li><a class="reference internal" href="#bug-tracker" id="id4">Bug Tracker</a></li>
|
||||
<li><a class="reference internal" href="#credits" id="id5">Credits</a><ul>
|
||||
<li><a class="reference internal" href="#authors" id="id6">Authors</a></li>
|
||||
<li><a class="reference internal" href="#contributors" id="id7">Contributors</a></li>
|
||||
<li><a class="reference internal" href="#other-credits" id="id8">Other credits</a></li>
|
||||
<li><a class="reference internal" href="#maintainers" id="id9">Maintainers</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="configuration">
|
||||
<h1><a class="toc-backref" href="#id1">Configuration</a></h1>
|
||||
<p>To configure this module:</p>
|
||||
<ul class="simple">
|
||||
<li>Go to Agreement > Configuration > Templates</li>
|
||||
<li>Create a new template with sections and clauses and their respective content</li>
|
||||
<li>Go to Agreement > Configuration > Stages</li>
|
||||
<li>Create and reorder stages to match your process</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="usage">
|
||||
<h1><a class="toc-backref" href="#id2">Usage</a></h1>
|
||||
<p>To use this module:</p>
|
||||
<ul class="simple">
|
||||
<li>Go to Agreement > Agreements</li>
|
||||
<li>Create a new agreement</li>
|
||||
<li>Select a template</li>
|
||||
<li>Follow the process to get the required approval</li>
|
||||
<li>Send the invitation to the customer to review and sign the agreement</li>
|
||||
<li>Define Field using widget domain but having partial_use option true:</li>
|
||||
<li>For Ex:</li>
|
||||
<li><field name=”field_domain” widget=”domain” nolabel=”1”</li>
|
||||
<li>options=”{‘model’: ‘agreement.recital’,</li>
|
||||
<li>‘partial_use’: True}”/></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="known-issues-roadmap">
|
||||
<h1><a class="toc-backref" href="#id3">Known issues / Roadmap</a></h1>
|
||||
<ul class="simple">
|
||||
<li>Split the module to remove the dependencies on sale and account and provide
|
||||
the same feature in extra modules (agreement_sale, agreement_account,
|
||||
agreement_purchase)</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="bug-tracker">
|
||||
<h1><a class="toc-backref" href="#id4">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_legal%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="#id5">Credits</a></h1>
|
||||
<div class="section" id="authors">
|
||||
<h2><a class="toc-backref" href="#id6">Authors</a></h2>
|
||||
<ul class="simple">
|
||||
<li>Pavlov Media</li>
|
||||
<li>Open Source Integrators</li>
|
||||
<li>Yves Goldberg (Ygol Internetwork)</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="contributors">
|
||||
<h2><a class="toc-backref" href="#id7">Contributors</a></h2>
|
||||
<ul class="simple">
|
||||
<li>Patrick Wilson <<a class="reference external" href="mailto:pwilson@pavlovmedia.com">pwilson@pavlovmedia.com</a>></li>
|
||||
<li>Bhavesh Odedra <<a class="reference external" href="mailto:bodedra@opensourceintegrators.com">bodedra@opensourceintegrators.com</a>></li>
|
||||
<li>Wolfgang Hall <<a class="reference external" href="mailto:whall@opensourceintegrators.com">whall@opensourceintegrators.com</a>></li>
|
||||
<li>Maxime Chambreuil <<a class="reference external" href="mailto:mchambreuil@opensourceintegrators.com">mchambreuil@opensourceintegrators.com</a>></li>
|
||||
<li>Sandip Mangukiya <<a class="reference external" href="mailto:smangukiya@opensourceintegrators.com">smangukiya@opensourceintegrators.com</a>></li>
|
||||
<li>Yves Goldberg <<a class="reference external" href="mailto:yves@ygol.com">yves@ygol.com</a>></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="other-credits">
|
||||
<h2><a class="toc-backref" href="#id8">Other credits</a></h2>
|
||||
<p>The development of this module has been financially supported by:</p>
|
||||
<ul class="simple">
|
||||
<li>Pavlov Media</li>
|
||||
<li>Open Source Integrators</li>
|
||||
<li>Yves Goldberg</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="maintainers">
|
||||
<h2><a class="toc-backref" href="#id9">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">maintainers</a>:</p>
|
||||
<p><a class="reference external" href="https://github.com/max3903"><img alt="max3903" src="https://github.com/max3903.png?size=40px" /></a> <a class="reference external" href="https://github.com/ygol"><img alt="ygol" src="https://github.com/ygol.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_legal">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>
|
||||
85
agreement_legal/static/src/js/domain_widget_ext.js
Normal file
85
agreement_legal/static/src/js/domain_widget_ext.js
Normal file
@@ -0,0 +1,85 @@
|
||||
odoo.define("agreement_legal.domain_widget_ext", function (require) {
|
||||
"use strict";
|
||||
|
||||
var basic_fields = require("web.basic_fields");
|
||||
var DomainSelector = require("web.DomainSelector");
|
||||
var session = require("web.session");
|
||||
var core = require("web.core");
|
||||
var qweb = core.qweb;
|
||||
|
||||
basic_fields.FieldDomain.include({
|
||||
/**
|
||||
* Init
|
||||
*/
|
||||
init: function () {
|
||||
this._super.apply(this, arguments);
|
||||
// Add Additional options
|
||||
this.partialUse = this.nodeOptions.partial_use || false;
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Private
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @override _render from AbstractField
|
||||
* @returns {Deferred}
|
||||
*/
|
||||
_render: function () {
|
||||
// If there is no model, only change the non-domain-selector content
|
||||
if (!this._domainModel) {
|
||||
this._replaceContent();
|
||||
return $.when();
|
||||
}
|
||||
|
||||
// Convert char value to array value
|
||||
var value = this.value || "[]";
|
||||
|
||||
// Create the domain selector or change the value of the current
|
||||
// one...
|
||||
var def = null;
|
||||
if (this.domainSelector) {
|
||||
def = this.domainSelector.setDomain(value);
|
||||
} else {
|
||||
this.domainSelector = new DomainSelector(
|
||||
this,
|
||||
this._domainModel,
|
||||
value,
|
||||
{
|
||||
readonly: this.mode === "readonly" || this.inDialog,
|
||||
filters: this.fsFilters,
|
||||
debugMode: session.debug,
|
||||
partialUse: this.partialUse || false,
|
||||
}
|
||||
);
|
||||
def = this.domainSelector.prependTo(this.$el);
|
||||
}
|
||||
// ... then replace the other content (matched records, etc)
|
||||
return def.then(this._replaceContent.bind(this));
|
||||
},
|
||||
/**
|
||||
* Render the field DOM except for the domain selector part. The full
|
||||
* field DOM is composed of a DIV which contains the domain selector
|
||||
* widget, followed by other content. This other content is handled by
|
||||
* this method.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_replaceContent: function () {
|
||||
if (this._$content) {
|
||||
this._$content.remove();
|
||||
}
|
||||
this._$content = $(
|
||||
qweb.render("FieldDomain.content", {
|
||||
hasModel: Boolean(this._domainModel),
|
||||
isValid: Boolean(this._isValidForModel),
|
||||
nbRecords: this.record.specialData[this.name].nbRecords || 0,
|
||||
inDialogEdit: this.inDialog && this.mode === "edit",
|
||||
partialUse: this.partialUse || false,
|
||||
})
|
||||
);
|
||||
this._$content.appendTo(this.$el);
|
||||
},
|
||||
});
|
||||
});
|
||||
298
agreement_legal/static/src/xml/domain_widget_view.xml
Normal file
298
agreement_legal/static/src/xml/domain_widget_view.xml
Normal file
@@ -0,0 +1,298 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<templates id="template" xml:space="preserve">
|
||||
<t t-name="FieldDomain.content">
|
||||
<t t-if="partialUse">
|
||||
<div t-if="hasModel" class="o_field_domain_panel">
|
||||
</div>
|
||||
</t>
|
||||
<t t-if="!partialUse">
|
||||
<div t-if="hasModel" class="o_field_domain_panel">
|
||||
<i
|
||||
class="fa fa-arrow-right"
|
||||
role="img"
|
||||
aria-label="Domain"
|
||||
title="Domain"
|
||||
/>
|
||||
|
||||
<button
|
||||
t-if="isValid"
|
||||
class="btn btn-sm btn-secondary o_domain_show_selection_button"
|
||||
type="button"
|
||||
>
|
||||
<t t-esc="nbRecords" /> record(s)
|
||||
</button>
|
||||
<span t-else="" class="text-warning" role="alert"><i
|
||||
class="fa fa-exclamation-triangle"
|
||||
role="img"
|
||||
aria-label="Warning"
|
||||
title="Warning"
|
||||
/> Invalid domain</span>
|
||||
|
||||
<button
|
||||
t-if="inDialogEdit"
|
||||
class="btn btn-sm btn-primary o_field_domain_dialog_button"
|
||||
>Edit Domain</button>
|
||||
</div>
|
||||
<div t-else="">Select a model to add a filter.</div>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<div
|
||||
aria-atomic="true"
|
||||
t-name="DomainSelector"
|
||||
t-attf-class="o_domain_node o_domain_tree o_domain_selector #{widget.readonly ? 'o_read_mode' : 'o_edit_mode'}"
|
||||
>
|
||||
<t t-if="widget.options.partialUse">
|
||||
<t t-if="widget.children.length === 0">
|
||||
<span>SMatch <strong>all records</strong></span>
|
||||
<button
|
||||
t-if="!widget.readonly"
|
||||
class="btn btn-sm btn-primary o_domain_add_first_node_button"
|
||||
><i class="fa fa-plus" /> Add filter</button>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<div class="o_domain_tree_header">
|
||||
<t
|
||||
t-if="widget.children.length === 1"
|
||||
>Please navigate below and select field:</t>
|
||||
<t t-else="">
|
||||
<span>SSMatch records with</span>
|
||||
<t t-call="DomainTree.OperatorSelector" />
|
||||
<span>of the following rules:</span>
|
||||
</t>
|
||||
</div>
|
||||
|
||||
<div class="o_domain_node_children_container" />
|
||||
</t>
|
||||
</t>
|
||||
<t t-if="!widget.options.partialUse">
|
||||
<t t-if="widget.children.length === 0">
|
||||
<span>Match <strong>all records</strong></span>
|
||||
<button
|
||||
t-if="!widget.readonly"
|
||||
class="btn btn-sm btn-primary o_domain_add_first_node_button"
|
||||
><i class="fa fa-plus" /> Add filter</button>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<div class="o_domain_tree_header">
|
||||
<t
|
||||
t-if="widget.children.length === 1"
|
||||
>Match records with the following rule:</t>
|
||||
<t t-else="">
|
||||
<span>Match records with</span>
|
||||
<t t-call="DomainTree.OperatorSelector" />
|
||||
<span>of the following rules:</span>
|
||||
</t>
|
||||
</div>
|
||||
|
||||
<div class="o_domain_node_children_container" />
|
||||
</t>
|
||||
|
||||
<label
|
||||
t-if="widget.debug && !widget.readonly"
|
||||
class="o_domain_debug_container"
|
||||
>
|
||||
<span class="small"># Code editor</span>
|
||||
<input type="text" class="o_domain_debug_input" />
|
||||
</label>
|
||||
</t>
|
||||
</div>
|
||||
<t t-name="DomainNode.ControlPanel">
|
||||
<t t-if="widget.options.partialUse">
|
||||
<div
|
||||
t-if="!widget.readonly && !widget.noControlPanel"
|
||||
class="o_domain_node_control_panel"
|
||||
role="toolbar"
|
||||
aria-label="Domain node"
|
||||
>
|
||||
</div>
|
||||
</t>
|
||||
<t t-if="!widget.options.partialUse">
|
||||
<div
|
||||
t-if="!widget.readonly && !widget.noControlPanel"
|
||||
class="o_domain_node_control_panel"
|
||||
role="toolbar"
|
||||
aria-label="Domain node"
|
||||
>
|
||||
<button
|
||||
class="btn o_domain_delete_node_button"
|
||||
title="Delete node"
|
||||
aria-label="Delete node"
|
||||
><i class="fa fa-times" /></button>
|
||||
<button
|
||||
class="btn o_domain_add_node_button"
|
||||
title="Add node"
|
||||
aria-label="Add node"
|
||||
><i class="fa fa-plus-circle" /></button>
|
||||
<button
|
||||
class="btn o_domain_add_node_button"
|
||||
title="Add branch"
|
||||
aria-label="Add branch"
|
||||
data-branch="1"
|
||||
><i class="fa fa-ellipsis-h" /></button>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
<div
|
||||
t-name="DomainLeaf"
|
||||
t-attf-class="o_domain_node o_domain_leaf o_domain_selector_row #{widget.readonly ? 'o_read_mode' : 'o_edit_mode'}"
|
||||
>
|
||||
<t t-call="DomainNode.ControlPanel" />
|
||||
|
||||
<div t-if="!widget.readonly" class="o_domain_leaf_edition">
|
||||
<!-- field selector will be instantiated here -->
|
||||
<t t-if="!widget.options.partialUse">
|
||||
<div> <!-- used for flex stretching -->
|
||||
<select class="o_domain_leaf_operator_select o_input">
|
||||
<option
|
||||
t-foreach="widget.operators"
|
||||
t-as="key"
|
||||
t-att-value="key"
|
||||
t-att-selected="widget.displayOperator === key ? 'selected' : None"
|
||||
>
|
||||
<t t-esc="key_value" />
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div
|
||||
t-attf-class="o_ds_value_cell#{_.contains(['set', 'not set'], widget.displayOperator) ? ' d-none' : ''}"
|
||||
>
|
||||
<t t-if="widget.selectionChoices !== null">
|
||||
<select class="o_domain_leaf_value_input o_input">
|
||||
<option
|
||||
t-foreach="widget.selectionChoices"
|
||||
t-as="val"
|
||||
t-att-value="val[0]"
|
||||
t-att-selected="_.contains(val, widget.displayValue) ? 'selected' : None"
|
||||
>
|
||||
<t t-esc="val[1]" />
|
||||
</option>
|
||||
</select>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<t t-if="_.contains(['in', 'not in'], widget.operator)">
|
||||
<div class="o_domain_leaf_value_input">
|
||||
<span
|
||||
class="badge badge-pill"
|
||||
t-foreach="widget.displayValue"
|
||||
t-as="val"
|
||||
>
|
||||
<t t-esc="val" /> <i
|
||||
class="o_domain_leaf_value_remove_tag_button fa fa-times"
|
||||
t-att-data-value="val"
|
||||
role="img"
|
||||
aria-label="Remove tag"
|
||||
title="Remove tag"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<div class="o_domain_leaf_value_tags">
|
||||
<input
|
||||
placeholder="Add new value"
|
||||
type="text"
|
||||
class="o_input"
|
||||
/>
|
||||
<button
|
||||
class="btn btn-sm btn-primary fa fa-plus o_domain_leaf_value_add_tag_button"
|
||||
aria-label="Add tag"
|
||||
title="Add tag"
|
||||
/>
|
||||
</div>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<input
|
||||
class="o_domain_leaf_value_input o_input"
|
||||
type="text"
|
||||
t-att-value="widget.displayValue"
|
||||
/>
|
||||
</t>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
<div t-else="" class="o_domain_leaf_info">
|
||||
<!-- field selector will be instantiated here -->
|
||||
<t t-if="_.isString(widget.value)">
|
||||
<span class="o_domain_leaf_operator"><t
|
||||
t-esc="widget.operator_mapping[widget.operator]"
|
||||
/></span>
|
||||
<span class="o_domain_leaf_value text-primary">"<t
|
||||
t-esc="widget.value"
|
||||
/>"</span>
|
||||
</t>
|
||||
<t t-if="_.isArray(widget.value)">
|
||||
<span class="o_domain_leaf_operator"><t
|
||||
t-esc="widget.operator_mapping[widget.operator]"
|
||||
/></span>
|
||||
<t t-foreach="widget.value" t-as="v">
|
||||
<span class="o_domain_leaf_value text-primary">"<t
|
||||
t-esc="v"
|
||||
/>"</span>
|
||||
<t t-if="!v_last"> or </t>
|
||||
</t>
|
||||
</t>
|
||||
<t t-if="_.isNumber(widget.value)">
|
||||
<span class="o_domain_leaf_operator"><t
|
||||
t-esc="widget.operator_mapping[widget.operator]"
|
||||
/></span>
|
||||
<span class="o_domain_leaf_value text-primary"><t
|
||||
t-esc="widget.value"
|
||||
/></span>
|
||||
</t>
|
||||
<t t-if="_.isBoolean(widget.value)">
|
||||
is
|
||||
<t
|
||||
t-if="widget.operator === '=' && widget.value === false || widget.operator === '!=' && widget.value === true"
|
||||
>not</t>
|
||||
set
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
aria-atomic="true"
|
||||
t-name="ModelFieldSelector"
|
||||
t-attf-class="o_field_selector#{!widget.options.readonly ? ' o_edit_mode o_input' : ''}"
|
||||
>
|
||||
<div class="o_field_selector_value" tabindex="0" />
|
||||
<t t-if="!widget.options.partialUse">
|
||||
<div class="o_field_selector_controls" tabindex="0">
|
||||
<i
|
||||
role="alert"
|
||||
class="fa fa-exclamation-triangle o_field_selector_warning d-none"
|
||||
title="Invalid field chain"
|
||||
aria-label="Invalid field chain"
|
||||
/>
|
||||
</div>
|
||||
</t>
|
||||
<div
|
||||
t-if="!widget.options.readonly"
|
||||
class="o_field_selector_popover d-none"
|
||||
tabindex="0"
|
||||
>
|
||||
<div class="o_field_selector_popover_header text-center">
|
||||
<i
|
||||
class="fa fa-arrow-left o_field_selector_popover_option o_field_selector_prev_page"
|
||||
title="Previous"
|
||||
role="img"
|
||||
aria-label="Previous"
|
||||
/>
|
||||
<div class="o_field_selector_title" />
|
||||
<i
|
||||
class="fa fa-times o_field_selector_popover_option o_field_selector_close"
|
||||
title="Close"
|
||||
role="img"
|
||||
aria-label="Close"
|
||||
/>
|
||||
</div>
|
||||
<div class="o_field_selector_popover_body">
|
||||
<ul class="o_field_selector_page" />
|
||||
</div>
|
||||
<div
|
||||
t-if="widget.options.debugMode"
|
||||
class="o_field_selector_popover_footer"
|
||||
>
|
||||
<input type="text" class="o_input" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</templates>
|
||||
8
agreement_legal/tests/__init__.py
Normal file
8
agreement_legal/tests/__init__.py
Normal file
@@ -0,0 +1,8 @@
|
||||
# License LGPLv3.0 or later (https://www.gnu.org/licenses/lgpl-3.0.en.html).
|
||||
|
||||
from . import test_agreement
|
||||
from . import test_agreement_appendix
|
||||
from . import test_agreement_clause
|
||||
from . import test_agreement_line
|
||||
from . import test_agreement_recital
|
||||
from . import test_agreement_section
|
||||
131
agreement_legal/tests/test_agreement.py
Normal file
131
agreement_legal/tests/test_agreement.py
Normal file
@@ -0,0 +1,131 @@
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html)
|
||||
|
||||
from datetime import timedelta
|
||||
|
||||
from odoo import fields
|
||||
from odoo.tests.common import TransactionCase
|
||||
|
||||
|
||||
class TestAgreement(TransactionCase):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.test_customer = self.env["res.partner"].create({"name": "TestCustomer"})
|
||||
self.agreement_type = self.env["agreement.type"].create(
|
||||
{
|
||||
"name": "Test Agreement Type",
|
||||
"domain": "sale",
|
||||
}
|
||||
)
|
||||
self.test_agreement = self.env["agreement"].create(
|
||||
{
|
||||
"name": "TestAgreement",
|
||||
"description": "Test",
|
||||
"special_terms": "Test",
|
||||
"partner_id": self.test_customer.id,
|
||||
"start_date": fields.Date.today(),
|
||||
"end_date": fields.Date.today() + timedelta(days=365),
|
||||
"state": "active",
|
||||
}
|
||||
)
|
||||
|
||||
# TEST 01: Set 'Field' for dynamic placeholder, test onchange method
|
||||
def test_onchange_copyvalue(self):
|
||||
agreement_01 = self.test_agreement
|
||||
field_01 = self.env["ir.model.fields"].search(
|
||||
[
|
||||
("model", "=", "agreement"),
|
||||
("name", "=", "active"),
|
||||
]
|
||||
)
|
||||
agreement_01.field_id = field_01.id
|
||||
agreement_01.onchange_copyvalue()
|
||||
self.assertEqual(agreement_01.copyvalue, "${object.active or ''}")
|
||||
|
||||
# TEST 02: Set related 'Field' for dynamic placeholder to
|
||||
# test onchange method
|
||||
def test_onchange_copyvalue2(self):
|
||||
agreement_01 = self.test_agreement
|
||||
field_01 = self.env["ir.model.fields"].search(
|
||||
[
|
||||
("model", "=", "agreement"),
|
||||
("name", "=", "agreement_type_id"),
|
||||
]
|
||||
)
|
||||
sub_field_01 = self.env["ir.model.fields"].search(
|
||||
[
|
||||
("model", "=", "agreement.type"),
|
||||
("name", "=", "active"),
|
||||
]
|
||||
)
|
||||
agreement_01.field_id = field_01.id
|
||||
agreement_01.onchange_copyvalue()
|
||||
self.assertEqual(agreement_01.sub_object_id.model, "agreement.type")
|
||||
agreement_01.sub_model_object_field_id = sub_field_01.id
|
||||
agreement_01.onchange_copyvalue()
|
||||
self.assertEqual(
|
||||
agreement_01.copyvalue, "${object.agreement_type_id.active or ''}"
|
||||
)
|
||||
|
||||
# TEST 03: Create New Version
|
||||
def test_create_new_version(self):
|
||||
agreement_01 = self.test_agreement
|
||||
agreement_01.create_new_version()
|
||||
old_agreement = self.env["agreement"].search(
|
||||
[
|
||||
("code", "=", agreement_01.code + "-V1"),
|
||||
("active", "=", False),
|
||||
]
|
||||
)
|
||||
self.assertEqual(len(old_agreement), 1)
|
||||
new_agreement = self.env["agreement"].search(
|
||||
[
|
||||
("name", "=", "TestAgreement"),
|
||||
("version", "=", 2),
|
||||
]
|
||||
)
|
||||
self.assertEqual(len(new_agreement), 1)
|
||||
|
||||
# TEST 04: Create New Agreement
|
||||
def test_create_new_agreement(self):
|
||||
agreement_01 = self.test_agreement
|
||||
agreement_01.create_new_agreement()
|
||||
new_agreement = self.env["agreement"].search([("name", "=", "New")])
|
||||
self.assertEqual(len(new_agreement), 1)
|
||||
|
||||
# TEST 05: Test Description Dynamic Field
|
||||
def test_compute_dynamic_description(self):
|
||||
agreement_01 = self.test_agreement
|
||||
agreement_01.description = "${object.name}"
|
||||
self.assertEqual(
|
||||
agreement_01.dynamic_description,
|
||||
"TestAgreement",
|
||||
)
|
||||
|
||||
# TEST 06: Test Parties Dynamic Field
|
||||
def test_compute_dynamic_parties(self):
|
||||
agreement_01 = self.test_agreement
|
||||
agreement_01.parties = "${object.name}"
|
||||
self.assertEqual(
|
||||
agreement_01.dynamic_parties,
|
||||
"<p>{" + str(agreement_01.id) + ": '</p><p>TestAgreement</p>'}",
|
||||
)
|
||||
|
||||
# TEST 07: Test Special Terms Dynamic Field
|
||||
def test_compute_dynamic_special_terms(self):
|
||||
agreement_01 = self.test_agreement
|
||||
agreement_01.special_terms = "${object.name}"
|
||||
self.assertEqual(
|
||||
agreement_01.dynamic_special_terms,
|
||||
"{" + str(agreement_01.id) + ": 'TestAgreement'}",
|
||||
)
|
||||
|
||||
# TEST 02: Check Read Stages
|
||||
def test_read_group_stage_ids(self):
|
||||
agreement_01 = self.test_agreement
|
||||
self.assertEqual(
|
||||
agreement_01._read_group_stage_ids(self.env["agreement.stage"], [], "id"),
|
||||
self.env["agreement.stage"].search(
|
||||
[("stage_type", "=", "agreement")],
|
||||
order="id",
|
||||
),
|
||||
)
|
||||
81
agreement_legal/tests/test_agreement_appendix.py
Normal file
81
agreement_legal/tests/test_agreement_appendix.py
Normal file
@@ -0,0 +1,81 @@
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html)
|
||||
|
||||
from datetime import timedelta
|
||||
|
||||
from odoo import fields
|
||||
from odoo.tests.common import TransactionCase
|
||||
|
||||
|
||||
class TestAgreementAppendices(TransactionCase):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.test_customer = self.env["res.partner"].create({"name": "TestCustomer"})
|
||||
self.agreement_type = self.env["agreement.type"].create(
|
||||
{
|
||||
"name": "Test Agreement Type",
|
||||
"domain": "sale",
|
||||
}
|
||||
)
|
||||
self.test_agreement = self.env["agreement"].create(
|
||||
{
|
||||
"name": "TestAgreement",
|
||||
"description": "Test",
|
||||
"special_terms": "Test",
|
||||
"partner_id": self.test_customer.id,
|
||||
"start_date": fields.Date.today(),
|
||||
"end_date": fields.Date.today() + timedelta(days=365),
|
||||
}
|
||||
)
|
||||
self.test_appendices = self.env["agreement.appendix"].create(
|
||||
{
|
||||
"name": "TestAppendices",
|
||||
"title": "Test",
|
||||
"content": "Test",
|
||||
"agreement_id": self.test_agreement.id,
|
||||
}
|
||||
)
|
||||
|
||||
# TEST 01: Set 'Field' for dynamic placeholder, test onchange method
|
||||
def test_onchange_copyvalue(self):
|
||||
appendix_01 = self.test_appendices
|
||||
field_01 = self.env["ir.model.fields"].search(
|
||||
[
|
||||
("model", "=", "agreement.appendix"),
|
||||
("name", "=", "active"),
|
||||
]
|
||||
)
|
||||
appendix_01.field_id = field_01.id
|
||||
appendix_01.onchange_copyvalue()
|
||||
self.assertEqual(appendix_01.copyvalue, "${object.active or ''}")
|
||||
|
||||
# TEST 02: Set related 'Field' for dynamic placeholder to
|
||||
# test onchange method
|
||||
def test_onchange_copyvalue2(self):
|
||||
appendix_01 = self.test_appendices
|
||||
field_01 = self.env["ir.model.fields"].search(
|
||||
[
|
||||
("model", "=", "agreement.appendix"),
|
||||
("name", "=", "agreement_id"),
|
||||
]
|
||||
)
|
||||
sub_field_01 = self.env["ir.model.fields"].search(
|
||||
[
|
||||
("model", "=", "agreement"),
|
||||
("name", "=", "active"),
|
||||
]
|
||||
)
|
||||
appendix_01.field_id = field_01.id
|
||||
appendix_01.onchange_copyvalue()
|
||||
self.assertEqual(appendix_01.sub_object_id.model, "agreement")
|
||||
appendix_01.sub_model_object_field_id = sub_field_01.id
|
||||
appendix_01.onchange_copyvalue()
|
||||
self.assertEqual(appendix_01.copyvalue, "${object.agreement_id.active or ''}")
|
||||
|
||||
# TEST 03: Test Dynamic Field
|
||||
def test_compute_dynamic_content(self):
|
||||
appendix_01 = self.test_appendices
|
||||
appendix_01.content = "${object.name}"
|
||||
self.assertEqual(
|
||||
appendix_01.dynamic_content,
|
||||
"<p>{" + str(appendix_01.id) + ": '</p><p>TestAppendices</p>'}",
|
||||
)
|
||||
81
agreement_legal/tests/test_agreement_clause.py
Normal file
81
agreement_legal/tests/test_agreement_clause.py
Normal file
@@ -0,0 +1,81 @@
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html)
|
||||
|
||||
from datetime import timedelta
|
||||
|
||||
from odoo import fields
|
||||
from odoo.tests.common import TransactionCase
|
||||
|
||||
|
||||
class TestAgreementClauses(TransactionCase):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.test_customer = self.env["res.partner"].create({"name": "TestCustomer"})
|
||||
self.agreement_type = self.env["agreement.type"].create(
|
||||
{
|
||||
"name": "Test Agreement Type",
|
||||
"domain": "sale",
|
||||
}
|
||||
)
|
||||
self.test_agreement = self.env["agreement"].create(
|
||||
{
|
||||
"name": "TestAgreement",
|
||||
"description": "Test",
|
||||
"special_terms": "Test",
|
||||
"partner_id": self.test_customer.id,
|
||||
"start_date": fields.Date.today(),
|
||||
"end_date": fields.Date.today() + timedelta(days=365),
|
||||
}
|
||||
)
|
||||
self.test_clause = self.env["agreement.clause"].create(
|
||||
{
|
||||
"name": "TestClause",
|
||||
"title": "Test",
|
||||
"content": "Test",
|
||||
"agreement_id": self.test_agreement.id,
|
||||
}
|
||||
)
|
||||
|
||||
# TEST 01: Set 'Field' for dynamic placeholder, test onchange method
|
||||
def test_onchange_copyvalue(self):
|
||||
clause_01 = self.test_clause
|
||||
field_01 = self.env["ir.model.fields"].search(
|
||||
[
|
||||
("model", "=", "agreement.clause"),
|
||||
("name", "=", "active"),
|
||||
]
|
||||
)
|
||||
clause_01.field_id = field_01.id
|
||||
clause_01.onchange_copyvalue()
|
||||
self.assertEqual(clause_01.copyvalue, "${object.active or ''}")
|
||||
|
||||
# TEST 02: Set related 'Field' for dynamic placeholder to
|
||||
# test onchange method
|
||||
def test_onchange_copyvalue2(self):
|
||||
clause_01 = self.test_clause
|
||||
field_01 = self.env["ir.model.fields"].search(
|
||||
[
|
||||
("model", "=", "agreement.clause"),
|
||||
("name", "=", "agreement_id"),
|
||||
]
|
||||
)
|
||||
sub_field_01 = self.env["ir.model.fields"].search(
|
||||
[
|
||||
("model", "=", "agreement"),
|
||||
("name", "=", "active"),
|
||||
]
|
||||
)
|
||||
clause_01.field_id = field_01.id
|
||||
clause_01.onchange_copyvalue()
|
||||
self.assertEqual(clause_01.sub_object_id.model, "agreement")
|
||||
clause_01.sub_model_object_field_id = sub_field_01.id
|
||||
clause_01.onchange_copyvalue()
|
||||
self.assertEqual(clause_01.copyvalue, "${object.agreement_id.active or ''}")
|
||||
|
||||
# TEST 03: Test Dynamic Field
|
||||
def test_compute_dynamic_content(self):
|
||||
clause_01 = self.test_clause
|
||||
clause_01.content = "${object.name}"
|
||||
self.assertEqual(
|
||||
clause_01.dynamic_content,
|
||||
"<p>{" + str(clause_01.id) + ": '</p><p>TestClause</p>'}",
|
||||
)
|
||||
45
agreement_legal/tests/test_agreement_line.py
Normal file
45
agreement_legal/tests/test_agreement_line.py
Normal file
@@ -0,0 +1,45 @@
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html)
|
||||
|
||||
from datetime import timedelta
|
||||
|
||||
from odoo import fields
|
||||
from odoo.tests.common import TransactionCase
|
||||
|
||||
|
||||
class TestAgreementLine(TransactionCase):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.test_customer = self.env["res.partner"].create({"name": "TestCustomer"})
|
||||
self.agreement_type = self.env["agreement.type"].create(
|
||||
{
|
||||
"name": "Test Agreement Type",
|
||||
"domain": "sale",
|
||||
}
|
||||
)
|
||||
self.test_agreement = self.env["agreement"].create(
|
||||
{
|
||||
"name": "TestAgreement",
|
||||
"description": "Test",
|
||||
"special_terms": "Test",
|
||||
"partner_id": self.test_customer.id,
|
||||
"start_date": fields.Date.today(),
|
||||
"end_date": fields.Date.today() + timedelta(days=365),
|
||||
}
|
||||
)
|
||||
self.test_product1 = self.env["product.product"].create({"name": "TEST1"})
|
||||
self.test_product2 = self.env["product.product"].create({"name": "TEST2"})
|
||||
self.test_line = self.env["agreement.line"].create(
|
||||
{
|
||||
"product_id": self.test_product1.id,
|
||||
"name": "Test",
|
||||
"uom_id": 1,
|
||||
"agreement_id": self.test_agreement.id,
|
||||
}
|
||||
)
|
||||
|
||||
# TEST 01: Set line product onchange method
|
||||
def test_onchange_product_id(self):
|
||||
line_01 = self.test_line
|
||||
line_01.product_id = self.test_product2.id
|
||||
line_01._onchange_product_id()
|
||||
self.assertEqual(line_01.name, "TEST2")
|
||||
81
agreement_legal/tests/test_agreement_recital.py
Normal file
81
agreement_legal/tests/test_agreement_recital.py
Normal file
@@ -0,0 +1,81 @@
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html)
|
||||
|
||||
from datetime import timedelta
|
||||
|
||||
from odoo import fields
|
||||
from odoo.tests.common import TransactionCase
|
||||
|
||||
|
||||
class TestAgreementRectical(TransactionCase):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.test_customer = self.env["res.partner"].create({"name": "TestCustomer"})
|
||||
self.agreement_type = self.env["agreement.type"].create(
|
||||
{
|
||||
"name": "Test Agreement Type",
|
||||
"domain": "sale",
|
||||
}
|
||||
)
|
||||
self.test_agreement = self.env["agreement"].create(
|
||||
{
|
||||
"name": "TestAgreement",
|
||||
"description": "Test",
|
||||
"special_terms": "Test",
|
||||
"partner_id": self.test_customer.id,
|
||||
"start_date": fields.Date.today(),
|
||||
"end_date": fields.Date.today() + timedelta(days=365),
|
||||
}
|
||||
)
|
||||
self.test_recital = self.env["agreement.recital"].create(
|
||||
{
|
||||
"name": "TestRecital",
|
||||
"title": "Test",
|
||||
"content": "Test",
|
||||
"agreement_id": self.test_agreement.id,
|
||||
}
|
||||
)
|
||||
|
||||
# TEST 01: Set 'Field' for dynamic placeholder, test onchange method
|
||||
def test_onchange_copyvalue(self):
|
||||
recital_01 = self.test_recital
|
||||
field_01 = self.env["ir.model.fields"].search(
|
||||
[
|
||||
("model", "=", "agreement.recital"),
|
||||
("name", "=", "active"),
|
||||
]
|
||||
)
|
||||
recital_01.field_id = field_01.id
|
||||
recital_01.onchange_copyvalue()
|
||||
self.assertEqual(recital_01.copyvalue, "${object.active or ''}")
|
||||
|
||||
# TEST 02: Set related 'Field' for dynamic placeholder to
|
||||
# test onchange method
|
||||
def test_onchange_copyvalue2(self):
|
||||
recital_01 = self.test_recital
|
||||
field_01 = self.env["ir.model.fields"].search(
|
||||
[
|
||||
("model", "=", "agreement.recital"),
|
||||
("name", "=", "agreement_id"),
|
||||
]
|
||||
)
|
||||
sub_field_01 = self.env["ir.model.fields"].search(
|
||||
[
|
||||
("model", "=", "agreement"),
|
||||
("name", "=", "active"),
|
||||
]
|
||||
)
|
||||
recital_01.field_id = field_01.id
|
||||
recital_01.onchange_copyvalue()
|
||||
self.assertEqual(recital_01.sub_object_id.model, "agreement")
|
||||
recital_01.sub_model_object_field_id = sub_field_01.id
|
||||
recital_01.onchange_copyvalue()
|
||||
self.assertEqual(recital_01.copyvalue, "${object.agreement_id.active or ''}")
|
||||
|
||||
# TEST 03: Test Dynamic Field
|
||||
def test_compute_dynamic_content(self):
|
||||
recital_01 = self.test_recital
|
||||
recital_01.content = "${object.name}"
|
||||
self.assertEqual(
|
||||
recital_01.dynamic_content,
|
||||
"<p>{" + str(recital_01.id) + ": '</p><p>TestRecital</p>'}",
|
||||
)
|
||||
81
agreement_legal/tests/test_agreement_section.py
Normal file
81
agreement_legal/tests/test_agreement_section.py
Normal file
@@ -0,0 +1,81 @@
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html)
|
||||
|
||||
from datetime import timedelta
|
||||
|
||||
from odoo import fields
|
||||
from odoo.tests.common import TransactionCase
|
||||
|
||||
|
||||
class TestAgreementSection(TransactionCase):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.test_customer = self.env["res.partner"].create({"name": "TestCustomer"})
|
||||
self.agreement_type = self.env["agreement.type"].create(
|
||||
{
|
||||
"name": "Test Agreement Type",
|
||||
"domain": "sale",
|
||||
}
|
||||
)
|
||||
self.test_agreement = self.env["agreement"].create(
|
||||
{
|
||||
"name": "TestAgreement",
|
||||
"description": "Test",
|
||||
"special_terms": "Test",
|
||||
"partner_id": self.test_customer.id,
|
||||
"start_date": fields.Date.today(),
|
||||
"end_date": fields.Date.today() + timedelta(days=365),
|
||||
}
|
||||
)
|
||||
self.test_section = self.env["agreement.section"].create(
|
||||
{
|
||||
"name": "TestSection",
|
||||
"title": "Test",
|
||||
"content": "Test",
|
||||
"agreement_id": self.test_agreement.id,
|
||||
}
|
||||
)
|
||||
|
||||
# TEST 01: Set 'Field' for dynamic placeholder, test onchange method
|
||||
def test_onchange_copyvalue(self):
|
||||
section_01 = self.test_section
|
||||
field_01 = self.env["ir.model.fields"].search(
|
||||
[
|
||||
("model", "=", "agreement.section"),
|
||||
("name", "=", "active"),
|
||||
]
|
||||
)
|
||||
section_01.field_id = field_01.id
|
||||
section_01.onchange_copyvalue()
|
||||
self.assertEqual(section_01.copyvalue, "${object.active or ''}")
|
||||
|
||||
# TEST 02: Set related 'Field' for dynamic placeholder to
|
||||
# test onchange method
|
||||
def test_onchange_copyvalue2(self):
|
||||
section_01 = self.test_section
|
||||
field_01 = self.env["ir.model.fields"].search(
|
||||
[
|
||||
("model", "=", "agreement.section"),
|
||||
("name", "=", "agreement_id"),
|
||||
]
|
||||
)
|
||||
sub_field_01 = self.env["ir.model.fields"].search(
|
||||
[
|
||||
("model", "=", "agreement"),
|
||||
("name", "=", "active"),
|
||||
]
|
||||
)
|
||||
section_01.field_id = field_01.id
|
||||
section_01.onchange_copyvalue()
|
||||
self.assertEqual(section_01.sub_object_id.model, "agreement")
|
||||
section_01.sub_model_object_field_id = sub_field_01.id
|
||||
section_01.onchange_copyvalue()
|
||||
self.assertEqual(section_01.copyvalue, "${object.agreement_id.active or ''}")
|
||||
|
||||
# TEST 03: Test Dynamic Field
|
||||
def test_compute_dynamic_content(self):
|
||||
section_01 = self.test_section
|
||||
section_01.content = "${object.name}"
|
||||
self.assertEqual(
|
||||
section_01.dynamic_content,
|
||||
"<p>{" + str(section_01.id) + ": '</p><p>TestSection</p>'}",
|
||||
)
|
||||
556
agreement_legal/views/agreement.xml
Normal file
556
agreement_legal/views/agreement.xml
Normal file
@@ -0,0 +1,556 @@
|
||||
<odoo>
|
||||
|
||||
<!-- Agreement List View-->
|
||||
<record model="ir.ui.view" id="partner_agreement_list_view">
|
||||
<field name="name">Agreement List</field>
|
||||
<field name="model">agreement</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Agreements" default_order='name'>
|
||||
<field name="name" />
|
||||
<field name="partner_id" />
|
||||
<field name="company_id" />
|
||||
<field name="parent_agreement_id" />
|
||||
<field name="agreement_type_id" />
|
||||
<field name="agreement_subtype_id" />
|
||||
<field name="active" invisible="1" />
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Agreement Form View -->
|
||||
<record model="ir.ui.view" id="partner_agreement_form_view">
|
||||
<field name="name">Agreement Form</field>
|
||||
<field name="model">agreement</field>
|
||||
<field name="priority" eval="1" />
|
||||
<field name="arch" type="xml">
|
||||
<form string="Agreement">
|
||||
<header>
|
||||
<button
|
||||
string="New Version"
|
||||
type="object"
|
||||
name="create_new_version"
|
||||
class="oe_highlight"
|
||||
attrs="{'invisible': [('state', '=', 'active')]}"
|
||||
/>
|
||||
<button
|
||||
string="New Agreement"
|
||||
type="object"
|
||||
name="create_new_agreement"
|
||||
class="oe_highlight"
|
||||
attrs="{'invisible': [('is_template', '=', False)]}"
|
||||
/>
|
||||
<field
|
||||
name="stage_id"
|
||||
widget="statusbar"
|
||||
clickable="True"
|
||||
options="{'fold_field': 'fold'}"
|
||||
domain="[('stage_type', '=', 'agreement')]"
|
||||
/>
|
||||
</header>
|
||||
<sheet>
|
||||
<div class="oe_button_box" name="button_box" />
|
||||
<div class="oe_title">
|
||||
<label
|
||||
for="name"
|
||||
class="oe_edit_only"
|
||||
string="Agreement Name"
|
||||
/>
|
||||
<h1>
|
||||
<field name="name" />
|
||||
</h1>
|
||||
</div>
|
||||
<group string="General">
|
||||
<group>
|
||||
<field name="code" readonly="1" />
|
||||
<field
|
||||
name="parent_agreement_id"
|
||||
domain="[('partner_id', '=', partner_id)]"
|
||||
/>
|
||||
<field name="is_template" />
|
||||
</group>
|
||||
<group>
|
||||
<field
|
||||
name="agreement_type_id"
|
||||
widget="selection"
|
||||
required="True"
|
||||
/>
|
||||
<field
|
||||
name="agreement_subtype_id"
|
||||
widget="selection"
|
||||
domain="[('agreement_type_id', '=', agreement_type_id)]"
|
||||
/>
|
||||
<field
|
||||
name="assigned_user_id"
|
||||
attrs="{'invisible': [('is_template', '=', True)], 'readonly':[('is_template', '=', True)]}"
|
||||
/>
|
||||
<field name="active" invisible="1" />
|
||||
<field name="state" invisible="1" />
|
||||
</group>
|
||||
</group>
|
||||
<group string="Description">
|
||||
<field name="description" required="True" nolabel="1" />
|
||||
</group>
|
||||
<group class="oe_edit_only">
|
||||
<group>
|
||||
<field
|
||||
name="field_id"
|
||||
domain="[('model_id', '=', active_model),
|
||||
('ttype', '!=', 'one2many'),
|
||||
('ttype', '!=', 'many2many')]"
|
||||
/>
|
||||
<field name="sub_object_id" readonly="1" />
|
||||
<field
|
||||
name="sub_model_object_field_id"
|
||||
domain="[('model_id', '=', sub_object_id),
|
||||
('ttype', '!=', 'one2many'),
|
||||
('ttype', '!=', 'many2many')]"
|
||||
attrs="{'readonly':[('sub_object_id', '=', False)],
|
||||
'required':[('sub_object_id', '!=', False)]}"
|
||||
/>
|
||||
<field name="default_value" />
|
||||
<field name="copyvalue" />
|
||||
</group>
|
||||
<p>
|
||||
This section (on the left) allows you to add dynamic fields inside the description and special terms.
|
||||
<ol>
|
||||
<li>Select the agreement field</li>
|
||||
<li>Select the sub-field</li>
|
||||
<li>Enter the default value if the field is empty</li>
|
||||
<li
|
||||
>Copy and paste the placeholder expression in the description or the special terms</li>
|
||||
</ol>
|
||||
</p>
|
||||
</group>
|
||||
<group name="parties" string="Parties">
|
||||
<group name="cust_parties">
|
||||
<field
|
||||
name="use_parties_content"
|
||||
string="Use custom content"
|
||||
/>
|
||||
</group>
|
||||
<group name="cust_parties">
|
||||
<p>
|
||||
This section (on the left) allows you to replace the default listing of the parties with custom dynamic content.
|
||||
</p>
|
||||
</group>
|
||||
<group name="partner" string="Partner">
|
||||
<div class="o_address_format">
|
||||
<field
|
||||
name="partner_id"
|
||||
context="{'show_address': 1}"
|
||||
options="{"always_reload": True}"
|
||||
/>
|
||||
</div>
|
||||
</group>
|
||||
<group name="company" string="Company">
|
||||
<div class="o_address_format">
|
||||
<field
|
||||
name="company_id"
|
||||
readonly="1"
|
||||
context="{'show_address': 1}"
|
||||
options="{"always_reload": True}"
|
||||
/>
|
||||
</div>
|
||||
<field name="company_partner_id" invisible="1" />
|
||||
</group>
|
||||
<group name="partner_left" string="Primary Contact">
|
||||
<field
|
||||
name="partner_contact_id"
|
||||
domain="[('parent_id', '=', partner_id)]"
|
||||
nolabel="1"
|
||||
/>
|
||||
<field
|
||||
name="partner_contact_phone"
|
||||
widget="phone"
|
||||
readonly="1"
|
||||
nolabel="1"
|
||||
/>
|
||||
<field
|
||||
name="partner_contact_email"
|
||||
widget="email"
|
||||
readonly="1"
|
||||
nolabel="1"
|
||||
/>
|
||||
</group>
|
||||
<group name="contact_right" string="Primary Contact">
|
||||
<field
|
||||
name="company_contact_id"
|
||||
domain="[('parent_id', '=', company_partner_id)]"
|
||||
nolabel="1"
|
||||
/>
|
||||
<field
|
||||
name="company_contact_phone"
|
||||
widget="phone"
|
||||
readonly="1"
|
||||
nolabel="1"
|
||||
/>
|
||||
<field
|
||||
name="company_contact_email"
|
||||
widget="email"
|
||||
readonly="1"
|
||||
nolabel="1"
|
||||
/>
|
||||
</group>
|
||||
</group>
|
||||
<group
|
||||
name="parties_content"
|
||||
string="Parties Content"
|
||||
attrs="{'invisible':[('use_parties_content', '=', False)]}"
|
||||
>
|
||||
<field name="parties" nolabel="1" />
|
||||
</group>
|
||||
<group name="term_information">
|
||||
<group name="termdates_left" string="Term Dates">
|
||||
<field
|
||||
name="start_date"
|
||||
attrs="{'required': [('is_template', '=', False)], 'invisible': [('is_template', '=', True)]}"
|
||||
/>
|
||||
<field
|
||||
name="end_date"
|
||||
attrs="{'required': [('is_template', '=', False)], 'invisible': [('is_template', '=', True)]}"
|
||||
/>
|
||||
<field name="expiration_notice" />
|
||||
<field name="change_notice" />
|
||||
<field
|
||||
name="notification_address_id"
|
||||
domain="['|', ('parent_id', '=', partner_id), ('parent_id', '=', company_partner_id)]"
|
||||
/>
|
||||
<field name="termination_requested" />
|
||||
<field name="termination_date" />
|
||||
</group>
|
||||
</group>
|
||||
<group string="Special Terms">
|
||||
<field name="special_terms" nolabel="1" />
|
||||
</group>
|
||||
<notebook>
|
||||
<page name="structure" string="Structure">
|
||||
<div>
|
||||
<button
|
||||
name="%(partner_agreement_contract_document_preview)d"
|
||||
string="Preview"
|
||||
type="action"
|
||||
class="oe_highlight"
|
||||
/>
|
||||
<button
|
||||
name="%(partner_agreement_contract_document)d"
|
||||
string="Print"
|
||||
type="action"
|
||||
class="oe_highlight"
|
||||
/>
|
||||
</div>
|
||||
<separator string="Recitals" />
|
||||
<field
|
||||
name="recital_ids"
|
||||
default_order="sequence"
|
||||
nolabel="1"
|
||||
context="{'default_agreement': active_id}"
|
||||
/>
|
||||
<separator string="Sections" />
|
||||
<field
|
||||
name="sections_ids"
|
||||
default_order='sequence'
|
||||
nolabel="1"
|
||||
context="{'default_agreement': active_id}"
|
||||
/>
|
||||
<separator string="Clauses" />
|
||||
<field
|
||||
name="clauses_ids"
|
||||
default_order='clause_id, sequence'
|
||||
nolabel="1"
|
||||
context="{'default_agreement': active_id}"
|
||||
/>
|
||||
<separator string="Appendices" />
|
||||
<field
|
||||
name="appendix_ids"
|
||||
default_order='sequence'
|
||||
nolabel="1"
|
||||
context="{'default_agreement': active_id}"
|
||||
/>
|
||||
</page>
|
||||
<page name="signature" string="Signatures">
|
||||
<group>
|
||||
<group string="Partner">
|
||||
<field name="partner_signed_date" />
|
||||
<field
|
||||
name="partner_signed_user_id"
|
||||
domain="[('parent_id', '=', partner_id)]"
|
||||
/>
|
||||
</group>
|
||||
<group string="Company">
|
||||
<field name="company_signed_date" />
|
||||
<field name="company_signed_user_id" />
|
||||
<field
|
||||
name="signed_contract"
|
||||
filename="signed_contract_filename"
|
||||
/>
|
||||
<field
|
||||
name="signed_contract_filename"
|
||||
invisible="1"
|
||||
/>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
<page name="products" string="Products/Services">
|
||||
<field name="line_ids" nolabel="1">
|
||||
<tree editable="top">
|
||||
<field name="product_id" />
|
||||
<field name="name" />
|
||||
<field name="qty" />
|
||||
<field name="uom_id" groups="uom.group_uom" />
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
<page name="child_agreements" string="Child Agreements">
|
||||
<field name="child_agreements_ids">
|
||||
<tree default_order='version desc'>
|
||||
<field name="name" />
|
||||
<field name="version" />
|
||||
<field name="revision" />
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
<page name="old_versions" string="Revisions">
|
||||
<field
|
||||
name="previous_version_agreements_ids"
|
||||
string="Previouse Versions"
|
||||
>
|
||||
<tree default_order='version desc'>
|
||||
<field name="name" />
|
||||
<field name="version" />
|
||||
<field name="revision" />
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
<page name="performance" string="Performance">
|
||||
<p
|
||||
>This section is a place where financial records will show the current performance of this agreement.</p>
|
||||
<p>Perhaps include invoices with total vs costs? </p>
|
||||
</page>
|
||||
</notebook>
|
||||
<group string="Administration">
|
||||
<div>
|
||||
<p>Reviewed by <field
|
||||
name="reviewed_user_id"
|
||||
class="oe_inline"
|
||||
/> on <field
|
||||
name="reviewed_date"
|
||||
class="oe_inline"
|
||||
/>.</p>
|
||||
<p>Approved by <field
|
||||
name="approved_user_id"
|
||||
class="oe_inline"
|
||||
/> on <field
|
||||
name="approved_date"
|
||||
class="oe_inline"
|
||||
/>.</p>
|
||||
</div>
|
||||
</group>
|
||||
<footer>
|
||||
Version: <field name="version" readonly="True" />.<field
|
||||
name="revision"
|
||||
readonly="True"
|
||||
/>
|
||||
| Created By: <field name="create_uid" readonly="True" />
|
||||
| Created On: <field name="create_date" readonly="True" />
|
||||
</footer>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_follower_ids" widget="mail_followers" />
|
||||
<field name="activity_ids" widget="mail_activity" />
|
||||
<field name="message_ids" widget="mail_thread" />
|
||||
</div>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Agreement Kanban View -->
|
||||
<record id="view_project_agreement_kanban" model="ir.ui.view">
|
||||
<field name="name">Agreement Kanban</field>
|
||||
<field name="model">agreement</field>
|
||||
<field name="arch" type="xml">
|
||||
<kanban default_group_by="stage_id">
|
||||
<field name="color" />
|
||||
<field name="assigned_user_id" />
|
||||
<templates>
|
||||
<t t-name="kanban-box">
|
||||
<div
|
||||
t-attf-class="oe_kanban_color_#{kanban_getcolor(record.color.raw_value)} oe_kanban_card oe_kanban_global_click"
|
||||
>
|
||||
<div class="oe_kanban_content">
|
||||
<div class="o_kanban_record_top">
|
||||
<div class="o_kanban_record_headings">
|
||||
<strong class="o_kanban_record_title">
|
||||
<field name="name" />
|
||||
</strong><br />
|
||||
<div
|
||||
class="o_kanban_record_subtitle text-muted"
|
||||
>
|
||||
<field name="partner_id" />
|
||||
<t
|
||||
t-if="record.end_date.raw_value and record.end_date.raw_value lt (new Date())"
|
||||
t-set="red"
|
||||
>oe_kanban_text_red</t>
|
||||
<div t-attf-class="#{red || ''}">
|
||||
<i><field name="end_date" /></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="o_dropdown_kanban dropdown"
|
||||
groups="base.group_user"
|
||||
>
|
||||
<a
|
||||
role="button"
|
||||
class="dropdown-toggle btn"
|
||||
data-toggle="dropdown"
|
||||
href="#"
|
||||
>
|
||||
<span
|
||||
class="fa fa-ellipsis-v"
|
||||
aria-hidden="true"
|
||||
title="Icon"
|
||||
/>
|
||||
</a>
|
||||
<ul
|
||||
class="dropdown-menu"
|
||||
role="menu"
|
||||
aria-labelledby="dLabel"
|
||||
>
|
||||
<li t-if="widget.editable"><a
|
||||
type="edit"
|
||||
>Edit</a></li>
|
||||
<li class="divider" />
|
||||
<li
|
||||
class="dropdown-header"
|
||||
>Record's Colour</li>
|
||||
<li>
|
||||
<ul
|
||||
class="oe_kanban_colorpicker"
|
||||
data-field="color"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="o_kanban_record_body">
|
||||
<field name="agreement_type_id" /> - <field
|
||||
name="agreement_subtype_id"
|
||||
/>
|
||||
</div>
|
||||
<div class="o_kanban_record_bottom">
|
||||
<div class="oe_kanban_bottom_left">
|
||||
V: <field name="version" />
|
||||
</div>
|
||||
<div class="oe_kanban_bottom_right">
|
||||
<img
|
||||
t-att-src="kanban_image('res.users', 'image_small', record.assigned_user_id.raw_value)"
|
||||
t-att-title="record.assigned_user_id.value"
|
||||
width="36"
|
||||
height="36"
|
||||
class="oe_kanban_avatar"
|
||||
alt="user & picture"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="oe_clear" />
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
</kanban>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Agreement Search View -->
|
||||
<record model="ir.ui.view" id="partner_agreement_search_view">
|
||||
<field name="name">Agreement Search</field>
|
||||
<field name="model">agreement</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Agreement Search">
|
||||
<field name="name" />
|
||||
<field name="partner_id" />
|
||||
<field name="agreement_type_id" />
|
||||
<field name="agreement_subtype_id" />
|
||||
<filter
|
||||
name="filter_non_template"
|
||||
string="Non-Templates"
|
||||
domain="[('active','=',True),('is_template', '=', False)]"
|
||||
/>
|
||||
<filter
|
||||
name="filter_inactive"
|
||||
string="Archived"
|
||||
domain="[('active','=',False)]"
|
||||
/>
|
||||
<filter
|
||||
name="filter_templates"
|
||||
string="Templates"
|
||||
domain="[('active','=',True),('is_template', '=', True)]"
|
||||
/>
|
||||
<filter
|
||||
name="group_partner_id"
|
||||
string="Partners"
|
||||
icon="terp-partner"
|
||||
context="{'group_by':'partner_id'}"
|
||||
/>
|
||||
<filter
|
||||
name="group_status"
|
||||
string="Status"
|
||||
icon="terp-partner"
|
||||
context="{'group_by':'state'}"
|
||||
/>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Agreement Reporting -->
|
||||
<record id="agreement_graph_view" model="ir.ui.view">
|
||||
<field name="name">agreement.graph</field>
|
||||
<field name="model">agreement</field>
|
||||
<field name="arch" type="xml">
|
||||
<graph string="Agreements" type="bar">
|
||||
<field name="stage_id" type="row" />
|
||||
</graph>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="agreement_pivot_view" model="ir.ui.view">
|
||||
<field name="name">agreement.pivot</field>
|
||||
<field name="model">agreement</field>
|
||||
<field name="arch" type="xml">
|
||||
<pivot string="Agreements" display_quantity="true">
|
||||
<field name="stage_id" type="row" />
|
||||
</pivot>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_agreement_report_order" model="ir.actions.act_window">
|
||||
<field name="name">Agreements</field>
|
||||
<field name="res_model">agreement</field>
|
||||
<field name="view_mode">graph,pivot</field>
|
||||
</record>
|
||||
|
||||
<!-- actions opening views on models -->
|
||||
|
||||
<record model="ir.actions.act_window" id="agreement_dashboard_agreement">
|
||||
<field name="name">Agreements</field>
|
||||
<field name="res_model">agreement</field>
|
||||
<field name="domain">[('is_template', '=', False)]</field>
|
||||
<field name="view_mode">kanban,tree,form</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.actions.act_window" id="agreement_operations_agreement">
|
||||
<field name="name">Agreements</field>
|
||||
<field name="res_model">agreement</field>
|
||||
<field name="domain">[('is_template', '=', False)]</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.actions.act_window" id="partner_agreement_agreement_templates">
|
||||
<field name="name">Templates</field>
|
||||
<field name="res_model">agreement</field>
|
||||
<field name="domain">[('is_template', '=', True)]</field>
|
||||
<!-- <field name="context">[('is_template', '=', True)]</field> -->
|
||||
<field name="view_mode">tree,kanban,form</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
106
agreement_legal/views/agreement_appendix.xml
Normal file
106
agreement_legal/views/agreement_appendix.xml
Normal file
@@ -0,0 +1,106 @@
|
||||
<odoo>
|
||||
|
||||
<!-- Agreement Appendix List View-->
|
||||
<record model="ir.ui.view" id="agreement_appendix_tree">
|
||||
<field name="name">Agreement Appendix Tree</field>
|
||||
<field name="model">agreement.appendix</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Appendices" default_order='agreement_id, sequence'>
|
||||
<field name="sequence" widget="handle" />
|
||||
<field name="name" />
|
||||
<field name="title" />
|
||||
<field name="agreement_id" />
|
||||
<field name="active" invisible="1" />
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Agreement Appendix Form View -->
|
||||
<record model="ir.ui.view" id="agreement_appendix_form">
|
||||
<field name="name">Agreement Appendix Form</field>
|
||||
<field name="model">agreement.appendix</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Appendix">
|
||||
<sheet>
|
||||
<div class="oe_button_box" name="button_box" />
|
||||
<widget
|
||||
name="web_ribbon"
|
||||
title="Archived"
|
||||
bg_color="bg-danger"
|
||||
attrs="{'invisible': [('active', '=', True)]}"
|
||||
/>
|
||||
<field name="active" invisible="1" />
|
||||
<div class="oe_title">
|
||||
<label for="name" class="oe_edit_only" />
|
||||
<h1><field name="name" /></h1>
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
<field name="title" />
|
||||
<field name="agreement_id" />
|
||||
</group>
|
||||
<group>
|
||||
<field name="sequence" />
|
||||
</group>
|
||||
</group>
|
||||
<field name="content" widget="html" />
|
||||
<group class="oe_edit_only">
|
||||
<group>
|
||||
<field
|
||||
name="field_id"
|
||||
domain="[('model_id', '=', active_model),
|
||||
('ttype', '!=', 'one2many'),
|
||||
('ttype', '!=', 'many2many')]"
|
||||
/>
|
||||
<field name="sub_object_id" readonly="1" />
|
||||
<field
|
||||
name="sub_model_object_field_id"
|
||||
domain="[('model_id', '=', sub_object_id),
|
||||
('ttype', '!=', 'one2many'),
|
||||
('ttype', '!=', 'many2many')]"
|
||||
attrs="{'readonly':[('sub_object_id', '=', False)],
|
||||
'required':[('sub_object_id', '!=', False)]}"
|
||||
/>
|
||||
<field name="default_value" />
|
||||
<field name="copyvalue" />
|
||||
</group>
|
||||
<p>
|
||||
This section (on the left) allows you to add dynamic fields inside the content.
|
||||
<ol>
|
||||
<li>Select the appendix field</li>
|
||||
<li>Select the sub-field</li>
|
||||
<li>Enter the default value if the field is empty</li>
|
||||
<li
|
||||
>Copy and paste the placeholder expression in the content</li>
|
||||
</ol>
|
||||
</p>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Agreement Appendix Search View -->
|
||||
<record model="ir.ui.view" id="agreement_appendix_search">
|
||||
<field name="name">Agreement Appendix Search</field>
|
||||
<field name="model">agreement.appendix</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Appendix">
|
||||
<field name="name" />
|
||||
<filter
|
||||
name="group_agreement"
|
||||
icon="terp-partner"
|
||||
context="{'group_by':'agreement_id'}"
|
||||
/>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Actions opening views on models -->
|
||||
<record model="ir.actions.act_window" id="agreement_appendix_action">
|
||||
<field name="name">Appendices</field>
|
||||
<field name="res_model">agreement.appendix</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
116
agreement_legal/views/agreement_clause.xml
Normal file
116
agreement_legal/views/agreement_clause.xml
Normal file
@@ -0,0 +1,116 @@
|
||||
<odoo>
|
||||
|
||||
<!-- Agreement Clause List View-->
|
||||
<record model="ir.ui.view" id="partner_agreement_clause_list_view">
|
||||
<field name="name">Agreement Clause List</field>
|
||||
<field name="model">agreement.clause</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Clauses" default_order='agreement_id, sequence'>
|
||||
<field name="sequence" widget="handle" />
|
||||
<field name="name" />
|
||||
<field name="title" />
|
||||
<field name="agreement_id" />
|
||||
<field name="section_id" />
|
||||
<field name="active" invisible="1" />
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Agreement Clause Form View -->
|
||||
<record model="ir.ui.view" id="partner_agreement_clause_form_view">
|
||||
<field name="name">Agreement clause Form</field>
|
||||
<field name="model">agreement.clause</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Clause">
|
||||
<sheet>
|
||||
<div class="oe_button_box" name="button_box" />
|
||||
<widget
|
||||
name="web_ribbon"
|
||||
title="Archived"
|
||||
bg_color="bg-danger"
|
||||
attrs="{'invisible': [('active', '=', True)]}"
|
||||
/>
|
||||
<field name="active" invisible="1" />
|
||||
<div class="oe_title">
|
||||
<label for="name" class="oe_edit_only" />
|
||||
<h1><field name="name" /></h1>
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
<field name="title" />
|
||||
<field name="agreement_id" />
|
||||
<field
|
||||
name="section_id"
|
||||
domain="[('agreement_id', '=', agreement_id)]"
|
||||
/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="sequence" />
|
||||
</group>
|
||||
</group>
|
||||
<field name="content" widget="html" />
|
||||
<group class="oe_edit_only">
|
||||
<group>
|
||||
<field
|
||||
name="field_id"
|
||||
domain="[('model_id', '=', active_model),
|
||||
('ttype', '!=', 'one2many'),
|
||||
('ttype', '!=', 'many2many')]"
|
||||
/>
|
||||
<field name="sub_object_id" readonly="1" />
|
||||
<field
|
||||
name="sub_model_object_field_id"
|
||||
domain="[('model_id', '=', sub_object_id),
|
||||
('ttype', '!=', 'one2many'),
|
||||
('ttype', '!=', 'many2many')]"
|
||||
attrs="{'readonly':[('sub_object_id', '=', False)],
|
||||
'required':[('sub_object_id', '!=', False)]}"
|
||||
/>
|
||||
<field name="default_value" />
|
||||
<field name="copyvalue" />
|
||||
</group>
|
||||
<p>
|
||||
This section (on the left) allows you to add dynamic fields inside the content.
|
||||
<ol>
|
||||
<li>Select the clause field</li>
|
||||
<li>Select the sub-field</li>
|
||||
<li>Enter the default value if the field is empty</li>
|
||||
<li
|
||||
>Copy and paste the placeholder expression in the content</li>
|
||||
</ol>
|
||||
</p>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Agreement Clause Search View -->
|
||||
<record model="ir.ui.view" id="agreement_clause_search_view">
|
||||
<field name="name">Agreement Clause Search</field>
|
||||
<field name="model">agreement.clause</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Clause">
|
||||
<field name="name" />
|
||||
<filter
|
||||
name="group_agreement"
|
||||
icon="terp-partner"
|
||||
context="{'group_by':'agreement_id'}"
|
||||
/>
|
||||
<filter
|
||||
name="group_section"
|
||||
icon="terp-partner"
|
||||
context="{'group_by':'section_id'}"
|
||||
/>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Actions opening views on models -->
|
||||
<record model="ir.actions.act_window" id="partner_agreement_action_clause">
|
||||
<field name="name">Clauses</field>
|
||||
<field name="res_model">agreement.clause</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
44
agreement_legal/views/agreement_increasetype.xml
Normal file
44
agreement_legal/views/agreement_increasetype.xml
Normal file
@@ -0,0 +1,44 @@
|
||||
<odoo>
|
||||
|
||||
<!-- Agreement Increase Type List View-->
|
||||
<record model="ir.ui.view" id="partner_agreement_increasetype_list_view">
|
||||
<field name="name">Agreement Increase Type List</field>
|
||||
<field name="model">agreement.increasetype</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree default_order='name'>
|
||||
<field name="name" />
|
||||
<field name="description" />
|
||||
<field name="increase_percent" />
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Agreement Increase Type Form View -->
|
||||
<record model="ir.ui.view" id="partner_agreement_increasetype_form_view">
|
||||
<field name="name">Agreement Increase Type Form</field>
|
||||
<field name="model">agreement.increasetype</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Agreements Type Form">
|
||||
<sheet>
|
||||
<group>
|
||||
<field name="name" />
|
||||
</group>
|
||||
<group>
|
||||
<field name="increase_percent" />
|
||||
</group>
|
||||
<group string="Description">
|
||||
<field name="description" nolabel="1" />
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Actions opening views on models -->
|
||||
<record model="ir.actions.act_window" id="partner_agreement_action_increasetype">
|
||||
<field name="name">Agreement Increase Type</field>
|
||||
<field name="res_model">agreement.increasetype</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
106
agreement_legal/views/agreement_recital.xml
Normal file
106
agreement_legal/views/agreement_recital.xml
Normal file
@@ -0,0 +1,106 @@
|
||||
<odoo>
|
||||
|
||||
<!-- Agreement Recital List View-->
|
||||
<record model="ir.ui.view" id="agreement_recital_tree">
|
||||
<field name="name">Agreement Recital Tree</field>
|
||||
<field name="model">agreement.recital</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Recitals" default_order='agreement_id, sequence'>
|
||||
<field name="sequence" widget="handle" />
|
||||
<field name="name" />
|
||||
<field name="title" />
|
||||
<field name="agreement_id" />
|
||||
<field name="active" invisible="1" />
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Agreement Recital Form View -->
|
||||
<record model="ir.ui.view" id="agreement_recital_form">
|
||||
<field name="name">Agreement Recital Form</field>
|
||||
<field name="model">agreement.recital</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Recital">
|
||||
<sheet>
|
||||
<div class="oe_button_box" name="button_box" />
|
||||
<widget
|
||||
name="web_ribbon"
|
||||
title="Archived"
|
||||
bg_color="bg-danger"
|
||||
attrs="{'invisible': [('active', '=', True)]}"
|
||||
/>
|
||||
<field name="active" invisible="1" />
|
||||
<div class="oe_title">
|
||||
<label for="name" class="oe_edit_only" />
|
||||
<h1><field name="name" /></h1>
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
<field name="title" />
|
||||
<field name="agreement_id" />
|
||||
</group>
|
||||
<group>
|
||||
<field name="sequence" />
|
||||
</group>
|
||||
</group>
|
||||
<field name="content" widget="html" />
|
||||
<group class="oe_edit_only">
|
||||
<group>
|
||||
<field
|
||||
name="field_id"
|
||||
domain="[('model_id', '=', active_model),
|
||||
('ttype', '!=', 'one2many'),
|
||||
('ttype', '!=', 'many2many')]"
|
||||
/>
|
||||
<field name="sub_object_id" readonly="1" />
|
||||
<field
|
||||
name="sub_model_object_field_id"
|
||||
domain="[('model_id', '=', sub_object_id),
|
||||
('ttype', '!=', 'one2many'),
|
||||
('ttype', '!=', 'many2many')]"
|
||||
attrs="{'readonly':[('sub_object_id', '=', False)],
|
||||
'required':[('sub_object_id', '!=', False)]}"
|
||||
/>
|
||||
<field name="default_value" />
|
||||
<field name="copyvalue" />
|
||||
</group>
|
||||
<p>
|
||||
This section (on the left) allows you to add dynamic fields inside the content.
|
||||
<ol>
|
||||
<li>Select the recital field</li>
|
||||
<li>Select the sub-field</li>
|
||||
<li>Enter the default value if the field is empty</li>
|
||||
<li
|
||||
>Copy and paste the placeholder expression in the content</li>
|
||||
</ol>
|
||||
</p>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Agreement Recital Search View -->
|
||||
<record model="ir.ui.view" id="agreement_recital_search">
|
||||
<field name="name">Agreement Recital Search</field>
|
||||
<field name="model">agreement.recital</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Recitals">
|
||||
<field name="name" />
|
||||
<filter
|
||||
name="group_agreement"
|
||||
icon="terp-partner"
|
||||
context="{'group_by':'agreement_id'}"
|
||||
/>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Actions opening views on models -->
|
||||
<record model="ir.actions.act_window" id="agreement_recital_action">
|
||||
<field name="name">Recitals</field>
|
||||
<field name="res_model">agreement.recital</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
40
agreement_legal/views/agreement_renewaltype.xml
Normal file
40
agreement_legal/views/agreement_renewaltype.xml
Normal file
@@ -0,0 +1,40 @@
|
||||
<odoo>
|
||||
|
||||
<!-- Agreement Renewal Type List View-->
|
||||
<record model="ir.ui.view" id="partner_agreement_renewaltype_list_view">
|
||||
<field name="name">Agreement Renewal Type List</field>
|
||||
<field name="model">agreement.renewaltype</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree default_order='name'>
|
||||
<field name="name" />
|
||||
<field name="description" />
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Agreement Renewal Type Form View -->
|
||||
<record model="ir.ui.view" id="partner_agreement_renewaltype_form_view">
|
||||
<field name="name">Agreement Renewal Type Form</field>
|
||||
<field name="model">agreement.renewaltype</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Agreements Type Form">
|
||||
<sheet>
|
||||
<group>
|
||||
<field name="name" />
|
||||
</group>
|
||||
<group string="Description">
|
||||
<field name="description" nolabel="1" />
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Actions opening views on models -->
|
||||
<record model="ir.actions.act_window" id="partner_agreement_action_renewaltype">
|
||||
<field name="name">Agreement Renewal Type</field>
|
||||
<field name="res_model">agreement.renewaltype</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
125
agreement_legal/views/agreement_section.xml
Normal file
125
agreement_legal/views/agreement_section.xml
Normal file
@@ -0,0 +1,125 @@
|
||||
<odoo>
|
||||
|
||||
<!-- Agreement Sections List View-->
|
||||
<record model="ir.ui.view" id="partner_agreement_section_list_view">
|
||||
<field name="name">Agreement Section List</field>
|
||||
<field name="model">agreement.section</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Sections" default_order='agreement_id, sequence'>
|
||||
<field name="sequence" widget="handle" />
|
||||
<field name="name" />
|
||||
<field name="title" />
|
||||
<field name="agreement_id" />
|
||||
<field name="active" invisible="1" />
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Agreement Sections Form View -->
|
||||
<record model="ir.ui.view" id="partner_agreement_section_form_view">
|
||||
<field name="name">Agreement Section Form</field>
|
||||
<field name="model">agreement.section</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Section">
|
||||
<sheet>
|
||||
<div class="oe_button_box" name="button_box" />
|
||||
<widget
|
||||
name="web_ribbon"
|
||||
title="Archived"
|
||||
bg_color="bg-danger"
|
||||
attrs="{'invisible': [('active', '=', True)]}"
|
||||
/>
|
||||
<field name="active" invisible="1" />
|
||||
<div class="oe_title">
|
||||
<label for="name" class="oe_edit_only" />
|
||||
<h1><field name="name" /></h1>
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
<field name="title" />
|
||||
<field name="agreement_id" />
|
||||
</group>
|
||||
<group>
|
||||
<field name="sequence" />
|
||||
</group>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="Content">
|
||||
<field name='content' nolabel="1" />
|
||||
<group class="oe_edit_only">
|
||||
<group>
|
||||
<field
|
||||
name="field_id"
|
||||
domain="[('model_id', '=', active_model),
|
||||
('ttype', '!=', 'one2many'),
|
||||
('ttype', '!=', 'many2many')]"
|
||||
/>
|
||||
<field name="sub_object_id" readonly="1" />
|
||||
<field
|
||||
name="sub_model_object_field_id"
|
||||
domain="[('model_id', '=', sub_object_id),
|
||||
('ttype', '!=', 'one2many'),
|
||||
('ttype', '!=', 'many2many')]"
|
||||
attrs="{'readonly':[('sub_object_id', '=', False)],
|
||||
'required':[('sub_object_id', '!=', False)]}"
|
||||
/>
|
||||
<field name="default_value" />
|
||||
<field name="copyvalue" />
|
||||
</group>
|
||||
<p>
|
||||
This section (on the left) allows you to add dynamic fields inside the content.
|
||||
<ol>
|
||||
<li>Select the section field</li>
|
||||
<li>Select the sub-field</li>
|
||||
<li
|
||||
>Enter the default value if the field is empty</li>
|
||||
<li
|
||||
>Copy and paste the placeholder expression in the content</li>
|
||||
</ol>
|
||||
</p>
|
||||
</group>
|
||||
</page>
|
||||
<page string="Clauses">
|
||||
<field
|
||||
name="clauses_ids"
|
||||
nolabel="1"
|
||||
context="{'default_section_id': active_id, 'default_agreement_id': agreement_id}"
|
||||
>
|
||||
<tree>
|
||||
<field name="sequence" widget="handle" />
|
||||
<field name="name" />
|
||||
<field name="title" />
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Agreement Section Search View -->
|
||||
<record model="ir.ui.view" id="partner_agreement_section_search_view">
|
||||
<field name="name">Agreement Section Search</field>
|
||||
<field name="model">agreement.section</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Section">
|
||||
<field name="name" />
|
||||
<filter
|
||||
name="group_agreement"
|
||||
string="Agreements"
|
||||
icon="terp-partner"
|
||||
context="{'group_by':'agreement_id'}"
|
||||
/>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Actions opening views on models -->
|
||||
<record model="ir.actions.act_window" id="partner_agreement_action_section">
|
||||
<field name="name">Agreement Sections</field>
|
||||
<field name="res_model">agreement.section</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
44
agreement_legal/views/agreement_stages.xml
Normal file
44
agreement_legal/views/agreement_stages.xml
Normal file
@@ -0,0 +1,44 @@
|
||||
<odoo>
|
||||
|
||||
<!-- Agreement Stage List View-->
|
||||
<record model="ir.ui.view" id="partner_agreement_stage_list_view">
|
||||
<field name="name">Agreement Stage List</field>
|
||||
<field name="model">agreement.stage</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree default_order='sequence, name'>
|
||||
<field name="sequence" widget="handle" />
|
||||
<field name="name" string="Stage Name" />
|
||||
<field name="stage_type" />
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Agreement Stage Form View -->
|
||||
<record model="ir.ui.view" id="partner_agreement_stage_form_view">
|
||||
<field name="name">Agreement Stage Form</field>
|
||||
<field name="model">agreement.stage</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Agreements Stage Form">
|
||||
<sheet>
|
||||
<div class="oe_title">
|
||||
<label for="name" class="oe_edit_only" string="Stage Name" />
|
||||
<h1><field name="name" string="Stage Name" /></h1>
|
||||
</div>
|
||||
<group>
|
||||
<field name="sequence" />
|
||||
<field name="stage_type" />
|
||||
<field name="fold" />
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Actions opening views on models -->
|
||||
<record model="ir.actions.act_window" id="partner_agreement_action_stage">
|
||||
<field name="name">Agreement Stage</field>
|
||||
<field name="res_model">agreement.stage</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
44
agreement_legal/views/agreement_subtype.xml
Normal file
44
agreement_legal/views/agreement_subtype.xml
Normal file
@@ -0,0 +1,44 @@
|
||||
<odoo>
|
||||
|
||||
<!-- Agreement Sub Type List View-->
|
||||
<record model="ir.ui.view" id="partner_agreement_subtype_list_view">
|
||||
<field name="name">Agreement Subtype List</field>
|
||||
<field name="model">agreement.subtype</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree default_order='name'>
|
||||
<field name="name" string="Sub-Type Name" />
|
||||
<field name="agreement_type_id" string="Agreement Type" />
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Agreement Sub Type Form View -->
|
||||
<record model="ir.ui.view" id="partner_agreement_subtype_form_view">
|
||||
<field name="name">Agreement Sub Type Form</field>
|
||||
<field name="model">agreement.subtype</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Agreement Sub-Types">
|
||||
<sheet>
|
||||
<div class="oe_title">
|
||||
<label for="name" class="oe_edit_only" />
|
||||
<h1><field name="name" /></h1>
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
<field name="agreement_type_id" />
|
||||
</group>
|
||||
<group />
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Actions opening views on models -->
|
||||
<record model="ir.actions.act_window" id="partner_agreement_action_subtype">
|
||||
<field name="name">Agreement Sub-Types</field>
|
||||
<field name="res_model">agreement.subtype</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
38
agreement_legal/views/agreement_type.xml
Normal file
38
agreement_legal/views/agreement_type.xml
Normal file
@@ -0,0 +1,38 @@
|
||||
<odoo>
|
||||
|
||||
<!-- Agreement Type List View-->
|
||||
<record model="ir.ui.view" id="partner_agreement_type_list_view">
|
||||
<field name="name">Agreement Type List</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="after">
|
||||
<field name="agreement_subtypes_ids" string="Sub-Types" />
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Agreement Type Form View -->
|
||||
<record model="ir.ui.view" id="partner_agreement_type_form_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" position="inside">
|
||||
<field name="agreement_subtypes_ids" nolabel="1">
|
||||
<tree editable="bottom">
|
||||
<field name="name" />
|
||||
</tree>
|
||||
</field>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Actions opening views on models -->
|
||||
<record model="ir.actions.act_window" id="partner_agreement_action_type">
|
||||
<field name="name">Agreement Types</field>
|
||||
<field name="res_model">agreement.type</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
167
agreement_legal/views/menu.xml
Normal file
167
agreement_legal/views/menu.xml
Normal file
@@ -0,0 +1,167 @@
|
||||
<odoo>
|
||||
<!-- Remove top menu from agreement module -->
|
||||
<!-- <delete model="ir.ui.menu" id="agreement.agreement_menu" /> -->
|
||||
|
||||
<!-- Top menu item -->
|
||||
<menuitem
|
||||
name="Agreements"
|
||||
id="agreement.agreement_menu"
|
||||
web_icon="agreement_legal,static/description/icon.png"
|
||||
sequence="80"
|
||||
action="agreement_dashboard_agreement"
|
||||
groups="agreement_legal.group_agreement_readonly"
|
||||
/>
|
||||
<!-- Dashboard -->
|
||||
<menuitem
|
||||
name="Dashboard"
|
||||
id="agreement_dashboard"
|
||||
parent="agreement.agreement_menu"
|
||||
sequence="10"
|
||||
/>
|
||||
<menuitem
|
||||
name="Agreements"
|
||||
id="dashboard_agreements"
|
||||
parent="agreement_dashboard"
|
||||
sequence="10"
|
||||
action="agreement_dashboard_agreement"
|
||||
/>
|
||||
|
||||
<!-- Operations -->
|
||||
<menuitem
|
||||
name="Operations"
|
||||
id="agreement_operations"
|
||||
parent="agreement.agreement_menu"
|
||||
sequence="20"
|
||||
/>
|
||||
<menuitem
|
||||
name="Agreements"
|
||||
id="operations_agreements"
|
||||
parent="agreement_operations"
|
||||
sequence="10"
|
||||
action="agreement_operations_agreement"
|
||||
/>
|
||||
|
||||
<!-- Master Data -->
|
||||
<menuitem
|
||||
name="Master Data"
|
||||
id="agreement_masterdata"
|
||||
parent="agreement.agreement_menu"
|
||||
sequence="30"
|
||||
/>
|
||||
<menuitem
|
||||
name="Contents"
|
||||
id="agreement_data_contents"
|
||||
parent="agreement_masterdata"
|
||||
sequence="10"
|
||||
/>
|
||||
<menuitem
|
||||
name="Recitals"
|
||||
id="agreement_recitals"
|
||||
parent="agreement_data_contents"
|
||||
sequence="10"
|
||||
action="agreement_recital_action"
|
||||
/>
|
||||
<menuitem
|
||||
name="Clauses"
|
||||
id="agreement_clauses"
|
||||
parent="agreement_data_contents"
|
||||
sequence="20"
|
||||
action="partner_agreement_action_clause"
|
||||
/>
|
||||
<menuitem
|
||||
name="Sections"
|
||||
id="agreement_sections"
|
||||
parent="agreement_data_contents"
|
||||
sequence="30"
|
||||
action="partner_agreement_action_section"
|
||||
/>
|
||||
<menuitem
|
||||
name="Appendices"
|
||||
id="agreement_appendices"
|
||||
parent="agreement_data_contents"
|
||||
sequence="40"
|
||||
action="agreement_appendix_action"
|
||||
/>
|
||||
<menuitem
|
||||
name="Products"
|
||||
id="agreement_products"
|
||||
sequence="100"
|
||||
parent="agreement_masterdata"
|
||||
action="product.product_template_action"
|
||||
/>
|
||||
|
||||
<!-- Reporting -->
|
||||
<menuitem
|
||||
name="Reporting"
|
||||
id="agreement_reporting"
|
||||
sequence="40"
|
||||
parent="agreement.agreement_menu"
|
||||
groups="agreement_legal.group_agreement_manager"
|
||||
/>
|
||||
|
||||
<menuitem
|
||||
name="Agreements"
|
||||
id="agreement_agreement_reporting"
|
||||
sequence="10"
|
||||
parent="agreement_reporting"
|
||||
action="action_agreement_report_order"
|
||||
/>
|
||||
|
||||
<!-- Configuration -->
|
||||
<menuitem
|
||||
name="Configuration"
|
||||
id="agreement_configuration"
|
||||
sequence="50"
|
||||
parent="agreement.agreement_menu"
|
||||
groups="agreement_legal.group_agreement_manager"
|
||||
/>
|
||||
<menuitem
|
||||
name="Settings"
|
||||
id="agreement_settings"
|
||||
sequence="10"
|
||||
parent="agreement_configuration"
|
||||
action="agreement_legal.action_agreement_config"
|
||||
/>
|
||||
<menuitem
|
||||
name="Templates"
|
||||
id="template"
|
||||
parent="agreement_configuration"
|
||||
sequence="20"
|
||||
action="partner_agreement_agreement_templates"
|
||||
/>
|
||||
<menuitem
|
||||
name="Renewal Types"
|
||||
id="agreement_renewaltype"
|
||||
parent="agreement_configuration"
|
||||
sequence="30"
|
||||
action="partner_agreement_action_renewaltype"
|
||||
/>
|
||||
<menuitem
|
||||
name="Increase Types"
|
||||
id="agreement_increamenttypes"
|
||||
parent="agreement_configuration"
|
||||
sequence="31"
|
||||
action="partner_agreement_action_increasetype"
|
||||
/>
|
||||
<menuitem
|
||||
name="Stages"
|
||||
id="agreement_stages"
|
||||
parent="agreement_configuration"
|
||||
sequence="40"
|
||||
action="partner_agreement_action_stage"
|
||||
/>
|
||||
<menuitem
|
||||
name="Types"
|
||||
id="agreement_types"
|
||||
parent="agreement_configuration"
|
||||
sequence="50"
|
||||
action="partner_agreement_action_type"
|
||||
/>
|
||||
<menuitem
|
||||
name="Sub-Types"
|
||||
id="agreement_subtypes"
|
||||
parent="agreement_configuration"
|
||||
sequence="60"
|
||||
action="partner_agreement_action_subtype"
|
||||
/>
|
||||
</odoo>
|
||||
195
agreement_legal/views/res_config_settings.xml
Normal file
195
agreement_legal/views/res_config_settings.xml
Normal file
@@ -0,0 +1,195 @@
|
||||
<odoo>
|
||||
|
||||
<record id="res_config_settings_view_form" model="ir.ui.view">
|
||||
<field name="name">res.config.settings.view.form.agreement</field>
|
||||
<field name="model">res.config.settings</field>
|
||||
<field name="priority" eval="40" />
|
||||
<field name="inherit_id" ref="base.res_config_settings_view_form" />
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//div[hasclass('settings')]" position="inside">
|
||||
<div
|
||||
class="app_settings_block"
|
||||
data-string="Agreements"
|
||||
string="Agreements"
|
||||
data-key="agreement_legal"
|
||||
groups="agreement_legal.group_agreement_manager"
|
||||
>
|
||||
<h2>Operations</h2>
|
||||
<div class="row mt16 o_settings_container">
|
||||
<div class="col-xs-12 col-md-6 o_setting_box">
|
||||
<div class="o_setting_left_pane">
|
||||
<field name="group_uom" />
|
||||
</div>
|
||||
<div class="o_setting_right_pane">
|
||||
<label for="group_uom" />
|
||||
<div class="text-muted">
|
||||
Sell and purchase products in different units of measure
|
||||
</div>
|
||||
<div class="content-group">
|
||||
<div
|
||||
class="mt16"
|
||||
attrs="{'invisible': [('group_uom', '=', False)]}"
|
||||
>
|
||||
<button
|
||||
name="%(uom.product_uom_form_action)d"
|
||||
icon="fa-arrow-right"
|
||||
type="action"
|
||||
string="Units Of Measure"
|
||||
class="btn-link"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<h2>Advanced Features</h2>
|
||||
<div class="row mt16 o_settings_container">
|
||||
<div class="col-xs-12 col-md-6 o_setting_box">
|
||||
<div class="o_setting_left_pane">
|
||||
<field name="module_agreement_sale" />
|
||||
</div>
|
||||
<div class="o_setting_right_pane">
|
||||
<label for="module_agreement_sale" string="Sales" />
|
||||
<div class="text-muted">
|
||||
Create an agreement when the sales order is confirmed
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="col-xs-12 col-md-6 o_setting_box"
|
||||
attrs="{'invisible': [('module_agreement_sale', '!=', True)]}"
|
||||
>
|
||||
<div class="o_setting_left_pane">
|
||||
<field name="module_agreement_sale_subscription" />
|
||||
</div>
|
||||
<div class="o_setting_right_pane">
|
||||
<label
|
||||
for="module_agreement_sale_subscription"
|
||||
string="Sale Subscriptions"
|
||||
/>
|
||||
<div class="text-muted">
|
||||
Link your subscriptions to an agreement
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-12 col-md-6 o_setting_box">
|
||||
<div class="o_setting_left_pane">
|
||||
<field name="module_fieldservice_agreement" />
|
||||
</div>
|
||||
<div class="o_setting_right_pane">
|
||||
<label
|
||||
for="module_fieldservice_agreement"
|
||||
string="Field Service"
|
||||
/>
|
||||
<div class="text-muted">
|
||||
Link your Field Service orders and equipments to an agreement
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-12 col-md-6 o_setting_box">
|
||||
<div class="o_setting_left_pane">
|
||||
<field name="module_agreement_stock" />
|
||||
</div>
|
||||
<div class="o_setting_right_pane">
|
||||
<label
|
||||
for="module_agreement_stock"
|
||||
string="Inventory"
|
||||
/>
|
||||
<div class="text-muted">
|
||||
Link your transfers to an agreement
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-12 col-md-6 o_setting_box">
|
||||
<div class="o_setting_left_pane">
|
||||
<field name="module_agreement_rma" />
|
||||
</div>
|
||||
<div class="o_setting_right_pane">
|
||||
<label for="module_agreement_rma" string="Returns" />
|
||||
<div class="text-muted">
|
||||
Link your returns to an agreement
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-12 col-md-6 o_setting_box">
|
||||
<div class="o_setting_left_pane">
|
||||
<field name="module_agreement_maintenance" />
|
||||
</div>
|
||||
<div class="o_setting_right_pane">
|
||||
<label
|
||||
for="module_agreement_maintenance"
|
||||
string="Maintenance"
|
||||
/>
|
||||
<div class="text-muted">
|
||||
Manage maintenance agreements and contracts
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-12 col-md-6 o_setting_box">
|
||||
<div class="o_setting_left_pane">
|
||||
<field name="module_agreement_mrp" />
|
||||
</div>
|
||||
<div class="o_setting_right_pane">
|
||||
<label
|
||||
for="module_agreement_mrp"
|
||||
string="Manufacturing"
|
||||
/>
|
||||
<div class="text-muted">
|
||||
Link your manufacturing orders to an agreement
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-12 col-md-6 o_setting_box">
|
||||
<div class="o_setting_left_pane">
|
||||
<field name="module_agreement_repair" />
|
||||
</div>
|
||||
<div class="o_setting_right_pane">
|
||||
<label for="module_agreement_repair" string="Repair" />
|
||||
<div class="text-muted">
|
||||
Link your repair orders to an agreement
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-12 col-md-6 o_setting_box">
|
||||
<div class="o_setting_left_pane">
|
||||
<field name="module_agreement_project" />
|
||||
</div>
|
||||
<div class="o_setting_right_pane">
|
||||
<label
|
||||
for="module_agreement_project"
|
||||
string="Project"
|
||||
/>
|
||||
<div class="text-muted">
|
||||
Link your projects and tasks to an agreement
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-12 col-md-6 o_setting_box">
|
||||
<div class="o_setting_left_pane">
|
||||
<field name="module_agreement_helpdesk" />
|
||||
</div>
|
||||
<div class="o_setting_right_pane">
|
||||
<label
|
||||
for="module_agreement_helpdesk"
|
||||
string="Helpdesk"
|
||||
/>
|
||||
<div class="text-muted">
|
||||
Link your Helpdesk tickets to an agreement
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_agreement_config" model="ir.actions.act_window">
|
||||
<field name="name">Settings</field>
|
||||
<field name="res_model">res.config.settings</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">inline</field>
|
||||
<field name="context">{'module': 'agreement'}</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
17
agreement_legal/views/res_partner.xml
Normal file
17
agreement_legal/views/res_partner.xml
Normal file
@@ -0,0 +1,17 @@
|
||||
<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="after">
|
||||
<page name="agreement" string="Agreements">
|
||||
<group>
|
||||
<field name="agreement_ids" nolabel="1" />
|
||||
</group>
|
||||
</page>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
Reference in New Issue
Block a user