Merge PR #864 into 13.0

Signed-off-by rafaelbn
This commit is contained in:
OCA-git-bot
2022-09-30 19:34:01 +00:00
20 changed files with 1137 additions and 0 deletions

View File

@@ -0,0 +1,107 @@
=======================
Contract Price Revision
=======================
.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| image:: https://img.shields.io/badge/maturity-Production%2FStable-green.png
:target: https://odoo-community.org/page/development-status
:alt: Production/Stable
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fcontract-lightgray.png?logo=github
:target: https://github.com/OCA/contract/tree/13.0/contract_price_revision
:alt: OCA/contract
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/contract-13-0/contract-13-0-contract_price_revision
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png
:target: https://runbot.odoo-community.org/runbot/110/13.0
:alt: Try me on Runbot
|badge1| |badge2| |badge3| |badge4| |badge5|
This module allows to create revisions of contract line prices.
**Table of contents**
.. contents::
:local:
Usage
=====
To use this module:
#. Go to **Invoicing > Customers > Customer Contracts** if you are a billing
user.
#. Select as many contracts as you want to update line prices.
#. Click on Action button and execute the wizard **Create revision of contract
lines**.
#. Enter date start from which the new price will be valid and enter date
end and percentage to increase old contract lines.
#. By clicking on Apply button, a new contract line will be created with
a price increased accordingly to the percent entered. Old contract lines
will have as ending date the day before the entered date.
#. When create invoices related to contracts selected, prices will be update
with the prices that are not out of date.
#. When managing contract with recurrence on line level, you maybe want not
to revise price for some lines.
Check 'Never Revise Price' on line level to avoid price revisions.
Bug Tracker
===========
Bugs are tracked on `GitHub Issues <https://github.com/OCA/contract/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed
`feedback <https://github.com/OCA/contract/issues/new?body=module:%20contract_price_revision%0Aversion:%2013.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Do not contact contributors directly about support or help with technical issues.
Credits
=======
Authors
~~~~~~~
* ACSONE SA/NV
* Tecnativa
Contributors
~~~~~~~~~~~~
* `Tecnativa <https://www.tecnativa.com>`_:
* Vicent Cubells
* Carlos Dauden
Maintainers
~~~~~~~~~~~
This module is maintained by the OCA.
.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org
OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.
.. |maintainer-carlosdauden| image:: https://github.com/carlosdauden.png?size=40px
:target: https://github.com/carlosdauden
:alt: carlosdauden
Current `maintainer <https://odoo-community.org/page/maintainer-role>`__:
|maintainer-carlosdauden|
This module is part of the `OCA/contract <https://github.com/OCA/contract/tree/13.0/contract_price_revision>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

View File

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

View File

@@ -0,0 +1,18 @@
# Copyright 2019 Tecnativa - Vicent Cubells
# Copyright 2019 Tecnativa - Carlos Dauden
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
{
"name": "Contract Price Revision",
"summary": "Easy revision of contract prices",
"version": "13.0.1.0.0",
"category": "Contract",
"author": "ACSONE SA/NV, Tecnativa, Odoo Community Association (OCA)",
"license": "AGPL-3",
"website": "https://github.com/OCA/contract",
"depends": ["contract"],
"data": ["views/contract_line.xml", "wizards/contract_price_revision_views.xml"],
"installable": True,
"development_status": "Production/Stable",
"maintainers": ["carlosdauden"],
}

View File

@@ -0,0 +1,105 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * contract_price_revision
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 12.0\n"
"Report-Msgid-Bugs-To: \n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: contract_price_revision
#: model_terms:ir.ui.view,arch_db:contract_price_revision.contract_line_duplicate_wizard_view
msgid "Apply"
msgstr ""
#. module: contract_price_revision
#: model_terms:ir.ui.view,arch_db:contract_price_revision.contract_line_duplicate_wizard_view
msgid "Cancel"
msgstr ""
#. module: contract_price_revision
#: model:ir.model,name:contract_price_revision.model_contract_line
msgid "Contract Line"
msgstr ""
#. module: contract_price_revision
#: model:ir.actions.act_window,name:contract_price_revision.contract_line_duplicate_wizard_action
msgid "Create revision of contract lines"
msgstr ""
#. module: contract_price_revision
#: model:ir.model.fields,field_description:contract_price_revision.field_contract_price_revision_wizard__create_uid
msgid "Created by"
msgstr ""
#. module: contract_price_revision
#: model:ir.model.fields,field_description:contract_price_revision.field_contract_price_revision_wizard__create_date
msgid "Created on"
msgstr ""
#. module: contract_price_revision
#: model:ir.model.fields,field_description:contract_price_revision.field_contract_price_revision_wizard__date_end
msgid "Date End"
msgstr ""
#. module: contract_price_revision
#: model:ir.model.fields,field_description:contract_price_revision.field_contract_price_revision_wizard__date_start
msgid "Date Start"
msgstr ""
#. module: contract_price_revision
#: model:ir.model.fields,field_description:contract_price_revision.field_contract_price_revision_wizard__display_name
msgid "Display Name"
msgstr ""
#. module: contract_price_revision
#: model:ir.model.fields,field_description:contract_price_revision.field_contract_price_revision_wizard__id
msgid "ID"
msgstr ""
#. module: contract_price_revision
#: model:ir.model.fields,field_description:contract_price_revision.field_contract_price_revision_wizard____last_update
msgid "Last Modified on"
msgstr ""
#. module: contract_price_revision
#: model:ir.model.fields,field_description:contract_price_revision.field_contract_price_revision_wizard__write_uid
msgid "Last Updated by"
msgstr ""
#. module: contract_price_revision
#: model:ir.model.fields,field_description:contract_price_revision.field_contract_price_revision_wizard__write_date
msgid "Last Updated on"
msgstr ""
#. module: contract_price_revision
#: model:ir.model.fields,field_description:contract_price_revision.field_contract_line__previous_price
msgid "Previous price"
msgstr ""
#. module: contract_price_revision
#: model_terms:ir.ui.view,arch_db:contract_price_revision.contract_line_duplicate_wizard_view
msgid "Set new start date and variation percent to duplicate.\n"
" This process set start date previous day as end date of\n"
" origin record.\n"
" <br/>\n"
" <br/>"
msgstr ""
#. module: contract_price_revision
#: model:ir.model.fields,field_description:contract_price_revision.field_contract_line__variation_percent
#: model:ir.model.fields,field_description:contract_price_revision.field_contract_price_revision_wizard__variation_percent
msgid "Variation %"
msgstr ""
#. module: contract_price_revision
#: model:ir.model,name:contract_price_revision.model_contract_price_revision_wizard
msgid "Wizard to update price based on percentage variation"
msgstr ""

View File

@@ -0,0 +1,113 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * contract_price_revision
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 11.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-12-17 12:20+0100\n"
"PO-Revision-Date: 2019-12-17 12:22+0100\n"
"Last-Translator: Carlos Dauden <carlos.dauden@tecnativa.com>\n"
"Language-Team: \n"
"Language: es\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: \n"
"X-Generator: Poedit 1.8.7.1\n"
#. module: contract_price_revision
#: model_terms:ir.ui.view,arch_db:contract_price_revision.contract_line_duplicate_wizard_view
msgid "Apply"
msgstr "Aplicar"
#. module: contract_price_revision
#: model_terms:ir.ui.view,arch_db:contract_price_revision.contract_line_duplicate_wizard_view
msgid "Cancel"
msgstr "Cancelar"
#. module: contract_price_revision
#: model:ir.model,name:contract_price_revision.model_contract_line
msgid "Contract Line"
msgstr "Línea de contrato"
#. module: contract_price_revision
#: model:ir.actions.act_window,name:contract_price_revision.contract_line_duplicate_wizard_action
msgid "Create revision of contract lines"
msgstr "Crear revisión de las líneas de contrato"
#. module: contract_price_revision
#: model:ir.model.fields,field_description:contract_price_revision.field_contract_price_revision_wizard__create_uid
msgid "Created by"
msgstr "Creado por"
#. module: contract_price_revision
#: model:ir.model.fields,field_description:contract_price_revision.field_contract_price_revision_wizard__create_date
msgid "Created on"
msgstr "Creado el"
#. module: contract_price_revision
#: model:ir.model.fields,field_description:contract_price_revision.field_contract_price_revision_wizard__date_end
msgid "Date End"
msgstr "Fecha fin"
#. module: contract_price_revision
#: model:ir.model.fields,field_description:contract_price_revision.field_contract_price_revision_wizard__date_start
msgid "Date Start"
msgstr "Fecha inicio"
#. module: contract_price_revision
#: model:ir.model.fields,field_description:contract_price_revision.field_contract_price_revision_wizard__display_name
msgid "Display Name"
msgstr "Nombre mostrado"
#. module: contract_price_revision
#: model:ir.model.fields,field_description:contract_price_revision.field_contract_price_revision_wizard__id
msgid "ID"
msgstr "Id"
#. module: contract_price_revision
#: model:ir.model.fields,field_description:contract_price_revision.field_contract_price_revision_wizard____last_update
msgid "Last Modified on"
msgstr "Última modificación en"
#. module: contract_price_revision
#: model:ir.model.fields,field_description:contract_price_revision.field_contract_price_revision_wizard__write_uid
msgid "Last Updated by"
msgstr "Última modificación de"
#. module: contract_price_revision
#: model:ir.model.fields,field_description:contract_price_revision.field_contract_price_revision_wizard__write_date
msgid "Last Updated on"
msgstr "Última actualización en"
#. module: contract_price_revision
#: model:ir.model.fields,field_description:contract_price_revision.field_contract_line__previous_price
msgid "Previous price"
msgstr "Precio anterior"
#. module: contract_price_revision
#: model_terms:ir.ui.view,arch_db:contract_price_revision.contract_line_duplicate_wizard_view
msgid ""
"Set new start date and variation percent to duplicate.\n"
" This process set start date previous day as end date of\n"
" origin record.\n"
" <br/>\n"
" <br/>"
msgstr ""
"Establezca nueva fecha y porcentaje de variación para duplicar.\n"
" Este proceso establece la fecha de inicio anterior como fecha de finalización de registro de origen.\n"
"<br/>\n"
"<br/>"
#. module: contract_price_revision
#: model:ir.model.fields,field_description:contract_price_revision.field_contract_line__variation_percent
#: model:ir.model.fields,field_description:contract_price_revision.field_contract_price_revision_wizard__variation_percent
msgid "Variation %"
msgstr "Variación %"
#. module: contract_price_revision
#: model:ir.model,name:contract_price_revision.model_contract_price_revision_wizard
msgid "Wizard to update price based on percentage variation"
msgstr "Asistente para actualizar el precio basado en un porcentaje de variación"

View File

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

View File

@@ -0,0 +1,66 @@
# Copyright 2019 Tecnativa - Vicent Cubells
# Copyright 2019 Tecnativa - Carlos Dauden
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from odoo import api, fields, models
class ContractLine(models.Model):
_inherit = "contract.line"
previous_price = fields.Float(
string="Previous price",
related="predecessor_contract_line_id.price_unit",
readonly=True,
)
variation_percent = fields.Float(
compute="_compute_variation_percent",
store=True,
digits="Product Price",
string="Variation %",
)
never_revise_price = fields.Boolean(
help="Check this if you don't want to allow price revision."
)
price_can_be_revised = fields.Boolean(
compute="_compute_price_can_be_revised",
help="Technical field in order to know if the line price can be revised.",
)
@api.depends_context("date_start")
def _compute_price_can_be_revised(self):
date_start = self.env.context.get("date_start", fields.Datetime.now())
lines_can_be_revised = self.filtered(
lambda line: not line.never_revise_price
and not line.automatic_price
and not line.successor_contract_line_id
and line.recurring_next_date
and not line.display_type
and (not line.date_end or line.date_end >= date_start)
)
lines_can_be_revised.price_can_be_revised = True
(self - lines_can_be_revised).price_can_be_revised = False
@api.depends("price_unit", "predecessor_contract_line_id.price_unit")
def _compute_variation_percent(self):
for line in self:
if line.price_unit and line.previous_price:
line.variation_percent = (
line.price_unit / line.previous_price - 1
) * 100
else:
line.variation_percent = 0.0
def _prepare_value_for_plan_successor_price(
self, date_start, date_end, is_auto_renew, price, recurring_next_date=False
):
"""
Override contract function to prepare values for new contract line
adding the new price as parameter
"""
res = super()._prepare_value_for_plan_successor(
date_start, date_end, is_auto_renew, recurring_next_date=recurring_next_date
)
res.update({"price_unit": price})
return res

View File

@@ -0,0 +1,4 @@
* `Tecnativa <https://www.tecnativa.com>`_:
* Vicent Cubells
* Carlos Dauden

