Merge PR #154 into 13.0

Signed-off-by pedrobaeza
This commit is contained in:
OCA-git-bot
2021-06-10 11:39:11 +00:00
18 changed files with 953 additions and 0 deletions

View File

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

View File

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

View File

@@ -0,0 +1,114 @@
===================================
Valued picking linked with MRP Kits
===================================
.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |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%2Fstock--logistics--reporting-lightgray.png?logo=github
:target: https://github.com/OCA/stock-logistics-reporting/tree/12.0/stock_picking_report_valued_sale_mrp
:alt: OCA/stock-logistics-reporting
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/stock-logistics-reporting-12-0/stock-logistics-reporting-12-0-stock_picking_report_valued_sale_mrp
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png
:target: https://runbot.odoo-community.org/runbot/151/12.0
:alt: Try me on Runbot
|badge1| |badge2| |badge3| |badge4| |badge5|
This module extends the functionality of `stock_picking_report_valued` with
compatibility of MRP kits. Now we'll be able to correctly summarize the picking
value related to the selled kit with a relations of components and serials/lots
delivered.
**Table of contents**
.. contents::
:local:
Usage
=====
To test this module:
#. Configure some products with traceability and make them kit components.
#. Sell the kits and go to the stock picking.
#. Print the valued delivery slip:
- The total amount will now be correct.
- The kit components will be summarized in a single kit product line.
Known issues / Roadmap
======================
* Matching selled kits and their delivered components it's quite tricky. There
are two possible approaches to findout from the component how many units
correspond with every whole kit:
- We could have a link to the original BoM line and guess it from it. This
approach is the one that Odoo has taken in v13 with the sale order line
deliveried quantities computation. The main issue is that if the original
BoM changes then we'd loose the correct units per kit reference.
- Another aproach (the one in this module) is to compute the component units
per kit matching the sale order line and its related moves demands. But if
the user manually adjust the demand on one model without adjusting it in
the order we'll have an incorrect reference as well.
Bug Tracker
===========
Bugs are tracked on `GitHub Issues <https://github.com/OCA/stock-logistics-reporting/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/stock-logistics-reporting/issues/new?body=module:%20stock_picking_report_valued_sale_mrp%0Aversion:%2012.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
~~~~~~~
* Tecnativa
Contributors
~~~~~~~~~~~~
* `Tecnativa <https://www.tecnativa.com>`_:
* David Vidal
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-chienandalu| image:: https://github.com/chienandalu.png?size=40px
:target: https://github.com/chienandalu
:alt: chienandalu
Current `maintainer <https://odoo-community.org/page/maintainer-role>`__:
|maintainer-chienandalu|
This module is part of the `OCA/stock-logistics-reporting <https://github.com/OCA/stock-logistics-reporting/tree/12.0/stock_picking_report_valued_sale_mrp>`_ 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,15 @@
# Copyright 2020 Tecnativa - David Vidal
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
{
"name": "Valued picking linked with MRP Kits",
"summary": "Allow to summarize the picking related with the selled kits",
"version": "13.0.1.0.0",
"development_status": "Beta",
"category": "Warehouse Management",
"website": "https://github.com/OCA/stock-logistics-reporting",
"author": "Tecnativa, Odoo Community Association (OCA)",
"maintainers": ["chienandalu"],
"license": "AGPL-3",
"depends": ["stock_picking_report_valued", "sale_mrp"],
"data": ["report/stock_picking_report_valued.xml"],
}

View File

@@ -0,0 +1,40 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * stock_picking_report_valued_sale_mrp
#
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: stock_picking_report_valued_sale_mrp
#: model:ir.model.fields,field_description:stock_picking_report_valued_sale_mrp.field_stock_move_line__phantom_delivered_qty
msgid "Phantom Delivered Qty"
msgstr ""
#. module: stock_picking_report_valued_sale_mrp
#: model:ir.model.fields,field_description:stock_picking_report_valued_sale_mrp.field_stock_move_line__phantom_line
msgid "Phantom Line"
msgstr ""
#. module: stock_picking_report_valued_sale_mrp
#: model:ir.model.fields,field_description:stock_picking_report_valued_sale_mrp.field_stock_move_line__phantom_product_id
msgid "Product Kit"
msgstr ""
#. module: stock_picking_report_valued_sale_mrp
#: model:ir.model,name:stock_picking_report_valued_sale_mrp.model_stock_move_line
msgid "Product Moves (Stock Move Line)"
msgstr ""
#. module: stock_picking_report_valued_sale_mrp
#: model:ir.model,name:stock_picking_report_valued_sale_mrp.model_stock_move
msgid "Stock Move"
msgstr ""

View File

@@ -0,0 +1,2 @@
from . import stock_move
from . import stock_move_line

View File

