Merge PR #454 into 13.0

Signed-off-by LoisRForgeFlow
This commit is contained in:
OCA-git-bot
2020-01-13 10:58:26 +00:00
21 changed files with 1242 additions and 1 deletions

View File

@@ -9,4 +9,4 @@ line_length=88
known_odoo=odoo
known_odoo_addons=odoo.addons
sections=FUTURE,STDLIB,THIRDPARTY,ODOO,ODOO_ADDONS,FIRSTPARTY,LOCALFOLDER
known_third_party=setuptools
known_third_party=dateutil,setuptools

View File

@@ -0,0 +1,147 @@
=============================
Production Grouped By Product
=============================
.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! 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%2Fmanufacture-lightgray.png?logo=github
:target: https://github.com/OCA/manufacture/tree/13.0/mrp_production_grouped_by_product
:alt: OCA/manufacture
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/manufacture-13-0/manufacture-13-0-mrp_production_grouped_by_product
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png
:target: https://runbot.odoo-community.org/runbot/129/13.0
:alt: Try me on Runbot
|badge1| |badge2| |badge3| |badge4| |badge5|
When you have several sales orders with make to order (MTO) products that
require to be manufactured, you end up with one manufacturing order for each of
these sales orders, which is very bad for the management.
With this module, each time an MTO manufacturing order is required to be
created, it first checks that there's no other existing order not yet started
for the same product and bill of materials inside the specied time frame , and
if there's one, then the quantity of that order is increased instead of
creating a new one.
**Table of contents**
.. contents::
:local:
Configuration
=============
To configure the time frame for grouping manufacturing order:
#. Go to *Inventory > Configuration > Warehouse Management > Operation Types*
#. Locate the manufacturing type you are using (default one is called
"Manufacturing").
#. Open it and change these 2 values:
* MO grouping max. hour (UTC): The maximum hour (between 0 and 23) for
considering new manufacturing orders inside the same interval period, and
thus being grouped on the same MO. IMPORTANT: The hour should be expressed
in UTC.
* MO grouping interval (days): The number of days for grouping together on
the same manufacturing order.
Example: If you leave the default values 19 and 1, all the planned orders
between 19:00:01 of the previous day and 20:00:00 of the target date will
be grouped together.
Known issues / Roadmap
======================
* Add a check in the product form for excluding it from being grouped.
Changelog
=========
13.0.1.0.0 (2020-01-09)
~~~~~~~~~~~~~~~~~~~~~~~
* [MIG] Migration to v13.
12.0.1.0.0 (2019-04-17)
~~~~~~~~~~~~~~~~~~~~~~~
* [MIG] Migration to v12:
11.0.2.0.1 (2018-07-02)
~~~~~~~~~~~~~~~~~~~~~~~
* [FIX] fix test in mrp_production_grouped_by_product
11.0.2.0.0 (2018-06-04)
~~~~~~~~~~~~~~~~~~~~~~~
* [IMP] mrp_production_grouped_by_product: Time frames
11.0.1.0.1 (2018-05-11)
~~~~~~~~~~~~~~~~~~~~~~~
* [IMP] mrp_production_grouped_by_company: Context evaluation on mrp.production + tests
11.0.1.0.0 (2018-05-11)
~~~~~~~~~~~~~~~~~~~~~~~
* Start of the history.
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 smashing it by providing a detailed and welcomed
`feedback <https://github.com/OCA/manufacture/issues/new?body=module:%20mrp_production_grouped_by_product%0Aversion:%2013.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Do not contact contributors directly about support or help with technical issues.
Credits
=======
Authors
~~~~~~~
* Tecnativa
Contributors
~~~~~~~~~~~~
* Tecnativa <https://www.tecnativa.com>__
* David Vidal
* Pedro M. Baeza
* `Ecosoft <https://ecosoft.co.th/>`__:
* Pimolnat Suntian <pimolnats@ecosoft.co.th>
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/13.0/mrp_production_grouped_by_product>`_ 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,16 @@
# Copyright 2018 Tecnativa - David Vidal
# Copyright 2018 Tecnativa - Pedro M. Baeza
# Copyright 2019 Rubén Bravo <rubenred18@gmail.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
"name": "Production Grouped By Product",
"version": "13.0.1.0.0",
"category": "MRP",
"author": "Tecnativa, " "Odoo Community Association (OCA)",
"website": "https://github.com/oca/manufacture",
"license": "AGPL-3",
"depends": ["mrp"],
"data": ["views/stock_picking_type_views.xml"],
"installable": True,
}

View File

@@ -0,0 +1,81 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * mrp_production_grouped_by_product
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 11.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2018-12-09 10:43+0000\n"
"Last-Translator: Maria Sparenberg <maria.sparenberg@gmx.net>\n"
"Language-Team: none\n"
"Language: de\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 3.3\n"
#. module: mrp_production_grouped_by_product
#: model:ir.model.fields,field_description:mrp_production_grouped_by_product.field_stock_picking_type__mo_grouping_interval
msgid "MO grouping interval (days)"
msgstr "Gruppierungsintervall für Fertigungsaufträge (Tage)"
#. module: mrp_production_grouped_by_product
#: model:ir.model.fields,field_description:mrp_production_grouped_by_product.field_stock_picking_type__mo_grouping_max_hour
msgid "MO grouping max. hour (UTC)"
msgstr "Späteste Uhrzeit (UTC) für die Gruppierung von Fertigungsaufträgen"
#. module: mrp_production_grouped_by_product
#: model:ir.model,name:mrp_production_grouped_by_product.model_stock_picking_type
msgid "Picking Type"
msgstr ""
#. module: mrp_production_grouped_by_product
#: model:ir.model,name:mrp_production_grouped_by_product.model_mrp_production
#, fuzzy
#| msgid "Manufacturing Order"
msgid "Production Order"
msgstr "Fertigungsauftrag"
#. module: mrp_production_grouped_by_product
#: model:ir.model,name:mrp_production_grouped_by_product.model_stock_rule
msgid "Stock Rule"
msgstr ""
#. module: mrp_production_grouped_by_product
#: model:ir.model.fields,help:mrp_production_grouped_by_product.field_stock_picking_type__mo_grouping_max_hour
msgid ""
"The maximum hour (between 0 and 23) for considering new manufacturing orders "
"inside the same interval period, and thus being grouped on the same MO. "
"IMPORTANT: The hour should be expressed in UTC."
msgstr ""
"Dies ist die späteste Uhrzeit (zwischen 0 und 23) zur Berücksichtigung von "
"neuen Fertigungsaufträgen innerhalb desselben Intervals, die dabei zum "
"selben Fertigungsauftrag gruppiert werden. WICHTIG: Die Uhrzeit muss in UTC "
"angegeben werden."
#. module: mrp_production_grouped_by_product
#: model:ir.model.fields,help:mrp_production_grouped_by_product.field_stock_picking_type__mo_grouping_interval
msgid ""
"The number of days for grouping together on the same manufacturing order."
msgstr ""
"Dies ist die Anzahl von Tagen zur Gruppierung in demselben Fertigungsauftrag."
#. module: mrp_production_grouped_by_product
#: code:addons/mrp_production_grouped_by_product/models/stock_picking_type.py:36
#, python-format
msgid "You have to enter a positive value for interval."
msgstr "Sie müssen für das Intervall einen Wert größer 0 eingeben."
#. module: mrp_production_grouped_by_product
#: code:addons/mrp_production_grouped_by_product/models/stock_picking_type.py:29
#, python-format
msgid "You have to enter a valid hour between 0 and 23."
msgstr "Sie müssen eine gültige Uhrzeit zwischen 0 und 23 eingeben."
#~ msgid "Procurement Rule"
#~ msgstr "Beschaffungsregel"
#~ msgid "The operation type determines the picking view"
#~ msgstr "Der Vorgangstyp legt die Pick-Ansicht fest"

View File

@@ -0,0 +1,79 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * mrp_production_grouped_by_product
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 11.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-06-03 23:16+0000\n"
"PO-Revision-Date: 2018-06-03 23:16+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: mrp_production_grouped_by_product
#: model:ir.model.fields,field_description:mrp_production_grouped_by_product.field_stock_picking_type__mo_grouping_interval
msgid "MO grouping interval (days)"
msgstr "Intervalo de agrupación de OFs (días)"
#. module: mrp_production_grouped_by_product
#: model:ir.model.fields,field_description:mrp_production_grouped_by_product.field_stock_picking_type__mo_grouping_max_hour
msgid "MO grouping max. hour (UTC)"
msgstr "Hora máx. agrupación OFs (UTC)"
#. module: mrp_production_grouped_by_product
#: model:ir.model,name:mrp_production_grouped_by_product.model_stock_picking_type
msgid "Picking Type"
msgstr ""
#. module: mrp_production_grouped_by_product
#: model:ir.model,name:mrp_production_grouped_by_product.model_mrp_production
#, fuzzy
#| msgid "Manufacturing Order"
msgid "Production Order"
msgstr "Orden de fabricación"
#. module: mrp_production_grouped_by_product
#: model:ir.model,name:mrp_production_grouped_by_product.model_stock_rule
msgid "Stock Rule"
msgstr ""
#. module: mrp_production_grouped_by_product
#: model:ir.model.fields,help:mrp_production_grouped_by_product.field_stock_picking_type__mo_grouping_max_hour
msgid ""
"The maximum hour (between 0 and 23) for considering new manufacturing orders "
"inside the same interval period, and thus being grouped on the same MO. "
"IMPORTANT: The hour should be expressed in UTC."
msgstr ""
"La hora máxima (entre 0 y 23) para considerar nuevas órdenes de fabricación "
"dentro del mismo periodo de tiempo, y por tanto siendo agrupadas dentro de "
"la misma OF. IMPORTANTE: La hora debe expresarse en UTC."
#. module: mrp_production_grouped_by_product
#: model:ir.model.fields,help:mrp_production_grouped_by_product.field_stock_picking_type__mo_grouping_interval
msgid ""
"The number of days for grouping together on the same manufacturing order."
msgstr "El número de días para agrupar juntas las órdenes de fabricación."
#. module: mrp_production_grouped_by_product
#: code:addons/mrp_production_grouped_by_product/models/stock_picking_type.py:36
#, python-format
msgid "You have to enter a positive value for interval."
msgstr "Debe introducir un valor positivo para el intervalo."
#. module: mrp_production_grouped_by_product
#: code:addons/mrp_production_grouped_by_product/models/stock_picking_type.py:29
#, python-format
msgid "You have to enter a valid hour between 0 and 23."
msgstr "Debe introducir una hora válida entre 0 y 23."
#~ msgid "Procurement Rule"
#~ msgstr "Regla de abastecimiento"
#~ msgid "The operation type determines the picking view"
#~ msgstr "El tipo de operación determina la vista de la operación"

View File

@@ -0,0 +1,62 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * mrp_production_grouped_by_product
#
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: mrp_production_grouped_by_product
#: model:ir.model.fields,field_description:mrp_production_grouped_by_product.field_stock_picking_type__mo_grouping_interval
msgid "MO grouping interval (days)"
msgstr ""
#. module: mrp_production_grouped_by_product
#: model:ir.model.fields,field_description:mrp_production_grouped_by_product.field_stock_picking_type__mo_grouping_max_hour
msgid "MO grouping max. hour (UTC)"
msgstr ""
#. module: mrp_production_grouped_by_product
#: model:ir.model,name:mrp_production_grouped_by_product.model_stock_picking_type
msgid "Picking Type"
msgstr ""
#. module: mrp_production_grouped_by_product
#: model:ir.model,name:mrp_production_grouped_by_product.model_mrp_production
msgid "Production Order"
msgstr ""
#. module: mrp_production_grouped_by_product
#: model:ir.model,name:mrp_production_grouped_by_product.model_stock_rule
msgid "Stock Rule"
msgstr ""
#. module: mrp_production_grouped_by_product
#: model:ir.model.fields,help:mrp_production_grouped_by_product.field_stock_picking_type__mo_grouping_max_hour
msgid "The maximum hour (between 0 and 23) for considering new manufacturing orders inside the same interval period, and thus being grouped on the same MO. IMPORTANT: The hour should be expressed in UTC."
msgstr ""
#. module: mrp_production_grouped_by_product
#: model:ir.model.fields,help:mrp_production_grouped_by_product.field_stock_picking_type__mo_grouping_interval
msgid "The number of days for grouping together on the same manufacturing order."
msgstr ""
#. module: mrp_production_grouped_by_product
#: code:addons/mrp_production_grouped_by_product/models/stock_picking_type.py:36
#, python-format
msgid "You have to enter a positive value for interval."
msgstr ""
#. module: mrp_production_grouped_by_product
#: code:addons/mrp_production_grouped_by_product/models/stock_picking_type.py:29
#, python-format
msgid "You have to enter a valid hour between 0 and 23."
msgstr ""

View File

@@ -0,0 +1,3 @@
from . import mrp_production
from . import stock_rule
from . import stock_picking_type

View File

@@ -0,0 +1,88 @@
# Copyright 2018 Tecnativa - David Vidal
# Copyright 2018 Tecnativa - Pedro M. Baeza
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from dateutil.relativedelta import relativedelta
from odoo import api, fields, models
from odoo.tools import config
class MrpProduction(models.Model):
_inherit = "mrp.production"
def _post_mo_merging_adjustments(self, vals):
"""Called when a new MO is merged onto existing one for adjusting the
needed values according this merging.
:param self: Single record of the target record where merging.
:param vals: Dictionary with the new record values.
"""
self.ensure_one()
new_vals = {"origin": (self.origin or "") + ",%s" % vals["origin"]}
if vals.get("move_dest_ids"):
new_vals["move_dest_ids"] = vals["move_dest_ids"]
self.move_finished_ids.move_dest_ids = vals["move_dest_ids"]
self.write(new_vals)
def _get_grouping_target_domain(self, vals):
"""Get the domain for searching manufacturing orders that can match
with the criteria we want to use.
:param vals: Values dictionary of the MO to be created.
:return: Odoo domain.
"""
domain = [
("product_id", "=", vals["product_id"]),
("picking_type_id", "=", vals["picking_type_id"]),
("bom_id", "=", vals.get("bom_id", False)),
("routing_id", "=", vals.get("routing_id", False)),
("company_id", "=", vals.get("company_id", False)),
("state", "=", "draft"),
]
if not vals.get("date_planned_finished"):
return domain
date = fields.Datetime.from_string(vals["date_planned_finished"])
pt = self.env["stock.picking.type"].browse(vals["picking_type_id"])
if date.hour < pt.mo_grouping_max_hour:
date_end = date.replace(hour=pt.mo_grouping_max_hour, minute=0, second=0)
else:
date_end = date.replace(
day=date.day + 1, hour=pt.mo_grouping_max_hour, minute=0, second=0
)
date_start = date_end - relativedelta(days=pt.mo_grouping_interval)
domain += [
("date_planned_finished", ">", fields.Datetime.to_string(date_start)),
("date_planned_finished", "<=", fields.Datetime.to_string(date_end)),
]
return domain
def _find_grouping_target(self, vals):
"""Return the matching order for grouping.
:param vals: Values dictionary of the MO to be created.
:return: Target manufacturing order record (or empty record).
"""
return self.env["mrp.production"].search(
self._get_grouping_target_domain(vals), limit=1
)
@api.model
def create(self, vals):
context = self.env.context
if context.get("group_mo_by_product") and (
not config["test_enable"] or context.get("test_group_mo")
):
mo = self._find_grouping_target(vals)
if mo:
self.env["change.production.qty"].create(
{
"mo_id": mo.id,
"product_qty": mo.product_qty + vals["product_qty"],
}
).change_prod_qty()
mo._post_mo_merging_adjustments(vals)
return mo
return super(MrpProduction, self).create(vals)

View File

@@ -0,0 +1,37 @@
# Copyright 2018 Tecnativa - Pedro M. Baeza
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import _, api, exceptions, fields, models
class StockPickingType(models.Model):
_inherit = "stock.picking.type"
mo_grouping_max_hour = fields.Integer(
string="MO grouping max. hour (UTC)",
help="The maximum hour (between 0 and 23) for considering new "
"manufacturing orders inside the same interval period, and thus "
"being grouped on the same MO. IMPORTANT: The hour should be "
"expressed in UTC.",
default=19,
)
mo_grouping_interval = fields.Integer(
string="MO grouping interval (days)",
help="The number of days for grouping together on the same "
"manufacturing order.",
default=1,
)
@api.constrains("mo_grouping_max_hour")
def _check_mo_grouping_max_hour(self):
if self.mo_grouping_max_hour < 0 or self.mo_grouping_max_hour > 23:
raise exceptions.ValidationError(
_("You have to enter a valid hour between 0 and 23.")
)
@api.constrains("mo_grouping_interval")
def _check_mo_grouping_interval(self):
if self.mo_grouping_interval < 0:
raise exceptions.ValidationError(
_("You have to enter a positive value for interval.")
)

View File

@@ -0,0 +1,14 @@
# Copyright 2018 Tecnativa - David Vidal
# Copyright 2018 Tecnativa - Pedro M. Baeza
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import models
class StockRule(models.Model):
_inherit = "stock.rule"
def _run_manufacture(self, procurements):
return super(
StockRule, self.with_context(group_mo_by_product=True)
)._run_manufacture(procurements)

View File

@@ -0,0 +1,17 @@
To configure the time frame for grouping manufacturing order:
#. Go to *Inventory > Configuration > Warehouse Management > Operation Types*
#. Locate the manufacturing type you are using (default one is called
"Manufacturing").
#. Open it and change these 2 values:
* MO grouping max. hour (UTC): The maximum hour (between 0 and 23) for
considering new manufacturing orders inside the same interval period, and
thus being grouped on the same MO. IMPORTANT: The hour should be expressed
in UTC.
* MO grouping interval (days): The number of days for grouping together on
the same manufacturing order.
Example: If you leave the default values 19 and 1, all the planned orders
between 19:00:01 of the previous day and 20:00:00 of the target date will
be grouped together.

View File

@@ -0,0 +1,8 @@
* Tecnativa <https://www.tecnativa.com>__
* David Vidal
* Pedro M. Baeza
* `Ecosoft <https://ecosoft.co.th/>`__:
* Pimolnat Suntian <pimolnats@ecosoft.co.th>