View File

@@ -0,0 +1 @@
This module allows to create revisions of contract line prices.

View File

@@ -0,0 +1,18 @@
To use this module:
#. Go to **Invoicing > Customers > Customer Contracts** if you are a billing
user.
#. Select as many contracts as you want to update line prices.
#. Click on Action button and execute the wizard **Create revision of contract
lines**.
#. Enter date start from which the new price will be valid and enter date
end and percentage to increase old contract lines.
#. By clicking on Apply button, a new contract line will be created with
a price increased accordingly to the percent entered. Old contract lines
will have as ending date the day before the entered date.
#. When create invoices related to contracts selected, prices will be update
with the prices that are not out of date.
#. When managing contract with recurrence on line level, you maybe want not
to revise price for some lines.
Check 'Never Revise Price' on line level to avoid price revisions.

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

View File

@@ -0,0 +1,448 @@
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils: http://docutils.sourceforge.net/" />
<title>Contract Price Revision</title>
<style type="text/css">
/*
:Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 7952 2016-07-26 18:15:59Z milde $
:Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils.
See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
customize this style sheet.
*/
/* used to remove borders from tables and images */
.borderless, table.borderless td, table.borderless th {
border: 0 }
table.borderless td, table.borderless th {
/* Override padding for "table.docutils td" with "! important".
The right padding separates the table cells. */
padding: 0 0.5em 0 0 ! important }
.first {
/* Override more specific margin styles with "! important". */
margin-top: 0 ! important }
.last, .with-subtitle {
margin-bottom: 0 ! important }
.hidden {
display: none }
.subscript {
vertical-align: sub;
font-size: smaller }
.superscript {
vertical-align: super;
font-size: smaller }
a.toc-backref {
text-decoration: none ;
color: black }
blockquote.epigraph {
margin: 2em 5em ; }
dl.docutils dd {
margin-bottom: 0.5em }
object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
overflow: hidden;
}
/* Uncomment (and remove this text!) to get bold-faced definition list terms
dl.docutils dt {
font-weight: bold }
*/
div.abstract {
margin: 2em 5em }
div.abstract p.topic-title {
font-weight: bold ;
text-align: center }
div.admonition, div.attention, div.caution, div.danger, div.error,
div.hint, div.important, div.note, div.tip, div.warning {
margin: 2em ;
border: medium outset ;
padding: 1em }
div.admonition p.admonition-title, div.hint p.admonition-title,
div.important p.admonition-title, div.note p.admonition-title,
div.tip p.admonition-title {
font-weight: bold ;
font-family: sans-serif }
div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title, .code .error {
color: red ;
font-weight: bold ;
font-family: sans-serif }
/* Uncomment (and remove this text!) to get reduced vertical space in
compound paragraphs.
div.compound .compound-first, div.compound .compound-middle {
margin-bottom: 0.5em }
div.compound .compound-last, div.compound .compound-middle {
margin-top: 0.5em }
*/
div.dedication {
margin: 2em 5em ;
text-align: center ;
font-style: italic }
div.dedication p.topic-title {
font-weight: bold ;
font-style: normal }
div.figure {
margin-left: 2em ;
margin-right: 2em }
div.footer, div.header {
clear: both;
font-size: smaller }
div.line-block {
display: block ;
margin-top: 1em ;
margin-bottom: 1em }
div.line-block div.line-block {
margin-top: 0 ;
margin-bottom: 0 ;
margin-left: 1.5em }
div.sidebar {
margin: 0 0 0.5em 1em ;
border: medium outset ;
padding: 1em ;
background-color: #ffffee ;
width: 40% ;
float: right ;
clear: right }
div.sidebar p.rubric {
font-family: sans-serif ;
font-size: medium }
div.system-messages {
margin: 5em }
div.system-messages h1 {
color: red }
div.system-message {
border: medium outset ;
padding: 1em }
div.system-message p.system-message-title {
color: red ;
font-weight: bold }
div.topic {
margin: 2em }
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
margin-top: 0.4em }
h1.title {
text-align: center }
h2.subtitle {
text-align: center }
hr.docutils {
width: 75% }
img.align-left, .figure.align-left, object.align-left, table.align-left {
clear: left ;
float: left ;
margin-right: 1em }
img.align-right, .figure.align-right, object.align-right, table.align-right {
clear: right ;
float: right ;
margin-left: 1em }
img.align-center, .figure.align-center, object.align-center {
display: block;
margin-left: auto;
margin-right: auto;
}
table.align-center {
margin-left: auto;
margin-right: auto;
}
.align-left {
text-align: left }
.align-center {
clear: both ;
text-align: center }
.align-right {
text-align: right }
/* reset inner alignment in figures */
div.align-right {
text-align: inherit }
/* div.align-center * { */
/* text-align: left } */
.align-top {
vertical-align: top }
.align-middle {
vertical-align: middle }
.align-bottom {
vertical-align: bottom }
ol.simple, ul.simple {
margin-bottom: 1em }
ol.arabic {
list-style: decimal }
ol.loweralpha {
list-style: lower-alpha }
ol.upperalpha {
list-style: upper-alpha }
ol.lowerroman {
list-style: lower-roman }
ol.upperroman {
list-style: upper-roman }
p.attribution {
text-align: right ;
margin-left: 50% }
p.caption {
font-style: italic }
p.credits {
font-style: italic ;
font-size: smaller }
p.label {
white-space: nowrap }
p.rubric {
font-weight: bold ;
font-size: larger ;
color: maroon ;
text-align: center }
p.sidebar-title {
font-family: sans-serif ;
font-weight: bold ;
font-size: larger }
p.sidebar-subtitle {
font-family: sans-serif ;
font-weight: bold }
p.topic-title {
font-weight: bold }
pre.address {
margin-bottom: 0 ;
margin-top: 0 ;
font: inherit }
pre.literal-block, pre.doctest-block, pre.math, pre.code {
margin-left: 2em ;
margin-right: 2em }
pre.code .ln { color: grey; } /* line numbers */
pre.code, code { background-color: #eeeeee }
pre.code .comment, code .comment { color: #5C6576 }
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
pre.code .literal.string, code .literal.string { color: #0C5404 }
pre.code .name.builtin, code .name.builtin { color: #352B84 }
pre.code .deleted, code .deleted { background-color: #DEB0A1}
pre.code .inserted, code .inserted { background-color: #A3D289}
span.classifier {
font-family: sans-serif ;
font-style: oblique }
span.classifier-delimiter {
font-family: sans-serif ;
font-weight: bold }
span.interpreted {
font-family: sans-serif }
span.option {
white-space: nowrap }
span.pre {
white-space: pre }
span.problematic {
color: red }
span.section-subtitle {
/* font-size relative to parent (h1..h6 element) */
font-size: 80% }
table.citation {
border-left: solid 1px gray;
margin-left: 1px }
table.docinfo {
margin: 2em 4em }
table.docutils {
margin-top: 0.5em ;
margin-bottom: 0.5em }
table.footnote {
border-left: solid 1px black;
margin-left: 1px }
table.docutils td, table.docutils th,
table.docinfo td, table.docinfo th {
padding-left: 0.5em ;
padding-right: 0.5em ;
vertical-align: top }
table.docutils th.field-name, table.docinfo th.docinfo-name {
font-weight: bold ;
text-align: left ;
white-space: nowrap ;
padding-left: 0 }
/* "booktabs" style (no vertical lines) */
table.docutils.booktabs {
border: 0px;
border-top: 2px solid;
border-bottom: 2px solid;
border-collapse: collapse;
}
table.docutils.booktabs * {
border: 0px;
}
table.docutils.booktabs th {
border-bottom: thin solid;
text-align: left;
}
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
font-size: 100% }
ul.auto-toc {
list-style-type: none }
</style>
</head>
<body>
<div class="document" id="contract-price-revision">
<h1 class="title">Contract Price Revision</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external" href="https://odoo-community.org/page/development-status"><img alt="Production/Stable" src="https://img.shields.io/badge/maturity-Production%2FStable-green.png" /></a> <a class="reference external" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external" href="https://github.com/OCA/contract/tree/13.0/contract_price_revision"><img alt="OCA/contract" src="https://img.shields.io/badge/github-OCA%2Fcontract-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/contract-13-0/contract-13-0-contract_price_revision"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runbot.odoo-community.org/runbot/110/13.0"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p>
<p>This module allows to create revisions of contract line prices.</p>
<p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#usage" id="id1">Usage</a></li>
<li><a class="reference internal" href="#bug-tracker" id="id2">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="id3">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="id4">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="id5">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="id6">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="usage">
<h1><a class="toc-backref" href="#id1">Usage</a></h1>
<p>To use this module:</p>
<ol class="arabic simple">
<li>Go to <strong>Invoicing &gt; Customers &gt; Customer Contracts</strong> if you are a billing
user.</li>
<li>Select as many contracts as you want to update line prices.</li>
<li>Click on Action button and execute the wizard <strong>Create revision of contract
lines</strong>.</li>
<li>Enter date start from which the new price will be valid and enter date
end and percentage to increase old contract lines.</li>
<li>By clicking on Apply button, a new contract line will be created with
a price increased accordingly to the percent entered. Old contract lines
will have as ending date the day before the entered date.</li>
<li>When create invoices related to contracts selected, prices will be update
with the prices that are not out of date.</li>
<li>When managing contract with recurrence on line level, you maybe want not
to revise price for some lines.
Check Never Revise Price on line level to avoid price revisions.</li>
</ol>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#id2">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/contract/issues">GitHub Issues</a>.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed
<a class="reference external" href="https://github.com/OCA/contract/issues/new?body=module:%20contract_price_revision%0Aversion:%2013.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p>
</div>
<div class="section" id="credits">
<h1><a class="toc-backref" href="#id3">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#id4">Authors</a></h2>
<ul class="simple">
<li>ACSONE SA/NV</li>
<li>Tecnativa</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#id5">Contributors</a></h2>
<ul class="simple">
<li><a class="reference external" href="https://www.tecnativa.com">Tecnativa</a>:<ul>
<li>Vicent Cubells</li>
<li>Carlos Dauden</li>
</ul>
</li>
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#id6">Maintainers</a></h2>
<p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org"><img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" /></a>
<p>OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.</p>
<p>Current <a class="reference external" href="https://odoo-community.org/page/maintainer-role">maintainer</a>:</p>
<p><a class="reference external" href="https://github.com/carlosdauden"><img alt="carlosdauden" src="https://github.com/carlosdauden.png?size=40px" /></a></p>
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/contract/tree/13.0/contract_price_revision">OCA/contract</a> project on GitHub.</p>
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
</div>
</div>
</div>
</body>
</html>

View File

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

View File

@@ -0,0 +1,83 @@
# Copyright 2019 Tecnativa - Vicent Cubells
# Copyright 2019 Tecnativa - Carlos Dauden
# Copyright 2020 ACSONE SA/NV
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from odoo.addons.contract.tests.test_contract import TestContractBase
class TestContractPriceRevision(TestContractBase):
def _create_wizard(self, v_type="percentage", value=0.0):
# TODO: Limitation here, start date should be on the
# beginning of next period (should not have a gap)
self.wizard = self.env["contract.price.revision.wizard"].create(
{
"date_start": "2018-02-01",
"variation_type": v_type,
"variation_percent": value,
"fixed_price": value,
}
)
def execute_wizard(self):
self.wizard.with_context({"active_ids": [self.contract.id]}).action_apply()
def test_contract_price_revision_wizard(self):
# This is for checking if this line is not versioned
self.acct_line.copy({"automatic_price": True})
self.assertEqual(len(self.contract.contract_line_ids.ids), 2)
self._create_wizard(value=100.0)
self.execute_wizard()
self.assertEqual(len(self.contract.contract_line_ids.ids), 3)
lines = self.contract.contract_line_ids.filtered(
lambda x: x.price_unit == 200.0
)
self.assertEqual(len(lines), 1)
def test_contract_price_fixed_revision_wizard(self):
# This is for checking if this line is not versioned
self.acct_line.copy({"automatic_price": True})
self.assertEqual(len(self.contract.contract_line_ids.ids), 2)
self._create_wizard(v_type="fixed", value=120.0)
self.execute_wizard()
self.assertEqual(len(self.contract.contract_line_ids.ids), 3)
lines = self.contract.contract_line_ids.filtered(
lambda x: x.price_unit == 120.0
)
self.assertEqual(len(lines), 1)
def test_contract_price_fixed_revision_wizard_never(self):
self.acct_line.copy({"never_revise_price": True})
self.assertEqual(len(self.contract.contract_line_ids.ids), 2)
self._create_wizard(v_type="fixed", value=120.0)
self.execute_wizard()
self.assertEqual(len(self.contract.contract_line_ids.ids), 3)
lines = self.contract.contract_line_ids.filtered(
lambda x: x.price_unit == 120.0
)
self.assertEqual(len(lines), 1)
def test_contract_price_revision_invoicing(self):
self.acct_line.copy({"automatic_price": True})
self._create_wizard(value=100.0)
self.execute_wizard()
invoice = self.contract.recurring_create_invoice()
invoices = self.env["account.move"].search(
[
(
"invoice_line_ids.contract_line_id",
"in",
self.contract.contract_line_ids.ids,
)
]
)
self.assertEqual(len(invoices), 1)
lines = invoice.invoice_line_ids
self.assertEqual(len(lines), 2)
lines = lines.filtered(lambda x: x.price_unit == 100.0)
self.assertEqual(len(lines), 1)
invoice = self.contract.recurring_create_invoice()
lines = invoice.invoice_line_ids
self.assertEqual(len(lines), 2)
lines = lines.filtered(lambda x: x.price_unit == 200.0)
self.assertEqual(len(lines), 1)

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<record id="contract_line_tree_view" model="ir.ui.view">
<field name="model">contract.line</field>
<field name="inherit_id" ref="contract.contract_line_tree_view" />
<field name="arch" type="xml">
<field name="last_date_invoiced" position="after">
<field name="never_revise_price" />
<field name="variation_percent" groups="base.group_no_one" />
</field>
</field>
</record>
<record id="contract_line_form_view" model="ir.ui.view">
<field name="model">contract.line</field>
<field name="inherit_id" ref="contract.contract_line_form_view" />
<field name="arch" type="xml">
<field name="discount" position="after">
<field name="never_revise_price" />
<field
name="variation_percent"
groups="base.group_no_one"
attrs="{'invisible': [('predecessor_contract_line_id', '=', False)]}"
/>
</field>
</field>
</record>
</odoo>

View File

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

View File

@@ -0,0 +1,81 @@
# Copyright 2019 Tecnativa - Vicent Cubells
# Copyright 2019 Tecnativa - Carlos Dauden
# Copyright 2020 ACSONE SA/NV
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from dateutil.relativedelta import relativedelta
from odoo import api, fields, models
class ContractPriceRevisionWizard(models.TransientModel):
""" Update contract price based on percentage variation """
_name = "contract.price.revision.wizard"
_description = "Wizard to update price based on percentage variation"
date_start = fields.Date(required=True,)
date_end = fields.Date()
variation_type = fields.Selection(
selection=lambda self: self._get_variation_type(),
required=True,
default=lambda self: self._get_default_variation_type(),
)
variation_percent = fields.Float(digits="Product Price", string="Variation %",)
fixed_price = fields.Float(digits="Product Price")
@api.model
def _get_variation_type(self):
return [
("percentage", "Percentage"),
("fixed", "Fixed Price"),
]
@api.model
def _get_default_variation_type(self):
return "percentage"
def _get_new_price(self, line):
"""Get the price depending the change type chosen
"""
if self.variation_type == "percentage":
return line.price_unit * (1.0 + self.variation_percent / 100.0)
elif self.variation_type == "fixed":
return self.fixed_price
return line.price_unit
def _get_new_line_value(self, line):
self.ensure_one()
return line._prepare_value_for_plan_successor_price(
self.date_start,
self.date_end,
line.is_auto_renew,
self._get_new_price(line),
False,
)
def _get_old_line_date_end(self, line):
return self.date_start - relativedelta(days=1)
def action_apply(self):
active_ids = self.env.context.get("active_ids")
contracts = self.env["contract.contract"].browse(active_ids)
for line in self._get_contract_lines_to_revise(contracts):
date_end = self._get_old_line_date_end(line)
line.stop(date_end)
new_line = line.copy(self._get_new_line_value(line))
line.update({"successor_contract_line_id": new_line.id})
action = self.env["ir.actions.act_window"].for_xml_id(
"contract", "action_customer_contract"
)
action["domain"] = [("id", "in", active_ids)]
return action
def _get_contract_lines_to_revise(self, contracts):
self.ensure_one()
to_revise = (
contracts.mapped("contract_line_ids")
.with_context(date_start=self.date_start)
.filtered("price_can_be_revised")
)
return to_revise

View File

@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<record id="contract_line_duplicate_wizard_view" model="ir.ui.view">
<field name="name">Create Revision Line</field>
<field name="model">contract.price.revision.wizard</field>
<field name="arch" type="xml">
<form>
<div>
Set new start date and variation percent to duplicate.
This process set start date previous day as end date of
origin record.
<br />
<br />
</div>
<group>
<group>
<field name="date_start" />
<field name="date_end" />
<field name="variation_type" />
</group>
<group
name="percentage"
attrs="{'invisible': [('variation_type', '!=', 'percentage')]}"
>
<field name="variation_percent" />
</group>
<group
name="fixed"
attrs="{'invisible': [('variation_type', '!=', 'fixed')]}"
>
<field name="fixed_price" />
</group>
</group>
<footer>
<button
string="Apply"
name="action_apply"
type="object"
class="oe_highlight"
/>
<button string="Cancel" class="oe_link" special="cancel" />
</footer>
</form>
</field>
</record>
<record id="contract_line_duplicate_wizard_action" model="ir.actions.act_window">
<field name="name">Create revision of contract lines</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">contract.price.revision.wizard</field>
<field name="view_mode">form</field>
<field name="target">new</field>
<field name="binding_model_id" ref="contract.model_contract_contract" />
</record>
</odoo>

View File

@@ -0,0 +1 @@
../../../../contract_price_revision

View File

@@ -0,0 +1,6 @@
import setuptools
setuptools.setup(
setup_requires=['setuptools-odoo'],
odoo_addon=True,
)