mirror of
https://github.com/OCA/contract.git
synced 2025-02-13 17:57:24 +02:00
[MIG] contract: Migration to 16.0
This commit is contained in:
committed by
Pedro M. Baeza
parent
c72ead9f67
commit
10e9287cb6
@@ -11,7 +11,7 @@
|
||||
|
||||
{
|
||||
"name": "Recurring - Contracts Management",
|
||||
"version": "15.0.1.5.2",
|
||||
"version": "16.0.1.0.0",
|
||||
"category": "Contract Management",
|
||||
"license": "AGPL-3",
|
||||
"author": "Tecnativa, ACSONE SA/NV, Odoo Community Association (OCA)",
|
||||
|
||||
@@ -1,24 +1,5 @@
|
||||
<?xml version="1.0" ?>
|
||||
<odoo>
|
||||
<template
|
||||
id="mail_notification_contract"
|
||||
inherit_id="mail.mail_notification_paynow"
|
||||
primary="True"
|
||||
>
|
||||
<xpath expr="//t[@t-out='message.body']" position="after">
|
||||
<t t-raw="0" />
|
||||
<t t-if="record._name == 'contract.contract'">
|
||||
<t
|
||||
t-set="share_url"
|
||||
t-value="record._get_share_url(redirect=True, signup_partner=True, share_token=True)"
|
||||
/>
|
||||
<t
|
||||
t-set="access_url"
|
||||
t-value="is_online and share_url and base_url + share_url or ''"
|
||||
/>
|
||||
</t>
|
||||
</xpath>
|
||||
</template>
|
||||
<template id="template_contract_modification" name="Contract Modification">
|
||||
<t t-call="contract.mail_notification_contract">
|
||||
<table border="1" align="center">
|
||||
|
||||
@@ -1,141 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<!--
|
||||
This is a copy / paste from contract/data/mail_template.xml
|
||||
The only differences are:
|
||||
- Use noupdate=0
|
||||
- remove template_contract_modification which remains unchanged between 14 and 15
|
||||
-->
|
||||
<odoo>
|
||||
<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 <%s>' % (object.user_id.name, object.user_id.email) or '') }}</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" type="html">
|
||||
<div
|
||||
style="font-family: 'Lucida Grande', Ubuntu, Arial, Verdana, sans-serif; font-size: 12px; color: rgb(34, 34, 34); background-color: #FFF; "
|
||||
>
|
||||
<p>Hello <t t-out="object.partner_id.name or '' " />,</p>
|
||||
<p>A new contract has been created: </p>
|
||||
|
||||
<p style="border-left: 1px solid #8e0000; margin-left: 30px;">
|
||||
&nbsp;&nbsp;<strong>REFERENCES</strong><br />
|
||||
&nbsp;&nbsp;Contract: <strong t-out="object.name" /><br />
|
||||
<t t-if="object.date_start">
|
||||
&nbsp;&nbsp;Contract Date Start: <t
|
||||
t-out="object.date_start or ''"
|
||||
/><br />
|
||||
</t>
|
||||
|
||||
<t t-if="object.user_id">
|
||||
<t t-if="object.user_id.email">
|
||||
&nbsp;&nbsp;Your Contact: <a
|
||||
t-att-href="'mailto:%s?subject=Contract %s' % (object.user_id.email, object.name)"
|
||||
t-out="object.user_id.name"
|
||||
/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
&nbsp;&nbsp;Your Contact: <t
|
||||
t-out="object.user_id.name"
|
||||
/>
|
||||
</t>
|
||||
</t>
|
||||
</p>
|
||||
|
||||
<br />
|
||||
<p>If you have any questions, do not hesitate to contact us.</p>
|
||||
<p>Thank you for choosing <t
|
||||
t-out="object.company_id.name or 'us'"
|
||||
/>!</p>
|
||||
<br />
|
||||
<br />
|
||||
<div
|
||||
style="width: 375px; margin: 0px; padding: 0px; background-color: #8E0000; border-top-left-radius: 5px 5px; border-top-right-radius: 5px 5px; background-repeat: repeat no-repeat;"
|
||||
>
|
||||
<h3
|
||||
style="margin: 0px; padding: 2px 14px; font-size: 12px; color: #DDD;"
|
||||
>
|
||||
<strong
|
||||
style="text-transform:uppercase;"
|
||||
t-out="object.company_id.name"
|
||||
/></h3>
|
||||
</div>
|
||||
<div
|
||||
style="width: 347px; margin: 0px; padding: 5px 14px; line-height: 16px; background-color: #F2F2F2;"
|
||||
>
|
||||
<span style="color: #222; margin-bottom: 5px; display: block; ">
|
||||
<address
|
||||
t-field="object.company_id.sudo().partner_id"
|
||||
t-options='{"widget": "contact", "fields": ["name", "address"], "no_marker": True}'
|
||||
/>
|
||||
</span>
|
||||
<t t-if="object.company_id.phone">
|
||||
<div
|
||||
style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "
|
||||
>
|
||||
Phone: <t t-out="object.company_id.phone" />
|
||||
</div>
|
||||
</t>
|
||||
<t t-if="object.company_id.website">
|
||||
<div>
|
||||
Web: <a
|
||||
t-att-href="object.company_id.website"
|
||||
t-out="object.company_id.website"
|
||||
/>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
<br />
|
||||
<a
|
||||
t-att-href="'%s/my/contracts/%s?access_token=%s' % (object.get_base_url(), object.id, object.access_token)"
|
||||
target="_blank"
|
||||
style="background-color:#875A7B;padding: 8px 16px 8px 16px; text-decoration: none; color: #fff; border-radius: 5px; font-size:13px;"
|
||||
>View contract</a>
|
||||
</div>
|
||||
</field>
|
||||
</record>
|
||||
<record id="mail_template_contract_modification" model="mail.template">
|
||||
<field name="name">Contract Modification Template</field>
|
||||
<field
|
||||
name="email_from"
|
||||
>{{ (object.user_id.email and '%s <%s>' % (object.user_id.name, object.user_id.email) or '') }}</field>
|
||||
<field
|
||||
name="subject"
|
||||
>{{ object.company_id.name }} Contract (Ref {{ object.name or 'n/a' }}) - Modifications</field>
|
||||
<field name="model_id" ref="model_contract_contract" />
|
||||
<field name="lang">{{ object.partner_id.lang }}</field>
|
||||
<field name="body_html" type="html">
|
||||
<p>Hello</p>
|
||||
<p>We have modifications on the contract that we want to notify you.</p>
|
||||
</field>
|
||||
</record>
|
||||
<template
|
||||
id="mail_notification_contract"
|
||||
inherit_id="mail.mail_notification_paynow"
|
||||
primary="True"
|
||||
>
|
||||
<xpath expr="//t[@t-out='message.body']" position="after">
|
||||
<t t-out="0" />
|
||||
<t t-if="record._name == 'contract.contract'">
|
||||
<t
|
||||
t-set="share_url"
|
||||
t-value="record._get_share_url(redirect=True, signup_partner=True, share_token=True)"
|
||||
/>
|
||||
<t
|
||||
t-set="access_url"
|
||||
t-value="is_online and share_url and base_url + share_url or ''"
|
||||
/>
|
||||
</t>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
</odoo>
|
||||
@@ -1,17 +0,0 @@
|
||||
from openupgradelib import openupgrade
|
||||
|
||||
|
||||
@openupgrade.migrate()
|
||||
def migrate(env, version):
|
||||
openupgrade.load_data(
|
||||
env.cr, "contract", "migrations/15.0.1.0.0/noupdate_changes.xml"
|
||||
)
|
||||
openupgrade.delete_record_translations(
|
||||
env.cr,
|
||||
"contract",
|
||||
[
|
||||
"email_contract_template",
|
||||
"mail_template_contract_modification",
|
||||
"mail_notification_contract",
|
||||
],
|
||||
)
|
||||
@@ -13,6 +13,7 @@ class ContractAbstractContract(models.AbstractModel):
|
||||
_inherit = "contract.recurrency.basic.mixin"
|
||||
_name = "contract.abstract.contract"
|
||||
_description = "Abstract Recurring Contract"
|
||||
_check_company_auto = True
|
||||
|
||||
# These fields will not be synced to the contract
|
||||
NO_SYNC = ["name", "partner_id", "company_id"]
|
||||
@@ -31,11 +32,12 @@ class ContractAbstractContract(models.AbstractModel):
|
||||
journal_id = fields.Many2one(
|
||||
comodel_name="account.journal",
|
||||
string="Journal",
|
||||
domain="[('type', '=', contract_type)," "('company_id', '=', company_id)]",
|
||||
domain="[('type', '=', contract_type)]",
|
||||
compute="_compute_journal_id",
|
||||
store=True,
|
||||
readonly=False,
|
||||
index=True,
|
||||
check_company=True,
|
||||
)
|
||||
company_id = fields.Many2one(
|
||||
"res.company",
|
||||
@@ -80,3 +82,5 @@ class ContractAbstractContract(models.AbstractModel):
|
||||
journal = AccountJournal.search(domain, limit=1)
|
||||
if journal:
|
||||
contract.journal_id = journal.id
|
||||
else:
|
||||
contract.journal_id = None
|
||||
|
||||
@@ -35,15 +35,17 @@ class ContractAbstractContractLine(models.AbstractModel):
|
||||
"applying the pricelist to the product. If not, you will be "
|
||||
"able to introduce a manual price",
|
||||
)
|
||||
specific_price = fields.Float()
|
||||
price_unit = fields.Float(
|
||||
# Just to have a currency_id here - will get overwriten in contract.line
|
||||
# model with the related currency from the contract
|
||||
currency_id = fields.Many2one("res.currency")
|
||||
specific_price = fields.Monetary()
|
||||
price_unit = fields.Monetary(
|
||||
string="Unit Price",
|
||||
compute="_compute_price_unit",
|
||||
inverse="_inverse_price_unit",
|
||||
)
|
||||
price_subtotal = fields.Float(
|
||||
price_subtotal = fields.Monetary(
|
||||
compute="_compute_price_subtotal",
|
||||
digits="Account",
|
||||
string="Sub Total",
|
||||
)
|
||||
discount = fields.Float(
|
||||
@@ -191,7 +193,7 @@ class ContractAbstractContractLine(models.AbstractModel):
|
||||
from the pricelist otherwise.
|
||||
"""
|
||||
for line in self:
|
||||
if line.automatic_price:
|
||||
if line.automatic_price and line.product_id:
|
||||
pricelist = (
|
||||
line.contract_id.pricelist_id
|
||||
or line.contract_id.partner_id.with_company(
|
||||
@@ -209,7 +211,7 @@ class ContractAbstractContractLine(models.AbstractModel):
|
||||
"old_date", fields.Date.context_today(line)
|
||||
),
|
||||
)
|
||||
line.price_unit = product.price
|
||||
line.price_unit = pricelist._get_product_price(product, quantity=1)
|
||||
else:
|
||||
line.price_unit = line.specific_price
|
||||
|
||||
@@ -248,14 +250,20 @@ class ContractAbstractContractLine(models.AbstractModel):
|
||||
|
||||
date = self.recurring_next_date or fields.Date.context_today(self)
|
||||
partner = self.contract_id.partner_id or self.env.user.partner_id
|
||||
product = self.product_id.with_context(
|
||||
lang=partner.lang,
|
||||
partner=partner.id,
|
||||
quantity=self.quantity,
|
||||
date=date,
|
||||
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
|
||||
if self.product_id:
|
||||
product = self.product_id.with_context(
|
||||
lang=partner.lang,
|
||||
partner=partner.id,
|
||||
quantity=self.quantity,
|
||||
date=date,
|
||||
pricelist=self.contract_id.pricelist_id.id,
|
||||
uom=self.uom_id.id,
|
||||
)
|
||||
vals["name"] = self.product_id.get_product_multiline_description_sale()
|
||||
if self.contract_id.pricelist_id:
|
||||
vals["price_unit"] = self.contract_id.pricelist_id._get_product_price(
|
||||
product, quantity=1
|
||||
)
|
||||
else:
|
||||
vals["price_unit"] = 0.0
|
||||
self.update(vals)
|
||||
|
||||
@@ -8,10 +8,9 @@
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
import logging
|
||||
|
||||
from odoo import api, fields, models
|
||||
from odoo import Command, api, fields, models
|
||||
from odoo.exceptions import UserError, ValidationError
|
||||
from odoo.osv import expression
|
||||
from odoo.tests import Form
|
||||
from odoo.tools.translate import _
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
@@ -312,7 +311,8 @@ class ContractContract(models.Model):
|
||||
@api.depends(
|
||||
"contract_line_ids.recurring_next_date",
|
||||
"contract_line_ids.is_canceled",
|
||||
) # pylint: disable=missing-return
|
||||
)
|
||||
# pylint: disable=missing-return
|
||||
def _compute_recurring_next_date(self):
|
||||
for contract in self:
|
||||
recurring_next_date = contract.contract_line_ids.filtered(
|
||||
@@ -378,7 +378,7 @@ class ContractContract(models.Model):
|
||||
self.pricelist_id = partner.property_product_pricelist.id
|
||||
self.fiscal_position_id = partner.env[
|
||||
"account.fiscal.position"
|
||||
].get_fiscal_position(partner.id)
|
||||
]._get_fiscal_position(partner)
|
||||
if self.contract_type == "purchase":
|
||||
self.payment_term_id = partner.property_supplier_payment_term_id
|
||||
else:
|
||||
@@ -400,10 +400,9 @@ class ContractContract(models.Model):
|
||||
return new_lines
|
||||
|
||||
def _prepare_invoice(self, date_invoice, journal=None):
|
||||
"""Prepare in a Form the values for the generated invoice record.
|
||||
"""Prepare the values for the generated invoice record.
|
||||
|
||||
:return: A tuple with the vals dictionary and the Form with the
|
||||
preloaded values for being used in lines.
|
||||
:return: A vals dictionary
|
||||
"""
|
||||
self.ensure_one()
|
||||
if not journal:
|
||||
@@ -429,33 +428,39 @@ class ContractContract(models.Model):
|
||||
"company": self.company_id.name or "",
|
||||
}
|
||||
)
|
||||
invoice_type = "out_invoice"
|
||||
if self.contract_type == "purchase":
|
||||
invoice_type = "in_invoice"
|
||||
move_form = Form(
|
||||
self.env["account.move"]
|
||||
.with_company(self.company_id)
|
||||
.with_context(default_move_type=invoice_type)
|
||||
invoice_type = (
|
||||
"in_invoice" if self.contract_type == "purchase" else "out_invoice"
|
||||
)
|
||||
move_form.partner_id = self.invoice_partner_id
|
||||
vals = {
|
||||
"move_type": invoice_type,
|
||||
"company_id": self.company_id.id,
|
||||
"partner_id": self.invoice_partner_id.id,
|
||||
"ref": self.code,
|
||||
"currency_id": self.currency_id.id,
|
||||
"invoice_date": date_invoice,
|
||||
"journal_id": journal.id,
|
||||
"invoice_origin": self.name,
|
||||
"invoice_line_ids": [],
|
||||
}
|
||||
if self.payment_term_id:
|
||||
move_form.invoice_payment_term_id = self.payment_term_id
|
||||
vals.update(
|
||||
{
|
||||
"invoice_payment_term_id": self.payment_term_id.id,
|
||||
}
|
||||
)
|
||||
if self.fiscal_position_id:
|
||||
move_form.fiscal_position_id = self.fiscal_position_id
|
||||
vals.update(
|
||||
{
|
||||
"fiscal_position_id": self.fiscal_position_id.id,
|
||||
}
|
||||
)
|
||||
if invoice_type == "out_invoice" and self.user_id:
|
||||
move_form.invoice_user_id = self.user_id
|
||||
invoice_vals = move_form._values_to_save(all_fields=True)
|
||||
invoice_vals.update(
|
||||
{
|
||||
"ref": self.code,
|
||||
"company_id": self.company_id.id,
|
||||
"currency_id": self.currency_id.id,
|
||||
"invoice_date": date_invoice,
|
||||
"journal_id": journal.id,
|
||||
"invoice_origin": self.name,
|
||||
}
|
||||
)
|
||||
return invoice_vals, move_form
|
||||
vals.update(
|
||||
{
|
||||
"invoice_user_id": self.user_id.id,
|
||||
}
|
||||
)
|
||||
return vals
|
||||
|
||||
def action_contract_send(self):
|
||||
self.ensure_one()
|
||||
@@ -551,19 +556,22 @@ class ContractContract(models.Model):
|
||||
contract_lines = contract._get_lines_to_invoice(date_ref)
|
||||
if not contract_lines:
|
||||
continue
|
||||
invoice_vals, move_form = contract._prepare_invoice(date_ref)
|
||||
invoice_vals = contract._prepare_invoice(date_ref)
|
||||
invoice_vals["invoice_line_ids"] = []
|
||||
for line in contract_lines:
|
||||
invoice_line_vals = line._prepare_invoice_line(move_form=move_form)
|
||||
invoice_line_vals = line._prepare_invoice_line()
|
||||
if invoice_line_vals:
|
||||
# Allow extension modules to return an empty dictionary for
|
||||
# nullifying line. We should then cleanup certain values.
|
||||
del invoice_line_vals["company_id"]
|
||||
del invoice_line_vals["company_currency_id"]
|
||||
invoice_vals["invoice_line_ids"].append((0, 0, invoice_line_vals))
|
||||
if "company_id" in invoice_line_vals:
|
||||
del invoice_line_vals["company_id"]
|
||||
if "company_currency_id" in invoice_line_vals:
|
||||
del invoice_line_vals["company_currency_id"]
|
||||
invoice_vals["invoice_line_ids"].append(
|
||||
Command.create(invoice_line_vals)
|
||||
)
|
||||
invoices_values.append(invoice_vals)
|
||||
# Force the recomputation of journal items
|
||||
del invoice_vals["line_ids"]
|
||||
contract_lines._update_recurring_next_date()
|
||||
return invoices_values
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ class ContractLine(models.Model):
|
||||
_inherit = [
|
||||
"contract.abstract.contract.line",
|
||||
"contract.recurrency.mixin",
|
||||
"analytic.mixin",
|
||||
]
|
||||
_order = "sequence,id"
|
||||
|
||||
@@ -31,14 +32,11 @@ class ContractLine(models.Model):
|
||||
auto_join=True,
|
||||
ondelete="cascade",
|
||||
)
|
||||
currency_id = fields.Many2one(related="contract_id.currency_id")
|
||||
analytic_account_id = fields.Many2one(
|
||||
string="Analytic account",
|
||||
comodel_name="account.analytic.account",
|
||||
)
|
||||
analytic_tag_ids = fields.Many2many(
|
||||
comodel_name="account.analytic.tag",
|
||||
string="Analytic Tags",
|
||||
)
|
||||
date_start = fields.Date(required=True)
|
||||
date_end = fields.Date(compute="_compute_date_end", store=True, readonly=False)
|
||||
termination_notice_date = fields.Date(
|
||||
@@ -107,8 +105,13 @@ class ContractLine(models.Model):
|
||||
)
|
||||
|
||||
@api.depends(
|
||||
"last_date_invoiced", "date_start", "date_end", "contract_id.last_date_invoiced"
|
||||
) # pylint: disable=missing-return
|
||||
"last_date_invoiced",
|
||||
"date_start",
|
||||
"date_end",
|
||||
"contract_id.last_date_invoiced",
|
||||
"contract_id.contract_line_ids.last_date_invoiced",
|
||||
)
|
||||
# pylint: disable=missing-return
|
||||
def _compute_next_period_date_start(self):
|
||||
"""Rectify next period date start if another line in the contract has been
|
||||
already invoiced previously when the recurrence is by contract.
|
||||
@@ -146,7 +149,15 @@ class ContractLine(models.Model):
|
||||
else:
|
||||
rec.termination_notice_date = False
|
||||
|
||||
@api.depends("is_canceled", "date_start", "date_end", "is_auto_renew")
|
||||
@api.depends(
|
||||
"is_canceled",
|
||||
"date_start",
|
||||
"date_end",
|
||||
"is_auto_renew",
|
||||
"manual_renew_needed",
|
||||
"termination_notice_date",
|
||||
"successor_contract_line_id",
|
||||
)
|
||||
def _compute_state(self):
|
||||
today = fields.Date.context_today(self)
|
||||
for rec in self:
|
||||
@@ -542,33 +553,24 @@ class ContractLine(models.Model):
|
||||
else:
|
||||
rec.create_invoice_visibility = False
|
||||
|
||||
def _prepare_invoice_line(self, move_form):
|
||||
def _prepare_invoice_line(self):
|
||||
self.ensure_one()
|
||||
dates = self._get_period_to_invoice(
|
||||
self.last_date_invoiced, self.recurring_next_date
|
||||
)
|
||||
line_form = move_form.invoice_line_ids.new()
|
||||
line_form.display_type = self.display_type
|
||||
line_form.product_id = self.product_id
|
||||
invoice_line_vals = line_form._values_to_save(all_fields=True)
|
||||
name = self._insert_markers(dates[0], dates[1])
|
||||
invoice_line_vals.update(
|
||||
{
|
||||
"account_id": invoice_line_vals["account_id"]
|
||||
if "account_id" in invoice_line_vals and not self.display_type
|
||||
else False,
|
||||
"quantity": self._get_quantity_to_invoice(*dates),
|
||||
"product_uom_id": self.uom_id.id,
|
||||
"discount": self.discount,
|
||||
"contract_line_id": self.id,
|
||||
"sequence": self.sequence,
|
||||
"name": name,
|
||||
"analytic_account_id": self.analytic_account_id.id,
|
||||
"analytic_tag_ids": [(6, 0, self.analytic_tag_ids.ids)],
|
||||
"price_unit": self.price_unit,
|
||||
}
|
||||
)
|
||||
return invoice_line_vals
|
||||
return {
|
||||
"quantity": self._get_quantity_to_invoice(*dates),
|
||||
"product_uom_id": self.uom_id.id,
|
||||
"discount": self.discount,
|
||||
"contract_line_id": self.id,
|
||||
"analytic_distribution": self.analytic_distribution,
|
||||
"sequence": self.sequence,
|
||||
"name": name,
|
||||
"price_unit": self.price_unit,
|
||||
"display_type": self.display_type or "product",
|
||||
"product_id": self.product_id.id,
|
||||
}
|
||||
|
||||
def _get_period_to_invoice(
|
||||
self, last_date_invoiced, recurring_next_date, stop_at_date_end=True
|
||||
@@ -1071,9 +1073,7 @@ class ContractLine(models.Model):
|
||||
to_renew.renew()
|
||||
|
||||
@api.model
|
||||
def fields_view_get(
|
||||
self, view_id=None, view_type="form", toolbar=False, submenu=False
|
||||
):
|
||||
def get_view(self, view_id=None, view_type="form", **options):
|
||||
default_contract_type = self.env.context.get("default_contract_type")
|
||||
if view_type == "tree" and default_contract_type == "purchase":
|
||||
view_id = self.env.ref("contract.contract_line_supplier_tree_view").id
|
||||
@@ -1082,7 +1082,7 @@ class ContractLine(models.Model):
|
||||
view_id = self.env.ref("contract.contract_line_supplier_form_view").id
|
||||
elif default_contract_type == "sale":
|
||||
view_id = self.env.ref("contract.contract_line_customer_form_view").id
|
||||
return super().fields_view_get(view_id, view_type, toolbar, submenu)
|
||||
return super().get_view(view_id, view_type, **options)
|
||||
|
||||
def unlink(self):
|
||||
"""stop unlink uncnacled lines"""
|
||||
|
||||
@@ -19,7 +19,7 @@ class ContractModification(models.Model):
|
||||
ondelete="cascade",
|
||||
index=True,
|
||||
)
|
||||
sent = fields.Boolean(default=False)
|
||||
sent = fields.Boolean()
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
|
||||
@@ -242,12 +242,12 @@ class TestContract(TestContractBase):
|
||||
self.assertEqual(self.acct_line.price_unit, 1100)
|
||||
# Try to write other price
|
||||
self.acct_line.price_unit = 10
|
||||
self.acct_line.refresh()
|
||||
self.acct_line.invalidate_model()
|
||||
self.assertEqual(self.acct_line.price_unit, 1100)
|
||||
# Now disable automatic price
|
||||
self.acct_line.automatic_price = False
|
||||
self.acct_line.price_unit = 10
|
||||
self.acct_line.refresh()
|
||||
self.acct_line.invalidate_model()
|
||||
self.assertEqual(self.acct_line.price_unit, 10)
|
||||
|
||||
def test_contract(self):
|
||||
@@ -266,7 +266,7 @@ class TestContract(TestContractBase):
|
||||
|
||||
def test_contract_level_recurrence(self):
|
||||
self.contract3.recurring_create_invoice()
|
||||
self.contract3.flush()
|
||||
self.contract3.flush_recordset()
|
||||
|
||||
def test_contract_daily(self):
|
||||
recurring_next_date = to_date("2018-02-23")
|
||||
@@ -608,7 +608,7 @@ class TestContract(TestContractBase):
|
||||
self.contract.copy()
|
||||
purchase_count = self.partner.purchase_contract_count + 1
|
||||
self.contract2.copy()
|
||||
self.partner.refresh()
|
||||
self.partner.invalidate_model()
|
||||
self.assertEqual(self.partner.sale_contract_count, sale_count)
|
||||
self.assertEqual(self.partner.purchase_contract_count, purchase_count)
|
||||
|
||||
@@ -1691,7 +1691,8 @@ class TestContract(TestContractBase):
|
||||
self.assertFalse(line_4.successor_contract_line_id)
|
||||
|
||||
def test_renew_create_new_line(self):
|
||||
date_start = fields.Date.from_string("2022-01-01")
|
||||
date_start = self.today - relativedelta(months=9)
|
||||
date_end = date_start + relativedelta(months=12) - relativedelta(days=1)
|
||||
self.acct_line.write(
|
||||
{
|
||||
"is_auto_renew": True,
|
||||
@@ -1701,16 +1702,17 @@ class TestContract(TestContractBase):
|
||||
}
|
||||
)
|
||||
self.acct_line._onchange_is_auto_renew()
|
||||
self.assertEqual(self.acct_line.date_end, fields.Date.from_string("2022-12-31"))
|
||||
self.assertEqual(self.acct_line.date_end, date_end)
|
||||
new_line = self.acct_line.renew()
|
||||
self.assertFalse(self.acct_line.is_auto_renew)
|
||||
self.assertTrue(new_line.is_auto_renew)
|
||||
self.assertEqual(new_line.date_start, fields.Date.from_string("2023-01-01"))
|
||||
self.assertEqual(new_line.date_end, fields.Date.from_string("2023-12-31"))
|
||||
self.assertEqual(new_line.date_start, date_start + relativedelta(months=12))
|
||||
self.assertEqual(new_line.date_end, date_end + relativedelta(months=12))
|
||||
|
||||
def test_renew_extend_original_line(self):
|
||||
self.contract.company_id.create_new_line_at_contract_line_renew = False
|
||||
date_start = fields.Date.from_string("2022-01-01")
|
||||
date_start = self.today - relativedelta(months=9)
|
||||
date_end = date_start + relativedelta(months=12) - relativedelta(days=1)
|
||||
self.acct_line.write(
|
||||
{
|
||||
"is_auto_renew": True,
|
||||
@@ -1720,13 +1722,11 @@ class TestContract(TestContractBase):
|
||||
}
|
||||
)
|
||||
self.acct_line._onchange_is_auto_renew()
|
||||
self.assertEqual(self.acct_line.date_end, fields.Date.from_string("2022-12-31"))
|
||||
self.assertEqual(self.acct_line.date_end, date_end)
|
||||
self.acct_line.renew()
|
||||
self.assertTrue(self.acct_line.is_auto_renew)
|
||||
self.assertEqual(
|
||||
self.acct_line.date_start, fields.Date.from_string("2022-01-01")
|
||||
)
|
||||
self.assertEqual(self.acct_line.date_end, fields.Date.from_string("2023-12-31"))
|
||||
self.assertEqual(self.acct_line.date_start, date_start)
|
||||
self.assertEqual(self.acct_line.date_end, date_end + relativedelta(months=12))
|
||||
|
||||
def test_cron_recurring_create_invoice(self):
|
||||
self.acct_line.date_start = "2018-01-01"
|
||||
@@ -2045,7 +2045,8 @@ class TestContract(TestContractBase):
|
||||
]
|
||||
self.assertEqual(set(lines.mapped("state")), set(states))
|
||||
# Test search method
|
||||
lines.flush() # Needed for computed stored fields like termination_notice_date
|
||||
lines.flush_recordset() # Needed for computed stored fields
|
||||
# like termination_notice_date
|
||||
for state in states:
|
||||
lines = self.env["contract.line"].search([("state", "=", state)])
|
||||
self.assertTrue(lines, state)
|
||||
@@ -2152,17 +2153,17 @@ class TestContract(TestContractBase):
|
||||
action["context"]["default_contract_line_id"], self.acct_line.id
|
||||
)
|
||||
|
||||
def test_purchase_fields_view_get(self):
|
||||
def test_purchase_get_view(self):
|
||||
purchase_tree_view = self.env.ref("contract.contract_line_supplier_tree_view")
|
||||
purchase_form_view = self.env.ref("contract.contract_line_supplier_form_view")
|
||||
view = self.acct_line.with_context(
|
||||
default_contract_type="purchase"
|
||||
).fields_view_get(view_type="tree")
|
||||
self.assertEqual(view["view_id"], purchase_tree_view.id)
|
||||
view = self.acct_line.with_context(
|
||||
default_contract_type="purchase"
|
||||
).fields_view_get(view_type="form")
|
||||
self.assertEqual(view["view_id"], purchase_form_view.id)
|
||||
view = self.acct_line.with_context(default_contract_type="purchase").get_view(
|
||||
view_type="tree"
|
||||
)
|
||||
self.assertEqual(view["id"], purchase_tree_view.id)
|
||||
view = self.acct_line.with_context(default_contract_type="purchase").get_view(
|
||||
view_type="form"
|
||||
)
|
||||
self.assertEqual(view["id"], purchase_form_view.id)
|
||||
|
||||
def test_multicompany_partner_edited(self):
|
||||
"""Editing a partner with contracts in several companies works."""
|
||||
@@ -2185,12 +2186,12 @@ class TestContract(TestContractBase):
|
||||
company_id=company2.id
|
||||
).write({"is_company": False, "parent_id": parent_partner.id})
|
||||
|
||||
def test_sale_fields_view_get(self):
|
||||
def test_sale_get_view(self):
|
||||
sale_form_view = self.env.ref("contract.contract_line_customer_form_view")
|
||||
view = self.acct_line.with_context(
|
||||
default_contract_type="sale"
|
||||
).fields_view_get(view_type="form")
|
||||
self.assertEqual(view["view_id"], sale_form_view.id)
|
||||
view = self.acct_line.with_context(default_contract_type="sale").get_view(
|
||||
view_type="form"
|
||||
)
|
||||
self.assertEqual(view["id"], sale_form_view.id)
|
||||
|
||||
def test_contract_count_invoice(self):
|
||||
self.contract.recurring_create_invoice()
|
||||
|
||||
@@ -12,34 +12,70 @@
|
||||
<header attrs="{'invisible': [('display_type', '!=', False)]}" />
|
||||
<sheet>
|
||||
<field name="specific_price" invisible="1" />
|
||||
<field name="currency_id" invisible="1" />
|
||||
<field colspan="1" name="product_uom_category_id" invisible="1" />
|
||||
<group>
|
||||
<field
|
||||
colspan="1"
|
||||
name="product_id"
|
||||
attrs="{'required': [('display_type', '=', 'product')],'invisible': [('display_type', '!=', False)]}"
|
||||
/>
|
||||
</group>
|
||||
<group
|
||||
col="4"
|
||||
col="6"
|
||||
attrs="{'invisible': [('display_type', '!=', False)]}"
|
||||
>
|
||||
<field
|
||||
colspan="4"
|
||||
name="product_id"
|
||||
attrs="{'required': [('display_type', '=', False)]}"
|
||||
/>
|
||||
<field name="product_uom_category_id" invisible="1" />
|
||||
|
||||
<label for="quantity" />
|
||||
<div class="o_row">
|
||||
<field name="quantity" class="oe_inline" />
|
||||
<group colspan="1">
|
||||
<label for="automatic_price" colspan="2" />
|
||||
<field colspan="2" name="automatic_price" nolabel="1" />
|
||||
</group>
|
||||
<group colspan="1">
|
||||
<label for="price_unit" colspan="2" />
|
||||
<field
|
||||
colspan="2"
|
||||
name="price_unit"
|
||||
attrs="{'readonly': [('automatic_price', '=', True)]}"
|
||||
nolabel="1"
|
||||
/>
|
||||
</group>
|
||||
<group colspan="1">
|
||||
<label for="quantity" colspan="2" />
|
||||
<field
|
||||
colspan="2"
|
||||
name="quantity"
|
||||
class="oe_inline"
|
||||
nolabel="1"
|
||||
/>
|
||||
</group>
|
||||
<group colspan="1">
|
||||
<label for="uom_id" colspan="2" />
|
||||
<field
|
||||
colspan="2"
|
||||
name="uom_id"
|
||||
class="oe_inline"
|
||||
groups="uom.group_uom"
|
||||
attrs="{'required': [('display_type', '=', False)]}"
|
||||
nolabel="1"
|
||||
/>
|
||||
</div>
|
||||
<field colspan="2" name="automatic_price" />
|
||||
<field
|
||||
colspan="2"
|
||||
name="price_unit"
|
||||
attrs="{'readonly': [('automatic_price', '=', True)]}"
|
||||
/>
|
||||
<field colspan="2" name="discount" groups="base.group_no_one" />
|
||||
</group>
|
||||
<group colspan="1">
|
||||
<label for="discount" colspan="2" />
|
||||
<field
|
||||
colspan="2"
|
||||
name="discount"
|
||||
groups="base.group_no_one"
|
||||
nolabel="1"
|
||||
/>
|
||||
</group>
|
||||
<group colspan="1">
|
||||
<label for="price_subtotal" colspan="2" />
|
||||
<field
|
||||
colspan="2"
|
||||
name="price_subtotal"
|
||||
readonly="1"
|
||||
nolabel="1"
|
||||
/>
|
||||
</group>
|
||||
</group>
|
||||
<label
|
||||
for="name"
|
||||
|
||||
@@ -207,6 +207,7 @@
|
||||
context="{'default_display_type': 'line_note'}"
|
||||
/>
|
||||
</control>
|
||||
<field name="currency_id" invisible="1" />
|
||||
<field name="display_type" invisible="1" />
|
||||
<field name="sequence" widget="handle" />
|
||||
<field name="product_id" />
|
||||
@@ -219,11 +220,6 @@
|
||||
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
|
||||
@@ -314,6 +310,7 @@
|
||||
context="{'default_display_type': 'line_note'}"
|
||||
/>
|
||||
</control>
|
||||
<field name="currency_id" invisible="1" />
|
||||
<field name="display_type" invisible="1" />
|
||||
<field name="sequence" widget="handle" />
|
||||
<field name="product_id" />
|
||||
@@ -322,11 +319,6 @@
|
||||
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
|
||||
@@ -502,9 +494,7 @@
|
||||
>{'default_customer_rank': 1, 'default_supplier_rank': 0, 'res_partner_search_mode': 'customer', 'show_vat': True}</attribute>
|
||||
</field>
|
||||
<field name="journal_id" position="attributes">
|
||||
<attribute
|
||||
name="domain"
|
||||
>[('type', '=', 'sale'),('company_id', '=', company_id)]</attribute>
|
||||
<attribute name="domain">[('type', '=', 'sale')]</attribute>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
@@ -523,9 +513,7 @@
|
||||
>{'default_customer_rank': False, 'default_supplier_rank': 1, 'res_partner_search_mode': 'supplier', 'show_vat': True}</attribute>
|
||||
</field>
|
||||
<field name="journal_id" position="attributes">
|
||||
<attribute
|
||||
name="domain"
|
||||
>[('type', '=', 'purchase'),('company_id', '=', company_id)]</attribute>
|
||||
<attribute name="domain">[('type', '=', 'purchase')]</attribute>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -13,6 +13,9 @@
|
||||
<group name="recurrence_info" position="inside">
|
||||
<group>
|
||||
<field name="create_invoice_visibility" 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="date_start" required="1" />
|
||||
<field name="next_period_date_start" />
|
||||
<field name="recurring_next_date" />
|
||||
@@ -41,7 +44,7 @@
|
||||
<group name="recurrence_info" position="after">
|
||||
<group
|
||||
name="analytic"
|
||||
groups="analytic.group_analytic_accounting,analytic.group_analytic_tags"
|
||||
groups="analytic.group_analytic_accounting"
|
||||
attrs="{'invisible': [('display_type', '!=', False)]}"
|
||||
>
|
||||
<field
|
||||
@@ -49,9 +52,9 @@
|
||||
groups="analytic.group_analytic_accounting"
|
||||
/>
|
||||
<field
|
||||
name="analytic_tag_ids"
|
||||
widget="many2many_tags"
|
||||
groups="analytic.group_analytic_tags"
|
||||
name="analytic_distribution"
|
||||
widget="analytic_distribution"
|
||||
groups="analytic.group_analytic_accounting"
|
||||
/>
|
||||
</group>
|
||||
</group>
|
||||
@@ -104,9 +107,9 @@
|
||||
groups="analytic.group_analytic_accounting"
|
||||
/>
|
||||
<field
|
||||
name="analytic_tag_ids"
|
||||
widget="many2many_tags"
|
||||
groups="analytic.group_analytic_tags"
|
||||
name="analytic_distribution"
|
||||
widget="analytic_distribution"
|
||||
groups="analytic.group_analytic_accounting"
|
||||
/>
|
||||
<field name="quantity" />
|
||||
<field name="uom_id" />
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
name="contract_line_ids"
|
||||
widget="section_and_note_one2many"
|
||||
nolabel="1"
|
||||
colspan="2"
|
||||
>
|
||||
<tree>
|
||||
<control>
|
||||
@@ -66,8 +67,11 @@
|
||||
name="group_legend"
|
||||
string="Legend (for the markers inside invoice lines description)"
|
||||
>
|
||||
<p> <strong>#START#</strong>: Start date of the invoiced period</p>
|
||||
<p> <strong>#END#</strong>: End date of the invoiced period</p>
|
||||
<div colspan="2">
|
||||
<p> <strong
|
||||
>#START#</strong>: Start date of the invoiced period</p>
|
||||
<p> <strong>#END#</strong>: End date of the invoiced period</p>
|
||||
</div>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
|
||||
@@ -5,14 +5,18 @@
|
||||
<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">
|
||||
<field name="customer_rank" invisible="1" />
|
||||
<field
|
||||
name="customer_rank"
|
||||
invisible="1"
|
||||
groups="account.group_account_invoice"
|
||||
/>
|
||||
<button
|
||||
name="act_show_contract"
|
||||
type="object"
|
||||
class="oe_stat_button"
|
||||
groups="account.group_account_invoice"
|
||||
icon="fa-book"
|
||||
context="{'default_contract_type': 'sale', 'contract_type': 'sale'}"
|
||||
attrs="{'invisible': [('customer_rank','=',0)]}"
|
||||
@@ -24,11 +28,16 @@
|
||||
string="Sale Contracts"
|
||||
/>
|
||||
</button>
|
||||
<field name="supplier_rank" invisible="1" />
|
||||
<field
|
||||
name="supplier_rank"
|
||||
invisible="1"
|
||||
groups="account.group_account_invoice"
|
||||
/>
|
||||
<button
|
||||
name="act_show_contract"
|
||||
type="object"
|
||||
class="oe_stat_button"
|
||||
groups="account.group_account_invoice"
|
||||
icon="fa-book"
|
||||
context="{'default_contract_type': 'purchase', 'contract_type': 'purchase'}"
|
||||
attrs="{'invisible': [('supplier_rank','=',0)]}"
|
||||
|
||||
Reference in New Issue
Block a user