View File

@@ -0,0 +1,9 @@
When you have several sales orders with make to order (MTO) products that
require to be manufactured, you end up with one manufacturing order for each of
these sales orders, which is very bad for the management.
With this module, each time an MTO manufacturing order is required to be
created, it first checks that there's no other existing order not yet started
for the same product and bill of materials inside the specied time frame , and
if there's one, then the quantity of that order is increased instead of
creating a new one.

View File

@@ -0,0 +1,29 @@
13.0.1.0.0 (2020-01-09)
~~~~~~~~~~~~~~~~~~~~~~~
* [MIG] Migration to v13.
12.0.1.0.0 (2019-04-17)
~~~~~~~~~~~~~~~~~~~~~~~
* [MIG] Migration to v12:
11.0.2.0.1 (2018-07-02)
~~~~~~~~~~~~~~~~~~~~~~~
* [FIX] fix test in mrp_production_grouped_by_product
11.0.2.0.0 (2018-06-04)
~~~~~~~~~~~~~~~~~~~~~~~
* [IMP] mrp_production_grouped_by_product: Time frames
11.0.1.0.1 (2018-05-11)
~~~~~~~~~~~~~~~~~~~~~~~
* [IMP] mrp_production_grouped_by_company: Context evaluation on mrp.production + tests
11.0.1.0.0 (2018-05-11)
~~~~~~~~~~~~~~~~~~~~~~~
* Start of the history.

