Merge PR #1227 into 16.0

Signed-off-by quentinDupont
This commit is contained in:
OCA-git-bot
2025-01-07 08:01:25 +00:00
20 changed files with 1103 additions and 0 deletions

View File

@@ -0,0 +1,92 @@
============================
MRP BoM Product Price Margin
============================
..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:29d32daaf1104aac3d5d6277b0370d603872ee94f8cb9a9c8f5a2d185fb54cbf
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |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 template linked to bill of material.
**Table of contents**
.. contents::
:local:
Usage
=====
Change BoM quantity or BoM lines quantity or price in one component.
See new panel to change Product Standard Price.
.. figure:: https://raw.githubusercontent.com/OCA/manufacture/16.0/mrp_bom_product_price_margin/static/mrp_bom_product_price_margin_diff.jpeg
.. figure:: https://raw.githubusercontent.com/OCA/manufacture/16.0/mrp_bom_product_price_margin/static/mrp_bom_product_price_margin_no_diff.jpeg
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,213 @@
# 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-12-20 13:38+0000\n"
"PO-Revision-Date: 2024-12-20 13:38+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 sale price:"
msgstr ""
").<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 ""
"<br/>\n"
" Product 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 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_template__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 "Devise"
#. 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_template__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'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,field_description:mrp_bom_product_price_margin.field_mrp_bom__product_margin_rate
msgid "Margin (%)"
msgstr "Taux de marque (%)"
#. 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 [ 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,help:mrp_bom_product_price_margin.field_mrp_bom__product_sale_price
msgid "Price at which the product is sold to customers."
msgstr ""
#. module: mrp_bom_product_price_margin
#: model:ir.model,name:mrp_bom_product_price_margin.model_product_template
msgid "Product"
msgstr "Produit"
#. 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_terms:ir.ui.view,arch_db:mrp_bom_product_price_margin.view_mrp_bom_sale_product_margin_form
msgid "Product cost is based on the cost of this Bill of Material ("
msgstr "Le coût du Produit est basé sur le coût de cette 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 "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__diff_product_bom_standard_price
msgid ""
"Technical field used to display or hide button 'Apply this cost to Product "
"standard price' in the form view"
msgstr ""
"Champ technique utilisé pour afficher ou cacher le bouton 'Définir le coût du Produit "
"avec ce prix.' dans la vue formulaire."
#. 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 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_template

View File

@@ -0,0 +1,62 @@
# 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(
compute="_compute_diff_product_bom_standard_price",
help="Technical field used to display or hide button 'Apply this cost "
"to Product standard price' in the form view",
)
# Fields related to sale price
product_sale_price = fields.Float(
string="Product Sale Price", related="product_tmpl_id.list_price"
)
product_margin_rate = fields.Float(related="product_tmpl_id.standard_margin_rate")
# Compute functions
@api.depends("product_tmpl_id", "product_tmpl_id.standard_price")
def _compute_product_standard_price(self):
for bom in self:
bom.product_standard_price = bom.product_tmpl_id.standard_price
@api.depends("product_tmpl_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_tmpl_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_tmpl_id:
diff = bom.product_tmpl_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
# Functions to change product fields
def set_product_standard_price(self):
for bom in self.filtered(lambda x: x.product_tmpl_id):
bom.product_tmpl_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) 2024 - 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 ProductTemplate(models.Model):
_inherit = "product.template"
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 template linked to bill of material.

View File

@@ -0,0 +1,12 @@
Change BoM quantity or BoM lines quantity or price in one component.
See new panel to change Product Standard Price.
.. figure:: ../static/mrp_bom_product_price_margin_diff.jpeg
.. figure:: ../static/mrp_bom_product_price_margin_no_diff.jpeg
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,444 @@
<?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 9511 2024-01-13 09:50:07Z milde $
:Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils.
Despite the name, some widely supported CSS2 features are used.
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: gray; } /* 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, pre.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:29d32daaf1104aac3d5d6277b0370d603872ee94f8cb9a9c8f5a2d185fb54cbf
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<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 template 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>Change BoM quantity or BoM lines quantity or price in one component.
See new panel to change Product 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.jpeg" src="https://raw.githubusercontent.com/OCA/manufacture/16.0/mrp_bom_product_price_margin/static/mrp_bom_product_price_margin_diff.jpeg" />
</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.jpeg" src="https://raw.githubusercontent.com/OCA/manufacture/16.0/mrp_bom_product_price_margin/static/mrp_bom_product_price_margin_no_diff.jpeg" />
</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: 149 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 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,36 @@
# 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") # [FURN_9666] Table
self.product_computer_desk = self.env.ref(
"mrp.product_product_computer_desk_product_template"
)
def test_01_bom_product_product_set_cost(self):
# Set product product
self.bom_desk.product_tmpl_id = self.product_computer_desk
self.assertNotEqual(
self.bom_desk.standard_price,
self.bom_desk.product_tmpl_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_tmpl_id.standard_price,
)

View File

@@ -0,0 +1,151 @@
<?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 standard price"
type="object"
class="oe_link"
help="It will set Product's standard price with this price"
/>
<br />
Product cost : <b><field
name="product_standard_price"
widget="monetary"
/></b>
<br />
Product 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_tmpl_id', '=', False)]}"
>
Product cost is based on the cost of this Bill of Material (<b><field
name="standard_price"
widget="monetary"
/></b>).<br />
Product 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 &lt; 0</attribute>
</xpath>
<xpath expr="//field[@name='product_tmpl_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's standard price with this price"
/>
<field name="product_standard_price" widget="monetary" />
<field name="product_sale_price" widget="monetary" optional="hide" />
<field name="product_margin_rate" optional="hide" />
</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,
)