[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).
{
'name': 'Recurring - Contracts Management',
'version': '12.0.7.2.2',
'category': 'Contract Management',
'license': 'AGPL-3',
'author': "OpenERP SA, "
"name": "Recurring - Contracts Management",
"version": "12.0.7.2.2",
"category": "Contract Management",
"license": "AGPL-3",
"author": "OpenERP SA, "
"Tecnativa, "
"LasLabs, "
"Odoo Community Association (OCA)",
'website': 'https://github.com/oca/contract',
'depends': ['base', 'account', 'product'],
"website": "https://github.com/oca/contract",
"depends": ["base", "account", "product"],
"external_dependencies": {"python": ["dateutil"]},
'data': [
'security/groups.xml',
'security/contract_tag.xml',
'security/ir.model.access.csv',
'security/contract_security.xml',
'security/contract_terminate_reason.xml',
'report/report_contract.xml',
'report/contract_views.xml',
'data/contract_cron.xml',
'data/contract_renew_cron.xml',
'data/mail_template.xml',
'data/ir_ui_menu.xml',
'wizards/contract_line_wizard.xml',
'wizards/contract_manually_create_invoice.xml',
'wizards/contract_contract_terminate.xml',
'views/contract_tag.xml',
'views/assets.xml',
'views/abstract_contract_line.xml',
'views/contract.xml',
'views/contract_line.xml',
'views/contract_template.xml',
'views/contract_template_line.xml',
'views/res_partner_view.xml',
'views/res_config_settings.xml',
'views/contract_terminate_reason.xml',
"data": [
"security/groups.xml",
"security/contract_tag.xml",
"security/ir.model.access.csv",
"security/contract_security.xml",
"security/contract_terminate_reason.xml",
"report/report_contract.xml",
"report/contract_views.xml",
"data/contract_cron.xml",
"data/contract_renew_cron.xml",
"data/mail_template.xml",
"data/ir_ui_menu.xml",
"wizards/contract_line_wizard.xml",
"wizards/contract_manually_create_invoice.xml",
"wizards/contract_contract_terminate.xml",
"views/contract_tag.xml",
"views/assets.xml",
"views/abstract_contract_line.xml",
"views/contract.xml",
"views/contract_line.xml",
"views/contract_template.xml",
"views/contract_template_line.xml",
"views/res_partner_view.xml",
"views/res_config_settings.xml",
"views/contract_terminate_reason.xml",
],
'installable': True,
"installable": True,
}

View File

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

View File

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

View File

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

View File

@@ -1,17 +1,22 @@
<?xml version="1.0" ?>
<odoo noupdate="1">
<record id="email_contract_template" model="mail.template">
<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 name="subject">${object.company_id.name} Contract (Ref ${object.name or 'n/a'})</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
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="model_id" ref="model_contract_contract" />
<field name="auto_delete" eval="True" />
<field name="report_template" ref="contract.report_contract" />
<field name="report_name">Contract</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; ">
<p>Hello ${object.partner_id.name or ''},</p>
<p>A new contract has been created: </p>
@@ -60,5 +65,4 @@
</div>
]]></field>
</record>
</odoo>

View File

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

View File

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

View File

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

View File

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

View File

