Skip to content

Commit

Permalink
Merge 2a0708d into 4a50437
Browse files Browse the repository at this point in the history
  • Loading branch information
legalsylvain committed Jan 8, 2020
2 parents 4a50437 + 2a0708d commit e2b1dcd
Show file tree
Hide file tree
Showing 17 changed files with 475 additions and 1 deletion.
2 changes: 1 addition & 1 deletion product_replenishment_cost/views/product_view.xml
Expand Up @@ -6,7 +6,7 @@
<field name="inherit_id" ref="product.product_normal_form_view" />
<field name="arch" type="xml">
<xpath expr="//field[@name='standard_price']/ancestor::*[1]" position="after">
<field name="replenishment_cost"/>
<field name="replenishment_cost"/>
</xpath>
</field>
</record>
Expand Down
58 changes: 58 additions & 0 deletions product_standard_margin/README.rst
@@ -0,0 +1,58 @@
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
:alt: License: AGPL-3

Product Margin and Margin Rate
==============================

Add a field on the product form that compute the standard (or theorical)
margin based on the current values of sale and replenishment cost present in
the product form. We take care of taxe included or excluded.

It will just compute it as follow:
(Sale Price without tax - Replenishment Cost) / Sale Price without tax

Remember that this module can be used in conjonction with
product_cost_incl_bom to have the replenishment cost computed from the BOM when
a product has one.

WARNING:

1) As this module will base his simple computation on sale and cost prices,
it suppose you have them both in the same currency (the price type must of
the same currency for both of them). Remember this is the default OpenERP
configuration (price type of all product price fields are set as the same as
the company currency). We don't take care of it cause otherwise we should
have added a dependency on sale module.

Bug Tracker
===========

Bugs are tracked on `GitHub Issues <https://github.com/OCA/web/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
`here <https://github.com/OCA/margin-analysis/issues/new?body=module:%20product_standard_margin%0Aversion:%208.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.

Credits
=======

Contributors
------------