@@ -0,0 +1,28 @@
# Copyright 2020 Tecnativa - David Vidal
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import models
class StockMove(models.Model):
_inherit = "stock.move"
def _get_components_per_kit(self):
"""Compute how many kit components were demanded from this line. We
rely on the matching of sale order and pickings demands, but if those
were manually changed, it could lead to inconsistencies"""
self.ensure_one()
sale_line = self.sale_line_id
if (
not sale_line
or not sale_line.product_id.get_components()
or sale_line.product_id.ids == sale_line.product_id.get_components()
):
return 0
component_demand = sum(
sale_line.move_ids.filtered(
lambda x: x.product_id == self.product_id
and not x.origin_returned_move_id
and (x.state != "cancel" or (x.state == "cancel" and x.backorder_id))
).mapped("product_uom_qty")
)
return component_demand / sale_line.product_uom_qty

View File

@@ -0,0 +1,102 @@
# Copyright 2020 Tecnativa - David Vidal
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, fields, models
class StockMoveLine(models.Model):
_inherit = "stock.move.line"
phantom_product_id = fields.Many2one(
comodel_name="product.product",
compute="_compute_phantom_product_id",
compute_sudo=True,
string="Product Kit",
readonly=True,
)
phantom_line = fields.Boolean(
compute="_compute_sale_order_line_fields", compute_sudo=True,
)
phantom_delivered_qty = fields.Float(
compute="_compute_sale_order_line_fields", compute_sudo=True,
)
@api.depends("sale_line")
def _compute_phantom_product_id(self):
"""Relate every line with its kit product"""
self.write({"phantom_product_id": False})
for line in self.filtered(
lambda x: x.sale_line
and x.sale_line.product_id.get_components()
and x.sale_line.product_id.ids != x.sale_line.product_id.get_components()
):
line.phantom_product_id = line.sale_line.product_id
def _compute_sale_order_line_fields(self):
"""For kits we only want to store the value in one of the move lines to
avoid duplicate the amounts. We also need to recompute the total
amounts according to the corresponding delivered kits"""
super()._compute_sale_order_line_fields()
pickings = self.mapped("picking_id")
kit_lines = pickings.move_line_ids.filtered("phantom_product_id")
pickings.move_line_ids.write(
{"phantom_line": False, "phantom_delivered_qty": 0.0}
)
for sale_line in kit_lines.mapped("sale_line"):
move_lines = kit_lines.filtered(lambda x: x.sale_line == sale_line)
# Deduct the kit quantity from the first component in the picking.
# If the the kit is partially delivered, this could lead to an
# unacurate value.
phantom_line = move_lines[:1]
if not phantom_line:
continue
price_unit = (
sale_line.price_subtotal / sale_line.product_uom_qty
if sale_line.product_uom_qty
else sale_line.price_reduce
)
# Compute how many kits were delivered from the components and
# the original demand. Note that if the qty is edited in the sale
# order this could lead to inconsitencies.
components_per_kit = phantom_line.move_id._get_components_per_kit()
phantom_line_qty_done = sum(
move_lines.filtered(
lambda x: x.product_id == phantom_line.product_id
).mapped("qty_done")
)
quantity = phantom_line_qty_done / components_per_kit
taxes = phantom_line.sale_tax_id.compute_all(
price_unit=price_unit,
currency=phantom_line.currency_id,
quantity=quantity,
product=phantom_line.product_id,
partner=sale_line.order_id.partner_shipping_id,
)
if sale_line.company_id.tax_calculation_rounding_method == (
"round_globally"
):
price_tax = sum(t.get("amount", 0.0) for t in taxes.get("taxes", []))
else:
price_tax = taxes["total_included"] - taxes["total_excluded"]
phantom_line.update(
{
"sale_tax_description": ", ".join(
t.name or t.description for t in phantom_line.sale_tax_id
),
"sale_price_subtotal": taxes["total_excluded"],
"sale_price_tax": price_tax,
"sale_price_total": taxes["total_included"],
"phantom_line": True,
"phantom_delivered_qty": quantity,
}
)
# Remove the other lines
redundant_lines = move_lines[1:]
if redundant_lines:
redundant_lines.update(
{
"sale_tax_description": "",
"sale_price_subtotal": 0,
"sale_price_tax": 0,
"sale_price_total": 0,
}
)

View File

@@ -0,0 +1,4 @@
* `Tecnativa <https://www.tecnativa.com>`_:
* David Vidal
* Carlos Roca

View File

@@ -0,0 +1,4 @@
This module extends the functionality of `stock_picking_report_valued` with
compatibility of MRP kits. Now we'll be able to correctly summarize the picking
value related to the selled kit with a relations of components and serials/lots
delivered.

View File

