[IMP] : black, isort, prettier

This commit is contained in:
Pedro M. Baeza
2020-07-13 18:28:03 +02:00
committed by Francisco Ivan Anton Prieto
parent 15423b63cd
commit a2f71595bf
46 changed files with 2703 additions and 2811 deletions

View File

@@ -8,42 +8,42 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{ {
'name': 'Recurring - Contracts Management', "name": "Recurring - Contracts Management",
'version': '12.0.7.2.2', "version": "12.0.7.2.2",
'category': 'Contract Management', "category": "Contract Management",
'license': 'AGPL-3', "license": "AGPL-3",
'author': "OpenERP SA, " "author": "OpenERP SA, "
"Tecnativa, " "Tecnativa, "
"LasLabs, " "LasLabs, "
"Odoo Community Association (OCA)", "Odoo Community Association (OCA)",
'website': 'https://github.com/oca/contract', "website": "https://github.com/oca/contract",
'depends': ['base', 'account', 'product'], "depends": ["base", "account", "product"],
"external_dependencies": {"python": ["dateutil"]}, "external_dependencies": {"python": ["dateutil"]},
'data': [ "data": [
'security/groups.xml', "security/groups.xml",
'security/contract_tag.xml', "security/contract_tag.xml",
'security/ir.model.access.csv', "security/ir.model.access.csv",
'security/contract_security.xml', "security/contract_security.xml",
'security/contract_terminate_reason.xml', "security/contract_terminate_reason.xml",
'report/report_contract.xml', "report/report_contract.xml",
'report/contract_views.xml', "report/contract_views.xml",
'data/contract_cron.xml', "data/contract_cron.xml",
'data/contract_renew_cron.xml', "data/contract_renew_cron.xml",
'data/mail_template.xml', "data/mail_template.xml",
'data/ir_ui_menu.xml', "data/ir_ui_menu.xml",
'wizards/contract_line_wizard.xml', "wizards/contract_line_wizard.xml",
'wizards/contract_manually_create_invoice.xml', "wizards/contract_manually_create_invoice.xml",
'wizards/contract_contract_terminate.xml', "wizards/contract_contract_terminate.xml",
'views/contract_tag.xml', "views/contract_tag.xml",
'views/assets.xml', "views/assets.xml",
'views/abstract_contract_line.xml', "views/abstract_contract_line.xml",
'views/contract.xml', "views/contract.xml",
'views/contract_line.xml', "views/contract_line.xml",
'views/contract_template.xml', "views/contract_template.xml",
'views/contract_template_line.xml', "views/contract_template_line.xml",
'views/res_partner_view.xml', "views/res_partner_view.xml",
'views/res_config_settings.xml', "views/res_config_settings.xml",
'views/contract_terminate_reason.xml', "views/contract_terminate_reason.xml",
], ],
'installable': True, "installable": True,
} }

View File

@@ -1,9 +1,8 @@
<?xml version="1.0" encoding='UTF-8'?> <?xml version="1.0" encoding='UTF-8' ?>
<odoo noupdate="1"> <odoo noupdate="1">
<record model="ir.cron" id="contract_cron_for_invoice"> <record model="ir.cron" id="contract_cron_for_invoice">
<field name="name">Generate Recurring Invoices from Contracts</field> <field name="name">Generate Recurring Invoices from Contracts</field>
<field name="model_id" ref="model_contract_contract"/> <field name="model_id" ref="model_contract_contract" />
<field name="state">code</field> <field name="state">code</field>
<field name="code">model.cron_recurring_create_invoice()</field> <field name="code">model.cron_recurring_create_invoice()</field>
<field name="user_id" ref="base.user_root" /> <field name="user_id" ref="base.user_root" />
@@ -12,5 +11,4 @@
<field name="numbercall">-1</field> <field name="numbercall">-1</field>
<field eval="False" name="doall" /> <field eval="False" name="doall" />
</record> </record>
</odoo> </odoo>

View File

@@ -1,9 +1,8 @@
<?xml version="1.0" encoding='UTF-8'?> <?xml version="1.0" encoding='UTF-8' ?>
<odoo noupdate="1"> <odoo noupdate="1">
<record model="ir.cron" id="contract_line_cron_for_renew"> <record model="ir.cron" id="contract_line_cron_for_renew">
<field name="name">Renew Contract lines</field> <field name="name">Renew Contract lines</field>
<field name="model_id" ref="model_contract_line"/> <field name="model_id" ref="model_contract_line" />
<field name="state">code</field> <field name="state">code</field>
<field name="code">model.cron_renew_contract_line()</field> <field name="code">model.cron_renew_contract_line()</field>
<field name="user_id" ref="base.user_root" /> <field name="user_id" ref="base.user_root" />
@@ -12,5 +11,4 @@
<field name="numbercall">-1</field> <field name="numbercall">-1</field>
<field eval="False" name="doall" /> <field eval="False" name="doall" />
</record> </record>
</odoo> </odoo>

View File

@@ -1,10 +1,9 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8" ?>
<odoo> <odoo>
<menuitem
<menuitem id="menu_config_contract" id="menu_config_contract"
name="Contracts" name="Contracts"
sequence="1" sequence="1"
parent="account.menu_finance_configuration" parent="account.menu_finance_configuration"
/> />
</odoo> </odoo>

View File

@@ -1,17 +1,22 @@
<?xml version="1.0" ?> <?xml version="1.0" ?>
<odoo noupdate="1"> <odoo noupdate="1">
<record id="email_contract_template" model="mail.template"> <record id="email_contract_template" model="mail.template">
<field name="name">Email Contract Template</field> <field name="name">Email Contract Template</field>
<field name="email_from">${(object.user_id.email and '%s &lt;%s&gt;' % (object.user_id.name, object.user_id.email) or '')|safe}</field> <field
<field name="subject">${object.company_id.name} Contract (Ref ${object.name or 'n/a'})</field> name="email_from"
>${(object.user_id.email and '%s &lt;%s&gt;' % (object.user_id.name, object.user_id.email) or '')|safe}</field>
<field
name="subject"
>${object.company_id.name} Contract (Ref ${object.name or 'n/a'})</field>
<field name="partner_to">${object.partner_id.id}</field> <field name="partner_to">${object.partner_id.id}</field>
<field name="model_id" ref="model_contract_contract"/> <field name="model_id" ref="model_contract_contract" />
<field name="auto_delete" eval="True"/> <field name="auto_delete" eval="True" />
<field name="report_template" ref="contract.report_contract"/> <field name="report_template" ref="contract.report_contract" />
<field name="report_name">Contract</field> <field name="report_name">Contract</field>
<field name="lang">${object.partner_id.lang}</field> <field name="lang">${object.partner_id.lang}</field>
<field name="body_html"><![CDATA[ <field
name="body_html"
><![CDATA[
<div style="font-family: 'Lucida Grande', Ubuntu, Arial, Verdana, sans-serif; font-size: 12px; color: rgb(34, 34, 34); background-color: #FFF; "> <div style="font-family: 'Lucida Grande', Ubuntu, Arial, Verdana, sans-serif; font-size: 12px; color: rgb(34, 34, 34); background-color: #FFF; ">
<p>Hello ${object.partner_id.name or ''},</p> <p>Hello ${object.partner_id.name or ''},</p>
<p>A new contract has been created: </p> <p>A new contract has been created: </p>
@@ -60,5 +65,4 @@
</div> </div>
]]></field> ]]></field>
</record> </record>
</odoo> </odoo>

View File

