[16.0][ADD] mrp_bom_product_price_margin

This commit is contained in:
Quentin Dupont
2024-03-11 17:17:42 +01:00
parent d91a463201
commit dd2d4ab6ee
20 changed files with 1098 additions and 0 deletions

View File

@@ -0,0 +1,93 @@
============================
MRP BoM Product Price Margin
============================
..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:aa37e05e4d2c66e364b2d427982b676b8f8dab4171dca239ab8a992ae5eeae62
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
:alt: Beta
.. |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%2Fmanufacture-lightgray.png?logo=github
:target: https://github.com/OCA/manufacture/tree/16.0/mrp_bom_product_price_margin
:alt: OCA/manufacture
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/manufacture-16-0/manufacture-16-0-mrp_bom_product_price_margin
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
:target: https://runboat.odoo-community.org/builds?repo=OCA/manufacture&target_branch=16.0
:alt: Try me on Runboat
|badge1| |badge2| |badge3| |badge4| |badge5|
Help handling cost and sale price of product variant linked to bill of material.
**Table of contents**
.. contents::
:local:
Usage
=====
Set Product Variant in your Bill of Material.
Change BoM quantity or BoM lines quantity or price in one component.
See new panel to change Product Variant Standard Price.
.. figure:: https://raw.githubusercontent.com/OCA/manufacture/16.0/mrp_bom_product_price_margin/static/mrp_bom_product_price_margin_diff.png
.. figure:: https://raw.githubusercontent.com/OCA/manufacture/16.0/mrp_bom_product_price_margin/static/mrp_bom_product_price_margin_no_diff.png
In tree view, quickly see difference between Product standard price and BoM cost.
You can also change Product standard price here
Lines are red when Sale margin in negative.
.. figure:: https://raw.githubusercontent.com/OCA/manufacture/16.0/mrp_bom_product_price_margin/static/mrp_bom_product_price_margin_tree.png
Bug Tracker
===========
Bugs are tracked on `GitHub Issues <https://github.com/OCA/manufacture/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
`feedback <https://github.com/OCA/manufacture/issues/new?body=module:%20mrp_bom_product_price_margin%0Aversion:%2016.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
~~~~~~~
* GRAP
Contributors
~~~~~~~~~~~~
* Quentin Dupont (quentin.dupont@grap.coop)
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.
This module is part of the `OCA/manufacture <https://github.com/OCA/manufacture/tree/16.0/mrp_bom_product_price_margin>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

View File

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

View File

@@ -0,0 +1,22 @@
# Copyright (C) 2022 - Today: GRAP (http://www.grap.coop)
# @author: Quentin Dupont (quentin.dupont@grap.coop)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
{
"name": "MRP BoM Product Price Margin",
"summary": "Handle Product Standard, Sale Price and Margin with its BoM cost",
"version": "16.0.1.0.0",
"category": "GRAP - Custom",
"author": "GRAP, Odoo Community Association (OCA)",
"website": "https://github.com/OCA/manufacture",
"license": "AGPL-3",
"depends": [
"mrp",
# OCA modules
"product_standard_margin",
],
"data": [
"views/view_mrp_bom.xml",
],
"installable": True,
}

View File

@@ -0,0 +1,206 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * mrp_bom_product_price_margin
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-03-11 15:59+0000\n"
"PO-Revision-Date: 2024-03-11 15:59+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: mrp_bom_product_price_margin
#: model_terms:ir.ui.view,arch_db:mrp_bom_product_price_margin.view_mrp_bom_sale_product_margin_form
msgid " (for 1x"
msgstr " (pour 1x"
#. module: mrp_bom_product_price_margin
#: model_terms:ir.ui.view,arch_db:mrp_bom_product_price_margin.view_mrp_bom_sale_product_margin_form
msgid "(margin"
msgstr "(marge"
#. module: mrp_bom_product_price_margin
#: model_terms:ir.ui.view,arch_db:mrp_bom_product_price_margin.view_mrp_bom_sale_product_margin_form
msgid "(margin:"
msgstr "(marge :"
#. module: mrp_bom_product_price_margin
#: model_terms:ir.ui.view,arch_db:mrp_bom_product_price_margin.view_mrp_bom_sale_product_margin_form
msgid ""
"<br/>\n"
" Product variant cost :"
msgstr ""
"<br/>\n"
" Coût du produit :"
#. module: mrp_bom_product_price_margin
#: model_terms:ir.ui.view,arch_db:mrp_bom_product_price_margin.view_mrp_bom_sale_product_margin_form
msgid ""
"<br/>\n"
" Product variant sale price:"
msgstr ""
"<br/>\n"
" Prix de vente du produit :"
#. module: mrp_bom_product_price_margin
#: model:ir.model,name:mrp_bom_product_price_margin.model_mrp_bom
msgid "Bill of Material"
msgstr "Nomenclature"
#. module: mrp_bom_product_price_margin
#: model:ir.model,name:mrp_bom_product_price_margin.model_mrp_bom_line
msgid "Bill of Material Line"
msgstr "Ligne de nomenclature"
#. module: mrp_bom_product_price_margin
#: model_terms:ir.ui.view,arch_db:mrp_bom_product_price_margin.view_mrp_bom_sale_product_margin_form
msgid "Bill of Material cost:"
msgstr "Coût de la nomenclature :"
#. module: mrp_bom_product_price_margin
#: model:ir.model.fields,field_description:mrp_bom_product_price_margin.field_mrp_bom__standard_price
#: model_terms:ir.ui.view,arch_db:mrp_bom_product_price_margin.view_mrp_bom_sale_product_margin_form
msgid "BoM Unit Cost"
msgstr "Coût unitaire"
#. module: mrp_bom_product_price_margin
#: model:ir.model.fields,help:mrp_bom_product_price_margin.field_mrp_bom__standard_price
msgid "Calculated with raw components cost divided by the BoM quantity."
msgstr ""
"Calculé à partir du coût des composants divisé par la quantité de la "
"nomenclature."
#. module: mrp_bom_product_price_margin
#: model:ir.model.fields,field_description:mrp_bom_product_price_margin.field_product_product__standard_price
msgid "Cost"
msgstr "Coût"
#. module: mrp_bom_product_price_margin
#: model:ir.model.fields,field_description:mrp_bom_product_price_margin.field_mrp_bom__currency_id
#: model:ir.model.fields,field_description:mrp_bom_product_price_margin.field_mrp_bom_line__currency_id
msgid "Currency"
msgstr ""
#. module: mrp_bom_product_price_margin
#: model_terms:ir.ui.view,arch_db:mrp_bom_product_price_margin.view_mrp_bom_tree
msgid "Diff BoM and Product"
msgstr ""
#. module: mrp_bom_product_price_margin
#: model:ir.model.fields,field_description:mrp_bom_product_price_margin.field_mrp_bom__diff_product_bom_standard_price
msgid "Diff Product Bom Standard Price"
msgstr ""
#. module: mrp_bom_product_price_margin
#: model:ir.model.fields,help:mrp_bom_product_price_margin.field_product_product__standard_price
msgid ""
"In Standard Price & AVCO: value of the product (automatically computed in AVCO).\n"
" In FIFO: value of the next unit that will leave the stock (automatically computed).\n"
" Used to value the product when the purchase cost is not known (e.g. inventory adjustment).\n"
" Used to compute margins on sale orders."
msgstr ""
"En prix standard en en coût moyen : valeur du produit (calculée automatiquement en coût moyen).\n"
" En FIFO : valeur de l'unité suivante qui quittera le stock (calculée automatiquement).\n"
" Utilisé pour évaluer le produit lorsque le coût d'achat n'est pas connu (par ex. ajustement de stock).\n"
" Utilisé pour calculer les marges sur les commandes."
#. module: mrp_bom_product_price_margin
#: model_terms:ir.ui.view,arch_db:mrp_bom_product_price_margin.view_mrp_bom_sale_product_margin_form
#: model_terms:ir.ui.view,arch_db:mrp_bom_product_price_margin.view_mrp_bom_tree
msgid "It will set product variant's standard price with this price"
msgstr "Cela définira le coût du Produit avec ce total."
#. module: mrp_bom_product_price_margin
#: model:ir.model.fields,help:mrp_bom_product_price_margin.field_mrp_bom__product_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 ""
#. module: mrp_bom_product_price_margin
#: model:ir.model.fields,field_description:mrp_bom_product_price_margin.field_mrp_bom__product_margin_rate_percentage
msgid "Product Margin"
msgstr "Produit - Marge"
#. module: mrp_bom_product_price_margin
#: model:ir.model.fields,field_description:mrp_bom_product_price_margin.field_mrp_bom__product_sale_price
msgid "Product Sale Price"
msgstr "Produit - Prix de vente"
#. module: mrp_bom_product_price_margin
#: model:ir.model.fields,field_description:mrp_bom_product_price_margin.field_mrp_bom__product_standard_price
msgid "Product Standard Price"
msgstr "Produit - Coût"
#. module: mrp_bom_product_price_margin
#: model:ir.model,name:mrp_bom_product_price_margin.model_product_product
msgid "Product Variant"
msgstr "Variante de produit"
#. module: mrp_bom_product_price_margin
#: model_terms:ir.ui.view,arch_db:mrp_bom_product_price_margin.view_mrp_bom_sale_product_margin_form
msgid ""
"Product cost is based on this Bill of Material.<br/>\n"
" Product variant sale price:"
msgstr ""
"Le coût du Produit est basé sur cette Nomenclature.<br/>\n"
" Prix de vente du produit :"
#. module: mrp_bom_product_price_margin
#: model_terms:ir.ui.view,arch_db:mrp_bom_product_price_margin.view_mrp_bom_sale_product_margin_form
msgid "ST %"
msgstr ""
#. module: mrp_bom_product_price_margin
#: model:ir.model.fields,field_description:mrp_bom_product_price_margin.field_mrp_bom_line__standard_price_unit
msgid "Standard Price Unit"
msgstr "Prix unitaire"
#. module: mrp_bom_product_price_margin
#: model:ir.model.fields,field_description:mrp_bom_product_price_margin.field_mrp_bom_line__standard_price_subtotal
msgid "Subtotal price"
msgstr "Sous-total"
#. module: mrp_bom_product_price_margin
#: model:ir.model.fields,field_description:mrp_bom_product_price_margin.field_mrp_bom_line__standard_price_subtotal_percentage
msgid "Subtotal price %"
msgstr "Sous-total %"
#. module: mrp_bom_product_price_margin
#: model:ir.model.fields,help:mrp_bom_product_price_margin.field_mrp_bom__product_sale_price
msgid ""
"The sale price is managed from the product template. Click on the 'Configure"
" Variants' button to set the extra attribute prices."
msgstr ""
#. module: mrp_bom_product_price_margin
#: model:ir.model.fields,field_description:mrp_bom_product_price_margin.field_mrp_bom__product_margin_rate
msgid "Theorical Margin (%)"
msgstr "Marge théorique (%)"
#. module: mrp_bom_product_price_margin
#: model_terms:ir.ui.view,arch_db:mrp_bom_product_price_margin.view_mrp_bom_sale_product_margin_form
msgid "Total"
msgstr ""
#. module: mrp_bom_product_price_margin
#: model_terms:ir.ui.view,arch_db:mrp_bom_product_price_margin.view_mrp_bom_tree
msgid "Update Product standard price"
msgstr "Mettre à jour le coût du Produit"
#. module: mrp_bom_product_price_margin
#: model_terms:ir.ui.view,arch_db:mrp_bom_product_price_margin.view_mrp_bom_sale_product_margin_form
msgid "for 1x"
msgstr "pour 1x"
#. module: mrp_bom_product_price_margin
#: model_terms:ir.ui.view,arch_db:mrp_bom_product_price_margin.view_mrp_bom_sale_product_margin_form
msgid "⇙ Apply this cost to Product variant standard price"
msgstr "⇙ Définir le coût du Produit avec ce prix."

View File

@@ -0,0 +1,3 @@
from . import mrp_bom
from . import mrp_bom_line
from . import product_product

View File

@@ -0,0 +1,69 @@
# Copyright (C) 2022 - Today: GRAP (http://www.grap.coop)
# @author: Quentin DUPONT (quentin.dupont@grap.coop)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo import api, fields, models
from odoo.tools.float_utils import float_round
class MrpBom(models.Model):
_inherit = "mrp.bom"
currency_id = fields.Many2one(related="product_tmpl_id.currency_id")
# Fields related to standard price
product_standard_price = fields.Float(compute="_compute_product_standard_price")
standard_price = fields.Float(
string="BoM Unit Cost",
tracking=True,
digits="Product Price",
compute="_compute_standard_price",
help="Calculated with raw components cost divided by the BoM quantity.",
)
diff_product_bom_standard_price = fields.Boolean(
default=False,
compute="_compute_diff_product_bom_standard_price",
)
# Fields related to sale price
product_sale_price = fields.Float(
string="Product Sale Price", related="product_id.lst_price"
)
product_margin_rate = fields.Float(related="product_id.standard_margin_rate")
product_margin_rate_percentage = fields.Float(
string="Product Margin", compute="_compute_product_margin_rate_percentage"
)
# Compute functions
@api.depends("product_id", "product_id.standard_price")
def _compute_product_standard_price(self):
for bom in self:
bom.product_standard_price = bom.product_id.standard_price
@api.depends("product_id", "bom_line_ids", "product_qty")
def _compute_standard_price(self):
for bom in self:
qty_to_divide = bom.product_qty if bom.product_qty != 0 else 1
bom.standard_price = (
sum(x.standard_price_subtotal for x in bom.bom_line_ids) / qty_to_divide
)
@api.depends("product_id.standard_price", "standard_price")
def _compute_diff_product_bom_standard_price(self):
price_dp = self.env["decimal.precision"].precision_get("Product Price")
for bom in self:
if bom.product_id:
diff = bom.product_id.standard_price - bom.standard_price
bom.diff_product_bom_standard_price = float_round(diff, price_dp)
else:
bom.diff_product_bom_standard_price = False
@api.depends("product_margin_rate")
def _compute_product_margin_rate_percentage(self):
for bom in self:
bom.product_margin_rate_percentage = bom.product_margin_rate / 100
# Functions to change product fields
def set_product_standard_price(self):
for bom in self.filtered(lambda x: x.product_id):
bom.product_id.standard_price = bom.standard_price

View File

@@ -0,0 +1,44 @@
# Copyright (C) 2022 - Today: GRAP (http://www.grap.coop)
# @author: Quentin DUPONT (quentin.dupont@grap.coop)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo import api, fields, models
class MrpBomLine(models.Model):
_inherit = "mrp.bom.line"
# New fields
standard_price_unit = fields.Float(compute="_compute_standard_price_unit")
currency_id = fields.Many2one(related="product_id.currency_id")
standard_price_subtotal = fields.Float(
string="Subtotal price", compute="_compute_standard_price_subtotal"
)
# Percentage float, so 25% is 0,25. For one number behind decimal, needs 3 digits
standard_price_subtotal_percentage = fields.Float(
string="Subtotal price %",
compute="_compute_standard_price_subtotal_percentage",
digits=(16, 3),
)
@api.depends("standard_price_unit", "product_qty")
def _compute_standard_price_subtotal(self):
for line in self:
line.standard_price_subtotal = line.standard_price_unit * line.product_qty
@api.depends("product_id")
def _compute_standard_price_unit(self):
for line in self:
line.standard_price_unit = line.product_id.standard_price
@api.depends(
"standard_price_subtotal", "bom_id.bom_line_ids.standard_price_subtotal"
)
def _compute_standard_price_subtotal_percentage(self):
for line in self:
bom = line.bom_id
total_price = sum(line.standard_price_subtotal for line in bom.bom_line_ids)
line.standard_price_subtotal_percentage = (
line.standard_price_subtotal / total_price if total_price != 0 else 0
)

View File

@@ -0,0 +1,13 @@
# Copyright (C) 2022 - Today: GRAP (http://www.grap.coop)
# @author: Quentin DUPONT (quentin.dupont@grap.coop)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo import fields, models
class ProductProduct(models.Model):
_inherit = "product.product"
standard_price = fields.Float(
tracking=True,
)

View File

@@ -0,0 +1 @@
* Quentin Dupont (quentin.dupont@grap.coop)

View File

@@ -0,0 +1 @@
Help handling cost and sale price of product variant linked to bill of material.

View File

@@ -0,0 +1,13 @@
Set Product Variant in your Bill of Material.
Change BoM quantity or BoM lines quantity or price in one component.
See new panel to change Product Variant Standard Price.
.. figure:: ../static/mrp_bom_product_price_margin_diff.png
.. figure:: ../static/mrp_bom_product_price_margin_no_diff.png
In tree view, quickly see difference between Product standard price and BoM cost.
You can also change Product standard price here
Lines are red when Sale margin in negative.
.. figure:: ../static/mrp_bom_product_price_margin_tree.png

View File

@@ -0,0 +1,442 @@
<?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: https://docutils.sourceforge.io/" />
<title>MRP BoM Product Price Margin</title>
<style type="text/css">
/*
:Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 8954 2022-01-20 10:10:25Z milde $
:Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils.
See https://docutils.sourceforge.io/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="mrp-bom-product-price-margin">
<h1 class="title">MRP BoM Product Price Margin</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:aa37e05e4d2c66e364b2d427982b676b8f8dab4171dca239ab8a992ae5eeae62
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external image-reference" 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 image-reference" href="https://github.com/OCA/manufacture/tree/16.0/mrp_bom_product_price_margin"><img alt="OCA/manufacture" src="https://img.shields.io/badge/github-OCA%2Fmanufacture-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/manufacture-16-0/manufacture-16-0-mrp_bom_product_price_margin"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/manufacture&amp;target_branch=16.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
<p>Help handling cost and sale price of product variant linked to bill of material.</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="toc-entry-1">Usage</a></li>
<li><a class="reference internal" href="#bug-tracker" id="toc-entry-2">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="toc-entry-3">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="toc-entry-4">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="toc-entry-5">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="toc-entry-6">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="usage">
<h1><a class="toc-backref" href="#toc-entry-1">Usage</a></h1>
<p>Set Product Variant in your Bill of Material.
Change BoM quantity or BoM lines quantity or price in one component.
See new panel to change Product Variant Standard Price.</p>
<blockquote>
<div class="figure">
<img alt="https://raw.githubusercontent.com/OCA/manufacture/16.0/mrp_bom_product_price_margin/static/mrp_bom_product_price_margin_diff.png" src="https://raw.githubusercontent.com/OCA/manufacture/16.0/mrp_bom_product_price_margin/static/mrp_bom_product_price_margin_diff.png" />
</div>
<div class="figure">
<img alt="https://raw.githubusercontent.com/OCA/manufacture/16.0/mrp_bom_product_price_margin/static/mrp_bom_product_price_margin_no_diff.png" src="https://raw.githubusercontent.com/OCA/manufacture/16.0/mrp_bom_product_price_margin/static/mrp_bom_product_price_margin_no_diff.png" />
</div>
</blockquote>
<p>In tree view, quickly see difference between Product standard price and BoM cost.
You can also change Product standard price here
Lines are red when Sale margin in negative.</p>
<div class="figure">
<img alt="https://raw.githubusercontent.com/OCA/manufacture/16.0/mrp_bom_product_price_margin/static/mrp_bom_product_price_margin_tree.png" src="https://raw.githubusercontent.com/OCA/manufacture/16.0/mrp_bom_product_price_margin/static/mrp_bom_product_price_margin_tree.png" />
</div>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#toc-entry-2">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/manufacture/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 to smash it by providing a detailed and welcomed
<a class="reference external" href="https://github.com/OCA/manufacture/issues/new?body=module:%20mrp_bom_product_price_margin%0Aversion:%2016.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="#toc-entry-3">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#toc-entry-4">Authors</a></h2>
<ul class="simple">
<li>GRAP</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#toc-entry-5">Contributors</a></h2>
<ul class="simple">
<li>Quentin Dupont (<a class="reference external" href="mailto:quentin.dupont&#64;grap.coop">quentin.dupont&#64;grap.coop</a>)</li>
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#toc-entry-6">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>This module is part of the <a class="reference external" href="https://github.com/OCA/manufacture/tree/16.0/mrp_bom_product_price_margin">OCA/manufacture</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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

View File

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

View File

@@ -0,0 +1,34 @@
# Copyright (C) 2022 - Today: GRAP (http://www.grap.coop)
# @author: Quentin DUPONT (quentin.dupont@grap.coop)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo.tests.common import TransactionCase
class TestMrpBomSaleMargin(TransactionCase):
def setUp(self):
super(TestMrpBomSaleMargin, self).setUp()
self.bom_desk = self.env.ref("mrp.mrp_bom_desk")
self.product_computer_desk = self.env.ref("mrp.product_product_computer_desk")
def test_01_bom_product_product_set_cost(self):
# Set product product
self.bom_desk.product_id = self.product_computer_desk
self.assertNotEqual(
self.bom_desk.standard_price,
self.bom_desk.product_id.standard_price,
)
self.assertNotEqual(
self.bom_desk.diff_product_bom_standard_price,
False,
)
# Set product product standard price based on bom
self.bom_desk.set_product_standard_price()
self.assertEqual(
self.bom_desk.diff_product_bom_standard_price,
False,
)
self.assertEqual(
self.bom_desk.standard_price,
self.bom_desk.product_id.standard_price,
)

View File

@@ -0,0 +1,148 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!--
Copyright (C) 2022 - Today: GRAP (http://www.grap.coop)
@author: Quentin DUPONT (quentin.dupont@grap.coop)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
-->
<odoo>
<record id="view_mrp_bom_sale_product_margin_form" model="ir.ui.view">
<field name="model">mrp.bom</field>
<field name="inherit_id" ref="mrp.mrp_bom_form_view" />
<field name="arch" type="xml">
<!-- Add panels in form -->
<xpath expr="/form/sheet" position="before">
<field name="currency_id" invisible="1" />
<field name="diff_product_bom_standard_price" invisible="1" />
<div
class="alert alert-warning"
role="alert"
attrs="{'invisible': [('diff_product_bom_standard_price', '=', False)]}"
>
Bill of Material cost: <b><field
name="standard_price"
widget="monetary"
/></b>
<span groups="uom.group_uom"> (for 1x <field
name="product_uom_id"
readonly="1"
style="pointer-events:none;"
/>)</span>
<button
name="set_product_standard_price"
string="⇙ Apply this cost to Product variant standard price"
type="object"
class="oe_link"
help="It will set product variant's standard price with this price"
/>
<br />
Product variant cost : <b><field
name="product_standard_price"
widget="monetary"
/></b>
<br />
Product variant sale price:
<b><field
name="product_sale_price"
widget="monetary"
nolabel="1"
/></b>
(margin <b><field name="product_margin_rate" />&#x25;</b>)
</div>
<div
class="alert alert-info"
role="alert"
attrs="{'invisible': ['|', ('diff_product_bom_standard_price', '!=', False), ('product_id', '=', False)]}"
>
Product cost is based on this Bill of Material.<br />
Product variant sale price:
<b><field
name="product_sale_price"
widget="monetary"
nolabel="1"
/></b>
(margin: <b><field name="product_margin_rate" /> &#x25;</b>).
</div>
</xpath>
<!-- Add field in form -->
<xpath expr="//group/group" position="inside">
<label for="standard_price" string="BoM Unit Cost" />
<div class="o_row">
<field name="standard_price" widget="monetary" />
for 1x <field
name="product_uom_id"
readonly="1"
style="pointer-events:none;"
/>
</div>
</xpath>
<!-- BoM Lines -->
<xpath
expr="//field[@name='bom_line_ids']/tree/field[@name='product_uom_id']"
position="before"
>
<field name="currency_id" invisible="1" />
<field name="standard_price_unit" widget="monetary" />
<field
name="standard_price_subtotal"
readonly="1"
sum="Total"
widget="monetary"
/>
<field
name="standard_price_subtotal_percentage"
string="ST %"
widget="percentage"
/>
</xpath>
</field>
</record>
<!-- ************************************************************ -->
<!-- MRP Bill of Materials - Tree -->
<!-- ************************************************************ -->
<record id="view_mrp_bom_tree" model="ir.ui.view">
<field name="model">mrp.bom</field>
<field name="inherit_id" ref="mrp.mrp_bom_tree_view" />
<field name="arch" type="xml">
<xpath expr="//field[@name='code']" position="after">
<field
name="diff_product_bom_standard_price"
string="Diff BoM and Product"
invisible="1"
/>
</xpath>
<xpath expr="//tree" position="attributes">
<attribute
name="decoration-warning"
>diff_product_bom_standard_price != False</attribute>
</xpath>
<xpath expr="//tree" position="attributes">
<attribute
name="decoration-danger"
>product_margin_rate_percentage &lt; 0</attribute>
</xpath>
<xpath expr="//field[@name='product_id']" position="after">
<field name="currency_id" invisible="1" />
<field name="standard_price" widget="monetary" />
<button
name="set_product_standard_price"
icon="fa-arrow-right"
string="Update Product standard price"
type="object"
attrs="{'invisible': [('diff_product_bom_standard_price', '=', False)]}"
help="It will set product variant's standard price with this price"
/>
<field name="product_standard_price" widget="monetary" />
<field name="product_sale_price" widget="monetary" />
<field name="product_margin_rate_percentage" widget="percentage" />
</xpath>
</field>
</record>
</odoo>

View File

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

View File

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