* Alexandre Fayolle <alexandre.fayolle@camptocamp.com>
* Yannick Vaucher <yannick.vaucher@camptocamp.com>
* Joël Grand-Guillaume <joel.grand-guillaume@camptocamp.com>
* Sylvain Le Gal (https://twitter.com/legalsylvain)

Maintainer
----------

.. image:: http://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: http://odoo-community.org

This module is maintained by the OCA.

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.

To contribute to this module, please visit http://odoo-community.org.

1 change: 1 addition & 0 deletions product_standard_margin/__init__.py
@@ -0,0 +1 @@
from . import models
18 changes: 18 additions & 0 deletions product_standard_margin/__manifest__.py
@@ -0,0 +1,18 @@
# Copyright (C) 2012 - Today: Camptocamp SA
# @author: Joel Grand-Guillaume
# Copyright (C) 2019 - Today: GRAP (http://www.grap.coop)
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
{
"name": "Product Margin and Margin Rate",
"version": "12.0.1.0.0",
"author": "Camptocamp,GRAP,Odoo Community Association (OCA)",
"category": "Product",
"depends": ["account"],
"maintainers": ["legalsylvain"],
"website": "https://www.github.com/OCA/margin-analysis",
"data": ["views/view_product_product.xml", "views/view_product_template.xml"],
"license": "AGPL-3",
"installable": True,
"images": ["static/description/product_form.png"],
}
59 changes: 59 additions & 0 deletions product_standard_margin/i18n/fr.po
@@ -0,0 +1,59 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * product_standard_margin
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 12.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-01-07 14:51+0000\n"
"PO-Revision-Date: 2020-01-07 14:51+0000\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: product_standard_margin
#: model:ir.model.fields,help:product_standard_margin.field_product_product__standard_margin_rate
#: model:ir.model.fields,help:product_standard_margin.field_product_template__standard_margin_rate
msgid "Margin rate is [ Theorical Margin / sale price (Wo Tax) ] of the product form (not based on historical values).Take care of tax include and exclude.. If no sale price set, will display 999.0"
msgstr "Taux de marque théorique [ (PV unitaire - Coût unitaire ) / PV unitaire du formulaire Produit] (ne tient pas compte de la facturation effective). Ce taux tient compte des PV TTC (TVA incluse). Si aucun PV n'a été saisi, le taux sera de 999.0"

#. module: product_standard_margin
#: model:ir.model,name:product_standard_margin.model_product_product
msgid "Product"
msgstr "Article"

#. module: product_standard_margin
#: model:ir.model,name:product_standard_margin.model_product_template
msgid "Product Template"
msgstr "Modèle d'article"

#. module: product_standard_margin
#: model:ir.model.fields,field_description:product_standard_margin.field_product_product__list_price_vat_excl
#: model:ir.model.fields,field_description:product_standard_margin.field_product_template__list_price_vat_excl
msgid "Sale Price VAT Excluded"
msgstr "Prix de vente (HT)"

#. module: product_standard_margin
#: model:ir.model.fields,field_description:product_standard_margin.field_product_product__standard_margin
#: model:ir.model.fields,field_description:product_standard_margin.field_product_template__standard_margin
msgid "Theorical Margin"
msgstr "Marge Théorique"

#. module: product_standard_margin
#: model:ir.model.fields,field_description:product_standard_margin.field_product_product__standard_margin_rate
#: model:ir.model.fields,field_description:product_standard_margin.field_product_template__standard_margin_rate
msgid "Theorical Margin (%)"
msgstr "Taux de marque Théorique (%)"

#. module: product_standard_margin
#: model:ir.model.fields,help:product_standard_margin.field_product_product__standard_margin
#: model:ir.model.fields,help:product_standard_margin.field_product_template__standard_margin
msgid "Theorical Margin is [ sale price (Wo Tax) - cost price ] of the product form (not based on historical values). Take care of tax include and exclude. If no sale price, the margin will be negativ."
msgstr ""
"Marge théorique [ Vente unitaire HT - coût unitaire ] du produit (ne tient "
"pas compte de la facturation effective). Ce taux tient compte des PV TTC "
"(TVA incluse). Si aucun PV n'a été saisi, la marge sera négative."
67 changes: 67 additions & 0 deletions product_standard_margin/i18n/nl.po
@@ -0,0 +1,67 @@
# Translation of OpenERP Server.
# This file contains the translation of the following modules:
# * product_standard_margin
#
msgid ""
msgstr ""
"Project-Id-Version: OpenERP Server 6.1\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-12-23 12:04+0000\n"
"PO-Revision-Date: 2012-12-23 13:35+0100\n"
"Last-Translator: Erwin van der Ploeg | Endian Solutions "
"<erwin@endiansolutions.nl>\n"
"Language-Team: \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.5.4\n"

#. module: product_standard_margin
#: model:ir.model,name:product_standard_margin.model_product_product
msgid "Product"
msgstr "Product"

#. module: product_standard_margin
#: field:product.product,standard_margin_rate:0
msgid "Theorical Margin (%)"
msgstr "Theoretische marge (%)"

#. module: product_standard_margin
#: help:product.product,standard_margin_rate:0
msgid ""
"Markup rate is [ Theorical Margin / sale price (Wo Tax) ] of the product "
"form (not based on historical values).Take care of tax include and exclude.. "
"If no sale price set, will display 999.0"
msgstr ""
"Theoretische marge (%) is [ Theoretische marge / Verkoopprijs (excl. BTW) ] "
"van het product (niet gebaseerd op historische waardes). Het veld houdt "
"rekening met prijzen incl. en excl. BTW. Indien geen verkooprijs is "
"ingevoerd, wordt 999,0 weergegeven."

#. module: product_standard_margin
#: constraint:product.product:0
msgid "Error: Invalid ean code"
msgstr "Fout: ongeldige ean code"

#. module: product_standard_margin
#: help:product.product,standard_margin:0
msgid ""
"Theorical Margin is [ sale price (Wo Tax) - cost price ] of the product form "
"(not based on historical values).Take care of tax include and exclude. If no "
"sale price, the margin will be negativ."
msgstr ""
"Theoretische marge is [ Verkoopprijs (excl. BTW) - Kostprijs) ] van het "
"product (niet gebaseerd op historische waardes). Het veld houdt rekening met "
"prijzen incl. en excl. BTW. Indien geen verkooprijs is ingevoerd, zal de "
"marge negatief zijn."

#. module: product_standard_margin
#: view:product.product:0
msgid "Margin"
msgstr "Marge"

#. module: product_standard_margin
#: field:product.product,standard_margin:0
msgid "Theorical Margin"
msgstr "Theoretische marge"
2 changes: 2 additions & 0 deletions product_standard_margin/models/__init__.py
@@ -0,0 +1,2 @@
from . import product_product
from . import product_template
68 changes: 68 additions & 0 deletions product_standard_margin/models/product_product.py
@@ -0,0 +1,68 @@
# Copyright (C) 2012 - Today: Camptocamp SA
# @author: Joel Grand-Guillaume
# Copyright (C) 2019 - Today: GRAP (http://www.grap.coop)
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from odoo import api, fields, models
import odoo.addons.decimal_precision as dp


class ProductProduct(models.Model):
_inherit = "product.product"

# Column Section
list_price_vat_excl = fields.Float(
compute="_compute_margin",
string="Sale Price VAT Excluded",
store=True,
digits=dp.get_precision("Product Price"),
)

standard_margin = fields.Float(
compute="_compute_margin",
string="Theorical Margin",
store=True,
digits=dp.get_precision("Product Price"),
help="Theorical Margin is [ sale price (Wo Tax) - cost price ] "
"of the product form (not based on historical values). "
"Take care of tax include and exclude. If no sale price, "
"the margin will be negativ.",
)

standard_margin_rate = fields.Float(
compute="_compute_margin",
string="Theorical Margin (%)",
store=True,
digits=dp.get_precision("Product Price"),
help="Markup rate is [ Theorical Margin / sale price (Wo Tax) ] "
"of the product form (not based on historical values)."
"Take care of tax include and exclude.. If no sale price "
"set, will display 999.0",
)

# Compute Section
@api.depends(
"lst_price",
"product_tmpl_id.list_price",
"standard_price",
"taxes_id.price_include",
"taxes_id.amount",
"taxes_id.include_base_amount",
)
def _compute_margin(self):
for product in self:
product.list_price_vat_excl = product.taxes_id.compute_all(
product.lst_price, product=product
)["total_excluded"]
product.standard_margin = (
product.list_price_vat_excl - product.standard_price
)
if product.list_price_vat_excl == 0:
product.standard_margin_rate = 999.0
else:
product.standard_margin_rate = (
(product.list_price_vat_excl - product.standard_price)
/ product.list_price_vat_excl
* 100
)
67 changes: 67 additions & 0 deletions product_standard_margin/models/product_template.py
@@ -0,0 +1,67 @@
# Copyright (C) 2012 - Today: Camptocamp SA
# @author: Joel Grand-Guillaume
# Copyright (C) 2019 - Today: GRAP (http://www.grap.coop)
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from odoo import api, fields, models
import odoo.addons.decimal_precision as dp


class ProductTemplate(models.Model):
_inherit = "product.template"

# Column Section
list_price_vat_excl = fields.Float(
compute="_compute_margin",
string="Sale Price VAT Excluded",
digits=dp.get_precision("Product Price"),
)

standard_margin = fields.Float(
compute="_compute_margin",
string="Theorical Margin",
digits=dp.get_precision("Product Price"),
help="Theorical Margin is [ sale price (Wo Tax) - cost price ] "
"of the product form (not based on historical values). "
"Take care of tax include and exclude. If no sale price, "
"the margin will be negativ.",
)

standard_margin_rate = fields.Float(
compute="_compute_margin",
string="Theorical Margin (%)",
digits=dp.get_precision("Product Price"),
help="Margin rate is [ Theorical Margin / sale price (Wo Tax) ] "
"of the product form (not based on historical values)."
"Take care of tax include and exclude.. If no sale price "
"set, will display 999.0",
)

# Compute Section
@api.depends(
"lst_price",
"standard_price",
"taxes_id.price_include",
"taxes_id.amount",
"taxes_id.include_base_amount",
)
def _compute_margin(self):
# The code is duplicated from product.product model
# because otherwise, the recomputation is not done correctly
# when the product datas are changed from the template view
for template in self:
template.list_price_vat_excl = template.taxes_id.compute_all(
template.list_price, product=template
)["total_excluded"]
template.standard_margin = (
template.list_price_vat_excl - template.standard_price
)
if template.list_price_vat_excl == 0:
template.standard_margin_rate = 999.0
else:
template.standard_margin_rate = (
(template.list_price_vat_excl - template.standard_price)
/ template.list_price_vat_excl
* 100
)
4 changes: 4 additions & 0 deletions product_standard_margin/readme/CONTRIBUTORS.rst
@@ -0,0 +1,4 @@
* Alexandre Fayolle <alexandre.fayolle@camptocamp.com>
* Yannick Vaucher <yannick.vaucher@camptocamp.com>
* Joël Grand-Guillaume <joel.grand-guillaume@camptocamp.com>
* Sylvain Le Gal (https://twitter.com/legalsylvain)
17 changes: 17 additions & 0 deletions product_standard_margin/readme/DESCRIPTION.rst
@@ -0,0 +1,17 @@
Add a field on the product form that compute the standard (or theorical)
margin based on the current values of sale and standard price present in
the product form. We take care of taxe included or excluded.

It will just compute it as follow:
(Sale Price without tax - Standard Price) / Sale Price without tax

.. figure:: ../static/description/product_form.png

**Note:**

As this module will base his simple computation on sale and cost prices,
it suppose you have them both in the same currency (the price type must of
the same currency for both of them). Remember this is the default OpenERP
configuration (price type of all product price fields are set as the same as
the company currency). We don't take care of it cause otherwise we should
have added a dependency on sale module.
7 changes: 7 additions & 0 deletions product_standard_margin/readme/ROADMAP.rst
@@ -0,0 +1,7 @@
* This module will not work properly if used in a multicompany context with product
prices depending on the company.

* It should be great to use the odoo widget ``percentpie`` for the display of the
field ``standard_margin_rate`` but for the time being, the field is not displayed
properly.
Ref of the Odoo Issue: https://github.com/odoo/odoo/issues/42869
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions product_standard_margin/tests/__init__.py
@@ -0,0 +1 @@
from . import test_module

0 comments on commit e2b1dcd

Please sign in to comment.