@@ -4,6 +4,7 @@
import logging import logging
from openupgradelib import openupgrade from openupgradelib import openupgrade
from odoo.tools import parse_version from odoo.tools import parse_version
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
@@ -11,22 +12,20 @@ _logger = logging.getLogger(__name__)
def _update_no_update_ir_cron(env): def _update_no_update_ir_cron(env):
# Update ir.cron # Update ir.cron
env.ref('contract.contract_cron_for_invoice').model_id = env.ref( env.ref("contract.contract_cron_for_invoice").model_id = env.ref(
'contract.model_contract_contract' "contract.model_contract_contract"
) )
env.ref('contract.contract_line_cron_for_renew').model_id = env.ref( env.ref("contract.contract_line_cron_for_renew").model_id = env.ref(
'contract.model_contract_line' "contract.model_contract_line"
) )
env.ref('contract.email_contract_template').model_id = env.ref( env.ref("contract.email_contract_template").model_id = env.ref(
'contract.model_contract_contract' "contract.model_contract_contract"
) )
def _init_last_date_invoiced_on_contract_lines(env): def _init_last_date_invoiced_on_contract_lines(env):
_logger.info("init last_date_invoiced field for contract lines") _logger.info("init last_date_invoiced field for contract lines")
contract_lines = env["contract.line"].search( contract_lines = env["contract.line"].search([("recurring_next_date", "!=", False)])
[("recurring_next_date", "!=", False)]
)
contract_lines._init_last_date_invoiced() contract_lines._init_last_date_invoiced()
@@ -43,7 +42,8 @@ def assign_salesman(env):
will have admin as responsible. will have admin as responsible.
""" """
openupgrade.logged_query( openupgrade.logged_query(
env.cr, """ env.cr,
"""
UPDATE contract_contract cc UPDATE contract_contract cc
SET user_id = rp.user_id SET user_id = rp.user_id
FROM res_partner rp FROM res_partner rp
@@ -54,7 +54,7 @@ def assign_salesman(env):
@openupgrade.migrate() @openupgrade.migrate()
def migrate(env, version): def migrate(env, version):
_update_no_update_ir_cron(env) _update_no_update_ir_cron(env)
if parse_version(version) < parse_version('12.0.2.0.0'): if parse_version(version) < parse_version("12.0.2.0.0"):
# We check the version here as this post-migration script was in # We check the version here as this post-migration script was in
# 12.0.2.0.0 and already done for those who used the module when # 12.0.2.0.0 and already done for those who used the module when
# it was a PR # it was a PR

View File

@@ -11,62 +11,51 @@ _logger = logging.getLogger(__name__)
models_to_rename = [ models_to_rename = [
# Contract Line Wizard # Contract Line Wizard
('account.analytic.invoice.line.wizard', 'contract.line.wizard'), ("account.analytic.invoice.line.wizard", "contract.line.wizard"),
# Abstract Contract # Abstract Contract
('account.abstract.analytic.contract', 'contract.abstract.contract'), ("account.abstract.analytic.contract", "contract.abstract.contract"),
# Abstract Contract Line # Abstract Contract Line
( ("account.abstract.analytic.contract.line", "contract.abstract.contract.line",),
'account.abstract.analytic.contract.line',
'contract.abstract.contract.line',
),
# Contract Line # Contract Line
('account.analytic.invoice.line', 'contract.line'), ("account.analytic.invoice.line", "contract.line"),
# Contract Template # Contract Template
('account.analytic.contract', 'contract.template'), ("account.analytic.contract", "contract.template"),
# Contract Template Line # Contract Template Line
('account.analytic.contract.line', 'contract.template.line'), ("account.analytic.contract.line", "contract.template.line"),
] ]
tables_to_rename = [ tables_to_rename = [
# Contract Line # Contract Line
('account_analytic_invoice_line', 'contract_line'), ("account_analytic_invoice_line", "contract_line"),
# Contract Template # Contract Template
('account_analytic_contract', 'contract_template'), ("account_analytic_contract", "contract_template"),
# Contract Template Line # Contract Template Line
('account_analytic_contract_line', 'contract_template_line'), ("account_analytic_contract_line", "contract_template_line"),
] ]
columns_to_copy = { columns_to_copy = {
'contract_line': [ "contract_line": [("analytic_account_id", "contract_id", None),],
('analytic_account_id', 'contract_id', None),
],
} }
xmlids_to_rename = [ xmlids_to_rename = [
( (
'contract.account_analytic_cron_for_invoice', "contract.account_analytic_cron_for_invoice",
'contract.contract_cron_for_invoice', "contract.contract_cron_for_invoice",
), ),
( (
'contract.account_analytic_contract_manager', "contract.account_analytic_contract_manager",
'contract.contract_template_manager', "contract.contract_template_manager",
),
("contract.account_analytic_contract_user", "contract.contract_template_user",),
(
"contract.account_analytic_invoice_line_manager",
"contract.contract_line_manager",
),
("contract.account_analytic_invoice_line_user", "contract.contract_line_user",),
(
"contract.account_analytic_contract_line_manager",
"contract.contract_template_line_manager",
), ),
( (
'contract.account_analytic_contract_user', "contract.account_analytic_contract_line_user",
'contract.contract_template_user', "contract.contract_template_line_user",
),
(
'contract.account_analytic_invoice_line_manager',
'contract.contract_line_manager',
),
(
'contract.account_analytic_invoice_line_user',
'contract.contract_line_user',
),
(
'contract.account_analytic_contract_line_manager',
'contract.contract_template_line_manager',
),
(
'contract.account_analytic_contract_line_user',
'contract.contract_template_line_user',
), ),
] ]
@@ -77,33 +66,34 @@ def _get_contract_field_name(cr):
in 12.0.2.0.0. This method used to get the contract field name in in 12.0.2.0.0. This method used to get the contract field name in
account_analytic_invoice_line""" account_analytic_invoice_line"""
return ( return (
'contract_id' "contract_id"
if openupgrade.column_exists( if openupgrade.column_exists(cr, "account_analytic_invoice_line", "contract_id")
cr, 'account_analytic_invoice_line', 'contract_id' else "analytic_account_id"
)
else 'analytic_account_id'
) )
def create_contract_records(cr): def create_contract_records(cr):
contract_field_name = _get_contract_field_name(cr) contract_field_name = _get_contract_field_name(cr)
openupgrade.logged_query( openupgrade.logged_query(
cr, """ cr,
"""
CREATE TABLE contract_contract CREATE TABLE contract_contract
(LIKE account_analytic_account INCLUDING ALL)""", (LIKE account_analytic_account INCLUDING ALL)""",
) )
openupgrade.logged_query( openupgrade.logged_query(
cr, sql.SQL(""" cr,
sql.SQL(
"""
INSERT INTO contract_contract INSERT INTO contract_contract
SELECT * FROM account_analytic_account SELECT * FROM account_analytic_account
WHERE id IN (SELECT DISTINCT {} FROM contract_line) WHERE id IN (SELECT DISTINCT {} FROM contract_line)
""").format( """
sql.Identifier(contract_field_name), ).format(sql.Identifier(contract_field_name),),
),
) )
# Deactivate disabled contracts # Deactivate disabled contracts
openupgrade.logged_query( openupgrade.logged_query(
cr, """UPDATE contract_contract cc cr,
"""UPDATE contract_contract cc
SET active = False SET active = False
FROM account_analytic_account aaa FROM account_analytic_account aaa
WHERE aaa.id = cc.id WHERE aaa.id = cc.id
@@ -111,24 +101,31 @@ def create_contract_records(cr):
) )
# Handle id sequence # Handle id sequence
cr.execute("CREATE SEQUENCE IF NOT EXISTS contract_contract_id_seq") cr.execute("CREATE SEQUENCE IF NOT EXISTS contract_contract_id_seq")
cr.execute("SELECT setval('contract_contract_id_seq', " cr.execute(
"(SELECT MAX(id) FROM contract_contract))") "SELECT setval('contract_contract_id_seq', "
cr.execute("ALTER TABLE contract_contract ALTER id " "(SELECT MAX(id) FROM contract_contract))"
"SET DEFAULT NEXTVAL('contract_contract_id_seq')") )
cr.execute(
"ALTER TABLE contract_contract ALTER id "
"SET DEFAULT NEXTVAL('contract_contract_id_seq')"
)
# Move common stuff from one table to the other # Move common stuff from one table to the other
mapping = [ mapping = [
('ir_attachment', 'res_model', 'res_id'), ("ir_attachment", "res_model", "res_id"),
('mail_message', 'model', 'res_id'), ("mail_message", "model", "res_id"),
('mail_activity', 'res_model', 'res_id'), ("mail_activity", "res_model", "res_id"),
('mail_followers', 'res_model', 'res_id'), ("mail_followers", "res_model", "res_id"),
] ]
for table, model_column, id_column in mapping: for table, model_column, id_column in mapping:
openupgrade.logged_query( openupgrade.logged_query(
cr, sql.SQL(""" cr,
sql.SQL(
"""
UPDATE {table} SET {model_column}='contract.contract' UPDATE {table} SET {model_column}='contract.contract'
WHERE {model_column}='account.analytic.account' WHERE {model_column}='account.analytic.account'
AND {id_column} IN (SELECT DISTINCT {col} FROM contract_line) AND {id_column} IN (SELECT DISTINCT {col} FROM contract_line)
""").format( """
).format(
table=sql.Identifier(table), table=sql.Identifier(table),
model_column=sql.Identifier(model_column), model_column=sql.Identifier(model_column),
id_column=sql.Identifier(id_column), id_column=sql.Identifier(id_column),

View File

@@ -6,68 +6,61 @@
# Copyright 2018 ACSONE SA/NV # Copyright 2018 ACSONE SA/NV
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, models, fields from odoo import api, fields, models
class ContractAbstractContract(models.AbstractModel): class ContractAbstractContract(models.AbstractModel):
_name = 'contract.abstract.contract' _name = "contract.abstract.contract"
_description = 'Abstract Recurring Contract' _description = "Abstract Recurring Contract"
# These fields will not be synced to the contract # These fields will not be synced to the contract
NO_SYNC = ['name', 'partner_id', 'company_id'] NO_SYNC = ["name", "partner_id", "company_id"]
name = fields.Char(required=True) name = fields.Char(required=True)
# Needed for avoiding errors on several inherited behaviors # Needed for avoiding errors on several inherited behaviors
partner_id = fields.Many2one( partner_id = fields.Many2one(
comodel_name="res.partner", string="Partner", index=True comodel_name="res.partner", string="Partner", index=True
) )
pricelist_id = fields.Many2one( pricelist_id = fields.Many2one(comodel_name="product.pricelist", string="Pricelist")
comodel_name='product.pricelist', string='Pricelist'
)
contract_type = fields.Selection( contract_type = fields.Selection(
selection=[('sale', 'Customer'), ('purchase', 'Supplier')], selection=[("sale", "Customer"), ("purchase", "Supplier")],
default='sale', default="sale",
index=True, index=True,
) )
journal_id = fields.Many2one( journal_id = fields.Many2one(
'account.journal', "account.journal",
string='Journal', string="Journal",
default=lambda s: s._default_journal(), default=lambda s: s._default_journal(),
domain="[('type', '=', contract_type)," domain="[('type', '=', contract_type)," "('company_id', '=', company_id)]",
"('company_id', '=', company_id)]",
index=True, index=True,
) )
company_id = fields.Many2one( company_id = fields.Many2one(
'res.company', "res.company",
string='Company', string="Company",
required=True, required=True,
default=lambda self: self.env['res.company']._company_default_get( default=lambda self: self.env["res.company"]._company_default_get(self._name),
self._name
),
) )
@api.onchange('contract_type') @api.onchange("contract_type")
def _onchange_contract_type(self): def _onchange_contract_type(self):
if self.contract_type == 'purchase': if self.contract_type == "purchase":
self.contract_line_ids.filtered('automatic_price').update( self.contract_line_ids.filtered("automatic_price").update(
{'automatic_price': False} {"automatic_price": False}
) )
self.journal_id = self.env['account.journal'].search( self.journal_id = self.env["account.journal"].search(
[ [
('type', '=', self.contract_type), ("type", "=", self.contract_type),
('company_id', '=', self.company_id.id), ("company_id", "=", self.company_id.id),
], ],
limit=1, limit=1,
) )
@api.model @api.model
def _default_journal(self): def _default_journal(self):
company_id = self.env.context.get( company_id = self.env.context.get("company_id", self.env.user.company_id.id)
'company_id', self.env.user.company_id.id
)
domain = [ domain = [
('type', '=', self.contract_type), ("type", "=", self.contract_type),
('company_id', '=', company_id), ("company_id", "=", company_id),
] ]
return self.env['account.journal'].search(domain, limit=1) return self.env["account.journal"].search(domain, limit=1)

View File

@@ -6,47 +6,44 @@
# Copyright 2018 ACSONE SA/NV # Copyright 2018 ACSONE SA/NV
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, models, fields from odoo import api, fields, models
from odoo.addons import decimal_precision as dp
from odoo.exceptions import ValidationError from odoo.exceptions import ValidationError
from odoo.tools.translate import _ from odoo.tools.translate import _
from odoo.addons import decimal_precision as dp
class ContractAbstractContractLine(models.AbstractModel): class ContractAbstractContractLine(models.AbstractModel):
_name = 'contract.abstract.contract.line' _name = "contract.abstract.contract.line"
_description = 'Abstract Recurring Contract Line' _description = "Abstract Recurring Contract Line"
product_id = fields.Many2one( product_id = fields.Many2one("product.product", string="Product")
'product.product', string='Product'
)
name = fields.Text(string='Description', required=True) name = fields.Text(string="Description", required=True)
quantity = fields.Float(default=1.0, required=True) quantity = fields.Float(default=1.0, required=True)
uom_id = fields.Many2one( uom_id = fields.Many2one("uom.uom", string="Unit of Measure")
'uom.uom', string='Unit of Measure'
)
automatic_price = fields.Boolean( automatic_price = fields.Boolean(
string="Auto-price?", string="Auto-price?",
help="If this is marked, the price will be obtained automatically " help="If this is marked, the price will be obtained automatically "
"applying the pricelist to the product. If not, you will be " "applying the pricelist to the product. If not, you will be "
"able to introduce a manual price", "able to introduce a manual price",
) )
specific_price = fields.Float(string='Specific Price') specific_price = fields.Float(string="Specific Price")
price_unit = fields.Float( price_unit = fields.Float(
string='Unit Price', string="Unit Price",
compute="_compute_price_unit", compute="_compute_price_unit",
inverse="_inverse_price_unit", inverse="_inverse_price_unit",
) )
price_subtotal = fields.Float( price_subtotal = fields.Float(
compute='_compute_price_subtotal', compute="_compute_price_subtotal",
digits=dp.get_precision('Account'), digits=dp.get_precision("Account"),
string='Sub Total', string="Sub Total",
) )
discount = fields.Float( discount = fields.Float(
string='Discount (%)', string="Discount (%)",
digits=dp.get_precision('Discount'), digits=dp.get_precision("Discount"),
help='Discount that is applied in generated invoices.' help="Discount that is applied in generated invoices."
' It should be less or equal to 100', " It should be less or equal to 100",
) )
sequence = fields.Integer( sequence = fields.Integer(
string="Sequence", string="Sequence",
@@ -55,23 +52,23 @@ class ContractAbstractContractLine(models.AbstractModel):
) )
recurring_rule_type = fields.Selection( recurring_rule_type = fields.Selection(
[ [
('daily', 'Day(s)'), ("daily", "Day(s)"),
('weekly', 'Week(s)'), ("weekly", "Week(s)"),
('monthly', 'Month(s)'), ("monthly", "Month(s)"),
('monthlylastday', 'Month(s) last day'), ("monthlylastday", "Month(s) last day"),
('quarterly', 'Quarter(s)'), ("quarterly", "Quarter(s)"),
('semesterly', 'Semester(s)'), ("semesterly", "Semester(s)"),
('yearly', 'Year(s)'), ("yearly", "Year(s)"),
], ],
default='monthly', default="monthly",
string='Recurrence', string="Recurrence",
help="Specify Interval for automatic invoice generation.", help="Specify Interval for automatic invoice generation.",
required=True, required=True,
) )
recurring_invoicing_type = fields.Selection( recurring_invoicing_type = fields.Selection(
[('pre-paid', 'Pre-paid'), ('post-paid', 'Post-paid')], [("pre-paid", "Pre-paid"), ("post-paid", "Post-paid")],
default='pre-paid', default="pre-paid",
string='Invoicing type', string="Invoicing type",
help=( help=(
"Specify if the invoice must be generated at the beginning " "Specify if the invoice must be generated at the beginning "
"(pre-paid) or end (post-paid) of the period." "(pre-paid) or end (post-paid) of the period."
@@ -84,68 +81,63 @@ class ContractAbstractContractLine(models.AbstractModel):
help=( help=(
"Number of days to offset the invoice from the period end " "Number of days to offset the invoice from the period end "
"date (in post-paid mode) or start date (in pre-paid mode)." "date (in post-paid mode) or start date (in pre-paid mode)."
) ),
) )
recurring_interval = fields.Integer( recurring_interval = fields.Integer(
default=1, default=1,
string='Invoice Every', string="Invoice Every",
help="Invoice every (Days/Week/Month/Year)", help="Invoice every (Days/Week/Month/Year)",
required=True, required=True,
) )
date_start = fields.Date(string='Date Start') date_start = fields.Date(string="Date Start")
recurring_next_date = fields.Date(string='Date of Next Invoice') recurring_next_date = fields.Date(string="Date of Next Invoice")
last_date_invoiced = fields.Date(string='Last Date Invoiced') last_date_invoiced = fields.Date(string="Last Date Invoiced")
is_canceled = fields.Boolean(string="Canceled", default=False) is_canceled = fields.Boolean(string="Canceled", default=False)
is_auto_renew = fields.Boolean(string="Auto Renew", default=False) is_auto_renew = fields.Boolean(string="Auto Renew", default=False)
auto_renew_interval = fields.Integer( auto_renew_interval = fields.Integer(
default=1, default=1, string="Renew Every", help="Renew every (Days/Week/Month/Year)",
string='Renew Every',
help="Renew every (Days/Week/Month/Year)",
) )
auto_renew_rule_type = fields.Selection( auto_renew_rule_type = fields.Selection(
[ [
('daily', 'Day(s)'), ("daily", "Day(s)"),
('weekly', 'Week(s)'), ("weekly", "Week(s)"),
('monthly', 'Month(s)'), ("monthly", "Month(s)"),
('yearly', 'Year(s)'), ("yearly", "Year(s)"),
], ],
default='yearly', default="yearly",
string='Renewal type', string="Renewal type",
help="Specify Interval for automatic renewal.", help="Specify Interval for automatic renewal.",
) )
termination_notice_interval = fields.Integer( termination_notice_interval = fields.Integer(
default=1, string='Termination Notice Before' default=1, string="Termination Notice Before"
) )
termination_notice_rule_type = fields.Selection( termination_notice_rule_type = fields.Selection(
[('daily', 'Day(s)'), ('weekly', 'Week(s)'), ('monthly', 'Month(s)')], [("daily", "Day(s)"), ("weekly", "Week(s)"), ("monthly", "Month(s)")],
default='monthly', default="monthly",
string='Termination Notice type', string="Termination Notice type",
) )
contract_id = fields.Many2one( contract_id = fields.Many2one(
string='Contract', string="Contract",
comodel_name='contract.abstract.contract', comodel_name="contract.abstract.contract",
required=True, required=True,
ondelete='cascade', ondelete="cascade",
) )
display_type = fields.Selection( display_type = fields.Selection(
selection=[ selection=[("line_section", "Section"), ("line_note", "Note"),],
('line_section', "Section"),
('line_note', "Note"),
],
default=False, default=False,
help="Technical field for UX purpose." help="Technical field for UX purpose.",
) )
note_invoicing_mode = fields.Selection( note_invoicing_mode = fields.Selection(
selection=[ selection=[
('with_previous_line', 'With previous line'), ("with_previous_line", "With previous line"),
('with_next_line', 'With next line'), ("with_next_line", "With next line"),
('custom', 'Custom'), ("custom", "Custom"),
], ],
default='with_previous_line', default="with_previous_line",
help="Defines when the Note is invoiced:\n" help="Defines when the Note is invoiced:\n"
"- With previous line: If the previous line can be invoiced.\n" "- With previous line: If the previous line can be invoiced.\n"
"- With next line: If the next line can be invoiced.\n" "- With next line: If the next line can be invoiced.\n"
"- Custom: Depending on the recurrence to be define." "- Custom: Depending on the recurrence to be define.",
) )
is_recurring_note = fields.Boolean(compute="_compute_is_recurring_note") is_recurring_note = fields.Boolean(compute="_compute_is_recurring_note")
@@ -154,8 +146,8 @@ class ContractAbstractContractLine(models.AbstractModel):
self, recurring_invoicing_type, recurring_rule_type self, recurring_invoicing_type, recurring_rule_type
): ):
if ( if (
recurring_invoicing_type == 'pre-paid' recurring_invoicing_type == "pre-paid"
or recurring_rule_type == 'monthlylastday' or recurring_rule_type == "monthlylastday"
): ):
return 0 return 0
else: else:
@@ -164,26 +156,24 @@ class ContractAbstractContractLine(models.AbstractModel):
def is_recurring_note(self): def is_recurring_note(self):
for record in self: for record in self:
record.is_recurring_note = ( record.is_recurring_note = (
record.display_type == 'line_note' record.display_type == "line_note"
and record.note_invoicing_mode == 'custom' and record.note_invoicing_mode == "custom"
) )
@api.depends('recurring_invoicing_type', 'recurring_rule_type') @api.depends("recurring_invoicing_type", "recurring_rule_type")
def _compute_recurring_invoicing_offset(self): def _compute_recurring_invoicing_offset(self):
for rec in self: for rec in self:
rec.recurring_invoicing_offset = ( rec.recurring_invoicing_offset = self._get_default_recurring_invoicing_offset(
self._get_default_recurring_invoicing_offset( rec.recurring_invoicing_type, rec.recurring_rule_type
rec.recurring_invoicing_type, rec.recurring_rule_type
)
) )
@api.depends( @api.depends(
'automatic_price', "automatic_price",
'specific_price', "specific_price",
'product_id', "product_id",
'quantity', "quantity",
'contract_id.pricelist_id', "contract_id.pricelist_id",
'contract_id.partner_id', "contract_id.partner_id",
) )
def _compute_price_unit(self): def _compute_price_unit(self):
"""Get the specific price if no auto-price, and the price obtained """Get the specific price if no auto-price, and the price obtained
@@ -192,20 +182,17 @@ class ContractAbstractContractLine(models.AbstractModel):
for line in self: for line in self:
if line.automatic_price: if line.automatic_price:
pricelist = ( pricelist = (
line.contract_id.pricelist_id or line.contract_id.pricelist_id
line.contract_id.partner_id.with_context( or line.contract_id.partner_id.with_context(
force_company=line.contract_id.company_id.id, force_company=line.contract_id.company_id.id,
).property_product_pricelist ).property_product_pricelist
) )
product = line.product_id.with_context( product = line.product_id.with_context(
quantity=line.env.context.get( quantity=line.env.context.get("contract_line_qty", line.quantity,),
'contract_line_qty',
line.quantity,
),
pricelist=pricelist.id, pricelist=pricelist.id,
partner=line.contract_id.partner_id.id, partner=line.contract_id.partner_id.id,
date=line.env.context.get( date=line.env.context.get(
'old_date', fields.Date.context_today(line) "old_date", fields.Date.context_today(line)
), ),
) )
line.price_unit = product.price line.price_unit = product.price
@@ -213,14 +200,14 @@ class ContractAbstractContractLine(models.AbstractModel):
line.price_unit = line.specific_price line.price_unit = line.specific_price
# Tip in https://github.com/odoo/odoo/issues/23891#issuecomment-376910788 # Tip in https://github.com/odoo/odoo/issues/23891#issuecomment-376910788
@api.onchange('price_unit') @api.onchange("price_unit")
def _inverse_price_unit(self): def _inverse_price_unit(self):
"""Store the specific price in the no auto-price records.""" """Store the specific price in the no auto-price records."""
for line in self.filtered(lambda x: not x.automatic_price): for line in self.filtered(lambda x: not x.automatic_price):
line.specific_price = line.price_unit line.specific_price = line.price_unit
@api.multi @api.multi
@api.depends('quantity', 'price_unit', 'discount') @api.depends("quantity", "price_unit", "discount")
def _compute_price_subtotal(self): def _compute_price_subtotal(self):
for line in self: for line in self:
subtotal = line.quantity * line.price_unit subtotal = line.quantity * line.price_unit
@@ -233,30 +220,26 @@ class ContractAbstractContractLine(models.AbstractModel):
line.price_subtotal = subtotal line.price_subtotal = subtotal
@api.multi @api.multi
@api.constrains('discount') @api.constrains("discount")
def _check_discount(self): def _check_discount(self):
for line in self: for line in self:
if line.discount > 100: if line.discount > 100:
raise ValidationError( raise ValidationError(_("Discount should be less or equal to 100"))
_("Discount should be less or equal to 100")
)
@api.multi @api.multi
@api.onchange('product_id') @api.onchange("product_id")
def _onchange_product_id(self): def _onchange_product_id(self):
if not self.product_id: if not self.product_id:
return {'domain': {'uom_id': []}} return {"domain": {"uom_id": []}}
vals = {} vals = {}
domain = { domain = {
'uom_id': [ "uom_id": [("category_id", "=", self.product_id.uom_id.category_id.id)]
('category_id', '=', self.product_id.uom_id.category_id.id)
]
} }
if not self.uom_id or ( if not self.uom_id or (
self.product_id.uom_id.category_id.id != self.uom_id.category_id.id self.product_id.uom_id.category_id.id != self.uom_id.category_id.id
): ):
vals['uom_id'] = self.product_id.uom_id vals["uom_id"] = self.product_id.uom_id
date = self.recurring_next_date or fields.Date.context_today(self) date = self.recurring_next_date or fields.Date.context_today(self)
partner = self.contract_id.partner_id or self.env.user.partner_id partner = self.contract_id.partner_id or self.env.user.partner_id
@@ -268,7 +251,7 @@ class ContractAbstractContractLine(models.AbstractModel):
pricelist=self.contract_id.pricelist_id.id, pricelist=self.contract_id.pricelist_id.id,
uom=self.uom_id.id, uom=self.uom_id.id,
) )
vals['name'] = self.product_id.get_product_multiline_description_sale() vals["name"] = self.product_id.get_product_multiline_description_sale()
vals['price_unit'] = product.price vals["price_unit"] = product.price
self.update(vals) self.update(vals)
return {'domain': domain} return {"domain": domain}

View File

@@ -5,8 +5,7 @@ from odoo import fields, models
class AccountInvoice(models.Model): class AccountInvoice(models.Model):
_inherit = 'account.invoice' _inherit = "account.invoice"
# We keep this field for migration purpose # We keep this field for migration purpose
old_contract_id = fields.Many2one( old_contract_id = fields.Many2one("contract.contract", oldname="contract_id")
'contract.contract', oldname='contract_id')

View File

@@ -5,8 +5,8 @@ from odoo import fields, models
class AccountInvoiceLine(models.Model): class AccountInvoiceLine(models.Model):
_inherit = 'account.invoice.line' _inherit = "account.invoice.line"
contract_line_id = fields.Many2one( contract_line_id = fields.Many2one(
'contract.line', string='Contract Line', index=True "contract.line", string="Contract Line", index=True
) )

View File

@@ -7,30 +7,24 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, fields, models from odoo import api, fields, models
from odoo.exceptions import ValidationError, UserError from odoo.exceptions import UserError, ValidationError
from odoo.tools.translate import _ from odoo.tools.translate import _
class ContractContract(models.Model): class ContractContract(models.Model):
_name = 'contract.contract' _name = "contract.contract"
_description = "Contract" _description = "Contract"
_order = 'code, name asc' _order = "code, name asc"
_inherit = [ _inherit = [
'mail.thread', "mail.thread",
'mail.activity.mixin', "mail.activity.mixin",
'contract.abstract.contract', "contract.abstract.contract",
] ]
active = fields.Boolean( active = fields.Boolean(default=True,)
default=True, code = fields.Char(string="Reference",)
)
code = fields.Char(
string="Reference",
)
group_id = fields.Many2one( group_id = fields.Many2one(
string="Group", string="Group", comodel_name="account.analytic.account", ondelete="restrict",
comodel_name='account.analytic.account',
ondelete='restrict',
) )
currency_id = fields.Many2one( currency_id = fields.Many2one(
compute="_compute_currency_id", compute="_compute_currency_id",
@@ -38,70 +32,59 @@ class ContractContract(models.Model):
comodel_name="res.currency", comodel_name="res.currency",
string="Currency", string="Currency",
) )
manual_currency_id = fields.Many2one( manual_currency_id = fields.Many2one(comodel_name="res.currency", readonly=True,)
comodel_name="res.currency",
readonly=True,
)
contract_template_id = fields.Many2one( contract_template_id = fields.Many2one(
string='Contract Template', comodel_name='contract.template' string="Contract Template", comodel_name="contract.template"
) )
contract_line_ids = fields.One2many( contract_line_ids = fields.One2many(
string='Contract lines', string="Contract lines",
comodel_name='contract.line', comodel_name="contract.line",
inverse_name='contract_id', inverse_name="contract_id",
copy=True, copy=True,
) )
user_id = fields.Many2one( user_id = fields.Many2one(
comodel_name='res.users', comodel_name="res.users",
string='Responsible', string="Responsible",
index=True, index=True,
default=lambda self: self.env.user, default=lambda self: self.env.user,
) )
create_invoice_visibility = fields.Boolean( create_invoice_visibility = fields.Boolean(
compute='_compute_create_invoice_visibility' compute="_compute_create_invoice_visibility"
) )
recurring_next_date = fields.Date( recurring_next_date = fields.Date(
compute='_compute_recurring_next_date', compute="_compute_recurring_next_date",
string='Date of Next Invoice', string="Date of Next Invoice",
store=True, store=True,
) )
date_end = fields.Date( date_end = fields.Date(compute="_compute_date_end", string="Date End", store=True)
compute='_compute_date_end', string='Date End', store=True
)
payment_term_id = fields.Many2one( payment_term_id = fields.Many2one(
comodel_name='account.payment.term', string='Payment Terms', index=True comodel_name="account.payment.term", string="Payment Terms", index=True
) )
invoice_count = fields.Integer(compute="_compute_invoice_count") invoice_count = fields.Integer(compute="_compute_invoice_count")
fiscal_position_id = fields.Many2one( fiscal_position_id = fields.Many2one(
comodel_name='account.fiscal.position', comodel_name="account.fiscal.position",
string='Fiscal Position', string="Fiscal Position",
ondelete='restrict', ondelete="restrict",
) )
invoice_partner_id = fields.Many2one( invoice_partner_id = fields.Many2one(
string="Invoicing contact", string="Invoicing contact", comodel_name="res.partner", ondelete="restrict",
comodel_name='res.partner',
ondelete='restrict',
) )
partner_id = fields.Many2one( partner_id = fields.Many2one(
comodel_name='res.partner', comodel_name="res.partner", inverse="_inverse_partner_id", required=True
inverse='_inverse_partner_id',
required=True
) )
commercial_partner_id = fields.Many2one( commercial_partner_id = fields.Many2one(
'res.partner', "res.partner",
compute_sudo=True, compute_sudo=True,
related='partner_id.commercial_partner_id', related="partner_id.commercial_partner_id",
store=True, store=True,
string='Commercial Entity', string="Commercial Entity",
index=True index=True,
) )
tag_ids = fields.Many2many(comodel_name="contract.tag", string="Tags") tag_ids = fields.Many2many(comodel_name="contract.tag", string="Tags")
note = fields.Text(string="Notes") note = fields.Text(string="Notes")
is_terminated = fields.Boolean( is_terminated = fields.Boolean(string="Terminated", readonly=True, copy=False)
string="Terminated", readonly=True, copy=False
)
terminate_reason_id = fields.Many2one( terminate_reason_id = fields.Many2one(
comodel_name="contract.terminate.reason", comodel_name="contract.terminate.reason",
string="Termination Reason", string="Termination Reason",
@@ -127,55 +110,40 @@ class ContractContract(models.Model):
def _inverse_partner_id(self): def _inverse_partner_id(self):
for rec in self: for rec in self:
if not rec.invoice_partner_id: if not rec.invoice_partner_id:
rec.invoice_partner_id = rec.partner_id.address_get( rec.invoice_partner_id = rec.partner_id.address_get(["invoice"])[
['invoice'] "invoice"
)['invoice'] ]
@api.multi @api.multi
def _get_related_invoices(self): def _get_related_invoices(self):
self.ensure_one() self.ensure_one()
invoices = ( invoices = (
self.env['account.invoice.line'] self.env["account.invoice.line"]
.search( .search([("contract_line_id", "in", self.contract_line_ids.ids,)])
[ .mapped("invoice_id")
(
'contract_line_id',
'in',
self.contract_line_ids.ids,
)
]
)
.mapped('invoice_id')
) )
invoices |= self.env['account.invoice'].search( invoices |= self.env["account.invoice"].search(
[('old_contract_id', '=', self.id)] [("old_contract_id", "=", self.id)]
) )
return invoices return invoices
def _get_computed_currency(self): def _get_computed_currency(self):
"""Helper method for returning the theoretical computed currency.""" """Helper method for returning the theoretical computed currency."""
self.ensure_one() self.ensure_one()
currency = self.env['res.currency'] currency = self.env["res.currency"]
if any(self.contract_line_ids.mapped('automatic_price')): if any(self.contract_line_ids.mapped("automatic_price")):
# Use pricelist currency # Use pricelist currency
currency = ( currency = (
self.pricelist_id.currency_id or self.pricelist_id.currency_id
self.partner_id.with_context( or self.partner_id.with_context(
force_company=self.company_id.id, force_company=self.company_id.id,
).property_product_pricelist.currency_id ).property_product_pricelist.currency_id
) )
return ( return currency or self.journal_id.currency_id or self.company_id.currency_id
currency or self.journal_id.currency_id or
self.company_id.currency_id
)
@api.depends( @api.depends(
"manual_currency_id", "manual_currency_id", "pricelist_id", "partner_id", "journal_id", "company_id",
"pricelist_id",
"partner_id",
"journal_id",
"company_id",
) )
def _compute_currency_id(self): def _compute_currency_id(self):
for rec in self: for rec in self:
@@ -203,60 +171,60 @@ class ContractContract(models.Model):
def action_show_invoices(self): def action_show_invoices(self):
self.ensure_one() self.ensure_one()
tree_view_ref = ( tree_view_ref = (
'account.invoice_supplier_tree' "account.invoice_supplier_tree"
if self.contract_type == 'purchase' if self.contract_type == "purchase"
else 'account.invoice_tree_with_onboarding' else "account.invoice_tree_with_onboarding"
) )
form_view_ref = ( form_view_ref = (
'account.invoice_supplier_form' "account.invoice_supplier_form"
if self.contract_type == 'purchase' if self.contract_type == "purchase"
else 'account.invoice_form' else "account.invoice_form"
) )
tree_view = self.env.ref(tree_view_ref, raise_if_not_found=False) tree_view = self.env.ref(tree_view_ref, raise_if_not_found=False)
form_view = self.env.ref(form_view_ref, raise_if_not_found=False) form_view = self.env.ref(form_view_ref, raise_if_not_found=False)
action = { action = {
'type': 'ir.actions.act_window', "type": "ir.actions.act_window",
'name': 'Invoices', "name": "Invoices",
'res_model': 'account.invoice', "res_model": "account.invoice",
'view_type': 'form', "view_type": "form",
'view_mode': 'tree,kanban,form,calendar,pivot,graph,activity', "view_mode": "tree,kanban,form,calendar,pivot,graph,activity",
'domain': [('id', 'in', self._get_related_invoices().ids)], "domain": [("id", "in", self._get_related_invoices().ids)],
} }
if tree_view and form_view: if tree_view and form_view:
action['views'] = [(tree_view.id, 'tree'), (form_view.id, 'form')] action["views"] = [(tree_view.id, "tree"), (form_view.id, "form")]
return action return action
@api.depends('contract_line_ids.date_end') @api.depends("contract_line_ids.date_end")
def _compute_date_end(self): def _compute_date_end(self):
for contract in self: for contract in self:
contract.date_end = False contract.date_end = False
date_end = contract.contract_line_ids.mapped('date_end') date_end = contract.contract_line_ids.mapped("date_end")
if date_end and all(date_end): if date_end and all(date_end):
contract.date_end = max(date_end) contract.date_end = max(date_end)
@api.depends( @api.depends(
'contract_line_ids.recurring_next_date', "contract_line_ids.recurring_next_date", "contract_line_ids.is_canceled",
'contract_line_ids.is_canceled',
) )
def _compute_recurring_next_date(self): def _compute_recurring_next_date(self):
for contract in self: for contract in self:
recurring_next_date = contract.contract_line_ids.filtered( recurring_next_date = contract.contract_line_ids.filtered(
lambda l: (l.recurring_next_date and not l.is_canceled lambda l: (
and (not l.display_type or l.is_recurring_note)) l.recurring_next_date
).mapped('recurring_next_date') and not l.is_canceled
and (not l.display_type or l.is_recurring_note)
)
).mapped("recurring_next_date")
if recurring_next_date: if recurring_next_date:
contract.recurring_next_date = min(recurring_next_date) contract.recurring_next_date = min(recurring_next_date)
@api.depends('contract_line_ids.create_invoice_visibility') @api.depends("contract_line_ids.create_invoice_visibility")
def _compute_create_invoice_visibility(self): def _compute_create_invoice_visibility(self):
for contract in self: for contract in self:
contract.create_invoice_visibility = any( contract.create_invoice_visibility = any(
contract.contract_line_ids.mapped( contract.contract_line_ids.mapped("create_invoice_visibility")
'create_invoice_visibility'
)
) )
@api.onchange('contract_template_id') @api.onchange("contract_template_id")
def _onchange_contract_template_id(self): def _onchange_contract_template_id(self):
"""Update the contract fields with that of the template. """Update the contract fields with that of the template.
@@ -269,7 +237,7 @@ class ContractContract(models.Model):
if not contract_template_id: if not contract_template_id:
return return
for field_name, field in contract_template_id._fields.items(): for field_name, field in contract_template_id._fields.items():
if field.name == 'contract_line_ids': if field.name == "contract_line_ids":
lines = self._convert_contract_lines(contract_template_id) lines = self._convert_contract_lines(contract_template_id)
self.contract_line_ids += lines self.contract_line_ids += lines
elif not any( elif not any(
@@ -285,7 +253,7 @@ class ContractContract(models.Model):
if self.contract_template_id[field_name]: if self.contract_template_id[field_name]:
self[field_name] = self.contract_template_id[field_name] self[field_name] = self.contract_template_id[field_name]
@api.onchange('partner_id', 'company_id') @api.onchange("partner_id", "company_id")
def _onchange_partner_id(self): def _onchange_partner_id(self):
partner = ( partner = (
self.partner_id self.partner_id
@@ -294,21 +262,19 @@ class ContractContract(models.Model):
) )
self.pricelist_id = partner.property_product_pricelist.id self.pricelist_id = partner.property_product_pricelist.id
self.fiscal_position_id = partner.env[ self.fiscal_position_id = partner.env[
'account.fiscal.position' "account.fiscal.position"
].get_fiscal_position(partner.id) ].get_fiscal_position(partner.id)
if self.contract_type == 'purchase': if self.contract_type == "purchase":
self.payment_term_id = partner.property_supplier_payment_term_id self.payment_term_id = partner.property_supplier_payment_term_id
else: else:
self.payment_term_id = partner.property_payment_term_id self.payment_term_id = partner.property_payment_term_id
self.invoice_partner_id = self.partner_id.address_get(['invoice'])[ self.invoice_partner_id = self.partner_id.address_get(["invoice"])["invoice"]
'invoice'
]
return { return {
'domain': { "domain": {
'invoice_partner_id': [ "invoice_partner_id": [
'|', "|",
('id', 'parent_of', self.partner_id.id), ("id", "parent_of", self.partner_id.id),
('id', 'child_of', self.partner_id.id), ("id", "child_of", self.partner_id.id),
] ]
} }
} }
@@ -316,16 +282,14 @@ class ContractContract(models.Model):
@api.multi @api.multi
def _convert_contract_lines(self, contract): def _convert_contract_lines(self, contract):
self.ensure_one() self.ensure_one()
new_lines = self.env['contract.line'] new_lines = self.env["contract.line"]
contract_line_model = self.env['contract.line'] contract_line_model = self.env["contract.line"]
for contract_line in contract.contract_line_ids: for contract_line in contract.contract_line_ids:
vals = contract_line._convert_to_write(contract_line.read()[0]) vals = contract_line._convert_to_write(contract_line.read()[0])
# Remove template link field # Remove template link field
vals.pop('contract_template_id', False) vals.pop("contract_template_id", False)
vals['date_start'] = fields.Date.context_today(contract_line) vals["date_start"] = fields.Date.context_today(contract_line)
vals['recurring_next_date'] = fields.Date.context_today( vals["recurring_next_date"] = fields.Date.context_today(contract_line)
contract_line
)
new_lines += contract_line_model.new(vals) new_lines += contract_line_model.new(vals)
new_lines._onchange_date_start() new_lines._onchange_date_start()
new_lines._onchange_is_auto_renew() new_lines._onchange_is_auto_renew()
@@ -338,10 +302,10 @@ class ContractContract(models.Model):
journal = ( journal = (
self.journal_id self.journal_id
if self.journal_id.type == self.contract_type if self.journal_id.type == self.contract_type
else self.env['account.journal'].search( else self.env["account.journal"].search(
[ [
('type', '=', self.contract_type), ("type", "=", self.contract_type),
('company_id', '=', self.company_id.id), ("company_id", "=", self.company_id.id),
], ],
limit=1, limit=1,
) )
@@ -349,56 +313,62 @@ class ContractContract(models.Model):
if not journal: if not journal:
raise ValidationError( raise ValidationError(
_("Please define a %s journal for the company '%s'.") _("Please define a %s journal for the company '%s'.")
% (self.contract_type, self.company_id.name or '') % (self.contract_type, self.company_id.name or "")
) )
invoice_type = 'out_invoice' invoice_type = "out_invoice"
if self.contract_type == 'purchase': if self.contract_type == "purchase":
invoice_type = 'in_invoice' invoice_type = "in_invoice"
vinvoice = self.env['account.invoice'].with_context( vinvoice = (
force_company=self.company_id.id, self.env["account.invoice"]
).new({ .with_context(force_company=self.company_id.id,)
'company_id': self.company_id.id, .new(
'partner_id': self.invoice_partner_id.id, {
'type': invoice_type, "company_id": self.company_id.id,
}) "partner_id": self.invoice_partner_id.id,
"type": invoice_type,
}
)
)
vinvoice._onchange_partner_id() vinvoice._onchange_partner_id()
invoice_vals = vinvoice._convert_to_write(vinvoice._cache) invoice_vals = vinvoice._convert_to_write(vinvoice._cache)
invoice_vals.update({ invoice_vals.update(
'name': self.code, {
'currency_id': self.currency_id.id, "name": self.code,
'date_invoice': date_invoice, "currency_id": self.currency_id.id,
'journal_id': journal.id, "date_invoice": date_invoice,
'origin': self.name, "journal_id": journal.id,
'user_id': self.user_id.id, "origin": self.name,
}) "user_id": self.user_id.id,
}
)
if self.payment_term_id: if self.payment_term_id:
invoice_vals['payment_term_id'] = self.payment_term_id.id invoice_vals["payment_term_id"] = self.payment_term_id.id
if self.fiscal_position_id: if self.fiscal_position_id:
invoice_vals['fiscal_position_id'] = self.fiscal_position_id.id invoice_vals["fiscal_position_id"] = self.fiscal_position_id.id
return invoice_vals return invoice_vals
@api.multi @api.multi
def action_contract_send(self): def action_contract_send(self):
self.ensure_one() self.ensure_one()
template = self.env.ref('contract.email_contract_template', False) template = self.env.ref("contract.email_contract_template", False)
compose_form = self.env.ref('mail.email_compose_message_wizard_form') compose_form = self.env.ref("mail.email_compose_message_wizard_form")
ctx = dict( ctx = dict(
default_model='contract.contract', default_model="contract.contract",
default_res_id=self.id, default_res_id=self.id,
default_use_template=bool(template), default_use_template=bool(template),
default_template_id=template and template.id or False, default_template_id=template and template.id or False,
default_composition_mode='comment', default_composition_mode="comment",
) )
return { return {
'name': _('Compose Email'), "name": _("Compose Email"),
'type': 'ir.actions.act_window', "type": "ir.actions.act_window",
'view_type': 'form', "view_type": "form",
'view_mode': 'form', "view_mode": "form",
'res_model': 'mail.compose.message', "res_model": "mail.compose.message",
'views': [(compose_form.id, 'form')], "views": [(compose_form.id, "form")],
'view_id': compose_form.id, "view_id": compose_form.id,
'target': 'new', "target": "new",
'context': ctx, "context": ctx,
} }
@api.model @api.model
@@ -430,10 +400,8 @@ class ContractContract(models.Model):
final_invoices_values = [] final_invoices_values = []
# TODO: This call must be removed in >=13.0 # TODO: This call must be removed in >=13.0
for invoice_values in invoices_values: for invoice_values in invoices_values:
final_invoices_values.append( final_invoices_values.append(self._finalize_invoice_values(invoice_values))
self._finalize_invoice_values(invoice_values) invoices = self.env["account.invoice"].create(final_invoices_values)
)
invoices = self.env['account.invoice'].create(final_invoices_values)
self._finalize_invoice_creation(invoices) self._finalize_invoice_creation(invoices)
return invoices return invoices
@@ -448,7 +416,7 @@ class ContractContract(models.Model):
domain = [] domain = []
if not date_ref: if not date_ref:
date_ref = fields.Date.context_today(self) date_ref = fields.Date.context_today(self)
domain.extend([('recurring_next_date', '<=', date_ref)]) domain.extend([("recurring_next_date", "<=", date_ref)])
return domain return domain
@api.multi @api.multi
@@ -462,16 +430,18 @@ class ContractContract(models.Model):
self.ensure_one() self.ensure_one()
def can_be_invoiced(l): def can_be_invoiced(l):
return (not l.is_canceled and l.recurring_next_date return (
and l.recurring_next_date <= date_ref) not l.is_canceled
and l.recurring_next_date
and l.recurring_next_date <= date_ref
)
lines2invoice = previous = self.env['contract.line'] lines2invoice = previous = self.env["contract.line"]
current_section = current_note = False current_section = current_note = False
for line in self.contract_line_ids: for line in self.contract_line_ids:
if line.display_type == 'line_section': if line.display_type == "line_section":
current_section = line current_section = line
elif (line.display_type == 'line_note' and elif line.display_type == "line_note" and not line.is_recurring_note:
not line.is_recurring_note):
if line.note_invoicing_mode == "with_previous_line": if line.note_invoicing_mode == "with_previous_line":
if previous in lines2invoice: if previous in lines2invoice:
lines2invoice |= line lines2invoice |= line
@@ -511,12 +481,12 @@ class ContractContract(models.Model):
continue continue
invoice_values = contract._prepare_invoice(date_ref) invoice_values = contract._prepare_invoice(date_ref)
for line in contract_lines: for line in contract_lines:
invoice_values.setdefault('invoice_line_ids', []) invoice_values.setdefault("invoice_line_ids", [])
invoice_line_values = line._prepare_invoice_line( invoice_line_values = line._prepare_invoice_line(
invoice_values=invoice_values, invoice_values=invoice_values,
) )
if invoice_line_values: if invoice_line_values:
invoice_values['invoice_line_ids'].append( invoice_values["invoice_line_ids"].append(
(0, 0, invoice_line_values) (0, 0, invoice_line_values)
) )
invoices_values.append(invoice_values) invoices_values.append(invoice_values)
@@ -533,9 +503,9 @@ class ContractContract(models.Model):
if invoice: if invoice:
self.message_post( self.message_post(
body=_( body=_(
'Contract manually invoiced: ' "Contract manually invoiced: "
'<a href="#" data-oe-model="%s" data-oe-id="%s">Invoice' '<a href="#" data-oe-model="%s" data-oe-id="%s">Invoice'
'</a>' "</a>"
) )
% (invoice._name, invoice.id) % (invoice._name, invoice.id)
) )
@@ -566,13 +536,13 @@ class ContractContract(models.Model):
self.ensure_one() self.ensure_one()
context = {"default_contract_id": self.id} context = {"default_contract_id": self.id}
return { return {
'type': 'ir.actions.act_window', "type": "ir.actions.act_window",
'name': _('Terminate Contract'), "name": _("Terminate Contract"),
'res_model': 'contract.contract.terminate', "res_model": "contract.contract.terminate",
'view_type': 'form', "view_type": "form",
'view_mode': 'form', "view_mode": "form",
'target': 'new', "target": "new",
'context': context, "context": context,
} }
@api.multi @api.multi
@@ -581,22 +551,26 @@ class ContractContract(models.Model):
): ):
self.ensure_one() self.ensure_one()
if not self.env.user.has_group("contract.can_terminate_contract"): if not self.env.user.has_group("contract.can_terminate_contract"):
raise UserError(_('You are not allowed to terminate contracts.')) raise UserError(_("You are not allowed to terminate contracts."))
self.contract_line_ids.filtered('is_stop_allowed').stop(terminate_date) self.contract_line_ids.filtered("is_stop_allowed").stop(terminate_date)
self.write({ self.write(
'is_terminated': True, {
'terminate_reason_id': terminate_reason_id.id, "is_terminated": True,
'terminate_comment': terminate_comment, "terminate_reason_id": terminate_reason_id.id,
'terminate_date': terminate_date, "terminate_comment": terminate_comment,
}) "terminate_date": terminate_date,
}
)
return True return True
@api.multi @api.multi
def action_cancel_contract_termination(self): def action_cancel_contract_termination(self):
self.ensure_one() self.ensure_one()
self.write({ self.write(
'is_terminated': False, {
'terminate_reason_id': False, "is_terminated": False,
'terminate_comment': False, "terminate_reason_id": False,
'terminate_date': False, "terminate_comment": False,
}) "terminate_date": False,
}
)

File diff suppressed because it is too large Load Diff

View File

@@ -3,17 +3,18 @@
import itertools import itertools
from collections import namedtuple from collections import namedtuple
from odoo.fields import Date from odoo.fields import Date
Criteria = namedtuple( Criteria = namedtuple(
'Criteria', "Criteria",
[ [
'when', # Contract line relatively to today (BEFORE, IN, AFTER) "when", # Contract line relatively to today (BEFORE, IN, AFTER)
'has_date_end', # Is date_end set on contract line (bool) "has_date_end", # Is date_end set on contract line (bool)
'has_last_date_invoiced', # Is last_date_invoiced set on contract line "has_last_date_invoiced", # Is last_date_invoiced set on contract line
'is_auto_renew', # Is is_auto_renew set on contract line (bool) "is_auto_renew", # Is is_auto_renew set on contract line (bool)
'has_successor', # Is contract line has_successor (bool) "has_successor", # Is contract line has_successor (bool)
'predecessor_has_successor', "predecessor_has_successor",
# Is contract line predecessor has successor (bool) # Is contract line predecessor has successor (bool)
# In almost of the cases # In almost of the cases
# contract_line.predecessor.successor == contract_line # contract_line.predecessor.successor == contract_line
@@ -23,12 +24,11 @@ Criteria = namedtuple(
# If contract_line.predecessor.successor != False # If contract_line.predecessor.successor != False
# and contract_line is canceled, we don't allow uncancel # and contract_line is canceled, we don't allow uncancel
# else we re-link contract_line and its predecessor # else we re-link contract_line and its predecessor
'canceled', # Is contract line canceled (bool) "canceled", # Is contract line canceled (bool)
], ],
) )
Allowed = namedtuple( Allowed = namedtuple(
'Allowed', "Allowed", ["plan_successor", "stop_plan_successor", "stop", "cancel", "uncancel"],
['plan_successor', 'stop_plan_successor', 'stop', 'cancel', 'uncancel'],
) )
@@ -36,8 +36,8 @@ def _expand_none(criteria):
variations = [] variations = []
for attribute, value in criteria._asdict().items(): for attribute, value in criteria._asdict().items():
if value is None: if value is None:
if attribute == 'when': if attribute == "when":
variations.append(['BEFORE', 'IN', 'AFTER']) variations.append(["BEFORE", "IN", "AFTER"])
else: else:
variations.append([True, False]) variations.append([True, False])
else: else:
@@ -53,7 +53,7 @@ def _add(matrix, criteria, allowed):
CRITERIA_ALLOWED_DICT = { CRITERIA_ALLOWED_DICT = {
Criteria( Criteria(
when='BEFORE', when="BEFORE",
has_date_end=True, has_date_end=True,
has_last_date_invoiced=False, has_last_date_invoiced=False,
is_auto_renew=True, is_auto_renew=True,
@@ -68,7 +68,7 @@ CRITERIA_ALLOWED_DICT = {
uncancel=False, uncancel=False,
), ),
Criteria( Criteria(
when='BEFORE', when="BEFORE",
has_date_end=True, has_date_end=True,
has_last_date_invoiced=False, has_last_date_invoiced=False,
is_auto_renew=False, is_auto_renew=False,
@@ -83,7 +83,7 @@ CRITERIA_ALLOWED_DICT = {
uncancel=False, uncancel=False,
), ),
Criteria( Criteria(
when='BEFORE', when="BEFORE",
has_date_end=True, has_date_end=True,
has_last_date_invoiced=False, has_last_date_invoiced=False,
is_auto_renew=False, is_auto_renew=False,
@@ -98,7 +98,7 @@ CRITERIA_ALLOWED_DICT = {
uncancel=False, uncancel=False,
), ),
Criteria( Criteria(
when='BEFORE', when="BEFORE",
has_date_end=False, has_date_end=False,
has_last_date_invoiced=False, has_last_date_invoiced=False,
is_auto_renew=False, is_auto_renew=False,
@@ -113,7 +113,7 @@ CRITERIA_ALLOWED_DICT = {
uncancel=False, uncancel=False,
), ),
Criteria( Criteria(
when='IN', when="IN",
has_date_end=True, has_date_end=True,
has_last_date_invoiced=False, has_last_date_invoiced=False,
is_auto_renew=True, is_auto_renew=True,
@@ -128,7 +128,7 @@ CRITERIA_ALLOWED_DICT = {
uncancel=False, uncancel=False,
), ),
Criteria( Criteria(
when='IN', when="IN",
has_date_end=True, has_date_end=True,
has_last_date_invoiced=False, has_last_date_invoiced=False,
is_auto_renew=False, is_auto_renew=False,
@@ -143,7 +143,7 @@ CRITERIA_ALLOWED_DICT = {
uncancel=False, uncancel=False,
), ),
Criteria( Criteria(
when='IN', when="IN",
has_date_end=True, has_date_end=True,
has_last_date_invoiced=False, has_last_date_invoiced=False,
is_auto_renew=False, is_auto_renew=False,
@@ -158,7 +158,7 @@ CRITERIA_ALLOWED_DICT = {
uncancel=False, uncancel=False,
), ),
Criteria( Criteria(
when='IN', when="IN",
has_date_end=False, has_date_end=False,
has_last_date_invoiced=False, has_last_date_invoiced=False,
is_auto_renew=False, is_auto_renew=False,
@@ -173,7 +173,7 @@ CRITERIA_ALLOWED_DICT = {
uncancel=False, uncancel=False,
), ),
Criteria( Criteria(
when='BEFORE', when="BEFORE",
has_date_end=True, has_date_end=True,
has_last_date_invoiced=True, has_last_date_invoiced=True,
is_auto_renew=True, is_auto_renew=True,
@@ -188,7 +188,7 @@ CRITERIA_ALLOWED_DICT = {
uncancel=False, uncancel=False,
), ),
Criteria( Criteria(
when='BEFORE', when="BEFORE",
has_date_end=True, has_date_end=True,
has_last_date_invoiced=True, has_last_date_invoiced=True,
is_auto_renew=False, is_auto_renew=False,
@@ -203,7 +203,7 @@ CRITERIA_ALLOWED_DICT = {
uncancel=False, uncancel=False,
), ),
Criteria( Criteria(
when='BEFORE', when="BEFORE",
has_date_end=True, has_date_end=True,
has_last_date_invoiced=True, has_last_date_invoiced=True,
is_auto_renew=False, is_auto_renew=False,
@@ -218,7 +218,7 @@ CRITERIA_ALLOWED_DICT = {
uncancel=False, uncancel=False,
), ),
Criteria( Criteria(
when='BEFORE', when="BEFORE",
has_date_end=False, has_date_end=False,
has_last_date_invoiced=True, has_last_date_invoiced=True,
is_auto_renew=False, is_auto_renew=False,
@@ -233,7 +233,7 @@ CRITERIA_ALLOWED_DICT = {
uncancel=False, uncancel=False,
), ),
Criteria( Criteria(
when='IN', when="IN",
has_date_end=True, has_date_end=True,
has_last_date_invoiced=True, has_last_date_invoiced=True,
is_auto_renew=True, is_auto_renew=True,
@@ -248,7 +248,7 @@ CRITERIA_ALLOWED_DICT = {
uncancel=False, uncancel=False,
), ),
Criteria( Criteria(
when='IN', when="IN",
has_date_end=True, has_date_end=True,
has_last_date_invoiced=True, has_last_date_invoiced=True,
is_auto_renew=False, is_auto_renew=False,
@@ -263,7 +263,7 @@ CRITERIA_ALLOWED_DICT = {
uncancel=False, uncancel=False,
), ),
Criteria( Criteria(
when='IN', when="IN",
has_date_end=True, has_date_end=True,
has_last_date_invoiced=True, has_last_date_invoiced=True,
is_auto_renew=False, is_auto_renew=False,
@@ -278,7 +278,7 @@ CRITERIA_ALLOWED_DICT = {
uncancel=False, uncancel=False,
), ),
Criteria( Criteria(
when='IN', when="IN",
has_date_end=False, has_date_end=False,
has_last_date_invoiced=True, has_last_date_invoiced=True,
is_auto_renew=False, is_auto_renew=False,
@@ -293,7 +293,7 @@ CRITERIA_ALLOWED_DICT = {
uncancel=False, uncancel=False,
), ),
Criteria( Criteria(
when='AFTER', when="AFTER",
has_date_end=True, has_date_end=True,
has_last_date_invoiced=None, has_last_date_invoiced=None,
is_auto_renew=True, is_auto_renew=True,
@@ -308,7 +308,7 @@ CRITERIA_ALLOWED_DICT = {
uncancel=False, uncancel=False,
), ),
Criteria( Criteria(
when='AFTER', when="AFTER",
has_date_end=True, has_date_end=True,
has_last_date_invoiced=None, has_last_date_invoiced=None,
is_auto_renew=False, is_auto_renew=False,
@@ -323,7 +323,7 @@ CRITERIA_ALLOWED_DICT = {
uncancel=False, uncancel=False,
), ),
Criteria( Criteria(
when='AFTER', when="AFTER",
has_date_end=True, has_date_end=True,
has_last_date_invoiced=None, has_last_date_invoiced=None,
is_auto_renew=False, is_auto_renew=False,
@@ -377,10 +377,10 @@ for c in CRITERIA_ALLOWED_DICT:
def compute_when(date_start, date_end): def compute_when(date_start, date_end):
today = Date.today() today = Date.today()
if today < date_start: if today < date_start:
return 'BEFORE' return "BEFORE"
if date_end and today > date_end: if date_end and today > date_end:
return 'AFTER' return "AFTER"
return 'IN' return "IN"
def compute_criteria( def compute_criteria(

View File

@@ -6,12 +6,10 @@ from odoo import fields, models
class ContractTag(models.Model): class ContractTag(models.Model):
_name = 'contract.tag' _name = "contract.tag"
_description = 'Contract Tag' _description = "Contract Tag"
name = fields.Char(requirment=True) name = fields.Char(requirment=True)
company_id = fields.Many2one( company_id = fields.Many2one(
'res.company', "res.company", string="Company", default=lambda self: self.env.user.company_id,
string='Company',
default=lambda self: self.env.user.company_id,
) )

View File

@@ -10,13 +10,13 @@ from odoo import fields, models
class ContractTemplate(models.Model): class ContractTemplate(models.Model):
_name = 'contract.template' _name = "contract.template"
_inherit = 'contract.abstract.contract' _inherit = "contract.abstract.contract"
_description = "Contract Template" _description = "Contract Template"
contract_line_ids = fields.One2many( contract_line_ids = fields.One2many(
comodel_name='contract.template.line', comodel_name="contract.template.line",
inverse_name='contract_id', inverse_name="contract_id",
copy=True, copy=True,
string='Contract template lines', string="Contract template lines",
) )

View File

@@ -10,15 +10,15 @@ from odoo import fields, models
class ContractTemplateLine(models.Model): class ContractTemplateLine(models.Model):
_name = 'contract.template.line' _name = "contract.template.line"
_inherit = 'contract.abstract.contract.line' _inherit = "contract.abstract.contract.line"
_description = "Contract Template Line" _description = "Contract Template Line"
_order = "sequence,id" _order = "sequence,id"
contract_id = fields.Many2one( contract_id = fields.Many2one(
string='Contract', string="Contract",
comodel_name='contract.template', comodel_name="contract.template",
required=True, required=True,
ondelete='cascade', ondelete="cascade",
oldname='analytic_account_id', oldname="analytic_account_id",
) )

View File

@@ -6,8 +6,8 @@ from odoo import fields, models
class ContractTerminateReason(models.Model): class ContractTerminateReason(models.Model):
_name = 'contract.terminate.reason' _name = "contract.terminate.reason"
_description = 'Contract Termination Reason' _description = "Contract Termination Reason"
name = fields.Char(required=True) name = fields.Char(required=True)
terminate_comment_required = fields.Boolean( terminate_comment_required = fields.Boolean(

View File

@@ -13,7 +13,9 @@ class IrUiView(models.Model):
# TODO Delete this method in v13; it's upstream there # TODO Delete this method in v13; it's upstream there
result = super()._prepare_qcontext() result = super()._prepare_qcontext()
if self.env.context.get("allowed_company_ids"): if self.env.context.get("allowed_company_ids"):
result["res_company"] = self.env["res.company"].browse( result["res_company"] = (
self.env.context["allowed_company_ids"][0] self.env["res.company"]
).sudo() .browse(self.env.context["allowed_company_ids"][0])
.sudo()
)
return result return result

View File

@@ -6,7 +6,7 @@ from odoo import fields, models
class ResCompany(models.Model): class ResCompany(models.Model):
_inherit = 'res.company' _inherit = "res.company"
create_new_line_at_contract_line_renew = fields.Boolean( create_new_line_at_contract_line_renew = fields.Boolean(
string="Create New Line At Contract Line Renew", string="Create New Line At Contract Line Renew",

View File

@@ -6,7 +6,7 @@ from odoo import fields, models
class ResConfigSettings(models.TransientModel): class ResConfigSettings(models.TransientModel):
_inherit = 'res.config.settings' _inherit = "res.config.settings"
create_new_line_at_contract_line_renew = fields.Boolean( create_new_line_at_contract_line_renew = fields.Boolean(
related="company_id.create_new_line_at_contract_line_renew", related="company_id.create_new_line_at_contract_line_renew",

View File

@@ -5,45 +5,49 @@ from odoo import fields, models
class ResPartner(models.Model): class ResPartner(models.Model):
_inherit = 'res.partner' _inherit = "res.partner"
sale_contract_count = fields.Integer( sale_contract_count = fields.Integer(
string='Sale Contracts', string="Sale Contracts", compute="_compute_contract_count",
compute='_compute_contract_count',
) )
purchase_contract_count = fields.Integer( purchase_contract_count = fields.Integer(
string='Purchase Contracts', string="Purchase Contracts", compute="_compute_contract_count",
compute='_compute_contract_count',
) )
contract_ids = fields.One2many( contract_ids = fields.One2many(
comodel_name='contract.contract', comodel_name="contract.contract", inverse="partner_id", string="Contracts",
inverse='partner_id',
string="Contracts",
) )
def _compute_contract_count(self): def _compute_contract_count(self):
contract_model = self.env['contract.contract'] contract_model = self.env["contract.contract"]
fetch_data = contract_model.read_group([ fetch_data = contract_model.read_group(
('partner_id', 'child_of', self.ids)], [("partner_id", "child_of", self.ids)],
['partner_id', 'contract_type'], ['partner_id', 'contract_type'], ["partner_id", "contract_type"],
lazy=False) ["partner_id", "contract_type"],
result = [[data['partner_id'][0], data['contract_type'], lazy=False,
data['__count']] for data in fetch_data] )
result = [
[data["partner_id"][0], data["contract_type"], data["__count"]]
for data in fetch_data
]
for partner in self: for partner in self:
partner_child_ids = partner.child_ids.ids + partner.ids partner_child_ids = partner.child_ids.ids + partner.ids
partner.sale_contract_count = sum([ partner.sale_contract_count = sum(
r[2] for r in result [r[2] for r in result if r[0] in partner_child_ids and r[1] == "sale"]
if r[0] in partner_child_ids and r[1] == 'sale']) )
partner.purchase_contract_count = sum([ partner.purchase_contract_count = sum(
r[2] for r in result [
if r[0] in partner_child_ids and r[1] == 'purchase']) r[2]
for r in result
if r[0] in partner_child_ids and r[1] == "purchase"
]
)
def act_show_contract(self): def act_show_contract(self):
""" This opens contract view """ This opens contract view
@return: the contract view @return: the contract view
""" """
self.ensure_one() self.ensure_one()
contract_type = self._context.get('contract_type') contract_type = self._context.get("contract_type")
res = self._get_act_window_contract_xml(contract_type) res = self._get_act_window_contract_xml(contract_type)
res.update( res.update(
@@ -57,11 +61,11 @@ class ResPartner(models.Model):
return res return res
def _get_act_window_contract_xml(self, contract_type): def _get_act_window_contract_xml(self, contract_type):
if contract_type == 'purchase': if contract_type == "purchase":
return self.env['ir.actions.act_window'].for_xml_id( return self.env["ir.actions.act_window"].for_xml_id(
'contract', 'action_supplier_contract' "contract", "action_supplier_contract"
) )
else: else:
return self.env['ir.actions.act_window'].for_xml_id( return self.env["ir.actions.act_window"].for_xml_id(
'contract', 'action_customer_contract' "contract", "action_customer_contract"
) )

View File

@@ -1,12 +1,11 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8" ?>
<odoo> <odoo>
<report <report
id="report_contract" id="report_contract"
model="contract.contract" model="contract.contract"
string="Contract" string="Contract"
report_type="qweb-pdf" report_type="qweb-pdf"
name="contract.report_contract_document" name="contract.report_contract_document"
file="contract.report_contract"/> file="contract.report_contract"
/>
</odoo> </odoo>

View File

@@ -1,80 +1,125 @@
<?xml version="1.0" ?> <?xml version="1.0" ?>
<odoo> <odoo>
<template id="report_contract_document"> <template id="report_contract_document">
<t t-call="web.html_container"> <t t-call="web.html_container">
<t t-foreach="docs" t-as="o"> <t t-foreach="docs" t-as="o">
<t t-call="web.external_layout"> <t t-call="web.external_layout">
<t t-set="o" t-value="o.with_context(lang=o.partner_id.lang)" /> <t t-set="o" t-value="o.with_context(lang=o.partner_id.lang)" />
<t t-set="address"> <t t-set="address">
<p id="partner_info"><strong>Partner:</strong></p> <p id="partner_info">
<div t-field="o.partner_id" <strong>Partner:</strong>
t-options='{"widget": "contact", "fields": ["address", "name", "phone", "mobile", "fax", "email"], "no_marker": true, "phone_icons": true}'/> </p>
<p t-if="o.partner_id.vat">VAT: <span t-field="o.partner_id.vat"/></p> <div
t-field="o.partner_id"
t-options='{"widget": "contact", "fields": ["address", "name", "phone", "mobile", "fax", "email"], "no_marker": true, "phone_icons": true}'
/>
<p t-if="o.partner_id.vat">VAT: <span
t-field="o.partner_id.vat"
/></p>
</t> </t>
<div class="page"> <div class="page">
<div class="oe_structure"/> <div class="oe_structure" />
<div class="row" id="header_info"> <div class="row" id="header_info">
<div class="col-3"> <div class="col-3">
<strong>Responsible: </strong><p t-field="o.user_id"/> <strong>Responsible: </strong>
<strong>Contract: </strong><p t-field="o.code"/> <p t-field="o.user_id" />
<strong>Contract: </strong>
<p t-field="o.code" />
</div> </div>
</div> </div>
<div class="row" id="invoice_info"> <div class="row" id="invoice_info">
<t t-set="total" t-value="0"/> <t t-set="total" t-value="0" />
<div class="col-12"> <div class="col-12">
<t t-set="total" t-value="0"/> <t t-set="total" t-value="0" />
<p id="services_info"><strong>Recurring Items</strong></p> <p id="services_info">
<strong>Recurring Items</strong>
</p>
<table class="table table-sm"> <table class="table table-sm">
<thead> <thead>
<tr> <tr>
<th><strong>Description</strong></th> <th>
<th class="text-right"><strong>Quantity</strong></th> <strong>Description</strong>
<th class="text-right"><strong>Unit Price</strong></th> </th>
<th class="text-right"><strong>Price</strong></th> <th class="text-right">
<th class="text-right"><strong>Date Start</strong></th> <strong>Quantity</strong>
</th>
<th class="text-right">
<strong>Unit Price</strong>
</th>
<th class="text-right">
<strong>Price</strong>
</th>
<th class="text-right">
<strong>Date Start</strong>
</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<t t-set="current_subtotal" t-value="0"/> <t t-set="current_subtotal" t-value="0" />
<t t-foreach="o.contract_line_ids" t-as="l"> <t t-foreach="o.contract_line_ids" t-as="l">
<t t-set="current_subtotal" t-value="current_subtotal + l.price_subtotal"/> <t
<tr t-att-class="'bg-200 font-weight-bold o_line_section' if l.display_type == 'line_section' else 'font-italic o_line_note' if l.display_type == 'line_note' else ''"> t-set="current_subtotal"
t-value="current_subtotal + l.price_subtotal"
/>
<tr
t-att-class="'bg-200 font-weight-bold o_line_section' if l.display_type == 'line_section' else 'font-italic o_line_note' if l.display_type == 'line_note' else ''"
>
<t t-if="not l.display_type"> <t t-if="not l.display_type">
<td> <td>
<span t-field="l.name"/> <span t-field="l.name" />
</td> </td>
<td class="text-right"> <td class="text-right">
<span t-field="l.quantity"/> <span t-field="l.quantity" />
</td> </td>
<td class="text-right"> <td class="text-right">
<span t-field="l.price_unit" t-options='{"widget": "monetary", "display_currency": o.currency_id}'/> <span
t-field="l.price_unit"
t-options='{"widget": "monetary", "display_currency": o.currency_id}'
/>
</td> </td>
<td class="text-right"> <td class="text-right">
<span t-field="l.price_subtotal" t-options='{"widget": "monetary", "display_currency": o.currency_id}'/> <span
t-field="l.price_subtotal"
t-options='{"widget": "monetary", "display_currency": o.currency_id}'
/>
</td> </td>
<td class="text-right"> <td class="text-right">
<span t-field="l.date_start"/> <span t-field="l.date_start" />
</td> </td>
<t t-set="total" t-value="total + l.price_subtotal"/> <t
t-set="total"
t-value="total + l.price_subtotal"
/>
</t> </t>
<t t-if="l.display_type == 'line_section'"> <t
t-if="l.display_type == 'line_section'"
>
<td colspan="99"> <td colspan="99">
<span t-field="l.name"/> <span t-field="l.name" />
</td> </td>
<t t-set="current_section" t-value="l"/> <t
<t t-set="current_subtotal" t-value="0"/> t-set="current_section"
t-value="l"
/>
<t
t-set="current_subtotal"
t-value="0"
/>
</t> </t>
<t t-if="l.display_type == 'line_note'"> <t t-if="l.display_type == 'line_note'">
<td colspan="99"> <td colspan="99">
<span t-field="l.name"/> <span t-field="l.name" />
</td> </td>
</t> </t>
</tr> </tr>
<t t-if="current_section and (l_last or o.contract_line_ids[l_index+1].display_type == 'line_section')"> <t
t-if="current_section and (l_last or o.contract_line_ids[l_index+1].display_type == 'line_section')"
>
<tr class="is-subtotal text-right"> <tr class="is-subtotal text-right">
<td colspan="99"> <td colspan="99">
<strong class="mr16">Subtotal</strong> <strong
class="mr16"
>Subtotal</strong>
<span <span
t-esc="current_subtotal" t-esc="current_subtotal"
t-options='{"widget": "monetary", "display_currency": o.currency_id}' t-options='{"widget": "monetary", "display_currency": o.currency_id}'
@@ -88,12 +133,17 @@
</div> </div>
</div> </div>
<div id="total" class="row" name="total"> <div id="total" class="row" name="total">
<div class="col-4 ml-auto"> <div class="col-4 ml-auto">
<table class="table table-sm"> <table class="table table-sm">
<tr class="border-black o_subtotal" style=""> <tr class="border-black o_subtotal" style="">
<td><strong>Total</strong></td> <td>
<strong>Total</strong>
</td>
<td class="text-right"> <td class="text-right">
<span t-esc="total" t-options='{"widget": "monetary", "display_currency": o.currency_id}'/> <span
t-esc="total"
t-options='{"widget": "monetary", "display_currency": o.currency_id}'
/>
</td> </td>
</tr> </tr>
</table> </table>
@@ -101,10 +151,12 @@
</div> </div>
<div> <div>
<div class="row mt-4" id="note"> <div class="row mt-4" id="note">
<div><strong>Notes: </strong></div> <div>
<strong>Notes: </strong>
</div>
</div> </div>
<div class="row"> <div class="row">
<p t-field="o.note"/> <p t-field="o.note" />
</div> </div>
</div> </div>
</div> </div>
@@ -112,5 +164,4 @@
</t> </t>
</t> </t>
</template> </template>
</odoo> </odoo>

View File

@@ -1,31 +1,34 @@
<odoo noupdate="1"> <odoo noupdate="1">
<record id="rule_contract_contract_multi_company" model="ir.rule"> <record id="rule_contract_contract_multi_company" model="ir.rule">
<field name="name">Contract contract multi-company</field> <field name="name">Contract contract multi-company</field>
<field name="model_id" ref="model_contract_contract"/> <field name="model_id" ref="model_contract_contract" />
<field name="global" eval="True"/> <field name="global" eval="True" />
<field name="domain_force">['|', ('company_id', '=', False), ('company_id', 'child_of', [user.company_id.id])]</field> <field
name="domain_force"
>['|', ('company_id', '=', False), ('company_id', 'child_of', [user.company_id.id])]</field>
</record> </record>
<record id="rule_contract_line_multi_company" model="ir.rule"> <record id="rule_contract_line_multi_company" model="ir.rule">
<field name="name">Contract line multi-company</field> <field name="name">Contract line multi-company</field>
<field name="model_id" ref="model_contract_line"/> <field name="model_id" ref="model_contract_line" />
<field name="global" eval="True"/> <field name="global" eval="True" />
<field name="domain_force">['|', ('contract_id.company_id', '=', False), ('contract_id.company_id', 'child_of', [user.company_id.id])]</field> <field
name="domain_force"
>['|', ('contract_id.company_id', '=', False), ('contract_id.company_id', 'child_of', [user.company_id.id])]</field>
</record> </record>
<record id="rule_contract_template_multi_company" model="ir.rule"> <record id="rule_contract_template_multi_company" model="ir.rule">
<field name="name">Contract template multi-company</field> <field name="name">Contract template multi-company</field>
<field name="model_id" ref="model_contract_template"/> <field name="model_id" ref="model_contract_template" />
<field name="global" eval="True"/> <field name="global" eval="True" />
<field name="domain_force">['|', ('company_id', '=', False), ('company_id', 'child_of', [user.company_id.id])]</field> <field
name="domain_force"
>['|', ('company_id', '=', False), ('company_id', 'child_of', [user.company_id.id])]</field>
</record> </record>
<record id="rule_contract_template_line_multi_company" model="ir.rule"> <record id="rule_contract_template_line_multi_company" model="ir.rule">
<field name="name">Contract template line multi-company</field> <field name="name">Contract template line multi-company</field>
<field name="model_id" ref="model_contract_template_line"/> <field name="model_id" ref="model_contract_template_line" />
<field name="global" eval="True"/> <field name="global" eval="True" />
<field name="domain_force">['|', ('contract_id.company_id', '=', False), ('contract_id.company_id', 'child_of', [user.company_id.id])]</field> <field
name="domain_force"
>['|', ('contract_id.company_id', '=', False), ('contract_id.company_id', 'child_of', [user.company_id.id])]</field>
</record> </record>
</odoo> </odoo>

View File

@@ -1,23 +1,21 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2019 ACSONE SA/NV <!-- Copyright 2019 ACSONE SA/NV
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). --> License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
<odoo> <odoo>
<record model="ir.model.access" id="contract_tag_access"> <record model="ir.model.access" id="contract_tag_access">
<field name="name">contract.tag access</field> <field name="name">contract.tag access</field>
<field name="model_id" ref="model_contract_tag"/> <field name="model_id" ref="model_contract_tag" />
<field name="group_id" ref="account.group_account_invoice"/> <field name="group_id" ref="account.group_account_invoice" />
<field name="perm_read" eval="1"/> <field name="perm_read" eval="1" />
<field name="perm_create" eval="1"/> <field name="perm_create" eval="1" />
<field name="perm_write" eval="1"/> <field name="perm_write" eval="1" />
<field name="perm_unlink" eval="1"/> <field name="perm_unlink" eval="1" />
</record> </record>
<record id="contract_tag_multi_company_rule" model="ir.rule"> <record id="contract_tag_multi_company_rule" model="ir.rule">
<field name="name">Contract tag multi-company</field> <field name="name">Contract tag multi-company</field>
<field name="model_id" ref="model_contract_tag"/> <field name="model_id" ref="model_contract_tag" />
<field name="domain_force">['|', ('company_id', '=', False), ('company_id', 'child_of', [user.company_id.id])]</field> <field
name="domain_force"
>['|', ('company_id', '=', False), ('company_id', 'child_of', [user.company_id.id])]</field>
</record> </record>
</odoo> </odoo>

View File

@@ -1,27 +1,23 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2020 ACSONE SA/NV <!-- Copyright 2020 ACSONE SA/NV
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). --> License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
<odoo> <odoo>
<record model="ir.model.access" id="contract_terminate_reason_access_manager"> <record model="ir.model.access" id="contract_terminate_reason_access_manager">
<field name="name">contract.terminate.reason access manager</field> <field name="name">contract.terminate.reason access manager</field>
<field name="model_id" ref="model_contract_terminate_reason"/> <field name="model_id" ref="model_contract_terminate_reason" />
<field name="group_id" ref="account.group_account_manager"/> <field name="group_id" ref="account.group_account_manager" />
<field name="perm_read" eval="1"/> <field name="perm_read" eval="1" />
<field name="perm_create" eval="1"/> <field name="perm_create" eval="1" />
<field name="perm_write" eval="1"/> <field name="perm_write" eval="1" />
<field name="perm_unlink" eval="1"/> <field name="perm_unlink" eval="1" />
</record> </record>
<record model="ir.model.access" id="contract_terminate_reason_access_user"> <record model="ir.model.access" id="contract_terminate_reason_access_user">
<field name="name">contract.terminate.reason access user</field> <field name="name">contract.terminate.reason access user</field>
<field name="model_id" ref="model_contract_terminate_reason"/> <field name="model_id" ref="model_contract_terminate_reason" />
<field name="group_id" ref="account.group_account_invoice"/> <field name="group_id" ref="account.group_account_invoice" />
<field name="perm_read" eval="1"/> <field name="perm_read" eval="1" />
<field name="perm_create" eval="1"/> <field name="perm_create" eval="1" />
<field name="perm_write" eval="1"/> <field name="perm_write" eval="1" />
<field name="perm_unlink" eval="1"/> <field name="perm_unlink" eval="1" />
</record> </record>
</odoo> </odoo>

View File

@@ -1,12 +1,9 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2020 ACSONE SA/NV <!-- Copyright 2020 ACSONE SA/NV
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). --> License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
<odoo> <odoo>
<record id="can_terminate_contract" model="res.groups"> <record id="can_terminate_contract" model="res.groups">
<field name="name">Contract: Can Terminate Contracts</field> <field name="name">Contract: Can Terminate Contracts</field>
<field name="implied_ids" eval="[(4, ref('account.group_account_invoice'))]"/> <field name="implied_ids" eval="[(4, ref('account.group_account_invoice'))]" />
</record> </record>
</odoo> </odoo>

View File

@@ -2,37 +2,37 @@
* License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). * License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
*/ */
/* /*
If in the sub-tree view where the sections and notes are to be used If in the sub-tree view where the sections and notes are to be used
there are fields that have defined in the XML attrs = {'invisible': ....} there are fields that have defined in the XML attrs = {'invisible': ....}
and this condition is met, then an extra space appears in the rows and this condition is met, then an extra space appears in the rows
corresponding to the sections and lines. corresponding to the sections and lines.
This js was written to deal with that problem, but a solution based on This js was written to deal with that problem, but a solution based on
this can be applied directly to Odoo*/ this can be applied directly to Odoo*/
odoo.define('contract.section_and_note_backend', function (require) { odoo.define("contract.section_and_note_backend", function(require) {
"use strict"; "use strict";
var fieldRegistry = require('web.field_registry'); var fieldRegistry = require("web.field_registry");
var section_and_note_one2many = fieldRegistry.get('section_and_note_one2many'); var section_and_note_one2many = fieldRegistry.get("section_and_note_one2many");
section_and_note_one2many.include({ section_and_note_one2many.include({
_getRenderer: function () { _getRenderer: function() {
var result = this._super.apply(this, arguments); var result = this._super.apply(this, arguments);
if (this.view.arch.tag === 'tree') { if (this.view.arch.tag === "tree") {
result.include({ result.include({
_renderBodyCell: function (record, node, index, options) { _renderBodyCell: function(record, node, index, options) {
var $cell = this._super.apply(this, arguments); var $cell = this._super.apply(this, arguments);
var isSection = record.data.display_type === 'line_section'; var isSection = record.data.display_type === "line_section";
var isNote = record.data.display_type === 'line_note'; var isNote = record.data.display_type === "line_note";
if (isSection || isNote) { if (isSection || isNote) {
$cell.removeClass('o_invisible_modifier'); $cell.removeClass("o_invisible_modifier");
} }
return $cell; return $cell;
} },
}) });
} }
return result return result;
}, },
}); });
}); });

File diff suppressed because it is too large Load Diff

View File

@@ -1,89 +1,137 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8" ?>
<odoo> <odoo>
<!--FORM view--> <!--FORM view-->
<record id="contract_abstract_contract_line_form_view" model="ir.ui.view"> <record id="contract_abstract_contract_line_form_view" model="ir.ui.view">
<field name="name">contract.abstract.contract.line form view (in contract)</field> <field
name="name"
>contract.abstract.contract.line form view (in contract)</field>
<field name="model">contract.abstract.contract.line</field> <field name="model">contract.abstract.contract.line</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form> <form>
<field name="display_type" invisible="1"/> <field name="display_type" invisible="1" />
<header attrs="{'invisible': [('display_type', '!=', False)]}"/> <header attrs="{'invisible': [('display_type', '!=', False)]}" />
<sheet> <sheet>
<field name="specific_price" invisible="1"/> <field name="specific_price" invisible="1" />
<group col="4" attrs="{'invisible': [('display_type', '!=', False)]}"> <group
<field colspan="4" col="4"
name="product_id" attrs="{'invisible': [('display_type', '!=', False)]}"
attrs="{'required': [('display_type', '=', False)]}"/> >
<label for="quantity"/> <field
colspan="4"
name="product_id"
attrs="{'required': [('display_type', '=', False)]}"
/>
<label for="quantity" />
<div class="o_row"> <div class="o_row">
<field name="quantity" class="oe_inline"/> <field name="quantity" class="oe_inline" />
<field name="uom_id" <field
class="oe_inline" name="uom_id"
groups="uom.group_uom" class="oe_inline"
attrs="{'required': [('display_type', '=', False)]}"/> groups="uom.group_uom"
attrs="{'required': [('display_type', '=', False)]}"
/>
</div> </div>
<field colspan="2" name="automatic_price"/> <field colspan="2" name="automatic_price" />
<field colspan="2" name="price_unit" <field
attrs="{'readonly': [('automatic_price', '=', True)]}"/> colspan="2"
<field colspan="2" name="discount" groups="base.group_no_one"/> name="price_unit"
attrs="{'readonly': [('automatic_price', '=', True)]}"
/>
<field colspan="2" name="discount" groups="base.group_no_one" />
</group> </group>
<label
<label for="name" string="Description" attrs="{'invisible': [('display_type', '!=', False)]}"/> for="name"
<label for="name" string="Section" attrs="{'invisible': [('display_type', '!=', 'line_section')]}"/> string="Description"
<label for="name" string="Note" attrs="{'invisible': [('display_type', '!=', 'line_note')]}"/> attrs="{'invisible': [('display_type', '!=', False)]}"
<field name="name" nolabel="1"/> />
<label
<group name="note_invoicing_mode" attrs="{'invisible': [('display_type', '!=', 'line_note')]}"> for="name"
<field name="note_invoicing_mode" widget="radio"/> string="Section"
attrs="{'invisible': [('display_type', '!=', 'line_section')]}"
/>
<label
for="name"
string="Note"
attrs="{'invisible': [('display_type', '!=', 'line_note')]}"
/>
<field name="name" nolabel="1" />
<group
name="note_invoicing_mode"
attrs="{'invisible': [('display_type', '!=', 'line_note')]}"
>
<field name="note_invoicing_mode" widget="radio" />
</group> </group>
<group
<group col="4" attrs="{'invisible': [('display_type', '!=', False)]}"> col="4"
<field colspan="2" name="is_auto_renew"/> attrs="{'invisible': [('display_type', '!=', False)]}"
<field colspan="2" name="is_canceled" invisible="1"/> >
<field colspan="2" name="is_auto_renew" />
<field colspan="2" name="is_canceled" invisible="1" />
</group> </group>
<group attrs="{'invisible':['|', ('is_auto_renew', '=', False), ('display_type', '!=', False)]}"> <group
attrs="{'invisible':['|', ('is_auto_renew', '=', False), ('display_type', '!=', False)]}"
>
<group> <group>
<label for="auto_renew_interval"/> <label for="auto_renew_interval" />
<div> <div>
<field name="auto_renew_interval" <field
class="oe_inline" nolabel="1" name="auto_renew_interval"
attrs="{'required':[('is_auto_renew', '=', True)]}"/> class="oe_inline"
<field name="auto_renew_rule_type" nolabel="1"
class="oe_inline" nolabel="1" attrs="{'required':[('is_auto_renew', '=', True)]}"
attrs="{'required':[('is_auto_renew', '=', True)]}"/> />
<field
name="auto_renew_rule_type"
class="oe_inline"
nolabel="1"
attrs="{'required':[('is_auto_renew', '=', True)]}"
/>
</div> </div>
</group> </group>
<group> <group>
<label for="termination_notice_interval"/> <label for="termination_notice_interval" />
<div> <div>
<field name="termination_notice_interval" <field
class="oe_inline" nolabel="1" name="termination_notice_interval"
attrs="{'required':[('is_auto_renew', '=', True)]}"/> class="oe_inline"
<field name="termination_notice_rule_type" nolabel="1"
class="oe_inline" nolabel="1" attrs="{'required':[('is_auto_renew', '=', True)]}"
attrs="{'required':[('is_auto_renew', '=', True)]}"/> />
<field
name="termination_notice_rule_type"
class="oe_inline"
nolabel="1"
attrs="{'required':[('is_auto_renew', '=', True)]}"
/>
</div> </div>
</group> </group>
</group> </group>
<group name="recurrence_info" attrs="{'invisible': ['|', ('display_type', '=', 'line_section'), '&amp;', ('display_type', '=', 'line_note'), ('note_invoicing_mode', '!=', 'custom')]}"> <group
name="recurrence_info"
attrs="{'invisible': ['|', ('display_type', '=', 'line_section'), '&amp;', ('display_type', '=', 'line_note'), ('note_invoicing_mode', '!=', 'custom')]}"
>
<group> <group>
<label for="recurring_interval"/> <label for="recurring_interval" />
<div class="o_row"> <div class="o_row">
<field name="recurring_interval" <field
class="oe_inline" nolabel="1"/> name="recurring_interval"
<field name="recurring_rule_type" class="oe_inline"
class="oe_inline" nolabel="1"/> nolabel="1"
/>
<field
name="recurring_rule_type"
class="oe_inline"
nolabel="1"
/>
</div> </div>
</group> </group>
<group> <group>
<field name="recurring_invoicing_type"/> <field name="recurring_invoicing_type" />
<field name="recurring_invoicing_offset"/> <field name="recurring_invoicing_offset" />
</group> </group>
</group> </group>
</sheet> </sheet>
</form> </form>
</field> </field>
</record> </record>
</odoo> </odoo>

View File

@@ -1,10 +1,17 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2020 Tecnativa - Ernesto Tejeda <!-- Copyright 2020 Tecnativa - Ernesto Tejeda
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). --> License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -->
<odoo> <odoo>
<template id="assets_backend" name="contract assets" inherit_id="web.assets_backend"> <template
id="assets_backend"
name="contract assets"
inherit_id="web.assets_backend"
>
<xpath expr="." position="inside"> <xpath expr="." position="inside">
<script type="text/javascript" src="/contract/static/src/js/section_and_note_fields_backend.js"></script> <script
type="text/javascript"
src="/contract/static/src/js/section_and_note_fields_backend.js"
/>
</xpath> </xpath>
</template> </template>
</odoo> </odoo>

View File

@@ -1,202 +1,317 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8" ?>
<odoo> <odoo>
<!--Main FORM view--> <!--Main FORM view-->
<record id="contract_contract_form_view" model="ir.ui.view"> <record id="contract_contract_form_view" model="ir.ui.view">
<field name="name">contract.contract form view (in contract)</field> <field name="name">contract.contract form view (in contract)</field>
<field name="model">contract.contract</field> <field name="model">contract.contract</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form> <form>
<field name="is_terminated" invisible="1"/> <field name="is_terminated" invisible="1" />
<div class="alert alert-danger" role="alert" style="margin-bottom:0px;" attrs="{'invisible': [('is_terminated','=',False)]}"> <div
class="alert alert-danger"
role="alert"
style="margin-bottom:0px;"
attrs="{'invisible': [('is_terminated','=',False)]}"
>
<p> <p>
This contract was terminated for the reason This contract was terminated for the reason
<strong> <strong>
<field name="terminate_reason_id" options="{'no_open':True}"/> <field
name="terminate_reason_id"
options="{'no_open':True}"
/>
</strong> </strong>
on on
<field name="terminate_date"/> <field name="terminate_date" />
. .
</p> </p>
<p> <p>
<field name="terminate_comment"/> <field name="terminate_comment" />
</p> </p>
</div> </div>
<header> <header>
<button name="action_contract_send" <button
name="action_contract_send"
type="object" type="object"
string="Send by Email" string="Send by Email"
attrs="{'invisible': [('is_terminated','=',True)]}" attrs="{'invisible': [('is_terminated','=',True)]}"
groups="base.group_user"/> groups="base.group_user"
<button name="recurring_create_invoice" />
<button
name="recurring_create_invoice"
type="object" type="object"
attrs="{'invisible': ['|', ('create_invoice_visibility', '=', False)]}" attrs="{'invisible': ['|', ('create_invoice_visibility', '=', False)]}"
string="Create invoices" string="Create invoices"
groups="base.group_no_one"/> groups="base.group_no_one"
<button name="action_terminate_contract" />
<button
name="action_terminate_contract"
type="object" type="object"
string="Terminate Contract" string="Terminate Contract"
attrs="{'invisible': [('is_terminated','=',True)]}" attrs="{'invisible': [('is_terminated','=',True)]}"
groups="contract.can_terminate_contract"/> groups="contract.can_terminate_contract"
<button name="action_terminate_contract" />
<button
name="action_terminate_contract"
type="object" type="object"
string="Update Termination Details" string="Update Termination Details"
attrs="{'invisible': [('is_terminated','=',False)]}" attrs="{'invisible': [('is_terminated','=',False)]}"
groups="contract.can_terminate_contract"/> groups="contract.can_terminate_contract"
<button name="action_cancel_contract_termination" />
<button
name="action_cancel_contract_termination"
type="object" type="object"
confirm="Are you sure you want to re-activate this contract?" confirm="Are you sure you want to re-activate this contract?"
string="Cancel Contract Termination" string="Cancel Contract Termination"
attrs="{'invisible': [('is_terminated','=',False)]}" attrs="{'invisible': [('is_terminated','=',False)]}"
groups="contract.can_terminate_contract"/> groups="contract.can_terminate_contract"
/>
</header> </header>
<sheet string="Contract"> <sheet string="Contract">
<div class="oe_button_box" name="button_box"> <div class="oe_button_box" name="button_box">
<button class="oe_stat_button" type="object" <button
name="toggle_active" icon="fa-archive"> class="oe_stat_button"
<field name="active" widget="boolean_button" type="object"
options="{&quot;terminology&quot;: &quot;archive&quot;}"/> name="toggle_active"
icon="fa-archive"
>
<field
name="active"
widget="boolean_button"
options="{&quot;terminology&quot;: &quot;archive&quot;}"
/>
</button> </button>
<button name="action_show_invoices" <button
type="object" icon="fa-list" name="action_show_invoices"
class="oe_stat_button"> type="object"
<field string="Invoices" icon="fa-list"
class="oe_stat_button"
>
<field
string="Invoices"
name="invoice_count" name="invoice_count"
widget="statinfo"/> widget="statinfo"
/>
</button> </button>
</div> </div>
<div class="oe_title"> <div class="oe_title">
<label for="name" string="Contract Name" <label for="name" string="Contract Name" class="oe_edit_only" />
class="oe_edit_only"/>
<h3> <h3>
<field name="name" class="oe_inline" <field
name="name"
class="oe_inline"
attrs="{'readonly': [('is_terminated','=',True)]}" attrs="{'readonly': [('is_terminated','=',True)]}"
placeholder="e.g. Contract XYZ"/> placeholder="e.g. Contract XYZ"
/>
</h3> </h3>
</div> </div>
<group name="main"> <group name="main">
<group> <group>
<field name="commercial_partner_id" invisible="1"/> <field name="commercial_partner_id" invisible="1" />
<field name="partner_id" required="1" attrs="{'readonly': [('is_terminated','=',True)]}"/> <field
<field name="payment_term_id" attrs="{'readonly': [('is_terminated','=',True)]}"/> name="partner_id"
<field name="user_id" attrs="{'readonly': [('is_terminated','=',True)]}"/> required="1"
attrs="{'readonly': [('is_terminated','=',True)]}"
/>
<field
name="payment_term_id"
attrs="{'readonly': [('is_terminated','=',True)]}"
/>
<field
name="user_id"
attrs="{'readonly': [('is_terminated','=',True)]}"
/>
</group> </group>
<group> <group>
<field name="contract_template_id" <field
name="contract_template_id"
attrs="{'readonly': [('is_terminated','=',True)]}" attrs="{'readonly': [('is_terminated','=',True)]}"
domain="['|', ('contract_type', '=', contract_type), ('contract_type', '=', False)]" domain="['|', ('contract_type', '=', contract_type), ('contract_type', '=', False)]"
context="{'default_contract_type': contract_type}"/> context="{'default_contract_type': contract_type}"
<field name="contract_type" invisible="1" />
required="1"/> <field name="contract_type" invisible="1" required="1" />
<field name="fiscal_position_id" attrs="{'readonly': [('is_terminated','=',True)]}"/> <field
<field name="tag_ids" widget="many2many_tags"/> name="fiscal_position_id"
attrs="{'readonly': [('is_terminated','=',True)]}"
/>
<field name="tag_ids" widget="many2many_tags" />
</group> </group>
</group> </group>
<group name="recurring_invoices"> <group name="recurring_invoices">
<group> <group>
<field name="journal_id" required="1" attrs="{'readonly': [('is_terminated','=',True)]}"/> <field
<field name="recurring_next_date"/> name="journal_id"
required="1"
attrs="{'readonly': [('is_terminated','=',True)]}"
/>
<field name="recurring_next_date" />
</group> </group>
<group> <group>
<field name="pricelist_id" attrs="{'readonly': [('is_terminated','=',True)]}"/> <field
<field name="date_end"/> name="pricelist_id"
attrs="{'readonly': [('is_terminated','=',True)]}"
/>
<field name="date_end" />
</group> </group>
</group> </group>
<notebook> <notebook>
<page name="recurring_invoice_line" <page name="recurring_invoice_line" string="Recurring Invoices">
string="Recurring Invoices"> <field
<field name="contract_line_ids" name="contract_line_ids"
attrs="{'readonly': [('is_terminated','=',True)]}" attrs="{'readonly': [('is_terminated','=',True)]}"
widget="section_and_note_one2many" widget="section_and_note_one2many"
context="{'default_contract_type': contract_type}"> context="{'default_contract_type': contract_type}"
<tree decoration-muted="is_canceled" >
decoration-info="create_invoice_visibility and not is_canceled"> <tree
decoration-muted="is_canceled"
decoration-info="create_invoice_visibility and not is_canceled"
>
<control> <control>
<create string="Add a line"/> <create string="Add a line" />
<create string="Add a section" context="{'default_display_type': 'line_section'}"/> <create
<create string="Add a note" context="{'default_display_type': 'line_note'}"/> string="Add a section"
context="{'default_display_type': 'line_section'}"
/>
<create
string="Add a note"
context="{'default_display_type': 'line_note'}"
/>
</control> </control>
<field name="display_type" invisible="1"/> <field name="display_type" invisible="1" />
<field name="sequence" widget="handle"/> <field name="sequence" widget="handle" />
<field name="product_id"/> <field name="product_id" />
<field name="name" widget="section_and_note_text"/> <field name="name" widget="section_and_note_text" />
<field name="analytic_account_id" groups="analytic.group_analytic_accounting"/> <field
<field name="analytic_tag_ids" widget="many2many_tags" groups="analytic.group_analytic_tags"/> name="analytic_account_id"
<field name="quantity"/> groups="analytic.group_analytic_accounting"
<field name="uom_id"/> />
<field name="automatic_price" attrs="{'column_invisible': [('parent.contract_type', '=', 'purchase')]}"/> <field
<field name="price_unit" name="analytic_tag_ids"
attrs="{'readonly': [('automatic_price', '=', True)]}"/> widget="many2many_tags"
<field name="specific_price" invisible="1"/> groups="analytic.group_analytic_tags"
<field name="discount" groups="base.group_no_one"/> />
<field name="price_subtotal"/> <field name="quantity" />
<field name="recurring_interval" invisible="1"/> <field name="uom_id" />
<field name="recurring_rule_type" invisible="1"/> <field
<field name="recurring_invoicing_type" invisible="1"/> name="automatic_price"
<field name="date_start" required="1"/> attrs="{'column_invisible': [('parent.contract_type', '=', 'purchase')]}"
<field name="date_end"/> />
<field name="recurring_next_date" required="1"/> <field
<field name="last_date_invoiced" groups="base.group_no_one"/> name="price_unit"
<field name="create_invoice_visibility" invisible="1"/> attrs="{'readonly': [('automatic_price', '=', True)]}"
<field name="is_plan_successor_allowed" invisible="1"/> />
<field name="is_stop_plan_successor_allowed" invisible="1"/> <field name="specific_price" invisible="1" />
<field name="is_stop_allowed" invisible="1"/> <field name="discount" groups="base.group_no_one" />
<field name="is_cancel_allowed" invisible="1"/> <field name="price_subtotal" />
<field name="is_un_cancel_allowed" invisible="1"/> <field name="recurring_interval" invisible="1" />
<field name="is_auto_renew" invisible="1"/> <field name="recurring_rule_type" invisible="1" />
<field name="is_canceled" invisible="1"/> <field
<button name="action_plan_successor" name="recurring_invoicing_type"
string="Plan Start" type="object" invisible="1"
icon="fa-calendar text-success" />
attrs="{'invisible': [('is_plan_successor_allowed', '=', False)]}"/> <field name="date_start" required="1" />
<button name="action_stop_plan_successor" <field name="date_end" />
string="Stop Plan Successor" <field name="recurring_next_date" required="1" />
type="object" <field
icon="fa-pause text-muted" name="last_date_invoiced"
attrs="{'invisible': [('is_stop_plan_successor_allowed', '=', False)]}"/> groups="base.group_no_one"
<button name="action_stop" string="Stop" />
type="object" <field
icon="fa-stop text-danger" name="create_invoice_visibility"
attrs="{'invisible': [('is_stop_allowed', '=', False)]}"/> invisible="1"
<button name="cancel" string="Cancel" />
type="object" <field
icon="fa-ban text-danger" name="is_plan_successor_allowed"
confirm="Are you sure you want to cancel this line" invisible="1"
attrs="{'invisible': [('is_cancel_allowed', '=', False)]}"/> />
<button name="action_uncancel" <field
string="Un-cancel" type="object" name="is_stop_plan_successor_allowed"
icon="fa-ban text-success" invisible="1"
attrs="{'invisible': [('is_un_cancel_allowed', '=', False)]}"/> />
<button name="renew" string="Renew" <field name="is_stop_allowed" invisible="1" />
type="object" <field name="is_cancel_allowed" invisible="1" />
icon="fa-fast-forward text-success" <field name="is_un_cancel_allowed" invisible="1" />
groups="base.group_no_one" <field name="is_auto_renew" invisible="1" />
attrs="{'invisible': [('is_auto_renew', '=', False)]}"/> <field name="is_canceled" invisible="1" />
<button
name="action_plan_successor"
string="Plan Start"
type="object"
icon="fa-calendar text-success"
attrs="{'invisible': [('is_plan_successor_allowed', '=', False)]}"
/>
<button
name="action_stop_plan_successor"
string="Stop Plan Successor"
type="object"
icon="fa-pause text-muted"
attrs="{'invisible': [('is_stop_plan_successor_allowed', '=', False)]}"
/>
<button
name="action_stop"
string="Stop"
type="object"
icon="fa-stop text-danger"
attrs="{'invisible': [('is_stop_allowed', '=', False)]}"
/>
<button
name="cancel"
string="Cancel"
type="object"
icon="fa-ban text-danger"
confirm="Are you sure you want to cancel this line"
attrs="{'invisible': [('is_cancel_allowed', '=', False)]}"
/>
<button
name="action_uncancel"
string="Un-cancel"
type="object"
icon="fa-ban text-success"
attrs="{'invisible': [('is_un_cancel_allowed', '=', False)]}"
/>
<button
name="renew"
string="Renew"
type="object"
icon="fa-fast-forward text-success"
groups="base.group_no_one"
attrs="{'invisible': [('is_auto_renew', '=', False)]}"
/>
</tree> </tree>
</field> </field>
<field name="note"/> <field name="note" />
</page> </page>
<page name="info" string="Other Information"> <page name="info" string="Other Information">
<field name="create_invoice_visibility" <field name="create_invoice_visibility" invisible="1" />
invisible="1"/>
<group> <group>
<field name="code" attrs="{'readonly': [('is_terminated','=',True)]}"/> <field
<field name="group_id" attrs="{'readonly': [('is_terminated','=',True)]}"/> name="code"
<field name="company_id" attrs="{'readonly': [('is_terminated','=',True)]}"
/>
<field
name="group_id"
attrs="{'readonly': [('is_terminated','=',True)]}"
/>
<field
name="company_id"
attrs="{'readonly': [('is_terminated','=',True)]}" attrs="{'readonly': [('is_terminated','=',True)]}"
options="{'no_create': True}" options="{'no_create': True}"
groups="base.group_multi_company"/> groups="base.group_multi_company"
<field name="currency_id" />
<field
name="currency_id"
groups="base.group_multi_currency"
/>
<field
name="invoice_partner_id"
attrs="{'readonly': [('is_terminated','=',True)]}" attrs="{'readonly': [('is_terminated','=',True)]}"
options="{'no_create': True}" required="1"
groups="base.group_multi_currency"/> />
<field name="invoice_partner_id"
attrs="{'readonly': [('is_terminated','=',True)]}"
required="1"/>
</group> </group>
<group string="Legend (for the markers inside invoice lines description)" <group
name="group_legend"> string="Legend (for the markers inside invoice lines description)"
name="group_legend"
>
<p colspan="2"> <p colspan="2">
<strong>#START#</strong> <strong>#START#</strong>
: Start : Start
@@ -216,117 +331,131 @@
</notebook> </notebook>
</sheet> </sheet>
<div class="oe_chatter"> <div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers"/> <field name="message_follower_ids" widget="mail_followers" />
<field name="activity_ids" widget="mail_activity"/> <field name="activity_ids" widget="mail_activity" />
<field name="message_ids" widget="mail_thread"/> <field name="message_ids" widget="mail_thread" />
</div> </div>
</form> </form>
</field> </field>
</record> </record>
<!--Customer FORM view--> <!--Customer FORM view-->
<record id="contract_contract_customer_form_view" model="ir.ui.view"> <record id="contract_contract_customer_form_view" model="ir.ui.view">
<field name="name">contract.contract customer form view (in contract)</field> <field name="name">contract.contract customer form view (in contract)</field>
<field name="model">contract.contract</field> <field name="model">contract.contract</field>
<field name="inherit_id" ref="contract_contract_form_view"/> <field name="inherit_id" ref="contract_contract_form_view" />
<field name="mode">primary</field> <field name="mode">primary</field>
<field name="priority" eval="20"/> <field name="priority" eval="20" />
<field name="arch" type="xml"> <field name="arch" type="xml">
<field name="partner_id" position="attributes"> <field name="partner_id" position="attributes">
<attribute name="string">Customer</attribute> <attribute name="string">Customer</attribute>
<attribute name="domain">[('customer', '=', True)]</attribute> <attribute name="domain">[('customer', '=', True)]</attribute>
<attribute name="context">{'default_customer': True, 'default_supplier': False}</attribute> <attribute
name="context"
>{'default_customer': True, 'default_supplier': False}</attribute>
</field> </field>
<field name="journal_id" position="attributes"> <field name="journal_id" position="attributes">
<attribute name="domain">[('type', '=', 'sale'),('company_id', '=', company_id)]</attribute> <attribute
name="domain"
>[('type', '=', 'sale'),('company_id', '=', company_id)]</attribute>
</field> </field>
</field> </field>
</record> </record>
<!--Supplier FORM view--> <!--Supplier FORM view-->
<record id="contract_contract_supplier_form_view" model="ir.ui.view"> <record id="contract_contract_supplier_form_view" model="ir.ui.view">
<field name="name">contract.contract supplier form view (in contract)</field> <field name="name">contract.contract supplier form view (in contract)</field>
<field name="model">contract.contract</field> <field name="model">contract.contract</field>
<field name="inherit_id" ref="contract_contract_form_view"/> <field name="inherit_id" ref="contract_contract_form_view" />
<field name="mode">primary</field> <field name="mode">primary</field>
<field name="priority" eval="20"/> <field name="priority" eval="20" />
<field name="arch" type="xml"> <field name="arch" type="xml">
<field name="partner_id" position="attributes"> <field name="partner_id" position="attributes">
<attribute name="string">Supplier</attribute> <attribute name="string">Supplier</attribute>
<attribute name="domain">[('supplier', '=', True)]</attribute> <attribute name="domain">[('supplier', '=', True)]</attribute>
<attribute name="context">{'default_customer': False, 'default_supplier': True}</attribute> <attribute
name="context"
>{'default_customer': False, 'default_supplier': True}</attribute>
</field> </field>
<field name="journal_id" position="attributes"> <field name="journal_id" position="attributes">
<attribute name="domain">[('type', '=', 'purchase'),('company_id', '=', company_id)]</attribute> <attribute
name="domain"
>[('type', '=', 'purchase'),('company_id', '=', company_id)]</attribute>
</field> </field>
</field> </field>
</record> </record>
<!--TREE view--> <!--TREE view-->
<record id="contract_contract_tree_view" model="ir.ui.view"> <record id="contract_contract_tree_view" model="ir.ui.view">
<field name="name">contract.contract tree view (in contract)</field> <field name="name">contract.contract tree view (in contract)</field>
<field name="model">contract.contract</field> <field name="model">contract.contract</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree> <tree>
<field name="name" string="Name"/> <field name="name" string="Name" />
<field name="code"/> <field name="code" />
<field name="journal_id" groups="account.group_account_user"/> <field name="journal_id" groups="account.group_account_user" />
<field name="partner_id"/> <field name="partner_id" />
<field name="active" invisible="1"/> <field name="active" invisible="1" />
<field name="company_id" groups="base.group_multi_company"/> <field name="company_id" groups="base.group_multi_company" />
</tree> </tree>
</field> </field>
</record> </record>
<!--SEARCH view--> <!--SEARCH view-->
<record id="contract_contract_search_view" model="ir.ui.view"> <record id="contract_contract_search_view" model="ir.ui.view">
<field name="name">contract.contract search view (in contract)</field> <field name="name">contract.contract search view (in contract)</field>
<field name="model">contract.contract</field> <field name="model">contract.contract</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<search> <search>
<field name="name" <field
filter_domain="['|', ('name','ilike',self), ('code','ilike',self)]"/> name="name"
<field name="journal_id"/> filter_domain="['|', ('name','ilike',self), ('code','ilike',self)]"
<field name="pricelist_id"/> />
<separator/> <field name="journal_id" />
<separator/> <field name="pricelist_id" />
<filter name="not_finished" <separator />
<separator />
<filter
name="not_finished"
string="In progress" string="In progress"
domain="['|', ('date_end', '&gt;=', context_today().strftime('%Y-%m-%d')), '&amp;', ('date_end', '=', False), ('recurring_next_date', '!=', False)]" domain="['|', ('date_end', '&gt;=', context_today().strftime('%Y-%m-%d')), '&amp;', ('date_end', '=', False), ('recurring_next_date', '!=', False)]"
/> />
<filter name="finished" <filter
name="finished"
string="Finished" string="Finished"
domain="[('date_end', '&lt;', context_today().strftime('%Y-%m-%d')), ('recurring_next_date', '=', False)]" domain="[('date_end', '&lt;', context_today().strftime('%Y-%m-%d')), ('recurring_next_date', '=', False)]"
/> />
<field name="partner_id"/> <field name="partner_id" />
<field name="commercial_partner_id"/> <field name="commercial_partner_id" />
<filter string="Archived" <filter
string="Archived"
domain="[('active', '=', False)]" domain="[('active', '=', False)]"
name="inactive"/> name="inactive"
/>
<group expand="0" string="Group By..."> <group expand="0" string="Group By...">
<filter string="Associated Partner" <filter
string="Associated Partner"
name="group_by_partner" name="group_by_partner"
domain="[]" domain="[]"
context="{'group_by':'partner_id'}"/> context="{'group_by':'partner_id'}"
<filter name="commercial_partner_groupby" />
<filter
name="commercial_partner_groupby"
string="Commercial Entity" string="Commercial Entity"
context="{'group_by': 'commercial_partner_id'}"/> context="{'group_by': 'commercial_partner_id'}"
<filter name="group_by_next_invoice" />
<filter
name="group_by_next_invoice"
string="Next Invoice" string="Next Invoice"
domain="[('recurring_next_date', '!=', False)]" domain="[('recurring_next_date', '!=', False)]"
context="{'group_by':'recurring_next_date'}" context="{'group_by':'recurring_next_date'}"
/> />
<filter name="group_by_date_end" <filter
name="group_by_date_end"
string="Date End" string="Date End"
domain="[]" domain="[]"
context="{'group_by':'date_end'}" context="{'group_by':'date_end'}"
/> />
</group> </group>
</search> </search>
</field> </field>
</record> </record>
<!--ACTION customer contracts--> <!--ACTION customer contracts-->
<record id="action_customer_contract" model="ir.actions.act_window"> <record id="action_customer_contract" model="ir.actions.act_window">
<field name="name">Customer Contracts</field> <field name="name">Customer Contracts</field>
@@ -339,34 +468,31 @@
'search_default_not_finished':1, 'search_default_not_finished':1,
'default_contract_type': 'sale'} 'default_contract_type': 'sale'}
</field> </field>
<field name="search_view_id" ref="contract_contract_search_view"/> <field name="search_view_id" ref="contract_contract_search_view" />
<field name="help" type="html"> <field name="help" type="html">
<p class="oe_view_nocontent_create"> <p class="oe_view_nocontent_create">
Click to create a new contract. Click to create a new contract.
</p> </p>
</field> </field>
</record> </record>
<record id="action_customer_contract_view_tree" model="ir.actions.act_window.view"> <record id="action_customer_contract_view_tree" model="ir.actions.act_window.view">
<field name="sequence" eval="1"/> <field name="sequence" eval="1" />
<field name="view_mode">tree</field> <field name="view_mode">tree</field>
<field name="view_id" ref="contract_contract_tree_view"/> <field name="view_id" ref="contract_contract_tree_view" />
<field name="act_window_id" ref="action_customer_contract"/> <field name="act_window_id" ref="action_customer_contract" />
</record> </record>
<record id="action_customer_contract_view_form" model="ir.actions.act_window.view"> <record id="action_customer_contract_view_form" model="ir.actions.act_window.view">
<field name="sequence" eval="2"/> <field name="sequence" eval="2" />
<field name="view_mode">form</field> <field name="view_mode">form</field>
<field name="view_id" ref="contract_contract_customer_form_view"/> <field name="view_id" ref="contract_contract_customer_form_view" />
<field name="act_window_id" ref="action_customer_contract"/> <field name="act_window_id" ref="action_customer_contract" />
</record> </record>
<menuitem
<menuitem id="menu_contract_contract_customer" id="menu_contract_contract_customer"
parent="account.menu_finance_receivables" parent="account.menu_finance_receivables"
action="action_customer_contract" action="action_customer_contract"
sequence="99" sequence="99"
/> />
<!--ACTION supplier contracts--> <!--ACTION supplier contracts-->
<record id="action_supplier_contract" model="ir.actions.act_window"> <record id="action_supplier_contract" model="ir.actions.act_window">
<field name="name">Supplier Contracts</field> <field name="name">Supplier Contracts</field>
@@ -379,32 +505,29 @@
'search_default_not_finished':1, 'search_default_not_finished':1,
'default_contract_type': 'purchase'} 'default_contract_type': 'purchase'}
</field> </field>
<field name="search_view_id" ref="contract_contract_search_view"/> <field name="search_view_id" ref="contract_contract_search_view" />
<field name="help" type="html"> <field name="help" type="html">
<p class="oe_view_nocontent_create"> <p class="oe_view_nocontent_create">
Click to create a new contract. Click to create a new contract.
</p> </p>
</field> </field>
</record> </record>
<record id="action_supplier_contract_view_tree" model="ir.actions.act_window.view"> <record id="action_supplier_contract_view_tree" model="ir.actions.act_window.view">
<field name="sequence" eval="1"/> <field name="sequence" eval="1" />
<field name="view_mode">tree</field> <field name="view_mode">tree</field>
<field name="view_id" ref="contract_contract_tree_view"/> <field name="view_id" ref="contract_contract_tree_view" />
<field name="act_window_id" ref="action_supplier_contract"/> <field name="act_window_id" ref="action_supplier_contract" />
</record> </record>
<record id="action_supplier_contract_view_form" model="ir.actions.act_window.view"> <record id="action_supplier_contract_view_form" model="ir.actions.act_window.view">
<field name="sequence" eval="2"/> <field name="sequence" eval="2" />
<field name="view_mode">form</field> <field name="view_mode">form</field>
<field name="view_id" ref="contract_contract_supplier_form_view"/> <field name="view_id" ref="contract_contract_supplier_form_view" />
<field name="act_window_id" ref="action_supplier_contract"/> <field name="act_window_id" ref="action_supplier_contract" />
</record> </record>
<menuitem
<menuitem id="menu_contract_contract_supplier" id="menu_contract_contract_supplier"
parent="account.menu_finance_payables" parent="account.menu_finance_payables"
action="action_supplier_contract" action="action_supplier_contract"
sequence="99" sequence="99"
/> />
</odoo> </odoo>

View File

@@ -1,74 +1,82 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8" ?>
<odoo> <odoo>
<!--FORM view--> <!--FORM view-->
<record id="contract_line_form_view" model="ir.ui.view"> <record id="contract_line_form_view" model="ir.ui.view">
<field name="name">contract.line form view (in contract)</field> <field name="name">contract.line form view (in contract)</field>
<field name="model">contract.line</field> <field name="model">contract.line</field>
<field name="inherit_id" ref="contract_abstract_contract_line_form_view"/> <field name="inherit_id" ref="contract_abstract_contract_line_form_view" />
<field name="mode">primary</field> <field name="mode">primary</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<header position="inside"> <header position="inside">
<field name="state" widget="statusbar"/> <field name="state" widget="statusbar" />
</header> </header>
<group name="recurrence_info" position="inside"> <group name="recurrence_info" position="inside">
<group> <group>
<field name="create_invoice_visibility" invisible="1"/> <field name="create_invoice_visibility" invisible="1" />
<field name="date_start" required="1"/> <field name="date_start" required="1" />
<field name="next_period_date_start"/> <field name="next_period_date_start" />
<field name="recurring_next_date"/> <field name="recurring_next_date" />
</group> </group>
<group> <group>
<field name="date_end" <field
attrs="{'required': [('is_auto_renew', '=', True)]}"/> name="date_end"
<field name="next_period_date_end"/> attrs="{'required': [('is_auto_renew', '=', True)]}"
/>
<field name="next_period_date_end" />
</group> </group>
<group groups="base.group_no_one"> <group groups="base.group_no_one">
<field name="last_date_invoiced" readonly="True"/> <field name="last_date_invoiced" readonly="True" />
<field name="termination_notice_date" readonly="True"/> <field name="termination_notice_date" readonly="True" />
</group> </group>
<group> <group>
<field name="manual_renew_needed"/> <field name="manual_renew_needed" />
</group> </group>
<group> <group>
<field name="predecessor_contract_line_id"/> <field name="predecessor_contract_line_id" />
</group> </group>
<group> <group>
<field name="successor_contract_line_id"/> <field name="successor_contract_line_id" />
</group> </group>
</group> </group>
<group name="recurrence_info" position="after"> <group name="recurrence_info" position="after">
<group name="analytic" <group
groups="analytic.group_analytic_accounting,analytic.group_analytic_tags" name="analytic"
attrs="{'invisible': [('display_type', '!=', False)]}"> groups="analytic.group_analytic_accounting,analytic.group_analytic_tags"
<field name="analytic_account_id" groups="analytic.group_analytic_accounting"/> attrs="{'invisible': [('display_type', '!=', False)]}"
<field name="analytic_tag_ids" widget="many2many_tags" groups="analytic.group_analytic_tags"/> >
<field
name="analytic_account_id"
groups="analytic.group_analytic_accounting"
/>
<field
name="analytic_tag_ids"
widget="many2many_tags"
groups="analytic.group_analytic_tags"
/>
</group> </group>
</group> </group>
</field> </field>
</record> </record>
<!--Customer FORM view--> <!--Customer FORM view-->
<record id="contract_line_customer_form_view" model="ir.ui.view"> <record id="contract_line_customer_form_view" model="ir.ui.view">
<field name="name">contract.line customer form view (in contract)</field> <field name="name">contract.line customer form view (in contract)</field>
<field name="model">contract.line</field> <field name="model">contract.line</field>
<field name="inherit_id" ref="contract_line_form_view"/> <field name="inherit_id" ref="contract_line_form_view" />
<field name="mode">primary</field> <field name="mode">primary</field>
<field name="priority" eval="20"/> <field name="priority" eval="20" />
<field name="arch" type="xml"> <field name="arch" type="xml">
<field name="product_id" position="attributes"> <field name="product_id" position="attributes">
<attribute name="domain">[('sale_ok', '=', True)]</attribute> <attribute name="domain">[('sale_ok', '=', True)]</attribute>
</field> </field>
</field> </field>
</record> </record>
<!--Supplier FORM view--> <!--Supplier FORM view-->
<record id="contract_line_supplier_form_view" model="ir.ui.view"> <record id="contract_line_supplier_form_view" model="ir.ui.view">
<field name="name">contract.line supplier form view (in contract)</field> <field name="name">contract.line supplier form view (in contract)</field>
<field name="model">contract.line</field> <field name="model">contract.line</field>
<field name="inherit_id" ref="contract_line_form_view"/> <field name="inherit_id" ref="contract_line_form_view" />
<field name="mode">primary</field> <field name="mode">primary</field>
<field name="priority" eval="20"/> <field name="priority" eval="20" />
<field name="arch" type="xml"> <field name="arch" type="xml">
<field name="product_id" position="attributes"> <field name="product_id" position="attributes">
<attribute name="domain">[('purchase_ok', '=', True)]</attribute> <attribute name="domain">[('purchase_ok', '=', True)]</attribute>
@@ -78,99 +86,111 @@
</field> </field>
</field> </field>
</record> </record>
<!-- TODO: Delete this view in migration to v13 or further migrations --> <!-- TODO: Delete this view in migration to v13 or further migrations -->
<!--TREE view--> <!--TREE view-->
<record id="contract_line_tree_view" model="ir.ui.view"> <record id="contract_line_tree_view" model="ir.ui.view">
<field name="name">contract.line tree view (in contract)</field> <field name="name">contract.line tree view (in contract)</field>
<field name="model">contract.line</field> <field name="model">contract.line</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree decoration-muted="is_canceled" <tree
decoration-info="create_invoice_visibility and not is_canceled"> decoration-muted="is_canceled"
<field name="sequence" widget="handle"/> decoration-info="create_invoice_visibility and not is_canceled"
<field name="product_id"/> >
<field name="name"/> <field name="sequence" widget="handle" />
<field name="analytic_account_id" groups="analytic.group_analytic_accounting"/> <field name="product_id" />
<field name="analytic_tag_ids" widget="many2many_tags" groups="analytic.group_analytic_tags"/> <field name="name" />
<field name="quantity"/> <field
<field name="uom_id"/> name="analytic_account_id"
<field name="automatic_price"/> groups="analytic.group_analytic_accounting"
<field name="price_unit" />
attrs="{'readonly': [('automatic_price', '=', True)]}"/> <field
<field name="specific_price" name="analytic_tag_ids"
invisible="1"/> widget="many2many_tags"
<field name="discount" groups="analytic.group_analytic_tags"
groups="base.group_no_one"/> />
<field name="price_subtotal"/> <field name="quantity" />
<field name="recurring_interval" <field name="uom_id" />
invisible="1"/> <field name="automatic_price" />
<field name="recurring_rule_type" <field
invisible="1"/> name="price_unit"
<field name="recurring_invoicing_type" attrs="{'readonly': [('automatic_price', '=', True)]}"
invisible="1"/> />
<field name="date_start" required="1"/> <field name="specific_price" invisible="1" />
<field name="date_end"/> <field name="discount" groups="base.group_no_one" />
<field name="recurring_next_date" <field name="price_subtotal" />
required="1"/> <field name="recurring_interval" invisible="1" />
<field name="last_date_invoiced" <field name="recurring_rule_type" invisible="1" />
groups="base.group_no_one"/> <field name="recurring_invoicing_type" invisible="1" />
<field name="create_invoice_visibility" <field name="date_start" required="1" />
invisible="1"/> <field name="date_end" />
<field name="is_plan_successor_allowed" <field name="recurring_next_date" required="1" />
invisible="1"/> <field name="last_date_invoiced" groups="base.group_no_one" />
<field name="is_stop_plan_successor_allowed" <field name="create_invoice_visibility" invisible="1" />
invisible="1"/> <field name="is_plan_successor_allowed" invisible="1" />
<field name="is_stop_allowed" <field name="is_stop_plan_successor_allowed" invisible="1" />
invisible="1"/> <field name="is_stop_allowed" invisible="1" />
<field name="is_cancel_allowed" <field name="is_cancel_allowed" invisible="1" />
invisible="1"/> <field name="is_un_cancel_allowed" invisible="1" />
<field name="is_un_cancel_allowed" <field name="is_auto_renew" invisible="1" />
invisible="1"/> <field name="is_canceled" invisible="1" />
<field name="is_auto_renew" invisible="1"/> <button
<field name="is_canceled" invisible="1"/> name="action_plan_successor"
<button name="action_plan_successor" string="Plan Start"
string="Plan Start" type="object" type="object"
icon="fa-calendar text-success" icon="fa-calendar text-success"
attrs="{'invisible': [('is_plan_successor_allowed', '=', False)]}"/> attrs="{'invisible': [('is_plan_successor_allowed', '=', False)]}"
<button name="action_stop_plan_successor" />
string="Stop Plan Successor" <button
type="object" name="action_stop_plan_successor"
icon="fa-pause text-muted" string="Stop Plan Successor"
attrs="{'invisible': [('is_stop_plan_successor_allowed', '=', False)]}"/> type="object"
<button name="action_stop" string="Stop" icon="fa-pause text-muted"
type="object" attrs="{'invisible': [('is_stop_plan_successor_allowed', '=', False)]}"
icon="fa-stop text-danger" />
attrs="{'invisible': [('is_stop_allowed', '=', False)]}"/> <button
<button name="cancel" string="Cancel" name="action_stop"
type="object" string="Stop"
icon="fa-ban text-danger" type="object"
confirm="Are you sure you want to cancel this line" icon="fa-stop text-danger"
attrs="{'invisible': [('is_cancel_allowed', '=', False)]}"/> attrs="{'invisible': [('is_stop_allowed', '=', False)]}"
<button name="action_uncancel" />
string="Un-cancel" type="object" <button
icon="fa-ban text-success" name="cancel"
attrs="{'invisible': [('is_un_cancel_allowed', '=', False)]}"/> string="Cancel"
<button name="renew" string="Renew" type="object"
type="object" icon="fa-ban text-danger"
icon="fa-fast-forward text-success" confirm="Are you sure you want to cancel this line"
groups="base.group_no_one" attrs="{'invisible': [('is_cancel_allowed', '=', False)]}"
attrs="{'invisible': [('is_auto_renew', '=', False)]}"/> />
<button
name="action_uncancel"
string="Un-cancel"
type="object"
icon="fa-ban text-success"
attrs="{'invisible': [('is_un_cancel_allowed', '=', False)]}"
/>
<button
name="renew"
string="Renew"
type="object"
icon="fa-fast-forward text-success"
groups="base.group_no_one"
attrs="{'invisible': [('is_auto_renew', '=', False)]}"
/>
</tree> </tree>
</field> </field>
</record> </record>
<!--Supplier TREE view--> <!--Supplier TREE view-->
<record id="contract_line_supplier_tree_view" model="ir.ui.view"> <record id="contract_line_supplier_tree_view" model="ir.ui.view">
<field name="name">contract.line supplier tree view (in contract)</field> <field name="name">contract.line supplier tree view (in contract)</field>
<field name="model">contract.line</field> <field name="model">contract.line</field>
<field name="mode">primary</field> <field name="mode">primary</field>
<field name="priority" eval="20"/> <field name="priority" eval="20" />
<field name="inherit_id" ref="contract_line_tree_view"/> <field name="inherit_id" ref="contract_line_tree_view" />
<field name="arch" type="xml"> <field name="arch" type="xml">
<field name="automatic_price" position="attributes"> <field name="automatic_price" position="attributes">
<attribute name="invisible">True</attribute> <attribute name="invisible">True</attribute>
</field> </field>
</field> </field>
</record> </record>
</odoo> </odoo>

View File

@@ -1,45 +1,44 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2020 ACSONE SA/NV <!-- Copyright 2020 ACSONE SA/NV
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). --> License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
<odoo> <odoo>
<record id="contract_tag_form_view" model="ir.ui.view"> <record id="contract_tag_form_view" model="ir.ui.view">
<field name="model">contract.tag</field> <field name="model">contract.tag</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form> <form>
<group> <group>
<field name="name"/> <field name="name" />
<field name="company_id" options="{'no_create': True}" <field
groups="base.group_multi_company"/> name="company_id"
options="{'no_create': True}"
groups="base.group_multi_company"
/>
</group> </group>
</form> </form>
</field> </field>
</record> </record>
<record model="ir.ui.view" id="contract_tag_tree_view"> <record model="ir.ui.view" id="contract_tag_tree_view">
<field name="model">contract.tag</field> <field name="model">contract.tag</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree> <tree>
<field name="name"/> <field name="name" />
<field name="company_id" options="{'no_create': True}" <field
groups="base.group_multi_company"/> name="company_id"
options="{'no_create': True}"
groups="base.group_multi_company"
/>
</tree> </tree>
</field> </field>
</record> </record>
<record model="ir.actions.act_window" id="contract_tag_act_window"> <record model="ir.actions.act_window" id="contract_tag_act_window">
<field name="name">Contract Tags</field> <field name="name">Contract Tags</field>
<field name="res_model">contract.tag</field> <field name="res_model">contract.tag</field>
<field name="view_mode">tree,form</field> <field name="view_mode">tree,form</field>
</record> </record>
<record model="ir.ui.menu" id="contract_tag_menu"> <record model="ir.ui.menu" id="contract_tag_menu">
<field name="name">Contract Tag</field> <field name="name">Contract Tag</field>
<field name="parent_id" ref="menu_config_contract"/> <field name="parent_id" ref="menu_config_contract" />
<field name="action" ref="contract_tag_act_window"/> <field name="action" ref="contract_tag_act_window" />
<field name="sequence" eval="16"/> <field name="sequence" eval="16" />
</record> </record>
</odoo> </odoo>

View File

@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8" ?>
<odoo> <odoo>
<!--FORM view--> <!--FORM view-->
<record id="contract_template_form_view" model="ir.ui.view"> <record id="contract_template_form_view" model="ir.ui.view">
<field name="name">contract.template form view (in contract)</field> <field name="name">contract.template form view (in contract)</field>
@@ -8,53 +7,71 @@
<field name="arch" type="xml"> <field name="arch" type="xml">
<form string="Contract Template"> <form string="Contract Template">
<group name="name"> <group name="name">
<field name="name"/> <field name="name" />
</group> </group>
<group name="group_main"> <group name="group_main">
<group name="group_main_left"> <group name="group_main_left">
<field name="contract_type" /> <field name="contract_type" />
<field name="journal_id" /> <field name="journal_id" />
<field name="pricelist_id" /> <field name="pricelist_id" />
<field name="company_id" options="{'no_create': True}" groups="base.group_multi_company"/> <field
name="company_id"
options="{'no_create': True}"
groups="base.group_multi_company"
/>
</group> </group>
</group> </group>
<group name="group_invoice_lines" string="Contract Template Lines"> <group name="group_invoice_lines" string="Contract Template Lines">
<field name="contract_line_ids" <field
widget="section_and_note_one2many" name="contract_line_ids"
nolabel="1"> widget="section_and_note_one2many"
nolabel="1"
>
<tree> <tree>
<control> <control>
<create string="Add a line"/> <create string="Add a line" />
<create string="Add a section" context="{'default_display_type': 'line_section'}"/> <create
<create string="Add a note" context="{'default_display_type': 'line_note'}"/> string="Add a section"
context="{'default_display_type': 'line_section'}"
/>
<create
string="Add a note"
context="{'default_display_type': 'line_note'}"
/>
</control> </control>
<field name="display_type" invisible="1"/> <field name="display_type" invisible="1" />
<field name="sequence" widget="handle" /> <field name="sequence" widget="handle" />
<field name="product_id" /> <field name="product_id" />
<field name="name" widget="section_and_note_text"/> <field name="name" widget="section_and_note_text" />
<field name="quantity" /> <field name="quantity" />
<field name="uom_id" /> <field name="uom_id" />
<field name="automatic_price" attrs="{'column_invisible': [('parent.contract_type','=','purchase')]}"/> <field
<field name="price_unit" attrs="{'readonly': [('automatic_price', '=', True)]}"/> name="automatic_price"
<field name="specific_price" invisible="1"/> attrs="{'column_invisible': [('parent.contract_type','=','purchase')]}"
/>
<field
name="price_unit"
attrs="{'readonly': [('automatic_price', '=', True)]}"
/>
<field name="specific_price" invisible="1" />
<field name="discount" groups="base.group_no_one" /> <field name="discount" groups="base.group_no_one" />
<field name="price_subtotal" /> <field name="price_subtotal" />
<field name="recurring_rule_type" invisible="1"/> <field name="recurring_rule_type" invisible="1" />
<field name="recurring_interval" invisible="1"/> <field name="recurring_interval" invisible="1" />
<field name="recurring_invoicing_type" invisible="1"/> <field name="recurring_invoicing_type" invisible="1" />
</tree> </tree>
</field> </field>
</group> </group>
<group name="group_legend" <group
string="Legend (for the markers inside invoice lines description)" name="group_legend"
> string="Legend (for the markers inside invoice lines description)"
>
<p> <strong>#START#</strong>: Start date of the invoiced period</p> <p> <strong>#START#</strong>: Start date of the invoiced period</p>
<p> <strong>#END#</strong>: End date of the invoiced period</p> <p> <strong>#END#</strong>: End date of the invoiced period</p>
</group> </group>
</form> </form>
</field> </field>
</record> </record>
<!--TREE view--> <!--TREE view-->
<record id="contract_template_tree_view" model="ir.ui.view"> <record id="contract_template_tree_view" model="ir.ui.view">
<field name="name">contract.template tree view (in contract)</field> <field name="name">contract.template tree view (in contract)</field>
@@ -67,7 +84,6 @@
</tree> </tree>
</field> </field>
</record> </record>
<!--SEARCH view--> <!--SEARCH view-->
<record id="contract_template_search_view" model="ir.ui.view"> <record id="contract_template_search_view" model="ir.ui.view">
<field name="name">contract.template search view (in contract)</field> <field name="name">contract.template search view (in contract)</field>
@@ -78,40 +94,41 @@
<field name="contract_type" /> <field name="contract_type" />
<field name="pricelist_id" /> <field name="pricelist_id" />
<field name="journal_id" /> <field name="journal_id" />
<filter name="contract_type" <filter
string="Contract Type" name="contract_type"
context="{'group_by': 'contract_type'}" string="Contract Type"
/> context="{'group_by': 'contract_type'}"
<filter name="pricelist_id" />
string="Pricelist" <filter
context="{'group_by': 'pricelist_id'}" name="pricelist_id"
/> string="Pricelist"
<filter name="journal_id" context="{'group_by': 'pricelist_id'}"
string="Journal" />
context="{'group_by': 'journal_id'}" <filter
/> name="journal_id"
string="Journal"
context="{'group_by': 'journal_id'}"
/>
</search> </search>
</field> </field>
</record> </record>
<!--ACTION--> <!--ACTION-->
<record id="contract_template_action" model="ir.actions.act_window"> <record id="contract_template_action" model="ir.actions.act_window">
<field name="name">Contract Templates</field> <field name="name">Contract Templates</field>
<field name="res_model">contract.template</field> <field name="res_model">contract.template</field>
<field name="view_type">form</field> <field name="view_type">form</field>
<field name="view_mode">tree,form</field> <field name="view_mode">tree,form</field>
<field name="search_view_id" ref="contract_template_search_view"/> <field name="search_view_id" ref="contract_template_search_view" />
<field name="help" type="html"> <field name="help" type="html">
<p class="oe_view_nocontent_create"> <p class="oe_view_nocontent_create">
Click to create a new contract template. Click to create a new contract template.
</p> </p>
</field> </field>
</record> </record>
<menuitem
<menuitem id="contract_template_menu" id="contract_template_menu"
parent="menu_config_contract" parent="menu_config_contract"
action="contract_template_action" action="contract_template_action"
sequence="1" sequence="1"
/> />
</odoo> </odoo>

View File

@@ -1,11 +1,10 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8" ?>
<odoo> <odoo>
<!--FORM view--> <!--FORM view-->
<record id="contract_template_line_form_view" model="ir.ui.view"> <record id="contract_template_line_form_view" model="ir.ui.view">
<field name="name">contract.template.line form view (in contract)</field> <field name="name">contract.template.line form view (in contract)</field>
<field name="model">contract.template.line</field> <field name="model">contract.template.line</field>
<field name="inherit_id" ref="contract_abstract_contract_line_form_view"/> <field name="inherit_id" ref="contract_abstract_contract_line_form_view" />
<field name="mode">primary</field> <field name="mode">primary</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form position="attributes"> <form position="attributes">
@@ -13,5 +12,4 @@
</form> </form>
</field> </field>
</record> </record>
</odoo> </odoo>

View File

@@ -1,45 +1,38 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2020 ACSONE SA/NV <!-- Copyright 2020 ACSONE SA/NV
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). --> License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
<odoo> <odoo>
<record model="ir.ui.view" id="contract_terminate_reason_form_view"> <record model="ir.ui.view" id="contract_terminate_reason_form_view">
<field name="model">contract.terminate.reason</field> <field name="model">contract.terminate.reason</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form> <form>
<sheet> <sheet>
<group> <group>
<field name="name"/> <field name="name" />
<field name="terminate_comment_required"/> <field name="terminate_comment_required" />
</group> </group>
</sheet> </sheet>
</form> </form>
</field> </field>
</record> </record>
<record model="ir.ui.view" id="contract_terminate_reason_tree_view"> <record model="ir.ui.view" id="contract_terminate_reason_tree_view">
<field name="model">contract.terminate.reason</field> <field name="model">contract.terminate.reason</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree> <tree>
<field name="name"/> <field name="name" />
<field name="terminate_comment_required"/> <field name="terminate_comment_required" />
</tree> </tree>
</field> </field>
</record> </record>
<record model="ir.actions.act_window" id="contract_terminate_reason_act_window"> <record model="ir.actions.act_window" id="contract_terminate_reason_act_window">
<field name="name">Contract Termination Reason</field> <field name="name">Contract Termination Reason</field>
<field name="res_model">contract.terminate.reason</field> <field name="res_model">contract.terminate.reason</field>
<field name="view_mode">tree,form</field> <field name="view_mode">tree,form</field>
</record> </record>
<record model="ir.ui.menu" id="contract_terminate_reason_menu"> <record model="ir.ui.menu" id="contract_terminate_reason_menu">
<field name="name">Contract Termination Reason</field> <field name="name">Contract Termination Reason</field>
<field name="parent_id" ref="menu_config_contract"/> <field name="parent_id" ref="menu_config_contract" />
<field name="action" ref="contract_terminate_reason_act_window"/> <field name="action" ref="contract_terminate_reason_act_window" />
<field name="sequence" eval="16"/> <field name="sequence" eval="16" />
</record> </record>
</odoo> </odoo>

View File

@@ -1,28 +1,24 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2019 ACSONE SA/NV <!-- Copyright 2019 ACSONE SA/NV
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). --> License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
<odoo> <odoo>
<record model="ir.ui.view" id="res_config_settings_form_view"> <record model="ir.ui.view" id="res_config_settings_form_view">
<field name="model">res.config.settings</field> <field name="model">res.config.settings</field>
<field name="inherit_id" ref="account.res_config_settings_view_form"/> <field name="inherit_id" ref="account.res_config_settings_view_form" />
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//div[@data-key='account']" position="inside"> <xpath expr="//div[@data-key='account']" position="inside">
<h2>Contract</h2> <h2>Contract</h2>
<div class="row mt16 o_settings_container"> <div class="row mt16 o_settings_container">
<div class="col-12 col-lg-6 o_setting_box"> <div class="col-12 col-lg-6 o_setting_box">
<div class="o_setting_left_pane"> <div class="o_setting_left_pane">
<field name="create_new_line_at_contract_line_renew"/> <field name="create_new_line_at_contract_line_renew" />
</div> </div>
<div class="o_setting_right_pane"> <div class="o_setting_right_pane">
<label for="create_new_line_at_contract_line_renew"/> <label for="create_new_line_at_contract_line_renew" />
</div> </div>
</div> </div>
</div> </div>
</xpath> </xpath>
</field> </field>
</record> </record>
</odoo> </odoo>

View File

@@ -1,36 +1,52 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2017 Carlos Dauden <carlos.dauden@tecnativa.com> <!-- Copyright 2017 Carlos Dauden <carlos.dauden@tecnativa.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). --> License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
<odoo> <odoo>
<record id="view_partner_form" model="ir.ui.view"> <record id="view_partner_form" model="ir.ui.view">
<field name="inherit_id" ref="base.view_partner_form" /> <field name="inherit_id" ref="base.view_partner_form" />
<field name="model">res.partner</field> <field name="model">res.partner</field>
<field name="groups_id" eval="[(4, ref('account.group_account_invoice'))]"/> <field name="groups_id" eval="[(4, ref('account.group_account_invoice'))]" />
<field type="xml" name="arch"> <field type="xml" name="arch">
<xpath expr="//div[@name='button_box']" position="inside"> <xpath expr="//div[@name='button_box']" position="inside">
<button name="act_show_contract" type="object" class="oe_stat_button" <button
icon="fa-book" context="{'default_contract_type': 'sale', 'contract_type': 'sale'}" name="act_show_contract"
type="object"
class="oe_stat_button"
icon="fa-book"
context="{'default_contract_type': 'sale', 'contract_type': 'sale'}"
attrs="{'invisible': [('customer','=',False)]}" attrs="{'invisible': [('customer','=',False)]}"
help="Show the sale contracts for this partner"> help="Show the sale contracts for this partner"
<field name="sale_contract_count" widget="statinfo" string="Sale Contracts"/> >
</button> <field
<button name="act_show_contract" type="object" class="oe_stat_button" name="sale_contract_count"
icon="fa-book" context="{'default_contract_type': 'purchase', 'contract_type': 'purchase'}" widget="statinfo"
string="Sale Contracts"
/>
</button>
<button
name="act_show_contract"
type="object"
class="oe_stat_button"
icon="fa-book"
context="{'default_contract_type': 'purchase', 'contract_type': 'purchase'}"
attrs="{'invisible': [('supplier','=',False)]}" attrs="{'invisible': [('supplier','=',False)]}"
help="Show the purchase contracts for this partner"> help="Show the purchase contracts for this partner"
<field name="purchase_contract_count" widget="statinfo" string="Purchase Contracts"/> >
</button> <field
</xpath> name="purchase_contract_count"
widget="statinfo"
string="Purchase Contracts"
/>
</button>
</xpath>
</field> </field>
</record> </record>
<record id="view_res_partner_filter" model="ir.ui.view"> <record id="view_res_partner_filter" model="ir.ui.view">
<field name="inherit_id" ref="base.view_res_partner_filter" /> <field name="inherit_id" ref="base.view_res_partner_filter" />
<field name="model">res.partner</field> <field name="model">res.partner</field>
<field type="xml" name="arch"> <field type="xml" name="arch">
<filter name="inactive" position="after"> <filter name="inactive" position="after">
<separator/> <separator />
<filter <filter
name="filter_running_contract" name="filter_running_contract"
string="With running contracts" string="With running contracts"
@@ -39,5 +55,4 @@
</filter> </filter>
</field> </field>
</record> </record>
</odoo> </odoo>

View File

@@ -6,7 +6,7 @@ from odoo import api, fields, models
class ContractContractTerminate(models.TransientModel): class ContractContractTerminate(models.TransientModel):
_name = 'contract.contract.terminate' _name = "contract.contract.terminate"
_description = "Terminate Contract Wizard" _description = "Terminate Contract Wizard"
contract_id = fields.Many2one( contract_id = fields.Many2one(

View File

@@ -1,34 +1,32 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2020 ACSONE SA/NV <!-- Copyright 2020 ACSONE SA/NV
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). --> License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
<odoo> <odoo>
<record model="ir.ui.view" id="contract_contract_terminate_form_view"> <record model="ir.ui.view" id="contract_contract_terminate_form_view">
<field name="model">contract.contract.terminate</field> <field name="model">contract.contract.terminate</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form string="Contract Contract Terminate"> <form string="Contract Contract Terminate">
<group> <group>
<field name="contract_id" invisible="True"/> <field name="contract_id" invisible="True" />
<field name="terminate_comment_required" invisible="True"/> <field name="terminate_comment_required" invisible="True" />
<field name="terminate_date"/> <field name="terminate_date" />
<field name="terminate_reason_id" widget="selection"/> <field name="terminate_reason_id" widget="selection" />
<field name="terminate_comment" attrs="{'required': [('terminate_comment_required', '=', True)]}"/> <field
name="terminate_comment"
attrs="{'required': [('terminate_comment_required', '=', True)]}"
/>
</group> </group>
<footer> <footer>
<button name="terminate_contract" <button
string="Terminate Contract" name="terminate_contract"
class="btn-primary" string="Terminate Contract"
confirm="Are you sure you want to terminate this contract?" class="btn-primary"
type="object"/> confirm="Are you sure you want to terminate this contract?"
<button string="Cancel" type="object"
class="btn-default" />
special="cancel"/> <button string="Cancel" class="btn-default" special="cancel" />
</footer> </footer>
</form> </form>
</field> </field>
</record> </record>
</odoo> </odoo>

View File

@@ -6,12 +6,12 @@ from odoo import api, fields, models
class ContractLineWizard(models.TransientModel): class ContractLineWizard(models.TransientModel):
_name = 'contract.line.wizard' _name = "contract.line.wizard"
_description = 'Contract Line Wizard' _description = "Contract Line Wizard"
date_start = fields.Date(string='Date Start') date_start = fields.Date(string="Date Start")
date_end = fields.Date(string='Date End') date_end = fields.Date(string="Date End")
recurring_next_date = fields.Date(string='Next Invoice Date') recurring_next_date = fields.Date(string="Next Invoice Date")
is_auto_renew = fields.Boolean(string="Auto Renew", default=False) is_auto_renew = fields.Boolean(string="Auto Renew", default=False)
manual_renew_needed = fields.Boolean( manual_renew_needed = fields.Boolean(
string="Manual renew needed", string="Manual renew needed",

View File

@@ -1,100 +1,114 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2018 ACSONE SA/NV <!-- Copyright 2018 ACSONE SA/NV
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). --> License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
<odoo> <odoo>
<record model="ir.ui.view" id="contract_line_wizard_stop_form_view"> <record model="ir.ui.view" id="contract_line_wizard_stop_form_view">
<field name="name">contract.line.stop.wizard.form (in contract)</field> <field name="name">contract.line.stop.wizard.form (in contract)</field>
<field name="model">contract.line.wizard</field> <field name="model">contract.line.wizard</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form> <form>
<group> <group>
<field name="contract_line_id" invisible="True"/> <field name="contract_line_id" invisible="True" />
<field string="Stop Date" name="date_end" required="True"/> <field string="Stop Date" name="date_end" required="True" />
<field string="Is suspension without end date" name="manual_renew_needed"/> <field
string="Is suspension without end date"
name="manual_renew_needed"
/>
</group> </group>
<footer> <footer>
<button name="stop" <button
string="Validate" name="stop"
class="btn-primary" string="Validate"
type="object"/> class="btn-primary"
<button string="Cancel" type="object"
class="btn-default" />
special="cancel"/> <button string="Cancel" class="btn-default" special="cancel" />
</footer> </footer>
</form> </form>
</field> </field>
</record> </record>
<record model="ir.ui.view" id="contract_line_wizard_plan_successor_form_view"> <record model="ir.ui.view" id="contract_line_wizard_plan_successor_form_view">
<field name="name">contract.line.plan_successor.wizard.form (in contract)</field> <field
name="name"
>contract.line.plan_successor.wizard.form (in contract)</field>
<field name="model">contract.line.wizard</field> <field name="model">contract.line.wizard</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form> <form>
<group> <group>
<field name="contract_line_id" invisible="True"/> <field name="contract_line_id" invisible="True" />
<field name="date_start" required="True"/> <field name="date_start" required="True" />
<field name="date_end" attrs="{'required': [('is_auto_renew', '=', True)]}"/> <field
<field name="is_auto_renew"/> name="date_end"
attrs="{'required': [('is_auto_renew', '=', True)]}"
/>
<field name="is_auto_renew" />
</group> </group>
<footer> <footer>
<button name="plan_successor" <button
string="Validate" name="plan_successor"
class="btn-primary" string="Validate"
type="object"/> class="btn-primary"
<button string="Cancel" type="object"
class="btn-default" />
special="cancel"/> <button string="Cancel" class="btn-default" special="cancel" />
</footer> </footer>
</form> </form>
</field> </field>
</record> </record>
<record model="ir.ui.view" id="contract_line_wizard_stop_plan_successor_form_view"> <record model="ir.ui.view" id="contract_line_wizard_stop_plan_successor_form_view">
<field name="name">contract.line.stop_plan_successor.wizard.form (in contract)</field> <field
name="name"
>contract.line.stop_plan_successor.wizard.form (in contract)</field>
<field name="model">contract.line.wizard</field> <field name="model">contract.line.wizard</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form> <form>
<group> <group>
<field name="contract_line_id" invisible="True"/> <field name="contract_line_id" invisible="True" />
<field string="Suspension Start Date" name="date_start" required="True"/> <field
<field string="Suspension End Date" name="date_end" required="True"/> string="Suspension Start Date"
<field name="is_auto_renew" invisible="1"/> name="date_start"
required="True"
/>
<field
string="Suspension End Date"
name="date_end"
required="True"
/>
<field name="is_auto_renew" invisible="1" />
</group> </group>
<footer> <footer>
<button name="stop_plan_successor" <button
string="Validate" name="stop_plan_successor"
class="btn-primary" string="Validate"
type="object"/> class="btn-primary"
<button string="Cancel" type="object"
class="btn-default" />
special="cancel"/> <button string="Cancel" class="btn-default" special="cancel" />
</footer> </footer>
</form> </form>
</field> </field>
</record> </record>
<record model="ir.ui.view" id="contract_line_wizard_uncancel_form_view"> <record model="ir.ui.view" id="contract_line_wizard_uncancel_form_view">
<field name="name">contract.line.stop_plan_successor.wizard.form (in contract)</field> <field
name="name"
>contract.line.stop_plan_successor.wizard.form (in contract)</field>
<field name="model">contract.line.wizard</field> <field name="model">contract.line.wizard</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form> <form>
<group> <group>
<field name="contract_line_id" invisible="True"/> <field name="contract_line_id" invisible="True" />
<field name="recurring_next_date" required="True"/> <field name="recurring_next_date" required="True" />
</group> </group>
<footer> <footer>
<button name="uncancel" <button
string="Validate" name="uncancel"
class="btn-primary" string="Validate"
type="object"/> class="btn-primary"
<button string="Cancel" type="object"
class="btn-default" />
special="cancel"/> <button string="Cancel" class="btn-default" special="cancel" />
</footer> </footer>
</form> </form>
</field> </field>
</record> </record>
</odoo> </odoo>

View File

@@ -1,40 +1,38 @@
# Copyright 2019 ACSONE SA/NV # Copyright 2019 ACSONE SA/NV
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, fields, models, _ from odoo import _, api, fields, models
class ContractManuallyCreateInvoice(models.TransientModel): class ContractManuallyCreateInvoice(models.TransientModel):
_name = 'contract.manually.create.invoice' _name = "contract.manually.create.invoice"
_description = 'Contract Manually Create Invoice Wizard' _description = "Contract Manually Create Invoice Wizard"
invoice_date = fields.Date(string="Invoice Date", required=True) invoice_date = fields.Date(string="Invoice Date", required=True)
contract_to_invoice_count = fields.Integer( contract_to_invoice_count = fields.Integer(
compute="_compute_contract_to_invoice_ids" compute="_compute_contract_to_invoice_ids"
) )
contract_to_invoice_ids = fields.Many2many( contract_to_invoice_ids = fields.Many2many(
comodel_name="contract.contract", comodel_name="contract.contract", compute="_compute_contract_to_invoice_ids",
compute="_compute_contract_to_invoice_ids",
) )
contract_type = fields.Selection( contract_type = fields.Selection(
selection=[('sale', 'Customer'), ('purchase', 'Supplier')], selection=[("sale", "Customer"), ("purchase", "Supplier")],
default='sale', default="sale",
required=True, required=True,
) )
@api.depends('invoice_date') @api.depends("invoice_date")
def _compute_contract_to_invoice_ids(self): def _compute_contract_to_invoice_ids(self):
if not self.invoice_date: if not self.invoice_date:
# trick to show no invoice when no date has been entered yet # trick to show no invoice when no date has been entered yet
contract_to_invoice_domain = [('id', '=', False)] contract_to_invoice_domain = [("id", "=", False)]
else: else:
contract_to_invoice_domain = self.env[ contract_to_invoice_domain = self.env[
'contract.contract' "contract.contract"
]._get_contracts_to_invoice_domain(self.invoice_date) ]._get_contracts_to_invoice_domain(self.invoice_date)
self.contract_to_invoice_ids = self.env['contract.contract'].search( self.contract_to_invoice_ids = self.env["contract.contract"].search(
contract_to_invoice_domain contract_to_invoice_domain + [("contract_type", "=", self.contract_type)]
+ [('contract_type', '=', self.contract_type)]
) )
self.contract_to_invoice_count = len(self.contract_to_invoice_ids) self.contract_to_invoice_count = len(self.contract_to_invoice_ids)
@@ -45,7 +43,7 @@ class ContractManuallyCreateInvoice(models.TransientModel):
"type": "ir.actions.act_window", "type": "ir.actions.act_window",
"name": _("Contracts to invoice"), "name": _("Contracts to invoice"),
"res_model": "contract.contract", "res_model": "contract.contract",
"domain": [('id', 'in', self.contract_to_invoice_ids.ids)], "domain": [("id", "in", self.contract_to_invoice_ids.ids)],
"view_mode": "tree,form", "view_mode": "tree,form",
"context": self.env.context, "context": self.env.context,
} }
@@ -53,14 +51,14 @@ class ContractManuallyCreateInvoice(models.TransientModel):
@api.multi @api.multi
def create_invoice(self): def create_invoice(self):
self.ensure_one() self.ensure_one()
invoices = self.env['account.invoice'] invoices = self.env["account.invoice"]
for contract in self.contract_to_invoice_ids: for contract in self.contract_to_invoice_ids:
invoices |= contract.recurring_create_invoice() invoices |= contract.recurring_create_invoice()
return { return {
"type": "ir.actions.act_window", "type": "ir.actions.act_window",
"name": _("Invoices"), "name": _("Invoices"),
"res_model": "account.invoice", "res_model": "account.invoice",
"domain": [('id', 'in', invoices.ids)], "domain": [("id", "in", invoices.ids)],
"view_mode": "tree,form", "view_mode": "tree,form",
"context": self.env.context, "context": self.env.context,
} }

View File

@@ -1,79 +1,91 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2019 ACSONE SA/NV <!-- Copyright 2019 ACSONE SA/NV
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). --> License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
<odoo> <odoo>
<record model="ir.ui.view" id="contract_manually_create_invoice_form_view"> <record model="ir.ui.view" id="contract_manually_create_invoice_form_view">
<field name="model">contract.manually.create.invoice</field> <field name="model">contract.manually.create.invoice</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form string="Contract Manually Create Invoice"> <form string="Contract Manually Create Invoice">
<group> <group>
<group> <group>
<field name="invoice_date"/> <field name="invoice_date" />
<field name="contract_type" invisible="1"/> <field name="contract_type" invisible="1" />
</group> </group>
<group> <group>
<button name="action_show_contract_to_invoice" type="object" <button
class="btn-link" name="action_show_contract_to_invoice"
attrs="{'invisible': [('contract_to_invoice_count', '=', 0)]}"> type="object"
<field name="contract_to_invoice_count"/> class="btn-link"
<span attrs="{'invisible': [('contract_to_invoice_count', '&gt;', 1)]}"> attrs="{'invisible': [('contract_to_invoice_count', '=', 0)]}"
>
<field name="contract_to_invoice_count" />
<span
attrs="{'invisible': [('contract_to_invoice_count', '&gt;', 1)]}"
>
contract to invoice contract to invoice
</span> </span>
<span attrs="{'invisible': [('contract_to_invoice_count', '&lt;', 1)]}"> <span
attrs="{'invisible': [('contract_to_invoice_count', '&lt;', 1)]}"
>
contracts to invoice contracts to invoice
</span> </span>
</button> </button>
</group> </group>
</group> </group>
<footer> <footer>
<button name="create_invoice" <button
attrs="{'invisible': [('contract_to_invoice_count', '=', 0)]}" name="create_invoice"
string="Create Invoices" attrs="{'invisible': [('contract_to_invoice_count', '=', 0)]}"
class="btn-primary" string="Create Invoices"
type="object"/> class="btn-primary"
<button string="Cancel" type="object"
class="btn-default" />
special="cancel"/> <button string="Cancel" class="btn-default" special="cancel" />
</footer> </footer>
</form> </form>
</field> </field>
</record> </record>
<record
<record model="ir.actions.act_window" model="ir.actions.act_window"
id="sale_contract_manually_create_invoice_act_window"> id="sale_contract_manually_create_invoice_act_window"
>
<field name="name">Manually Invoice Sale Contracts</field> <field name="name">Manually Invoice Sale Contracts</field>
<field name="res_model">contract.manually.create.invoice</field> <field name="res_model">contract.manually.create.invoice</field>
<field name="view_mode">form</field> <field name="view_mode">form</field>
<field name="context">{'default_contract_type': 'sale'}</field> <field name="context">{'default_contract_type': 'sale'}</field>
<field name="target">new</field> <field name="target">new</field>
</record> </record>
<record model="ir.ui.menu" id="sale_contract_manually_create_invoice_menu"> <record model="ir.ui.menu" id="sale_contract_manually_create_invoice_menu">
<field name="name">Manually Invoice Sale Contracts</field> <field name="name">Manually Invoice Sale Contracts</field>
<field name="parent_id" ref="account.menu_finance_receivables"/> <field name="parent_id" ref="account.menu_finance_receivables" />
<field name="groups_id" eval="[(6, 0, [ref('account.group_account_manager')])]"/> <field
<field name="action" name="groups_id"
ref="sale_contract_manually_create_invoice_act_window"/> eval="[(6, 0, [ref('account.group_account_manager')])]"
<field name="sequence" eval="999"/> />
<field name="action" ref="sale_contract_manually_create_invoice_act_window" />
<field name="sequence" eval="999" />
</record> </record>
<record
<record model="ir.actions.act_window" model="ir.actions.act_window"
id="purchase_contract_manually_create_invoice_act_window"> id="purchase_contract_manually_create_invoice_act_window"
>
<field name="name">Manually Invoice Purchase Contracts</field> <field name="name">Manually Invoice Purchase Contracts</field>
<field name="res_model">contract.manually.create.invoice</field> <field name="res_model">contract.manually.create.invoice</field>
<field name="view_mode">form</field> <field name="view_mode">form</field>
<field name="context">{'default_contract_type': 'purchase'}</field> <field name="context">{'default_contract_type': 'purchase'}</field>
<field name="target">new</field> <field name="target">new</field>
</record> </record>
<record model="ir.ui.menu" id="purchase_contract_manually_create_invoice_menu"> <record model="ir.ui.menu" id="purchase_contract_manually_create_invoice_menu">
<field name="name">Manually Invoice Purchase Contracts</field> <field name="name">Manually Invoice Purchase Contracts</field>
<field name="parent_id" ref="account.menu_finance_payables"/> <field name="parent_id" ref="account.menu_finance_payables" />
<field name="groups_id" eval="[(6, 0, [ref('account.group_account_manager')])]"/> <field
<field name="action" name="groups_id"
ref="purchase_contract_manually_create_invoice_act_window"/> eval="[(6, 0, [ref('account.group_account_manager')])]"
<field name="sequence" eval="999"/> />
<field
name="action"
ref="purchase_contract_manually_create_invoice_act_window"
/>
<field name="sequence" eval="999" />
</record> </record>
</odoo> </odoo>