View File

@@ -0,0 +1 @@
* Add a check in the product form for excluding it from being grouped.

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

View File

@@ -0,0 +1,514 @@
<?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>Production Grouped By Product</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="production-grouped-by-product">
<h1 class="title">Production Grouped By Product</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/manufacture/tree/13.0/mrp_production_grouped_by_product"><img alt="OCA/manufacture" src="https://img.shields.io/badge/github-OCA%2Fmanufacture-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/manufacture-13-0/manufacture-13-0-mrp_production_grouped_by_product"><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/129/13.0"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p>
<p>When you have several sales orders with make to order (MTO) products that
require to be manufactured, you end up with one manufacturing order for each of
these sales orders, which is very bad for the management.</p>
<p>With this module, each time an MTO manufacturing order is required to be
created, it first checks that theres no other existing order not yet started
for the same product and bill of materials inside the specied time frame , and
if theres one, then the quantity of that order is increased instead of
creating a new one.</p>
<p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#configuration" id="id7">Configuration</a></li>
<li><a class="reference internal" href="#known-issues-roadmap" id="id8">Known issues / Roadmap</a></li>
<li><a class="reference internal" href="#changelog" id="id9">Changelog</a><ul>
<li><a class="reference internal" href="#id1" id="id10">13.0.1.0.0 (2020-01-09)</a></li>
<li><a class="reference internal" href="#id2" id="id11">12.0.1.0.0 (2019-04-17)</a></li>
<li><a class="reference internal" href="#id3" id="id12">11.0.2.0.1 (2018-07-02)</a></li>
<li><a class="reference internal" href="#id4" id="id13">11.0.2.0.0 (2018-06-04)</a></li>
<li><a class="reference internal" href="#id5" id="id14">11.0.1.0.1 (2018-05-11)</a></li>
<li><a class="reference internal" href="#id6" id="id15">11.0.1.0.0 (2018-05-11)</a></li>
</ul>
</li>
<li><a class="reference internal" href="#bug-tracker" id="id16">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="id17">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="id18">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="id19">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="id20">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="configuration">
<h1><a class="toc-backref" href="#id7">Configuration</a></h1>
<p>To configure the time frame for grouping manufacturing order:</p>
<ol class="arabic">
<li><p class="first">Go to <em>Inventory &gt; Configuration &gt; Warehouse Management &gt; Operation Types</em></p>
</li>
<li><p class="first">Locate the manufacturing type you are using (default one is called
“Manufacturing”).</p>
</li>
<li><p class="first">Open it and change these 2 values:</p>
<ul class="simple">
<li>MO grouping max. hour (UTC): The maximum hour (between 0 and 23) for
considering new manufacturing orders inside the same interval period, and
thus being grouped on the same MO. IMPORTANT: The hour should be expressed
in UTC.</li>
<li>MO grouping interval (days): The number of days for grouping together on
the same manufacturing order.</li>
</ul>
<p>Example: If you leave the default values 19 and 1, all the planned orders
between 19:00:01 of the previous day and 20:00:00 of the target date will
be grouped together.</p>
</li>
</ol>
</div>
<div class="section" id="known-issues-roadmap">
<h1><a class="toc-backref" href="#id8">Known issues / Roadmap</a></h1>
<ul class="simple">
<li>Add a check in the product form for excluding it from being grouped.</li>
</ul>
</div>
<div class="section" id="changelog">
<h1><a class="toc-backref" href="#id9">Changelog</a></h1>
<div class="section" id="id1">
<h2><a class="toc-backref" href="#id10">13.0.1.0.0 (2020-01-09)</a></h2>
<ul class="simple">
<li>[MIG] Migration to v13.</li>
</ul>
</div>
<div class="section" id="id2">
<h2><a class="toc-backref" href="#id11">12.0.1.0.0 (2019-04-17)</a></h2>
<ul class="simple">
<li>[MIG] Migration to v12:</li>
</ul>
</div>
<div class="section" id="id3">
<h2><a class="toc-backref" href="#id12">11.0.2.0.1 (2018-07-02)</a></h2>
<ul class="simple">
<li>[FIX] fix test in mrp_production_grouped_by_product</li>
</ul>
</div>
<div class="section" id="id4">
<h2><a class="toc-backref" href="#id13">11.0.2.0.0 (2018-06-04)</a></h2>
<ul class="simple">
<li>[IMP] mrp_production_grouped_by_product: Time frames</li>
</ul>
</div>
<div class="section" id="id5">
<h2><a class="toc-backref" href="#id14">11.0.1.0.1 (2018-05-11)</a></h2>
<ul class="simple">
<li>[IMP] mrp_production_grouped_by_company: Context evaluation on mrp.production + tests</li>
</ul>
</div>
<div class="section" id="id6">
<h2><a class="toc-backref" href="#id15">11.0.1.0.0 (2018-05-11)</a></h2>
<ul class="simple">
<li>Start of the history.</li>
</ul>
</div>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#id16">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 smashing it by providing a detailed and welcomed
<a class="reference external" href="https://github.com/OCA/manufacture/issues/new?body=module:%20mrp_production_grouped_by_product%0Aversion:%2013.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p>
</div>
<div class="section" id="credits">
<h1><a class="toc-backref" href="#id17">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#id18">Authors</a></h2>
<ul class="simple">
<li>Tecnativa</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#id19">Contributors</a></h2>
<ul class="simple">
<li>Tecnativa &lt;<a class="reference external" href="https://www.tecnativa.com">https://www.tecnativa.com</a>&gt;__<ul>
<li>David Vidal</li>
<li>Pedro M. Baeza</li>
</ul>
</li>
<li><a class="reference external" href="https://ecosoft.co.th/">Ecosoft</a>:<ul>
<li>Pimolnat Suntian &lt;<a class="reference external" href="mailto:pimolnats&#64;ecosoft.co.th">pimolnats&#64;ecosoft.co.th</a>&gt;</li>
</ul>
</li>
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#id20">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/13.0/mrp_production_grouped_by_product">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>