@@ -0,0 +1,13 @@
* Matching selled kits and their delivered components it's quite tricky. There
are two possible approaches to findout from the component how many units
correspond with every whole kit:
- We could have a link to the original BoM line and guess it from it. This
approach is the one that Odoo has taken in v13 with the sale order line
deliveried quantities computation. The main issue is that if the original
BoM changes then we'd loose the correct units per kit reference.
- Another aproach (the one in this module) is to compute the component units
per kit matching the sale order line and its related moves demands. But if
the user manually adjust the demand on one model without adjusting it in
the order we'll have an incorrect reference as well.

View File

@@ -0,0 +1,7 @@
To test this module:
#. Configure some products with traceability and make them kit components.
#. Sell the kits and go to the stock picking.
#. Print the valued delivery slip:
- The total amount will now be correct.
- The kit components will be summarized in a single kit product line.

View File

@@ -0,0 +1,82 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<template
id="valued_report_picking"
inherit_id="stock_picking_report_valued.valued_report_picking"
>
<xpath
expr="//t[@t-if=&quot;move_line.picking_id.state != 'done'&quot;]/.."
position="attributes"
>
<attribute
name="t-if"
>o.valued and o.sale_id and o.move_line_ids and (move_line.phantom_line or not move_line.phantom_product_id)</attribute>
</xpath>
<xpath expr="//tr[@t-foreach='o.move_line_ids']" position="attributes">
<attribute
name="t-foreach"
>o.move_line_ids.filtered(lambda x: not x.phantom_product_id or x.phantom_line)</attribute>
</xpath>
<xpath expr="//span[@t-field='move_line.product_id']" position="attributes">
<attribute name="t-if">not move_line.phantom_line</attribute>
</xpath>
<xpath expr="//span[@t-field='move_line.product_id']" position="before">
<span
t-field="move_line.sale_line.product_id"
t-if="move_line.phantom_line"
/>
</xpath>
<xpath
expr="//span[@t-field='move_line.move_id.description_picking']"
position="attributes"
>
<attribute name="t-if">not move_line.phantom_line</attribute>
</xpath>
<xpath
expr="//span[@t-field='move_line.move_id.description_picking']"
position="before"
>
<span
t-esc="move_line.sale_line.product_id.sudo()._get_description(o.picking_type_id)"
t-if="move_line.phantom_line"
/>
</xpath>
<xpath expr="//span[@t-field='move_line.qty_done']/.." position="attributes">
<attribute name="t-if">not move_line.phantom_line</attribute>
</xpath>
<xpath expr="//span[@t-field='move_line.qty_done']/.." position="after">
<td class="text-center" t-if="move_line.phantom_line">
<span t-field="move_line.phantom_delivered_qty" />
<span t-field="move_line.sale_line.product_uom" />
</td>
</xpath>
<xpath expr="//span[@t-field='move_line.lot_id.name']" position="attributes">
<attribute name="t-if">not move_line.phantom_line</attribute>
</xpath>
<xpath expr="//span[@t-field='move_line.lot_id.name']" position="after">
<t
t-set="kit_move_lines"
t-value="move_line.sale_line.mapped('move_ids.move_line_ids').filtered(lambda x: x.sale_line == move_line.sale_line)"
/>
<t t-if="kit_move_lines and move_line.phantom_line">
<table class="table-borderless">
<t
t-foreach="kit_move_lines.mapped('product_id')"
t-as="kit_component"
>
<small class="font-italic" t-esc="kit_component.display_name" />
<t t-if="kit_move_lines.mapped('lot_id')">
<span class="font-italic">: </span>
</t>
<small
t-esc="', '.join([k.lot_id.name for k in kit_move_lines.filtered(lambda x: x.lot_id and x.product_id == kit_component)])"
/>
<br />
</t>
</table>
</t>
</xpath>
</template>
</odoo>

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

View File