@@ -5,8 +5,8 @@ from odoo import fields, models
class AccountInvoiceLine(models.Model):
_inherit = 'account.invoice.line'
_inherit = "account.invoice.line"
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).
from odoo import api, fields, models
from odoo.exceptions import ValidationError, UserError
from odoo.exceptions import UserError, ValidationError
from odoo.tools.translate import _
class ContractContract(models.Model):
_name = 'contract.contract'
_name = "contract.contract"
_description = "Contract"
_order = 'code, name asc'
_order = "code, name asc"
_inherit = [
'mail.thread',
'mail.activity.mixin',
'contract.abstract.contract',
"mail.thread",
"mail.activity.mixin",
"contract.abstract.contract",
]
active = fields.Boolean(
default=True,
)
code = fields.Char(
string="Reference",
)
active = fields.Boolean(default=True,)
code = fields.Char(string="Reference",)
group_id = fields.Many2one(
string="Group",
comodel_name='account.analytic.account',
ondelete='restrict',
string="Group", comodel_name="account.analytic.account", ondelete="restrict",
)
currency_id = fields.Many2one(
compute="_compute_currency_id",
@@ -38,70 +32,59 @@ class ContractContract(models.Model):
comodel_name="res.currency",
string="Currency",
)
manual_currency_id = fields.Many2one(
comodel_name="res.currency",
readonly=True,
)
manual_currency_id = fields.Many2one(comodel_name="res.currency", readonly=True,)
contract_template_id = fields.Many2one(
string='Contract Template', comodel_name='contract.template'
string="Contract Template", comodel_name="contract.template"
)
contract_line_ids = fields.One2many(
string='Contract lines',
comodel_name='contract.line',
inverse_name='contract_id',
string="Contract lines",
comodel_name="contract.line",
inverse_name="contract_id",
copy=True,
)
user_id = fields.Many2one(
comodel_name='res.users',
string='Responsible',
comodel_name="res.users",
string="Responsible",
index=True,
default=lambda self: self.env.user,
)
create_invoice_visibility = fields.Boolean(
compute='_compute_create_invoice_visibility'
compute="_compute_create_invoice_visibility"
)
recurring_next_date = fields.Date(
compute='_compute_recurring_next_date',
string='Date of Next Invoice',
compute="_compute_recurring_next_date",
string="Date of Next Invoice",
store=True,
)
date_end = fields.Date(
compute='_compute_date_end', string='Date End', store=True
)
date_end = fields.Date(compute="_compute_date_end", string="Date End", store=True)
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")
fiscal_position_id = fields.Many2one(
comodel_name='account.fiscal.position',
string='Fiscal Position',
ondelete='restrict',
comodel_name="account.fiscal.position",
string="Fiscal Position",
ondelete="restrict",
)
invoice_partner_id = fields.Many2one(
string="Invoicing contact",
comodel_name='res.partner',
ondelete='restrict',
string="Invoicing contact", comodel_name="res.partner", ondelete="restrict",
)
partner_id = fields.Many2one(
comodel_name='res.partner',
inverse='_inverse_partner_id',
required=True
comodel_name="res.partner", inverse="_inverse_partner_id", required=True
)
commercial_partner_id = fields.Many2one(
'res.partner',
"res.partner",
compute_sudo=True,
related='partner_id.commercial_partner_id',
related="partner_id.commercial_partner_id",
store=True,
string='Commercial Entity',
index=True
string="Commercial Entity",
index=True,
)
tag_ids = fields.Many2many(comodel_name="contract.tag", string="Tags")
note = fields.Text(string="Notes")
is_terminated = fields.Boolean(
string="Terminated", readonly=True, copy=False
)
is_terminated = fields.Boolean(string="Terminated", readonly=True, copy=False)
terminate_reason_id = fields.Many2one(
comodel_name="contract.terminate.reason",
string="Termination Reason",
@@ -127,55 +110,40 @@ class ContractContract(models.Model):
def _inverse_partner_id(self):
for rec in self:
if not rec.invoice_partner_id:
rec.invoice_partner_id = rec.partner_id.address_get(
['invoice']
)['invoice']
rec.invoice_partner_id = rec.partner_id.address_get(["invoice"])[
"invoice"
]
@api.multi
def _get_related_invoices(self):
self.ensure_one()
invoices = (
self.env['account.invoice.line']
.search(
[
(
'contract_line_id',
'in',
self.contract_line_ids.ids,
self.env["account.invoice.line"]
.search([("contract_line_id", "in", self.contract_line_ids.ids,)])
.mapped("invoice_id")
)
]
)
.mapped('invoice_id')
)
invoices |= self.env['account.invoice'].search(
[('old_contract_id', '=', self.id)]
invoices |= self.env["account.invoice"].search(
[("old_contract_id", "=", self.id)]
)
return invoices
def _get_computed_currency(self):
"""Helper method for returning the theoretical computed currency."""
self.ensure_one()
currency = self.env['res.currency']
if any(self.contract_line_ids.mapped('automatic_price')):
currency = self.env["res.currency"]
if any(self.contract_line_ids.mapped("automatic_price")):
# Use pricelist currency
currency = (
self.pricelist_id.currency_id or
self.partner_id.with_context(
self.pricelist_id.currency_id
or self.partner_id.with_context(
force_company=self.company_id.id,
).property_product_pricelist.currency_id
)
return (
currency or self.journal_id.currency_id or
self.company_id.currency_id
)
return currency or self.journal_id.currency_id or self.company_id.currency_id
@api.depends(
"manual_currency_id",
"pricelist_id",
"partner_id",
"journal_id",
"company_id",
"manual_currency_id", "pricelist_id", "partner_id", "journal_id", "company_id",
)
def _compute_currency_id(self):
for rec in self:
@@ -203,60 +171,60 @@ class ContractContract(models.Model):
def action_show_invoices(self):
self.ensure_one()
tree_view_ref = (
'account.invoice_supplier_tree'
if self.contract_type == 'purchase'
else 'account.invoice_tree_with_onboarding'
"account.invoice_supplier_tree"
if self.contract_type == "purchase"
else "account.invoice_tree_with_onboarding"
)
form_view_ref = (
'account.invoice_supplier_form'
if self.contract_type == 'purchase'
else 'account.invoice_form'
"account.invoice_supplier_form"
if self.contract_type == "purchase"
else "account.invoice_form"
)
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)
action = {
'type': 'ir.actions.act_window',
'name': 'Invoices',
'res_model': 'account.invoice',
'view_type': 'form',
'view_mode': 'tree,kanban,form,calendar,pivot,graph,activity',
'domain': [('id', 'in', self._get_related_invoices().ids)],
"type": "ir.actions.act_window",
"name": "Invoices",
"res_model": "account.invoice",
"view_type": "form",
"view_mode": "tree,kanban,form,calendar,pivot,graph,activity",
"domain": [("id", "in", self._get_related_invoices().ids)],
}
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
@api.depends('contract_line_ids.date_end')
@api.depends("contract_line_ids.date_end")
def _compute_date_end(self):
for contract in self:
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):
contract.date_end = max(date_end)
@api.depends(
'contract_line_ids.recurring_next_date',
'contract_line_ids.is_canceled',
"contract_line_ids.recurring_next_date", "contract_line_ids.is_canceled",
)
def _compute_recurring_next_date(self):
for contract in self:
recurring_next_date = contract.contract_line_ids.filtered(
lambda l: (l.recurring_next_date and not l.is_canceled
and (not l.display_type or l.is_recurring_note))
).mapped('recurring_next_date')
lambda l: (
l.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:
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):
for contract in self:
contract.create_invoice_visibility = any(
contract.contract_line_ids.mapped(
'create_invoice_visibility'
)
contract.contract_line_ids.mapped("create_invoice_visibility")
)
@api.onchange('contract_template_id')
@api.onchange("contract_template_id")
def _onchange_contract_template_id(self):
"""Update the contract fields with that of the template.
@@ -269,7 +237,7 @@ class ContractContract(models.Model):
if not contract_template_id:
return
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)
self.contract_line_ids += lines
elif not any(
@@ -285,7 +253,7 @@ class ContractContract(models.Model):
if 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):
partner = (
self.partner_id
@@ -294,21 +262,19 @@ class ContractContract(models.Model):
)
self.pricelist_id = partner.property_product_pricelist.id
self.fiscal_position_id = partner.env[
'account.fiscal.position'
"account.fiscal.position"
].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
else:
self.payment_term_id = partner.property_payment_term_id
self.invoice_partner_id = self.partner_id.address_get(['invoice'])[
'invoice'
]
self.invoice_partner_id = self.partner_id.address_get(["invoice"])["invoice"]
return {
'domain': {
'invoice_partner_id': [
'|',
('id', 'parent_of', self.partner_id.id),
('id', 'child_of', self.partner_id.id),
"domain": {
"invoice_partner_id": [
"|",
("id", "parent_of", self.partner_id.id),
("id", "child_of", self.partner_id.id),
]
}
}
@@ -316,16 +282,14 @@ class ContractContract(models.Model):
@api.multi
def _convert_contract_lines(self, contract):
self.ensure_one()
new_lines = self.env['contract.line']
contract_line_model = self.env['contract.line']
new_lines = self.env["contract.line"]
contract_line_model = self.env["contract.line"]
for contract_line in contract.contract_line_ids:
vals = contract_line._convert_to_write(contract_line.read()[0])
# Remove template link field
vals.pop('contract_template_id', False)
vals['date_start'] = fields.Date.context_today(contract_line)
vals['recurring_next_date'] = fields.Date.context_today(
contract_line
)
vals.pop("contract_template_id", False)
vals["date_start"] = fields.Date.context_today(contract_line)
vals["recurring_next_date"] = fields.Date.context_today(contract_line)
new_lines += contract_line_model.new(vals)
new_lines._onchange_date_start()
new_lines._onchange_is_auto_renew()
@@ -338,10 +302,10 @@ class ContractContract(models.Model):
journal = (
self.journal_id
if self.journal_id.type == self.contract_type
else self.env['account.journal'].search(
else self.env["account.journal"].search(
[
('type', '=', self.contract_type),
('company_id', '=', self.company_id.id),
("type", "=", self.contract_type),
("company_id", "=", self.company_id.id),
],
limit=1,
)
@@ -349,56 +313,62 @@ class ContractContract(models.Model):
if not journal:
raise ValidationError(
_("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"
if self.contract_type == "purchase":
invoice_type = "in_invoice"
vinvoice = (
self.env["account.invoice"]
.with_context(force_company=self.company_id.id,)
.new(
{
"company_id": self.company_id.id,
"partner_id": self.invoice_partner_id.id,
"type": invoice_type,
}
)
)
invoice_type = 'out_invoice'
if self.contract_type == 'purchase':
invoice_type = 'in_invoice'
vinvoice = self.env['account.invoice'].with_context(
force_company=self.company_id.id,
).new({
'company_id': self.company_id.id,
'partner_id': self.invoice_partner_id.id,
'type': invoice_type,
})
vinvoice._onchange_partner_id()
invoice_vals = vinvoice._convert_to_write(vinvoice._cache)
invoice_vals.update({
'name': self.code,
'currency_id': self.currency_id.id,
'date_invoice': date_invoice,
'journal_id': journal.id,
'origin': self.name,
'user_id': self.user_id.id,
})
invoice_vals.update(
{
"name": self.code,
"currency_id": self.currency_id.id,
"date_invoice": date_invoice,
"journal_id": journal.id,
"origin": self.name,
"user_id": self.user_id.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:
invoice_vals['fiscal_position_id'] = self.fiscal_position_id.id
invoice_vals["fiscal_position_id"] = self.fiscal_position_id.id
return invoice_vals
@api.multi
def action_contract_send(self):
self.ensure_one()
template = self.env.ref('contract.email_contract_template', False)
compose_form = self.env.ref('mail.email_compose_message_wizard_form')
template = self.env.ref("contract.email_contract_template", False)
compose_form = self.env.ref("mail.email_compose_message_wizard_form")
ctx = dict(
default_model='contract.contract',
default_model="contract.contract",
default_res_id=self.id,
default_use_template=bool(template),
default_template_id=template and template.id or False,
default_composition_mode='comment',
default_composition_mode="comment",
)
return {
'name': _('Compose Email'),
'type': 'ir.actions.act_window',
'view_type': 'form',
'view_mode': 'form',
'res_model': 'mail.compose.message',
'views': [(compose_form.id, 'form')],
'view_id': compose_form.id,
'target': 'new',
'context': ctx,
"name": _("Compose Email"),
"type": "ir.actions.act_window",
"view_type": "form",
"view_mode": "form",
"res_model": "mail.compose.message",
"views": [(compose_form.id, "form")],
"view_id": compose_form.id,
"target": "new",
"context": ctx,
}
@api.model
@@ -430,10 +400,8 @@ class ContractContract(models.Model):
final_invoices_values = []
# TODO: This call must be removed in >=13.0
for invoice_values in invoices_values:
final_invoices_values.append(
self._finalize_invoice_values(invoice_values)
)
invoices = self.env['account.invoice'].create(final_invoices_values)
final_invoices_values.append(self._finalize_invoice_values(invoice_values))
invoices = self.env["account.invoice"].create(final_invoices_values)
self._finalize_invoice_creation(invoices)
return invoices
@@ -448,7 +416,7 @@ class ContractContract(models.Model):
domain = []
if not date_ref:
date_ref = fields.Date.context_today(self)
domain.extend([('recurring_next_date', '<=', date_ref)])
domain.extend([("recurring_next_date", "<=", date_ref)])
return domain
@api.multi
@@ -462,16 +430,18 @@ class ContractContract(models.Model):
self.ensure_one()
def can_be_invoiced(l):
return (not l.is_canceled and l.recurring_next_date
and l.recurring_next_date <= date_ref)
return (
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
for line in self.contract_line_ids:
if line.display_type == 'line_section':
if line.display_type == "line_section":
current_section = line
elif (line.display_type == 'line_note' and
not line.is_recurring_note):
elif line.display_type == "line_note" and not line.is_recurring_note:
if line.note_invoicing_mode == "with_previous_line":
if previous in lines2invoice:
lines2invoice |= line
@@ -511,12 +481,12 @@ class ContractContract(models.Model):
continue
invoice_values = contract._prepare_invoice(date_ref)
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_values=invoice_values,
)
if invoice_line_values:
invoice_values['invoice_line_ids'].append(
invoice_values["invoice_line_ids"].append(
(0, 0, invoice_line_values)
)
invoices_values.append(invoice_values)
@@ -533,9 +503,9 @@ class ContractContract(models.Model):
if invoice:
self.message_post(
body=_(
'Contract manually invoiced: '
"Contract manually invoiced: "
'<a href="#" data-oe-model="%s" data-oe-id="%s">Invoice'
'</a>'
"</a>"
)
% (invoice._name, invoice.id)
)
@@ -566,13 +536,13 @@ class ContractContract(models.Model):
self.ensure_one()
context = {"default_contract_id": self.id}
return {
'type': 'ir.actions.act_window',
'name': _('Terminate Contract'),
'res_model': 'contract.contract.terminate',
'view_type': 'form',
'view_mode': 'form',
'target': 'new',
'context': context,
"type": "ir.actions.act_window",
"name": _("Terminate Contract"),
"res_model": "contract.contract.terminate",
"view_type": "form",
"view_mode": "form",
"target": "new",
"context": context,
}
@api.multi
@@ -581,22 +551,26 @@ class ContractContract(models.Model):
):
self.ensure_one()
if not self.env.user.has_group("contract.can_terminate_contract"):
raise UserError(_('You are not allowed to terminate contracts.'))
self.contract_line_ids.filtered('is_stop_allowed').stop(terminate_date)
self.write({
'is_terminated': True,
'terminate_reason_id': terminate_reason_id.id,
'terminate_comment': terminate_comment,
'terminate_date': terminate_date,
})
raise UserError(_("You are not allowed to terminate contracts."))
self.contract_line_ids.filtered("is_stop_allowed").stop(terminate_date)
self.write(
{
"is_terminated": True,
"terminate_reason_id": terminate_reason_id.id,
"terminate_comment": terminate_comment,
"terminate_date": terminate_date,
}
)
return True
@api.multi
def action_cancel_contract_termination(self):
self.ensure_one()
self.write({
'is_terminated': False,
'terminate_reason_id': False,
'terminate_comment': False,
'terminate_date': False,
})
self.write(
{
"is_terminated": False,
"terminate_reason_id": 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
from collections import namedtuple
from odoo.fields import Date
Criteria = namedtuple(
'Criteria',
"Criteria",
[
'when', # Contract line relatively to today (BEFORE, IN, AFTER)
'has_date_end', # Is date_end set on contract line (bool)
'has_last_date_invoiced', # Is last_date_invoiced set on contract line
'is_auto_renew', # Is is_auto_renew set on contract line (bool)
'has_successor', # Is contract line has_successor (bool)
'predecessor_has_successor',
"when", # Contract line relatively to today (BEFORE, IN, AFTER)
"has_date_end", # Is date_end set on contract line (bool)
"has_last_date_invoiced", # Is last_date_invoiced set on contract line
"is_auto_renew", # Is is_auto_renew set on contract line (bool)
"has_successor", # Is contract line has_successor (bool)
"predecessor_has_successor",
# Is contract line predecessor has successor (bool)
# In almost of the cases
# contract_line.predecessor.successor == contract_line
@@ -23,12 +24,11 @@ Criteria = namedtuple(
# If contract_line.predecessor.successor != False
# and contract_line is canceled, we don't allow uncancel
# else we re-link contract_line and its predecessor
'canceled', # Is contract line canceled (bool)
"canceled", # Is contract line canceled (bool)
],
)
Allowed = namedtuple(
'Allowed',
['plan_successor', 'stop_plan_successor', 'stop', 'cancel', 'uncancel'],
"Allowed", ["plan_successor", "stop_plan_successor", "stop", "cancel", "uncancel"],
)
@@ -36,8 +36,8 @@ def _expand_none(criteria):
variations = []
for attribute, value in criteria._asdict().items():
if value is None:
if attribute == 'when':
variations.append(['BEFORE', 'IN', 'AFTER'])
if attribute == "when":
variations.append(["BEFORE", "IN", "AFTER"])
else:
variations.append([True, False])
else:
@@ -53,7 +53,7 @@ def _add(matrix, criteria, allowed):
CRITERIA_ALLOWED_DICT = {
Criteria(
when='BEFORE',
when="BEFORE",
has_date_end=True,
has_last_date_invoiced=False,
is_auto_renew=True,
@@ -68,7 +68,7 @@ CRITERIA_ALLOWED_DICT = {
uncancel=False,
),
Criteria(
when='BEFORE',
when="BEFORE",
has_date_end=True,
has_last_date_invoiced=False,
is_auto_renew=False,
@@ -83,7 +83,7 @@ CRITERIA_ALLOWED_DICT = {
uncancel=False,
),
Criteria(
when='BEFORE',
when="BEFORE",
has_date_end=True,
has_last_date_invoiced=False,
is_auto_renew=False,
@@ -98,7 +98,7 @@ CRITERIA_ALLOWED_DICT = {
uncancel=False,
),
Criteria(
when='BEFORE',
when="BEFORE",
has_date_end=False,
has_last_date_invoiced=False,
is_auto_renew=False,
@@ -113,7 +113,7 @@ CRITERIA_ALLOWED_DICT = {
uncancel=False,
),
Criteria(
when='IN',
when="IN",
has_date_end=True,
has_last_date_invoiced=False,
is_auto_renew=True,
@@ -128,7 +128,7 @@ CRITERIA_ALLOWED_DICT = {
uncancel=False,
),
Criteria(
when='IN',
when="IN",
has_date_end=True,
has_last_date_invoiced=False,
is_auto_renew=False,
@@ -143,7 +143,7 @@ CRITERIA_ALLOWED_DICT = {
uncancel=False,
),
Criteria(
when='IN',
when="IN",
has_date_end=True,
has_last_date_invoiced=False,
is_auto_renew=False,
@@ -158,7 +158,7 @@ CRITERIA_ALLOWED_DICT = {
uncancel=False,
),
Criteria(
when='IN',
when="IN",
has_date_end=False,
has_last_date_invoiced=False,
is_auto_renew=False,
@@ -173,7 +173,7 @@ CRITERIA_ALLOWED_DICT = {
uncancel=False,
),
Criteria(
when='BEFORE',
when="BEFORE",
has_date_end=True,
has_last_date_invoiced=True,
is_auto_renew=True,
@@ -188,7 +188,7 @@ CRITERIA_ALLOWED_DICT = {
uncancel=False,
),
Criteria(
when='BEFORE',
when="BEFORE",
has_date_end=True,
has_last_date_invoiced=True,
is_auto_renew=False,
@@ -203,7 +203,7 @@ CRITERIA_ALLOWED_DICT = {
uncancel=False,
),
Criteria(
when='BEFORE',
when="BEFORE",
has_date_end=True,
has_last_date_invoiced=True,
is_auto_renew=False,
@@ -218,7 +218,7 @@ CRITERIA_ALLOWED_DICT = {
uncancel=False,
),
Criteria(
when='BEFORE',
when="BEFORE",
has_date_end=False,
has_last_date_invoiced=True,
is_auto_renew=False,
@@ -233,7 +233,7 @@ CRITERIA_ALLOWED_DICT = {
uncancel=False,
),
Criteria(
when='IN',
when="IN",
has_date_end=True,
has_last_date_invoiced=True,
is_auto_renew=True,
@@ -248,7 +248,7 @@ CRITERIA_ALLOWED_DICT = {
uncancel=False,
),
Criteria(
when='IN',
when="IN",
has_date_end=True,
has_last_date_invoiced=True,
is_auto_renew=False,
@@ -263,7 +263,7 @@ CRITERIA_ALLOWED_DICT = {
uncancel=False,
),
Criteria(
when='IN',
when="IN",
has_date_end=True,
has_last_date_invoiced=True,
is_auto_renew=False,
@@ -278,7 +278,7 @@ CRITERIA_ALLOWED_DICT = {
uncancel=False,
),
Criteria(
when='IN',
when="IN",
has_date_end=False,
has_last_date_invoiced=True,
is_auto_renew=False,
@@ -293,7 +293,7 @@ CRITERIA_ALLOWED_DICT = {
uncancel=False,
),
Criteria(
when='AFTER',
when="AFTER",
has_date_end=True,
has_last_date_invoiced=None,
is_auto_renew=True,
@@ -308,7 +308,7 @@ CRITERIA_ALLOWED_DICT = {
uncancel=False,
),
Criteria(
when='AFTER',
when="AFTER",
has_date_end=True,
has_last_date_invoiced=None,
is_auto_renew=False,
@@ -323,7 +323,7 @@ CRITERIA_ALLOWED_DICT = {
uncancel=False,
),
Criteria(
when='AFTER',
when="AFTER",
has_date_end=True,
has_last_date_invoiced=None,
is_auto_renew=False,
@@ -377,10 +377,10 @@ for c in CRITERIA_ALLOWED_DICT:
def compute_when(date_start, date_end):
today = Date.today()
if today < date_start:
return 'BEFORE'
return "BEFORE"
if date_end and today > date_end:
return 'AFTER'
return 'IN'
return "AFTER"
return "IN"
def compute_criteria(

View File

@@ -6,12 +6,10 @@ from odoo import fields, models
class ContractTag(models.Model):
_name = 'contract.tag'
_description = 'Contract Tag'
_name = "contract.tag"
_description = "Contract Tag"
name = fields.Char(requirment=True)
company_id = fields.Many2one(
'res.company',
string='Company',
default=lambda self: self.env.user.company_id,
"res.company", 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):
_name = 'contract.template'
_inherit = 'contract.abstract.contract'
_name = "contract.template"
_inherit = "contract.abstract.contract"
_description = "Contract Template"
contract_line_ids = fields.One2many(
comodel_name='contract.template.line',
inverse_name='contract_id',
comodel_name="contract.template.line",
inverse_name="contract_id",
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):
_name = 'contract.template.line'
_inherit = 'contract.abstract.contract.line'
_name = "contract.template.line"
_inherit = "contract.abstract.contract.line"
_description = "Contract Template Line"
_order = "sequence,id"
contract_id = fields.Many2one(
string='Contract',
comodel_name='contract.template',
string="Contract",
comodel_name="contract.template",
required=True,
ondelete='cascade',
oldname='analytic_account_id',
ondelete="cascade",
oldname="analytic_account_id",
)

View File

@@ -6,8 +6,8 @@ from odoo import fields, models
class ContractTerminateReason(models.Model):
_name = 'contract.terminate.reason'
_description = 'Contract Termination Reason'
_name = "contract.terminate.reason"
_description = "Contract Termination Reason"
name = fields.Char(required=True)
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
result = super()._prepare_qcontext()
if self.env.context.get("allowed_company_ids"):
result["res_company"] = self.env["res.company"].browse(
self.env.context["allowed_company_ids"][0]
).sudo()
result["res_company"] = (
self.env["res.company"]
.browse(self.env.context["allowed_company_ids"][0])
.sudo()
)
return result

View File

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

View File

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

View File

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

View File

@@ -1,45 +1,69 @@
<?xml version="1.0" ?>
<odoo>
<template id="report_contract_document">
<t t-call="web.html_container">
<t t-foreach="docs" t-as="o">
<t t-call="web.external_layout">
<t t-set="o" t-value="o.with_context(lang=o.partner_id.lang)" />
<t t-set="address">
<p id="partner_info"><strong>Partner:</strong></p>
<div t-field="o.partner_id"
t-options='{"widget": "contact", "fields": ["address", "name", "phone", "mobile", "fax", "email"], "no_marker": true, "phone_icons": true}'/>
<p t-if="o.partner_id.vat">VAT: <span t-field="o.partner_id.vat"/></p>
<p id="partner_info">
<strong>Partner:</strong>
</p>
<div
t-field="o.partner_id"
t-options='{"widget": "contact", "fields": ["address", "name", "phone", "mobile", "fax", "email"], "no_marker": true, "phone_icons": true}'
/>
<p t-if="o.partner_id.vat">VAT: <span
t-field="o.partner_id.vat"
/></p>
</t>
<div class="page">
<div class="oe_structure" />
<div class="row" id="header_info">
<div class="col-3">
<strong>Responsible: </strong><p t-field="o.user_id"/>
<strong>Contract: </strong><p t-field="o.code"/>
<strong>Responsible: </strong>
<p t-field="o.user_id" />
<strong>Contract: </strong>
<p t-field="o.code" />
</div>
</div>
<div class="row" id="invoice_info">
<t t-set="total" t-value="0" />
<div class="col-12">
<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">
<thead>
<tr>
<th><strong>Description</strong></th>
<th class="text-right"><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>
<th>
<strong>Description</strong>
</th>
<th class="text-right">
<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>
</thead>
<tbody>
<t t-set="current_subtotal" t-value="0" />
<t t-foreach="o.contract_line_ids" t-as="l">
<t t-set="current_subtotal" t-value="current_subtotal + l.price_subtotal"/>
<tr t-att-class="'bg-200 font-weight-bold o_line_section' if l.display_type == 'line_section' else 'font-italic o_line_note' if l.display_type == 'line_note' else ''">
<t
t-set="current_subtotal"
t-value="current_subtotal + l.price_subtotal"
/>
<tr
t-att-class="'bg-200 font-weight-bold o_line_section' if l.display_type == 'line_section' else 'font-italic o_line_note' if l.display_type == 'line_note' else ''"
>
<t t-if="not l.display_type">
<td>
<span t-field="l.name" />
@@ -48,22 +72,39 @@
<span t-field="l.quantity" />
</td>
<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 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 class="text-right">
<span t-field="l.date_start" />
</td>
<t t-set="total" t-value="total + l.price_subtotal"/>
<t
t-set="total"
t-value="total + l.price_subtotal"
/>
</t>
<t t-if="l.display_type == 'line_section'">
<t
t-if="l.display_type == 'line_section'"
>
<td colspan="99">
<span t-field="l.name" />
</td>
<t t-set="current_section" t-value="l"/>
<t t-set="current_subtotal" t-value="0"/>
<t
t-set="current_section"
t-value="l"
/>
<t
t-set="current_subtotal"
t-value="0"
/>
</t>
<t t-if="l.display_type == 'line_note'">
<td colspan="99">
@@ -71,10 +112,14 @@
</td>
</t>
</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">
<td colspan="99">
<strong class="mr16">Subtotal</strong>
<strong
class="mr16"
>Subtotal</strong>
<span
t-esc="current_subtotal"
t-options='{"widget": "monetary", "display_currency": o.currency_id}'
@@ -91,9 +136,14 @@
<div class="col-4 ml-auto">
<table class="table table-sm">
<tr class="border-black o_subtotal" style="">
<td><strong>Total</strong></td>
<td>
<strong>Total</strong>
</td>
<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>
</tr>
</table>
@@ -101,7 +151,9 @@
</div>
<div>
<div class="row mt-4" id="note">
<div><strong>Notes: </strong></div>
<div>
<strong>Notes: </strong>
</div>
</div>
<div class="row">
<p t-field="o.note" />
@@ -112,5 +164,4 @@
</t>
</t>
</template>
</odoo>

View File

@@ -1,31 +1,34 @@
<odoo noupdate="1">
<record id="rule_contract_contract_multi_company" model="ir.rule">
<field name="name">Contract contract multi-company</field>
<field name="model_id" ref="model_contract_contract" />
<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 id="rule_contract_line_multi_company" model="ir.rule">
<field name="name">Contract line multi-company</field>
<field name="model_id" ref="model_contract_line" />
<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 id="rule_contract_template_multi_company" model="ir.rule">
<field name="name">Contract template multi-company</field>
<field name="model_id" ref="model_contract_template" />
<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 id="rule_contract_template_line_multi_company" model="ir.rule">
<field name="name">Contract template line multi-company</field>
<field name="model_id" ref="model_contract_template_line" />
<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>
</odoo>

View File

@@ -1,9 +1,7 @@
<?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2019 ACSONE SA/NV
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
<odoo>
<record model="ir.model.access" id="contract_tag_access">
<field name="name">contract.tag access</field>
<field name="model_id" ref="model_contract_tag" />
@@ -13,11 +11,11 @@
<field name="perm_write" eval="1" />
<field name="perm_unlink" eval="1" />
</record>
<record id="contract_tag_multi_company_rule" model="ir.rule">
<field name="name">Contract tag multi-company</field>
<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>
</odoo>

View File

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

View File

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

View File

@@ -8,31 +8,31 @@ and this condition is met, then an extra space appears in the rows
corresponding to the sections and lines.
This js was written to deal with that problem, but a solution based on
this can be applied directly to Odoo*/
odoo.define('contract.section_and_note_backend', function (require) {
odoo.define("contract.section_and_note_backend", function(require) {
"use strict";
var fieldRegistry = require('web.field_registry');
var section_and_note_one2many = fieldRegistry.get('section_and_note_one2many');
var fieldRegistry = require("web.field_registry");
var section_and_note_one2many = fieldRegistry.get("section_and_note_one2many");
section_and_note_one2many.include({
_getRenderer: function() {
var result = this._super.apply(this, arguments);
if (this.view.arch.tag === 'tree') {
if (this.view.arch.tag === "tree") {
result.include({
_renderBodyCell: function(record, node, index, options) {
var $cell = this._super.apply(this, arguments);
var isSection = record.data.display_type === 'line_section';
var isNote = record.data.display_type === 'line_note';
var isSection = record.data.display_type === "line_section";
var isNote = record.data.display_type === "line_note";
if (isSection || isNote) {
$cell.removeClass('o_invisible_modifier');
$cell.removeClass("o_invisible_modifier");
}
return $cell;
},
});
}
})
}
return result
return result;
},
});
});

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +1,10 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<!--FORM 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="arch" type="xml">
<form>
@@ -11,69 +12,117 @@
<header attrs="{'invisible': [('display_type', '!=', False)]}" />
<sheet>
<field name="specific_price" invisible="1" />
<group col="4" attrs="{'invisible': [('display_type', '!=', False)]}">
<field colspan="4"
<group
col="4"
attrs="{'invisible': [('display_type', '!=', False)]}"
>
<field
colspan="4"
name="product_id"
attrs="{'required': [('display_type', '=', False)]}"/>
attrs="{'required': [('display_type', '=', False)]}"
/>
<label for="quantity" />
<div class="o_row">
<field name="quantity" class="oe_inline" />
<field name="uom_id"
<field
name="uom_id"
class="oe_inline"
groups="uom.group_uom"
attrs="{'required': [('display_type', '=', False)]}"/>
attrs="{'required': [('display_type', '=', False)]}"
/>
</div>
<field colspan="2" name="automatic_price" />
<field colspan="2" name="price_unit"
attrs="{'readonly': [('automatic_price', '=', True)]}"/>
<field
colspan="2"
name="price_unit"
attrs="{'readonly': [('automatic_price', '=', True)]}"
/>
<field colspan="2" name="discount" groups="base.group_no_one" />
</group>
<label for="name" string="Description" attrs="{'invisible': [('display_type', '!=', False)]}"/>
<label for="name" string="Section" attrs="{'invisible': [('display_type', '!=', 'line_section')]}"/>
<label for="name" string="Note" attrs="{'invisible': [('display_type', '!=', 'line_note')]}"/>
<label
for="name"
string="Description"
attrs="{'invisible': [('display_type', '!=', False)]}"
/>
<label
for="name"
string="Section"
attrs="{'invisible': [('display_type', '!=', 'line_section')]}"
/>
<label
for="name"
string="Note"
attrs="{'invisible': [('display_type', '!=', 'line_note')]}"
/>
<field name="name" nolabel="1" />
<group name="note_invoicing_mode" attrs="{'invisible': [('display_type', '!=', 'line_note')]}">
<group
name="note_invoicing_mode"
attrs="{'invisible': [('display_type', '!=', 'line_note')]}"
>
<field name="note_invoicing_mode" widget="radio" />
</group>
<group col="4" attrs="{'invisible': [('display_type', '!=', False)]}">
<group
col="4"
attrs="{'invisible': [('display_type', '!=', False)]}"
>
<field colspan="2" name="is_auto_renew" />
<field colspan="2" name="is_canceled" invisible="1" />
</group>
<group attrs="{'invisible':['|', ('is_auto_renew', '=', False), ('display_type', '!=', False)]}">
<group
attrs="{'invisible':['|', ('is_auto_renew', '=', False), ('display_type', '!=', False)]}"
>
<group>
<label for="auto_renew_interval" />
<div>
<field name="auto_renew_interval"
class="oe_inline" nolabel="1"
attrs="{'required':[('is_auto_renew', '=', True)]}"/>
<field name="auto_renew_rule_type"
class="oe_inline" nolabel="1"
attrs="{'required':[('is_auto_renew', '=', True)]}"/>
<field
name="auto_renew_interval"
class="oe_inline"
nolabel="1"
attrs="{'required':[('is_auto_renew', '=', True)]}"
/>
<field
name="auto_renew_rule_type"
class="oe_inline"
nolabel="1"
attrs="{'required':[('is_auto_renew', '=', True)]}"
/>
</div>
</group>
<group>
<label for="termination_notice_interval" />
<div>
<field name="termination_notice_interval"
class="oe_inline" nolabel="1"
attrs="{'required':[('is_auto_renew', '=', True)]}"/>
<field name="termination_notice_rule_type"
class="oe_inline" nolabel="1"
attrs="{'required':[('is_auto_renew', '=', True)]}"/>
<field
name="termination_notice_interval"
class="oe_inline"
nolabel="1"
attrs="{'required':[('is_auto_renew', '=', True)]}"
/>
<field
name="termination_notice_rule_type"
class="oe_inline"
nolabel="1"
attrs="{'required':[('is_auto_renew', '=', True)]}"
/>
</div>
</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>
<label for="recurring_interval" />
<div class="o_row">
<field name="recurring_interval"
class="oe_inline" nolabel="1"/>
<field name="recurring_rule_type"
class="oe_inline" nolabel="1"/>
<field
name="recurring_interval"
class="oe_inline"
nolabel="1"
/>
<field
name="recurring_rule_type"
class="oe_inline"
nolabel="1"
/>
</div>
</group>
<group>
@@ -85,5 +134,4 @@
</form>
</field>
</record>
</odoo>

View File

@@ -2,9 +2,16 @@
<!-- Copyright 2020 Tecnativa - Ernesto Tejeda
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -->
<odoo>
<template id="assets_backend" name="contract assets" inherit_id="web.assets_backend">
<template
id="assets_backend"
name="contract assets"
inherit_id="web.assets_backend"
>
<xpath expr="." position="inside">
<script type="text/javascript" src="/contract/static/src/js/section_and_note_fields_backend.js"></script>
<script
type="text/javascript"
src="/contract/static/src/js/section_and_note_fields_backend.js"
/>
</xpath>
</template>
</odoo>

View File

@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<!--Main FORM view-->
<record id="contract_contract_form_view" model="ir.ui.view">
<field name="name">contract.contract form view (in contract)</field>
@@ -8,11 +7,19 @@
<field name="arch" type="xml">
<form>
<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>
This contract was terminated for the reason
<strong>
<field name="terminate_reason_id" options="{'no_open':True}"/>
<field
name="terminate_reason_id"
options="{'no_open':True}"
/>
</strong>
on
<field name="terminate_date" />
@@ -23,180 +30,288 @@
</p>
</div>
<header>
<button name="action_contract_send"
<button
name="action_contract_send"
type="object"
string="Send by Email"
attrs="{'invisible': [('is_terminated','=',True)]}"
groups="base.group_user"/>
<button name="recurring_create_invoice"
groups="base.group_user"
/>
<button
name="recurring_create_invoice"
type="object"
attrs="{'invisible': ['|', ('create_invoice_visibility', '=', False)]}"
string="Create invoices"
groups="base.group_no_one"/>
<button name="action_terminate_contract"
groups="base.group_no_one"
/>
<button
name="action_terminate_contract"
type="object"
string="Terminate Contract"
attrs="{'invisible': [('is_terminated','=',True)]}"
groups="contract.can_terminate_contract"/>
<button name="action_terminate_contract"
groups="contract.can_terminate_contract"
/>
<button
name="action_terminate_contract"
type="object"
string="Update Termination Details"
attrs="{'invisible': [('is_terminated','=',False)]}"
groups="contract.can_terminate_contract"/>
<button name="action_cancel_contract_termination"
groups="contract.can_terminate_contract"
/>
<button
name="action_cancel_contract_termination"
type="object"
confirm="Are you sure you want to re-activate this contract?"
string="Cancel Contract Termination"
attrs="{'invisible': [('is_terminated','=',False)]}"
groups="contract.can_terminate_contract"/>
groups="contract.can_terminate_contract"
/>
</header>
<sheet string="Contract">
<div class="oe_button_box" name="button_box">
<button class="oe_stat_button" type="object"
name="toggle_active" icon="fa-archive">
<field name="active" widget="boolean_button"
options="{&quot;terminology&quot;: &quot;archive&quot;}"/>
<button
class="oe_stat_button"
type="object"
name="toggle_active"
icon="fa-archive"
>
<field
name="active"
widget="boolean_button"
options="{&quot;terminology&quot;: &quot;archive&quot;}"
/>
</button>
<button name="action_show_invoices"
type="object" icon="fa-list"
class="oe_stat_button">
<field string="Invoices"
<button
name="action_show_invoices"
type="object"
icon="fa-list"
class="oe_stat_button"
>
<field
string="Invoices"
name="invoice_count"
widget="statinfo"/>
widget="statinfo"
/>
</button>
</div>
<div class="oe_title">
<label for="name" string="Contract Name"
class="oe_edit_only"/>
<label for="name" string="Contract Name" class="oe_edit_only" />
<h3>
<field name="name" class="oe_inline"
<field
name="name"
class="oe_inline"
attrs="{'readonly': [('is_terminated','=',True)]}"
placeholder="e.g. Contract XYZ"/>
placeholder="e.g. Contract XYZ"
/>
</h3>
</div>
<group name="main">
<group>
<field name="commercial_partner_id" invisible="1" />
<field name="partner_id" 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)]}"/>
<field
name="partner_id"
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>
<field name="contract_template_id"
<field
name="contract_template_id"
attrs="{'readonly': [('is_terminated','=',True)]}"
domain="['|', ('contract_type', '=', contract_type), ('contract_type', '=', False)]"
context="{'default_contract_type': contract_type}"/>
<field name="contract_type" invisible="1"
required="1"/>
<field name="fiscal_position_id" attrs="{'readonly': [('is_terminated','=',True)]}"/>
context="{'default_contract_type': contract_type}"
/>
<field name="contract_type" invisible="1" required="1" />
<field
name="fiscal_position_id"
attrs="{'readonly': [('is_terminated','=',True)]}"
/>
<field name="tag_ids" widget="many2many_tags" />
</group>
</group>
<group name="recurring_invoices">
<group>
<field name="journal_id" required="1" attrs="{'readonly': [('is_terminated','=',True)]}"/>
<field
name="journal_id"
required="1"
attrs="{'readonly': [('is_terminated','=',True)]}"
/>
<field name="recurring_next_date" />
</group>
<group>
<field name="pricelist_id" attrs="{'readonly': [('is_terminated','=',True)]}"/>
<field
name="pricelist_id"
attrs="{'readonly': [('is_terminated','=',True)]}"
/>
<field name="date_end" />
</group>
</group>
<notebook>
<page name="recurring_invoice_line"
string="Recurring Invoices">
<field name="contract_line_ids"
<page name="recurring_invoice_line" string="Recurring Invoices">
<field
name="contract_line_ids"
attrs="{'readonly': [('is_terminated','=',True)]}"
widget="section_and_note_one2many"
context="{'default_contract_type': contract_type}">
<tree decoration-muted="is_canceled"
decoration-info="create_invoice_visibility and not is_canceled">
context="{'default_contract_type': contract_type}"
>
<tree
decoration-muted="is_canceled"
decoration-info="create_invoice_visibility and not is_canceled"
>
<control>
<create string="Add a line" />
<create string="Add a section" context="{'default_display_type': 'line_section'}"/>
<create string="Add a note" context="{'default_display_type': 'line_note'}"/>
<create
string="Add a section"
context="{'default_display_type': 'line_section'}"
/>
<create
string="Add a note"
context="{'default_display_type': 'line_note'}"
/>
</control>
<field name="display_type" invisible="1" />
<field name="sequence" widget="handle" />
<field name="product_id" />
<field name="name" widget="section_and_note_text" />
<field name="analytic_account_id" groups="analytic.group_analytic_accounting"/>
<field name="analytic_tag_ids" widget="many2many_tags" groups="analytic.group_analytic_tags"/>
<field
name="analytic_account_id"
groups="analytic.group_analytic_accounting"
/>
<field
name="analytic_tag_ids"
widget="many2many_tags"
groups="analytic.group_analytic_tags"
/>
<field name="quantity" />
<field name="uom_id" />
<field name="automatic_price" attrs="{'column_invisible': [('parent.contract_type', '=', 'purchase')]}"/>
<field name="price_unit"
attrs="{'readonly': [('automatic_price', '=', True)]}"/>
<field
name="automatic_price"
attrs="{'column_invisible': [('parent.contract_type', '=', 'purchase')]}"
/>
<field
name="price_unit"
attrs="{'readonly': [('automatic_price', '=', True)]}"
/>
<field name="specific_price" invisible="1" />
<field name="discount" groups="base.group_no_one" />
<field name="price_subtotal" />
<field name="recurring_interval" invisible="1" />
<field name="recurring_rule_type" invisible="1" />
<field name="recurring_invoicing_type" invisible="1"/>
<field
name="recurring_invoicing_type"
invisible="1"
/>
<field name="date_start" required="1" />
<field name="date_end" />
<field name="recurring_next_date" required="1" />
<field name="last_date_invoiced" groups="base.group_no_one"/>
<field name="create_invoice_visibility" invisible="1"/>
<field name="is_plan_successor_allowed" invisible="1"/>
<field name="is_stop_plan_successor_allowed" invisible="1"/>
<field
name="last_date_invoiced"
groups="base.group_no_one"
/>
<field
name="create_invoice_visibility"
invisible="1"
/>
<field
name="is_plan_successor_allowed"
invisible="1"
/>
<field
name="is_stop_plan_successor_allowed"
invisible="1"
/>
<field name="is_stop_allowed" invisible="1" />
<field name="is_cancel_allowed" invisible="1" />
<field name="is_un_cancel_allowed" invisible="1" />
<field name="is_auto_renew" invisible="1" />
<field name="is_canceled" invisible="1" />
<button name="action_plan_successor"
string="Plan Start" type="object"
<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"
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"
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"
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"
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"
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)]}"/>
attrs="{'invisible': [('is_auto_renew', '=', False)]}"
/>
</tree>
</field>
<field name="note" />
</page>
<page name="info" string="Other Information">
<field name="create_invoice_visibility"
invisible="1"/>
<field name="create_invoice_visibility" invisible="1" />
<group>
<field name="code" attrs="{'readonly': [('is_terminated','=',True)]}"/>
<field name="group_id" attrs="{'readonly': [('is_terminated','=',True)]}"/>
<field name="company_id"
<field
name="code"
attrs="{'readonly': [('is_terminated','=',True)]}"
/>
<field
name="group_id"
attrs="{'readonly': [('is_terminated','=',True)]}"
/>
<field
name="company_id"
attrs="{'readonly': [('is_terminated','=',True)]}"
options="{'no_create': True}"
groups="base.group_multi_company"/>
<field name="currency_id"
groups="base.group_multi_company"
/>
<field
name="currency_id"
groups="base.group_multi_currency"
/>
<field
name="invoice_partner_id"
attrs="{'readonly': [('is_terminated','=',True)]}"
options="{'no_create': True}"
groups="base.group_multi_currency"/>
<field name="invoice_partner_id"
attrs="{'readonly': [('is_terminated','=',True)]}"
required="1"/>
required="1"
/>
</group>
<group string="Legend (for the markers inside invoice lines description)"
name="group_legend">
<group
string="Legend (for the markers inside invoice lines description)"
name="group_legend"
>
<p colspan="2">
<strong>#START#</strong>
: Start
@@ -221,10 +336,8 @@
<field name="message_ids" widget="mail_thread" />
</div>
</form>
</field>
</record>
<!--Customer FORM view-->
<record id="contract_contract_customer_form_view" model="ir.ui.view">
<field name="name">contract.contract customer form view (in contract)</field>
@@ -236,14 +349,17 @@
<field name="partner_id" position="attributes">
<attribute name="string">Customer</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 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>
</record>
<!--Supplier FORM view-->
<record id="contract_contract_supplier_form_view" model="ir.ui.view">
<field name="name">contract.contract supplier form view (in contract)</field>
@@ -255,14 +371,17 @@
<field name="partner_id" position="attributes">
<attribute name="string">Supplier</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 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>
</record>
<!--TREE view-->
<record id="contract_contract_tree_view" model="ir.ui.view">
<field name="name">contract.contract tree view (in contract)</field>
@@ -278,46 +397,57 @@
</tree>
</field>
</record>
<!--SEARCH view-->
<record id="contract_contract_search_view" model="ir.ui.view">
<field name="name">contract.contract search view (in contract)</field>
<field name="model">contract.contract</field>
<field name="arch" type="xml">
<search>
<field name="name"
filter_domain="['|', ('name','ilike',self), ('code','ilike',self)]"/>
<field
name="name"
filter_domain="['|', ('name','ilike',self), ('code','ilike',self)]"
/>
<field name="journal_id" />
<field name="pricelist_id" />
<separator />
<separator />
<filter name="not_finished"
<filter
name="not_finished"
string="In progress"
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"
domain="[('date_end', '&lt;', context_today().strftime('%Y-%m-%d')), ('recurring_next_date', '=', False)]"
/>
<field name="partner_id" />
<field name="commercial_partner_id" />
<filter string="Archived"
<filter
string="Archived"
domain="[('active', '=', False)]"
name="inactive"/>
name="inactive"
/>
<group expand="0" string="Group By...">
<filter string="Associated Partner"
<filter
string="Associated Partner"
name="group_by_partner"
domain="[]"
context="{'group_by':'partner_id'}"/>
<filter name="commercial_partner_groupby"
context="{'group_by':'partner_id'}"
/>
<filter
name="commercial_partner_groupby"
string="Commercial Entity"
context="{'group_by': 'commercial_partner_id'}"/>
<filter name="group_by_next_invoice"
context="{'group_by': 'commercial_partner_id'}"
/>
<filter
name="group_by_next_invoice"
string="Next Invoice"
domain="[('recurring_next_date', '!=', False)]"
context="{'group_by':'recurring_next_date'}"
/>
<filter name="group_by_date_end"
<filter
name="group_by_date_end"
string="Date End"
domain="[]"
context="{'group_by':'date_end'}"
@@ -326,7 +456,6 @@
</search>
</field>
</record>
<!--ACTION customer contracts-->
<record id="action_customer_contract" model="ir.actions.act_window">
<field name="name">Customer Contracts</field>
@@ -346,27 +475,24 @@
</p>
</field>
</record>
<record id="action_customer_contract_view_tree" model="ir.actions.act_window.view">
<field name="sequence" eval="1" />
<field name="view_mode">tree</field>
<field name="view_id" ref="contract_contract_tree_view" />
<field name="act_window_id" ref="action_customer_contract" />
</record>
<record id="action_customer_contract_view_form" model="ir.actions.act_window.view">
<field name="sequence" eval="2" />
<field name="view_mode">form</field>
<field name="view_id" ref="contract_contract_customer_form_view" />
<field name="act_window_id" ref="action_customer_contract" />
</record>
<menuitem id="menu_contract_contract_customer"
<menuitem
id="menu_contract_contract_customer"
parent="account.menu_finance_receivables"
action="action_customer_contract"
sequence="99"
/>
<!--ACTION supplier contracts-->
<record id="action_supplier_contract" model="ir.actions.act_window">
<field name="name">Supplier Contracts</field>
@@ -386,25 +512,22 @@
</p>
</field>
</record>
<record id="action_supplier_contract_view_tree" model="ir.actions.act_window.view">
<field name="sequence" eval="1" />
<field name="view_mode">tree</field>
<field name="view_id" ref="contract_contract_tree_view" />
<field name="act_window_id" ref="action_supplier_contract" />
</record>
<record id="action_supplier_contract_view_form" model="ir.actions.act_window.view">
<field name="sequence" eval="2" />
<field name="view_mode">form</field>
<field name="view_id" ref="contract_contract_supplier_form_view" />
<field name="act_window_id" ref="action_supplier_contract" />
</record>
<menuitem id="menu_contract_contract_supplier"
<menuitem
id="menu_contract_contract_supplier"
parent="account.menu_finance_payables"
action="action_supplier_contract"
sequence="99"
/>
</odoo>

View File

@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<!--FORM view-->
<record id="contract_line_form_view" model="ir.ui.view">
<field name="name">contract.line form view (in contract)</field>
@@ -19,8 +18,10 @@
<field name="recurring_next_date" />
</group>
<group>
<field name="date_end"
attrs="{'required': [('is_auto_renew', '=', True)]}"/>
<field
name="date_end"
attrs="{'required': [('is_auto_renew', '=', True)]}"
/>
<field name="next_period_date_end" />
</group>
<group groups="base.group_no_one">
@@ -38,16 +39,24 @@
</group>
</group>
<group name="recurrence_info" position="after">
<group name="analytic"
<group
name="analytic"
groups="analytic.group_analytic_accounting,analytic.group_analytic_tags"
attrs="{'invisible': [('display_type', '!=', False)]}">
<field name="analytic_account_id" groups="analytic.group_analytic_accounting"/>
<field name="analytic_tag_ids" widget="many2many_tags" groups="analytic.group_analytic_tags"/>
attrs="{'invisible': [('display_type', '!=', False)]}"
>
<field
name="analytic_account_id"
groups="analytic.group_analytic_accounting"
/>
<field
name="analytic_tag_ids"
widget="many2many_tags"
groups="analytic.group_analytic_tags"
/>
</group>
</group>
</field>
</record>
<!--Customer FORM view-->
<record id="contract_line_customer_form_view" model="ir.ui.view">
<field name="name">contract.line customer form view (in contract)</field>
@@ -61,7 +70,6 @@
</field>
</field>
</record>
<!--Supplier FORM view-->
<record id="contract_line_supplier_form_view" model="ir.ui.view">
<field name="name">contract.line supplier form view (in contract)</field>
@@ -78,87 +86,100 @@
</field>
</field>
</record>
<!-- TODO: Delete this view in migration to v13 or further migrations -->
<!--TREE view-->
<record id="contract_line_tree_view" model="ir.ui.view">
<field name="name">contract.line tree view (in contract)</field>
<field name="model">contract.line</field>
<field name="arch" type="xml">
<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"
>
<field name="sequence" widget="handle" />
<field name="product_id" />
<field name="name" />
<field name="analytic_account_id" groups="analytic.group_analytic_accounting"/>
<field name="analytic_tag_ids" widget="many2many_tags" groups="analytic.group_analytic_tags"/>
<field
name="analytic_account_id"
groups="analytic.group_analytic_accounting"
/>
<field
name="analytic_tag_ids"
widget="many2many_tags"
groups="analytic.group_analytic_tags"
/>
<field name="quantity" />
<field name="uom_id" />
<field name="automatic_price" />
<field name="price_unit"
attrs="{'readonly': [('automatic_price', '=', True)]}"/>
<field name="specific_price"
invisible="1"/>
<field name="discount"
groups="base.group_no_one"/>
<field
name="price_unit"
attrs="{'readonly': [('automatic_price', '=', True)]}"
/>
<field name="specific_price" invisible="1" />
<field name="discount" groups="base.group_no_one" />
<field name="price_subtotal" />
<field name="recurring_interval"
invisible="1"/>
<field name="recurring_rule_type"
invisible="1"/>
<field name="recurring_invoicing_type"
invisible="1"/>
<field name="recurring_interval" invisible="1" />
<field name="recurring_rule_type" invisible="1" />
<field name="recurring_invoicing_type" invisible="1" />
<field name="date_start" required="1" />
<field name="date_end" />
<field name="recurring_next_date"
required="1"/>
<field name="last_date_invoiced"
groups="base.group_no_one"/>
<field name="create_invoice_visibility"
invisible="1"/>
<field name="is_plan_successor_allowed"
invisible="1"/>
<field name="is_stop_plan_successor_allowed"
invisible="1"/>
<field name="is_stop_allowed"
invisible="1"/>
<field name="is_cancel_allowed"
invisible="1"/>
<field name="is_un_cancel_allowed"
invisible="1"/>
<field name="recurring_next_date" required="1" />
<field name="last_date_invoiced" groups="base.group_no_one" />
<field name="create_invoice_visibility" invisible="1" />
<field name="is_plan_successor_allowed" invisible="1" />
<field name="is_stop_plan_successor_allowed" invisible="1" />
<field name="is_stop_allowed" invisible="1" />
<field name="is_cancel_allowed" invisible="1" />
<field name="is_un_cancel_allowed" invisible="1" />
<field name="is_auto_renew" invisible="1" />
<field name="is_canceled" invisible="1" />
<button name="action_plan_successor"
string="Plan Start" type="object"
<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"
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"
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"
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"
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"
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)]}"/>
attrs="{'invisible': [('is_auto_renew', '=', False)]}"
/>
</tree>
</field>
</record>
<!--Supplier TREE view-->
<record id="contract_line_supplier_tree_view" model="ir.ui.view">
<field name="name">contract.line supplier tree view (in contract)</field>
@@ -172,5 +193,4 @@
</field>
</field>
</record>
</odoo>

View File

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

View File

@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<!--FORM view-->
<record id="contract_template_form_view" model="ir.ui.view">
<field name="name">contract.template form view (in contract)</field>
@@ -15,18 +14,30 @@
<field name="contract_type" />
<field name="journal_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 name="group_invoice_lines" string="Contract Template Lines">
<field name="contract_line_ids"
<field
name="contract_line_ids"
widget="section_and_note_one2many"
nolabel="1">
nolabel="1"
>
<tree>
<control>
<create string="Add a line" />
<create string="Add a section" context="{'default_display_type': 'line_section'}"/>
<create string="Add a note" context="{'default_display_type': 'line_note'}"/>
<create
string="Add a section"
context="{'default_display_type': 'line_section'}"
/>
<create
string="Add a note"
context="{'default_display_type': 'line_note'}"
/>
</control>
<field name="display_type" invisible="1" />
<field name="sequence" widget="handle" />
@@ -34,8 +45,14 @@
<field name="name" widget="section_and_note_text" />
<field name="quantity" />
<field name="uom_id" />
<field name="automatic_price" attrs="{'column_invisible': [('parent.contract_type','=','purchase')]}"/>
<field name="price_unit" attrs="{'readonly': [('automatic_price', '=', True)]}"/>
<field
name="automatic_price"
attrs="{'column_invisible': [('parent.contract_type','=','purchase')]}"
/>
<field
name="price_unit"
attrs="{'readonly': [('automatic_price', '=', True)]}"
/>
<field name="specific_price" invisible="1" />
<field name="discount" groups="base.group_no_one" />
<field name="price_subtotal" />
@@ -45,7 +62,8 @@
</tree>
</field>
</group>
<group name="group_legend"
<group
name="group_legend"
string="Legend (for the markers inside invoice lines description)"
>
<p> <strong>#START#</strong>: Start date of the invoiced period</p>
@@ -54,7 +72,6 @@
</form>
</field>
</record>
<!--TREE view-->
<record id="contract_template_tree_view" model="ir.ui.view">
<field name="name">contract.template tree view (in contract)</field>
@@ -67,7 +84,6 @@
</tree>
</field>
</record>
<!--SEARCH view-->
<record id="contract_template_search_view" model="ir.ui.view">
<field name="name">contract.template search view (in contract)</field>
@@ -78,22 +94,24 @@
<field name="contract_type" />
<field name="pricelist_id" />
<field name="journal_id" />
<filter name="contract_type"
<filter
name="contract_type"
string="Contract Type"
context="{'group_by': 'contract_type'}"
/>
<filter name="pricelist_id"
<filter
name="pricelist_id"
string="Pricelist"
context="{'group_by': 'pricelist_id'}"
/>
<filter name="journal_id"
<filter
name="journal_id"
string="Journal"
context="{'group_by': 'journal_id'}"
/>
</search>
</field>
</record>
<!--ACTION-->
<record id="contract_template_action" model="ir.actions.act_window">
<field name="name">Contract Templates</field>
@@ -107,11 +125,10 @@
</p>
</field>
</record>
<menuitem id="contract_template_menu"
<menuitem
id="contract_template_menu"
parent="menu_config_contract"
action="contract_template_action"
sequence="1"
/>
</odoo>

View File

@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<!--FORM view-->
<record id="contract_template_line_form_view" model="ir.ui.view">
<field name="name">contract.template.line form view (in contract)</field>
@@ -13,5 +12,4 @@
</form>
</field>
</record>
</odoo>

View File

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

View File

@@ -1,9 +1,7 @@
<?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2019 ACSONE SA/NV
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
<odoo>
<record model="ir.ui.view" id="res_config_settings_form_view">
<field name="model">res.config.settings</field>
<field name="inherit_id" ref="account.res_config_settings_view_form" />
@@ -23,6 +21,4 @@
</xpath>
</field>
</record>
</odoo>

View File

@@ -2,29 +2,45 @@
<!-- Copyright 2017 Carlos Dauden <carlos.dauden@tecnativa.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
<odoo>
<record id="view_partner_form" model="ir.ui.view">
<field name="inherit_id" ref="base.view_partner_form" />
<field name="model">res.partner</field>
<field name="groups_id" eval="[(4, ref('account.group_account_invoice'))]" />
<field type="xml" name="arch">
<xpath expr="//div[@name='button_box']" position="inside">
<button name="act_show_contract" type="object" class="oe_stat_button"
icon="fa-book" context="{'default_contract_type': 'sale', 'contract_type': 'sale'}"
<button
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)]}"
help="Show the sale contracts for this partner">
<field name="sale_contract_count" widget="statinfo" string="Sale Contracts"/>
help="Show the sale contracts for this partner"
>
<field
name="sale_contract_count"
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'}"
<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)]}"
help="Show the purchase contracts for this partner">
<field name="purchase_contract_count" widget="statinfo" string="Purchase Contracts"/>
help="Show the purchase contracts for this partner"
>
<field
name="purchase_contract_count"
widget="statinfo"
string="Purchase Contracts"
/>
</button>
</xpath>
</field>
</record>
<record id="view_res_partner_filter" model="ir.ui.view">
<field name="inherit_id" ref="base.view_res_partner_filter" />
<field name="model">res.partner</field>
@@ -39,5 +55,4 @@
</filter>
</field>
</record>
</odoo>

View File

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

View File

@@ -1,9 +1,7 @@
<?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2020 ACSONE SA/NV
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
<odoo>
<record model="ir.ui.view" id="contract_contract_terminate_form_view">
<field name="model">contract.contract.terminate</field>
<field name="arch" type="xml">
@@ -13,22 +11,22 @@
<field name="terminate_comment_required" invisible="True" />
<field name="terminate_date" />
<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>
<footer>
<button name="terminate_contract"
<button
name="terminate_contract"
string="Terminate Contract"
class="btn-primary"
confirm="Are you sure you want to terminate this contract?"
type="object"/>
<button string="Cancel"
class="btn-default"
special="cancel"/>
type="object"
/>
<button string="Cancel" class="btn-default" special="cancel" />
</footer>
</form>
</field>
</record>
</odoo>

View File

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

View File

@@ -1,9 +1,7 @@
<?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2018 ACSONE SA/NV
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
<odoo>
<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="model">contract.line.wizard</field>
@@ -12,71 +10,88 @@
<group>
<field name="contract_line_id" invisible="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>
<footer>
<button name="stop"
<button
name="stop"
string="Validate"
class="btn-primary"
type="object"/>
<button string="Cancel"
class="btn-default"
special="cancel"/>
type="object"
/>
<button string="Cancel" class="btn-default" special="cancel" />
</footer>
</form>
</field>
</record>
<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="arch" type="xml">
<form>
<group>
<field name="contract_line_id" invisible="True" />
<field name="date_start" required="True" />
<field name="date_end" attrs="{'required': [('is_auto_renew', '=', True)]}"/>
<field
name="date_end"
attrs="{'required': [('is_auto_renew', '=', True)]}"
/>
<field name="is_auto_renew" />
</group>
<footer>
<button name="plan_successor"
<button
name="plan_successor"
string="Validate"
class="btn-primary"
type="object"/>
<button string="Cancel"
class="btn-default"
special="cancel"/>
type="object"
/>
<button string="Cancel" class="btn-default" special="cancel" />
</footer>
</form>
</field>
</record>
<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="arch" type="xml">
<form>
<group>
<field name="contract_line_id" invisible="True" />
<field string="Suspension Start Date" name="date_start" required="True"/>
<field string="Suspension End Date" name="date_end" required="True"/>
<field
string="Suspension Start Date"
name="date_start"
required="True"
/>
<field
string="Suspension End Date"
name="date_end"
required="True"
/>
<field name="is_auto_renew" invisible="1" />
</group>
<footer>
<button name="stop_plan_successor"
<button
name="stop_plan_successor"
string="Validate"
class="btn-primary"
type="object"/>
<button string="Cancel"
class="btn-default"
special="cancel"/>
type="object"
/>
<button string="Cancel" class="btn-default" special="cancel" />
</footer>
</form>
</field>
</record>
<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="arch" type="xml">
<form>
@@ -85,16 +100,15 @@
<field name="recurring_next_date" required="True" />
</group>
<footer>
<button name="uncancel"
<button
name="uncancel"
string="Validate"
class="btn-primary"
type="object"/>
<button string="Cancel"
class="btn-default"
special="cancel"/>
type="object"
/>
<button string="Cancel" class="btn-default" special="cancel" />
</footer>
</form>
</field>
</record>
</odoo>

View File

@@ -1,40 +1,38 @@
# Copyright 2019 ACSONE SA/NV
# 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):
_name = 'contract.manually.create.invoice'
_description = 'Contract Manually Create Invoice Wizard'
_name = "contract.manually.create.invoice"
_description = "Contract Manually Create Invoice Wizard"
invoice_date = fields.Date(string="Invoice Date", required=True)
contract_to_invoice_count = fields.Integer(
compute="_compute_contract_to_invoice_ids"
)
contract_to_invoice_ids = fields.Many2many(
comodel_name="contract.contract",
compute="_compute_contract_to_invoice_ids",
comodel_name="contract.contract", compute="_compute_contract_to_invoice_ids",
)
contract_type = fields.Selection(
selection=[('sale', 'Customer'), ('purchase', 'Supplier')],
default='sale',
selection=[("sale", "Customer"), ("purchase", "Supplier")],
default="sale",
required=True,
)
@api.depends('invoice_date')
@api.depends("invoice_date")
def _compute_contract_to_invoice_ids(self):
if not self.invoice_date:
# 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:
contract_to_invoice_domain = self.env[
'contract.contract'
"contract.contract"
]._get_contracts_to_invoice_domain(self.invoice_date)
self.contract_to_invoice_ids = self.env['contract.contract'].search(
contract_to_invoice_domain
+ [('contract_type', '=', self.contract_type)]
self.contract_to_invoice_ids = self.env["contract.contract"].search(
contract_to_invoice_domain + [("contract_type", "=", self.contract_type)]
)
self.contract_to_invoice_count = len(self.contract_to_invoice_ids)
@@ -45,7 +43,7 @@ class ContractManuallyCreateInvoice(models.TransientModel):
"type": "ir.actions.act_window",
"name": _("Contracts to invoice"),
"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",
"context": self.env.context,
}
@@ -53,14 +51,14 @@ class ContractManuallyCreateInvoice(models.TransientModel):
@api.multi
def create_invoice(self):
self.ensure_one()
invoices = self.env['account.invoice']
invoices = self.env["account.invoice"]
for contract in self.contract_to_invoice_ids:
invoices |= contract.recurring_create_invoice()
return {
"type": "ir.actions.act_window",
"name": _("Invoices"),
"res_model": "account.invoice",
"domain": [('id', 'in', invoices.ids)],
"domain": [("id", "in", invoices.ids)],
"view_mode": "tree,form",
"context": self.env.context,
}

View File

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