View File

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

View File

@@ -0,0 +1,117 @@
# Copyright 2018 Tecnativa - David Vidal
# Copyright 2018 Tecnativa - Pedro M. Baeza
# Copyright 2019 Rubén Bravo <rubenred18@gmail.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import exceptions
from odoo.tests import common
class TestProductionGroupedByProduct(common.SavepointCase):
at_install = False
post_install = True
@classmethod
def setUpClass(cls):
super(TestProductionGroupedByProduct, cls).setUpClass()
cls.ProcurementGroup = cls.env["procurement.group"]
cls.MrpProduction = cls.env["mrp.production"]
cls.env.user.company_id.manufacturing_lead = 0
cls.env.user.tz = False # Make sure there's no timezone in user
cls.picking_type = cls.env["stock.picking.type"].search(
[
("code", "=", "mrp_operation"),
("sequence_id.company_id", "=", cls.env.user.company_id.id),
],
limit=1,
)
cls.product1 = cls.env["product.product"].create(
{
"name": "TEST Muffin",
"route_ids": [
(6, 0, [cls.env.ref("mrp.route_warehouse0_manufacture").id])
],
"type": "product",
"produce_delay": 0,
}
)
cls.product2 = cls.env["product.product"].create(
{"name": "TEST Paper muffin cup", "type": "product"}
)
cls.product3 = cls.env["product.product"].create(
{"name": "TEST Muffin paset", "type": "product"}
)
cls.bom = cls.env["mrp.bom"].create(
{
"product_id": cls.product1.id,
"product_tmpl_id": cls.product1.product_tmpl_id.id,
"type": "normal",
"bom_line_ids": [
(0, 0, {"product_id": cls.product2.id, "product_qty": 1}),
(0, 0, {"product_id": cls.product3.id, "product_qty": 0.2}),
],
}
)
cls.stock_picking_type = cls.env.ref("stock.picking_type_out")
cls.mo = cls.MrpProduction.create(
{
"bom_id": cls.bom.id,
"product_id": cls.product1.id,
"product_qty": 2,
"product_uom_id": cls.product1.uom_id.id,
"date_planned_finished": "2018-06-01 15:00:00",
"date_planned_start": "2018-06-01 15:00:00",
}
)
cls.warehouse = cls.env["stock.warehouse"].search(
[("company_id", "=", cls.env.user.company_id.id)], limit=1
)
# Add an MTO move
cls.move = cls.env["stock.move"].create(
{
"name": cls.product1.name,
"product_id": cls.product1.id,
"product_uom_qty": 10,
"product_uom": cls.product1.uom_id.id,
"location_id": cls.warehouse.lot_stock_id.id,
"location_dest_id": (cls.env.ref("stock.stock_location_customers").id),
"procure_method": "make_to_order",
"warehouse_id": cls.warehouse.id,
"date": "2018-06-01 18:00:00",
"date_expected": "2018-06-01 18:00:00",
}
)
def test_mo_by_product(self):
self.move.with_context(test_group_mo=True)._action_confirm(merge=False)
self.ProcurementGroup.with_context(test_group_mo=True).run_scheduler()
mo = self.MrpProduction.search([("product_id", "=", self.product1.id)])
self.assertEqual(len(mo), 1)
self.assertEqual(mo.product_qty, 12)
# Run again the scheduler to see if quantities are altered
self.ProcurementGroup.with_context(test_group_mo=True).run_scheduler()
mo = self.MrpProduction.search([("product_id", "=", self.product1.id)])
self.assertEqual(len(mo), 1)
self.assertEqual(mo.product_qty, 12)
def test_mo_other_date(self):
self.move.write(
{"date_expected": "2018-06-01 20:01:00", "date": "2018-06-01 20:01:00"}
)
self.move.with_context(test_group_mo=True)._action_confirm(merge=False)
self.ProcurementGroup.with_context(test_group_mo=True).run_scheduler()
mo = self.MrpProduction.search([("product_id", "=", self.product1.id)])
self.assertEqual(len(mo), 2)
def test_check_mo_grouping_max_hour(self):
if self.picking_type:
with self.assertRaises(exceptions.ValidationError):
self.picking_type.mo_grouping_max_hour = 25
with self.assertRaises(exceptions.ValidationError):
self.picking_type.mo_grouping_max_hour = -1
def test_check_mo_grouping_interval(self):
if self.picking_type:
with self.assertRaises(exceptions.ValidationError):
self.picking_type.mo_grouping_interval = -1

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2018 Tecnativa - Pedro M. Baeza
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -->
<odoo>
<record id="view_picking_type_form" model="ir.ui.view">
<field name="model">stock.picking.type</field>
<field name="inherit_id" ref="stock.view_picking_type_form"/>
<field name="arch" type="xml">
<field name="code" position="after">
<field name="mo_grouping_max_hour"/>
<field name="mo_grouping_interval"/>
</field>
</field>
</record>
</odoo>