@@ -0,0 +1,458 @@
<?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 0.15.1: http://docutils.sourceforge.net/" />
<title>Valued picking linked with MRP Kits</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="valued-picking-linked-with-mrp-kits">
<h1 class="title">Valued picking linked with MRP Kits</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="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.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/stock-logistics-reporting/tree/12.0/stock_picking_report_valued_sale_mrp"><img alt="OCA/stock-logistics-reporting" src="https://img.shields.io/badge/github-OCA%2Fstock--logistics--reporting-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/stock-logistics-reporting-12-0/stock-logistics-reporting-12-0-stock_picking_report_valued_sale_mrp"><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/151/12.0"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p>
<p>This module extends the functionality of <cite>stock_picking_report_valued</cite> with
compatibility of MRP kits. Now well be able to correctly summarize the picking
value related to the selled kit with a relations of components and serials/lots
delivered.</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="#known-issues-roadmap" id="id2">Known issues / Roadmap</a></li>
<li><a class="reference internal" href="#bug-tracker" id="id3">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="id4">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="id5">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="id6">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="id7">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="usage">
<h1><a class="toc-backref" href="#id1">Usage</a></h1>
<p>To test this module:</p>
<ol class="arabic simple">
<li>Configure some products with traceability and make them kit components.</li>
<li>Sell the kits and go to the stock picking.</li>
<li>Print the valued delivery slip:
- The total amount will now be correct.
- The kit components will be summarized in a single kit product line.</li>
</ol>
</div>
<div class="section" id="known-issues-roadmap">
<h1><a class="toc-backref" href="#id2">Known issues / Roadmap</a></h1>
<ul class="simple">
<li>Matching selled kits and their delivered components its quite tricky. There
are two possible approaches to findout from the component how many units
correspond with every whole kit:<ul>
<li>We could have a link to the original BoM line and guess it from it. This
approach is the one that Odoo has taken in v13 with the sale order line
deliveried quantities computation. The main issue is that if the original
BoM changes then wed loose the correct units per kit reference.</li>
<li>Another aproach (the one in this module) is to compute the component units
per kit matching the sale order line and its related moves demands. But if
the user manually adjust the demand on one model without adjusting it in
the order well have an incorrect reference as well.</li>
</ul>
</li>
</ul>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#id3">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/stock-logistics-reporting/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/stock-logistics-reporting/issues/new?body=module:%20stock_picking_report_valued_sale_mrp%0Aversion:%2012.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="#id4">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#id5">Authors</a></h2>
<ul class="simple">
<li>Tecnativa</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#id6">Contributors</a></h2>
<ul class="simple">
<li><a class="reference external" href="https://www.tecnativa.com">Tecnativa</a>:<ul>
<li>David Vidal</li>
</ul>
</li>
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#id7">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/chienandalu"><img alt="chienandalu" src="https://github.com/chienandalu.png?size=40px" /></a></p>
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/stock-logistics-reporting/tree/12.0/stock_picking_report_valued_sale_mrp">OCA/stock-logistics-reporting</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_stock_picking_report_valued_mrp

View File

@@ -0,0 +1,75 @@
# Copyright 2020 Tecnativa - David Vidal
from odoo.tests import Form
from odoo.addons.stock_picking_report_valued.tests.test_stock_picking_valued import (
TestStockPickingValued,
)
class TestStockPickingValuedMrp(TestStockPickingValued):
@classmethod
def setUpClass(cls):
"""We want to run parent class tests again to ensure everything
works as expected even if no kits are present"""
super().setUpClass()
cls.res_partner = cls.env["res.partner"]
cls.product_product = cls.env["product.product"]
cls.product_kit = cls.product_product.create(
{"name": "Product test 1", "type": "consu"}
)
cls.product_kit_comp_1 = cls.product_product.create(
{"name": "Product Component 1", "type": "product"}
)
cls.product_kit_comp_2 = cls.product_product.create(
{"name": "Product Component 2", "type": "product"}
)
cls.bom = cls.env["mrp.bom"].create(
{
"product_id": cls.product_kit.id,
"product_tmpl_id": cls.product_kit.product_tmpl_id.id,
"type": "phantom",
"bom_line_ids": [
(
0,
0,
{"product_id": cls.product_kit_comp_1.id, "product_qty": 2},
),
(
0,
0,
{"product_id": cls.product_kit_comp_2.id, "product_qty": 4},
),
],
}
)
cls.product_2 = cls.product_product.create(
{"name": "Product test 2", "type": "product"}
)
order_form = Form(cls.env["sale.order"])
order_form.partner_id = cls.partner
with order_form.order_line.new() as line_form:
line_form.product_id = cls.product_kit
line_form.product_uom_qty = 5
line_form.price_unit = 29.9
line_form.tax_id.clear()
line_form.tax_id.add(cls.tax10)
cls.sale_order_3 = order_form.save()
cls.sale_order_3.action_confirm()
# Maybe other modules create additional lines in the create
# method in sale.order model, so let's find the correct line.
cls.order_line = cls.sale_order_3.order_line.filtered(
lambda r: r.product_id == cls.product_kit
)
cls.order_out_picking = cls.sale_order_3.picking_ids
def test_01_picking_confirmed(self):
for line in self.order_out_picking.move_lines:
line.quantity_done = line.product_uom_qty
self.order_out_picking.button_validate()
self.assertAlmostEqual(self.order_out_picking.amount_untaxed, 149.5)
self.assertAlmostEqual(self.order_out_picking.amount_tax, 14.95)
self.assertAlmostEqual(self.order_out_picking.amount_total, 164.45)
# Run the report to detect hidden errors
self.env.ref("stock.action_report_delivery").render_qweb_html(
self.order_out_picking.ids
)