diff --git a/mrp_multi_level/README.rst b/mrp_multi_level/README.rst new file mode 100644 index 000000000..f45bdc7df --- /dev/null +++ b/mrp_multi_level/README.rst @@ -0,0 +1,196 @@ +=============== +MRP Multi Level +=============== + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! 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-LGPL--3-blue.png + :target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html + :alt: License: LGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fmanufacture-lightgray.png?logo=github + :target: https://github.com/OCA/manufacture/tree/12.0/mrp_multi_level + :alt: OCA/manufacture +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/manufacture-12-0/manufacture-12-0-mrp_multi_level + :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/12.0 + :alt: Try me on Runbot + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module allows you to calculate, based in known inventory, demand, and +supply, and based on parameters set at product variant level, the new +procurements for each product. + +To do this, the calculation starts at top level of the bill of material +and explodes this down to the lowest level. + +Key Features +------------ + +* MRP parameters set by product variant MRP area pairs. +* Cron job to calculate the MRP demand. +* Manually calculate the MRP demand. +* Confirm the calculated MRP demand and create PO's, or MO's. +* Able to see the products for which action is needed throught Planned Orders. +* Integration with `Stock Demand Estimates `_ system. + Note: You need to install `mrp_multi_level_estimate module `_. + +**Table of contents** + +.. contents:: + :local: + +Configuration +============= + +MRP Areas +~~~~~~~~~ + +* Go to *Manufacturing > Configuration > MRP Areas* and define or edit + any existing area. You can specify the working hours for every area. + +Product MRP Area Parameters +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +* Go to *Manufacturing > Master Data > Product MRP Area Parameters* and set + the MRP parameters for a given product and area. + +Usage +===== + +To manually run the MRP scheduler: + +#. Go to *Manufacturing > Operations > Run MRP Multi Level*. +#. On the wizard click *Run MRP*. + +To launch replenishment orders (moves, purchases, production orders...): + +#. Go to *Manufacturing > Operations > MRP Inventory*. +#. Filter with *To procure*. +#. Select multiple records and click on *Action > Procure* or click the right + hand side gears in any record. +#. On the wizard, check everything is ok and click *Execute*. + +Changelog +========= + +12.0.1.0.0 (2019-08-05) +~~~~~~~~~~~~~~~~~~~~~~~ + +* [MIG] Migration to v12: + + * Estimates as a forecasting mechanism is moved to a new module + (mrp_multi_level_estimate). + +11.0.3.0.0 (2019-05-22) +~~~~~~~~~~~~~~~~~~~~~~~ + +* [REW/IMP] Rework to include Planned Orders. + (`#365 `_). +* [IMP] Able to procure from a different location than the area's location. + +11.0.2.2.0 (2019-05-02) +~~~~~~~~~~~~~~~~~~~~~~~ + +* [IMP] Able to run MRP only for selected areas. + (`#360 `_). + +11.0.2.1.0 (2019-04-02) +~~~~~~~~~~~~~~~~~~~~~~~ + +* [IMP] Implement *Nbr. Days* functionality to be able to group demand when + generating supply proposals. + (`#345 `_). + +11.0.2.0.0 (2018-11-20) +~~~~~~~~~~~~~~~~~~~~~~~ + +* [REW] Refactor MRP Area. + (`#322 `_): + + * MRP product concept dropped in favor of *Product MRP Area Parameters*. + This allow to set different MRP parameters for the same product in + different areas. + * Menu items reordering. + +11.0.1.1.0 (2018-08-30) +~~~~~~~~~~~~~~~~~~~~~~~ + +* [FIX] Consider *Qty Multiple* on product to propose the quantity to procure. + (`#297 `_) + +11.0.1.0.1 (2018-08-03) +~~~~~~~~~~~~~~~~~~~~~~~ + +* [FIX] User and system locales doesn't break MRP calculation. + (`#290 `_) +* [FIX] Working Hours are now defined only at Warehouse level and displayed + as a related on MRP Areas. + (`#290 `__) + +11.0.1.0.0 (2018-07-09) +~~~~~~~~~~~~~~~~~~~~~~~ + +* Start of the history. + +Bug Tracker +=========== + +Bugs are tracked on `GitHub 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 `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* Ucamco +* Eficent + +Contributors +~~~~~~~~~~~~ + +* Wim Audenaert +* Jordi Ballester +* Lois Rilo + +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-jbeficent| image:: https://github.com/jbeficent.png?size=40px + :target: https://github.com/jbeficent + :alt: jbeficent +.. |maintainer-lreficent| image:: https://github.com/lreficent.png?size=40px + :target: https://github.com/lreficent + :alt: lreficent + +Current `maintainers `__: + +|maintainer-jbeficent| |maintainer-lreficent| + +This module is part of the `OCA/manufacture `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/mrp_multi_level/__init__.py b/mrp_multi_level/__init__.py new file mode 100644 index 000000000..aee8895e7 --- /dev/null +++ b/mrp_multi_level/__init__.py @@ -0,0 +1,2 @@ +from . import models +from . import wizards diff --git a/mrp_multi_level/__manifest__.py b/mrp_multi_level/__manifest__.py new file mode 100644 index 000000000..63d5b4aa7 --- /dev/null +++ b/mrp_multi_level/__manifest__.py @@ -0,0 +1,48 @@ +# Copyright 2016 Ucamco - Wim Audenaert +# Copyright 2016-19 Eficent Business and IT Consulting Services S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). + +{ + 'name': 'MRP Multi Level', + 'version': '12.0.1.0.0', + 'development_status': 'Beta', + 'license': 'LGPL-3', + 'author': 'Ucamco, ' + 'Eficent, ' + 'Odoo Community Association (OCA)', + 'maintainers': ['jbeficent', 'lreficent'], + 'summary': 'Adds an MRP Scheduler', + 'website': 'https://github.com/OCA/manufacture', + 'category': 'Manufacturing', + 'depends': [ + 'mrp', + 'purchase_stock', + 'mrp_warehouse_calendar', + ], + 'data': [ + 'security/mrp_multi_level_security.xml', + 'security/ir.model.access.csv', + 'views/mrp_area_views.xml', + 'views/product_product_views.xml', + 'views/product_template_views.xml', + 'views/product_mrp_area_views.xml', + 'views/stock_location_views.xml', + 'wizards/mrp_inventory_procure_views.xml', + 'views/mrp_inventory_views.xml', + 'wizards/mrp_multi_level_views.xml', + 'views/mrp_menuitem.xml', + 'data/mrp_multi_level_cron.xml', + 'data/mrp_area_data.xml', + ], + 'demo': [ + 'demo/product_category_demo.xml', + 'demo/product_product_demo.xml', + 'demo/res_partner_demo.xml', + 'demo/product_supplierinfo_demo.xml', + 'demo/product_mrp_area_demo.xml', + 'demo/mrp_bom_demo.xml', + 'demo/initial_on_hand_demo.xml', + ], + 'installable': True, + 'application': True, +} diff --git a/mrp_multi_level/data/mrp_area_data.xml b/mrp_multi_level/data/mrp_area_data.xml new file mode 100644 index 000000000..a7c357e6e --- /dev/null +++ b/mrp_multi_level/data/mrp_area_data.xml @@ -0,0 +1,10 @@ + + + + + WH/Stock + + + + + diff --git a/mrp_multi_level/data/mrp_multi_level_cron.xml b/mrp_multi_level/data/mrp_multi_level_cron.xml new file mode 100755 index 000000000..40ec42e6d --- /dev/null +++ b/mrp_multi_level/data/mrp_multi_level_cron.xml @@ -0,0 +1,16 @@ + + + + + Multi Level MRP + + + 1 + days + -1 + + code + model.run_mrp_multi_level() + + + diff --git a/mrp_multi_level/demo/initial_on_hand_demo.xml b/mrp_multi_level/demo/initial_on_hand_demo.xml new file mode 100644 index 000000000..000bd9f8e --- /dev/null +++ b/mrp_multi_level/demo/initial_on_hand_demo.xml @@ -0,0 +1,32 @@ + + + + + Simulating MRP + + + + + + 10 + + + + + + + 20 + + + + + + + 15 + + + + + + + diff --git a/mrp_multi_level/demo/mrp_bom_demo.xml b/mrp_multi_level/demo/mrp_bom_demo.xml new file mode 100644 index 000000000..9eec23de1 --- /dev/null +++ b/mrp_multi_level/demo/mrp_bom_demo.xml @@ -0,0 +1,81 @@ + + + + + + + 5 + + + + 2 + + 5 + + + + + 3 + + 5 + + + + + + + + 5 + + + + 2 + + 5 + + + + + 3 + + 5 + + + + + + + 5 + + + + 3 + + 5 + + + + + 2 + + 5 + + + + + + + 5 + + + + 3 + + 5 + + + diff --git a/mrp_multi_level/demo/product_category_demo.xml b/mrp_multi_level/demo/product_category_demo.xml new file mode 100644 index 000000000..bf989ea45 --- /dev/null +++ b/mrp_multi_level/demo/product_category_demo.xml @@ -0,0 +1,6 @@ + + + + MRP + + diff --git a/mrp_multi_level/demo/product_mrp_area_demo.xml b/mrp_multi_level/demo/product_mrp_area_demo.xml new file mode 100644 index 000000000..e3684dffd --- /dev/null +++ b/mrp_multi_level/demo/product_mrp_area_demo.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mrp_multi_level/demo/product_product_demo.xml b/mrp_multi_level/demo/product_product_demo.xml new file mode 100644 index 000000000..78d90ca8f --- /dev/null +++ b/mrp_multi_level/demo/product_product_demo.xml @@ -0,0 +1,59 @@ + + + + FP-1 + + product + + + 2 + + + + + FP-2 + + product + + + 1 + + + + + SF-1 + + product + + + 1 + + + + SF-2 + + product + + + 3 + + + + + PP-1 + + product + + + + + + + PP-2 + + product + + + + + diff --git a/mrp_multi_level/demo/product_supplierinfo_demo.xml b/mrp_multi_level/demo/product_supplierinfo_demo.xml new file mode 100644 index 000000000..ab223f04c --- /dev/null +++ b/mrp_multi_level/demo/product_supplierinfo_demo.xml @@ -0,0 +1,18 @@ + + + + + + 4 + 0 + 100 + + + + + + 2 + 0 + 100 + + diff --git a/mrp_multi_level/demo/res_partner_demo.xml b/mrp_multi_level/demo/res_partner_demo.xml new file mode 100644 index 000000000..ecb86d323 --- /dev/null +++ b/mrp_multi_level/demo/res_partner_demo.xml @@ -0,0 +1,10 @@ + + + + Lazer Tech + 1 + + + + + diff --git a/mrp_multi_level/docs/mrp_multi_level_test_run.ods b/mrp_multi_level/docs/mrp_multi_level_test_run.ods new file mode 100644 index 000000000..e41f28115 Binary files /dev/null and b/mrp_multi_level/docs/mrp_multi_level_test_run.ods differ diff --git a/mrp_multi_level/i18n/de.po b/mrp_multi_level/i18n/de.po new file mode 100644 index 000000000..d9da41d2f --- /dev/null +++ b/mrp_multi_level/i18n/de.po @@ -0,0 +1,971 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * mrp_multi_level +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 11.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2019-06-28 14:42+0000\n" +"Last-Translator: Maria Sparenberg \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.6.1\n" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order_mrp_action +msgid "Action" +msgstr "Aktion" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_area_active +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_active +msgid "Active" +msgstr "Aktiv" + +#. module: mrp_multi_level +#: selection:mrp.move,state:0 +msgid "Approved" +msgstr "Genehmigt" + +#. module: mrp_multi_level +#: model:ir.ui.view,arch_db:mrp_multi_level.product_mrp_area_search +msgid "Archived" +msgstr "Archiviert" + +#. module: mrp_multi_level +#: selection:mrp.move,state:0 +msgid "Assigned" +msgstr "Zugewiesen" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order_mrp_inventory_id +msgid "Associated MRP Inventory" +msgstr "Zugehöriger MRP Bestand" + +#. module: mrp_multi_level +#: selection:product.mrp.area,supply_method:0 +msgid "Buy" +msgstr "Einkaufen" + +#. module: mrp_multi_level +#: model:ir.ui.view,arch_db:mrp_multi_level.view_mrp_inventory_procure_wizard +#: model:ir.ui.view,arch_db:mrp_multi_level.view_run_mrp_multi_level_wizard +msgid "Cancel" +msgstr "Abbrechen" + +#. module: mrp_multi_level +#: model:res.groups,name:mrp_multi_level.group_change_mrp_procure_qty +msgid "Change procure quantity in MRP" +msgstr "Beschaffungsmenge in der Fertigung ändern" + +#. module: mrp_multi_level +#: selection:mrp.move,state:0 +msgid "Confirmed" +msgstr "Bestätigt" + +#. module: mrp_multi_level +#: model:ir.ui.view,arch_db:mrp_multi_level.mrp_inventory_tree +msgid "Create Procurement" +msgstr "Beschaffung erzeugen" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_area_create_uid +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_create_uid +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_create_uid +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_item_create_uid +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move_create_uid +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_multi_level_create_uid +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order_create_uid +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_create_uid +msgid "Created by" +msgstr "Erstellt von" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_area_create_date +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_create_date +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_create_date +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_item_create_date +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move_create_date +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_multi_level_create_date +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order_create_date +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_create_date +msgid "Created on" +msgstr "Erstellt am" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move_current_date +msgid "Current Date" +msgstr "Aktuelles Datum" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move_current_qty +msgid "Current Qty" +msgstr "Aktuelle Menge" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_date +msgid "Date" +msgstr "Datum" + +#. module: mrp_multi_level +#: model:ir.model.fields,help:mrp_multi_level.field_mrp_planned_order_due_date +msgid "Date in which the supply must have been completed." +msgstr "Das ist das Fälligkeitsdatum, zu dem der Auftrag erledigt sein muss." + +#. module: mrp_multi_level +#: model:ir.ui.view,arch_db:mrp_multi_level.mrp_inventory_search +msgid "Date to Procure (By Day)" +msgstr "Beschaffungsdatum (nach Tagen)" + +#. module: mrp_multi_level +#: model:ir.ui.view,arch_db:mrp_multi_level.mrp_inventory_search +msgid "Date to Procure (By Month)" +msgstr "Beschaffungsdatum (nach Monaten)" + +#. module: mrp_multi_level +#: model:ir.ui.view,arch_db:mrp_multi_level.mrp_inventory_search +msgid "Date to Procure (By Week)" +msgstr "Beschaffungsdatum (nach Wochen)" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_demand_qty +#: selection:mrp.move,mrp_type:0 +msgid "Demand" +msgstr "Nachfrage" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move_name +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order_name +msgid "Description" +msgstr "Beschreibung" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_area_display_name +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_display_name +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_display_name +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_item_display_name +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move_display_name +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_multi_level_display_name +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order_display_name +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_display_name +msgid "Display Name" +msgstr "Anzeigename" + +#. module: mrp_multi_level +#: selection:mrp.move,state:0 +msgid "Draft" +msgstr "Entwurf" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order_due_date +msgid "Due Date" +msgstr "Fälligkeitsdatum" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_mrp_exclude +msgid "Exclude from MRP" +msgstr "von der Ressourcenplanung ausschließen" + +#. module: mrp_multi_level +#: model:ir.ui.view,arch_db:mrp_multi_level.view_mrp_inventory_procure_wizard +msgid "Execute" +msgstr "Ausführen" + +#. module: mrp_multi_level +#: model:product.product,name:mrp_multi_level.product_product_fp_1 +#: model:product.template,name:mrp_multi_level.product_product_fp_1_product_template +msgid "FP-1" +msgstr "FP-1" + +#. module: mrp_multi_level +#: model:product.product,name:mrp_multi_level.product_product_fp_2 +#: model:product.template,name:mrp_multi_level.product_product_fp_2_product_template +msgid "FP-2" +msgstr "FP-2" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order_fixed +msgid "Fixed" +msgstr "Fest" + +#. module: mrp_multi_level +#: selection:mrp.move,mrp_origin:0 +msgid "Forecast" +msgstr "Vorhersage" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_final_on_hand_qty +msgid "Forecasted Inventory" +msgstr "Vorhergesagter Bestand" + +#. module: mrp_multi_level +#: model:ir.ui.view,arch_db:mrp_multi_level.mrp_inventory_search +msgid "Group By..." +msgstr "Gruppiere nach..." + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_group_estimate_days +msgid "Group Days of Estimates" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_area_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_item_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_multi_level_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_id +msgid "ID" +msgstr "ID" + +#. module: mrp_multi_level +#: model:ir.model.fields,help:mrp_multi_level.field_product_mrp_area_mrp_verified +msgid "Identifies that this product has been verified to be valid for the MRP." +msgstr "" +"Dieses Produkt wurde als für die Fertigungsressourcenplanung gültig " +"verifiziert." + +#. module: mrp_multi_level +#: model:ir.model.fields,help:mrp_multi_level.field_mrp_multi_level_mrp_area_ids +msgid "If empty, all areas will be computed." +msgstr "Wenn das Feld leer ist, werden alle Bereiche berechnet." + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_mrp_inspection_delay +msgid "Inspection Delay" +msgstr "Inspektionsverzögerung" + +#. module: mrp_multi_level +#: model:ir.model,name:mrp_multi_level.model_stock_location +msgid "Inventory Locations" +msgstr "Lagerorte" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_item_ids +#: model:ir.ui.view,arch_db:mrp_multi_level.view_mrp_inventory_procure_wizard +msgid "Items" +msgstr "Positionen" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_area___last_update +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory___last_update +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure___last_update +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_item___last_update +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move___last_update +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_multi_level___last_update +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order___last_update +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area___last_update +msgid "Last Modified on" +msgstr "Zuletzt geändert am" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_area_write_uid +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_item_write_uid +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_write_uid +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_write_uid +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move_write_uid +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_multi_level_write_uid +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order_write_uid +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_write_uid +msgid "Last Updated by" +msgstr "Zuletzt aktualisiert von" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_area_write_date +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_item_write_date +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_write_date +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_write_date +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move_write_date +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_multi_level_write_date +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order_write_date +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_write_date +msgid "Last Updated on" +msgstr "Zuletzt aktualisiert am" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_mrp_lead_time +msgid "Lead Time" +msgstr "Durchlaufzeit" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_area_location_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_item_location_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_location_id +msgid "Location" +msgstr "Lagerort" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_product_llc +msgid "Low Level Code" +msgstr "Dispositionsstufe" + +#. module: mrp_multi_level +#: model:ir.ui.menu,name:mrp_multi_level.menu_mrp_mrp +#: selection:mrp.move,mrp_origin:0 +#: model:product.category,name:mrp_multi_level.product_category_mrp +msgid "MRP" +msgstr "Ressourcenplanung" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_mrp_applicable +msgid "MRP Applicable" +msgstr "Ressourcenplanung anwendbar" + +#. module: mrp_multi_level +#: model:ir.actions.act_window,name:mrp_multi_level.mrp_area_action +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_mrp_area_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move_mrp_area_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order_mrp_area_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_stock_location_mrp_area_id +#: model:ir.ui.view,arch_db:mrp_multi_level.mrp_area_form +#: model:ir.ui.view,arch_db:mrp_multi_level.mrp_area_tree +#: model:ir.ui.view,arch_db:mrp_multi_level.mrp_inventory_search +msgid "MRP Area" +msgstr "Bereich" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_product_mrp_area_count +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_template_mrp_area_count +msgid "MRP Area Parameter Count" +msgstr "Anzahl der Bereich-Parameter" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_product_mrp_area_ids +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_template_mrp_area_ids +msgid "MRP Area parameters" +msgstr "Bereich-Parameter" + +#. module: mrp_multi_level +#: model:ir.ui.menu,name:mrp_multi_level.menu_mrp_areas +#: model:ir.ui.view,arch_db:mrp_multi_level.product_template_only_form_view_mrp +#: model:ir.ui.view,arch_db:mrp_multi_level.view_mrp_product_product_form +msgid "MRP Areas" +msgstr "Bereiche" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_multi_level_mrp_area_ids +msgid "MRP Areas to run" +msgstr "Auszuführende Bereiche" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move_mrp_date +msgid "MRP Date" +msgstr "Datum (MRP)" + +#. module: mrp_multi_level +#: model:ir.actions.act_window,name:mrp_multi_level.mrp_inventory_action +#: model:ir.ui.menu,name:mrp_multi_level.menu_mrp_inventory +#: model:ir.ui.view,arch_db:mrp_multi_level.mrp_inventory_form +#: model:ir.ui.view,arch_db:mrp_multi_level.mrp_inventory_search +#: model:ir.ui.view,arch_db:mrp_multi_level.mrp_inventory_tree +#: model:ir.ui.view,arch_db:mrp_multi_level.view_mrp_inventory_graph +#: model:ir.ui.view,arch_db:mrp_multi_level.view_mrp_inventory_pivot +msgid "MRP Inventory" +msgstr "Bestand" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order_mrp_move_down_ids +msgid "MRP Move DOWN" +msgstr "nach unten verschieben" + +#. module: mrp_multi_level +#: model:ir.ui.view,arch_db:mrp_multi_level.product_mrp_area_form +msgid "MRP Moves" +msgstr "Lagerbewegungen" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move_mrp_qty +msgid "MRP Quantity" +msgstr "Menge (MRP)" + +#. module: mrp_multi_level +#: model:ir.model,name:mrp_multi_level.model_mrp_inventory +msgid "MRP inventory projections" +msgstr "Bestandsvorhersagen" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_main_supplier_id +msgid "Main Supplier" +msgstr "Hauptlieferant" + +#. module: mrp_multi_level +#: model:ir.model,name:mrp_multi_level.model_mrp_inventory_procure +msgid "Make Procurements from MRP inventory projections" +msgstr "Beschaffungen aus den Bestandsvorhersagen (MRP) erstellen" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move_production_id +#: selection:mrp.move,mrp_origin:0 selection:mrp.planned.order,mrp_action:0 +msgid "Manufacturing Order" +msgstr "Fertigungsauftrag" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_product_manufacturing_order_ids +msgid "Manufacturing Orders" +msgstr "Fertigungsaufträge" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_mrp_maximum_order_qty +msgid "Maximum Order Qty" +msgstr "Maximale Auftragsmenge" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_mrp_minimum_order_qty +msgid "Minimum Order Qty" +msgstr "Minimale Auftragsmenge" + +#. module: mrp_multi_level +#: selection:mrp.move,mrp_origin:0 +msgid "Move" +msgstr "Lagerbewegung" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_mrp_area_id +msgid "Mrp Area" +msgstr "Bereich" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_item_mrp_inventory_id +msgid "Mrp Inventory" +msgstr "Bestand (MRP)" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_mrp_move_ids +msgid "Mrp Move" +msgstr "Lagerbewegungen" + +#. module: mrp_multi_level +#: model:ir.actions.server,name:mrp_multi_level.mrp_multi_level_cron_ir_actions_server +#: model:ir.cron,cron_name:mrp_multi_level.mrp_multi_level_cron +#: model:ir.cron,name:mrp_multi_level.mrp_multi_level_cron +msgid "Multi Level MRP" +msgstr "Mehrstufige MRP" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_area_name +msgid "Name" +msgstr "Bezeichnung" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_mrp_nbr_days +msgid "Nbr. Days" +msgstr "# Tage" + +#. module: mrp_multi_level +#: code:addons/mrp_multi_level/wizards/mrp_multi_level.py:156 +#, python-format +msgid "No MRP product found" +msgstr "Kein Produkt für MRP gefunden" + +#. module: mrp_multi_level +#: selection:mrp.planned.order,mrp_action:0 +msgid "None" +msgstr "Keines" + +#. module: mrp_multi_level +#: model:ir.model.fields,help:mrp_multi_level.field_product_mrp_area_mrp_nbr_days +msgid "" +"Number of days to group demand for this product during the MRP run, in order " +"to determine the quantity to order." +msgstr "" +"Anzahl der Tage zur Gruppierung von Nachfragen für das Produkt während eines " +"MRP-Laufs, um die zu beschaffende Menge festzulegen." + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move_mrp_order_number +msgid "Order Number" +msgstr "Auftragsnummer" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_order_release_date +msgid "Order Release Date" +msgstr "Auftragsfreigabe-Datum" + +#. module: mrp_multi_level +#: model:ir.model.fields,help:mrp_multi_level.field_mrp_planned_order_order_release_date +#, fuzzy +#| msgid "Order Release Date" +msgid "Order release date planned by MRP." +msgstr "Auftragsfreigabe-Datum" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move_mrp_origin +msgid "Origin" +msgstr "Ursprung" + +#. module: mrp_multi_level +#: model:product.product,name:mrp_multi_level.product_product_pp_1 +#: model:product.template,name:mrp_multi_level.product_product_pp_1_product_template +#: model:stock.inventory.line,product_name:mrp_multi_level.stock_inventory_line_1 +msgid "PP-1" +msgstr "PP-1" + +#. module: mrp_multi_level +#: model:product.product,name:mrp_multi_level.product_product_pp_2 +#: model:product.template,name:mrp_multi_level.product_product_pp_2_product_template +#: model:stock.inventory.line,product_name:mrp_multi_level.stock_inventory_line_2 +msgid "PP-2" +msgstr "PP-2" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move_parent_product_id +msgid "Parent Product" +msgstr "Übergeordnetes Produkt" + +#. module: mrp_multi_level +#: selection:mrp.move,state:0 +msgid "Partially Available" +msgstr "Teilweise verfügbar" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_running_availability +msgid "Planned Availability" +msgstr "Geplante Verfügbarkeit" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_item_date_planned +msgid "Planned Date" +msgstr "Geplantes Datum" + +#. module: mrp_multi_level +#: model:ir.model,name:mrp_multi_level.model_mrp_planned_order +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_planned_order_ids +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_item_planned_order_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_planned_order_ids +msgid "Planned Order" +msgstr "Geplanter Auftrag" + +#. module: mrp_multi_level +#: model:ir.ui.view,arch_db:mrp_multi_level.product_mrp_area_form +msgid "Planned Orders" +msgstr "Geplante Aufträge" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move_planned_order_up_ids +#, fuzzy +#| msgid "Purchase Orders" +msgid "Planned Orders UP" +msgstr "Einkaufsbestellungen" + +#. module: mrp_multi_level +#: model:ir.actions.act_window,name:mrp_multi_level.act_mrp_inventory_procure +msgid "Procure" +msgstr "Beschaffen" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_location_proc_id +msgid "Procure Location" +msgstr "Beschaffungslagerort" + +#. module: mrp_multi_level +#: model:ir.ui.view,arch_db:mrp_multi_level.view_mrp_inventory_procure_wizard +msgid "Procurement Request" +msgstr "Beschaffungsanfrage" + +#. module: mrp_multi_level +#: selection:product.mrp.area,supply_method:0 +msgid "Produce" +msgstr "Produzieren" + +#. module: mrp_multi_level +#: model:ir.model,name:mrp_multi_level.model_product_product +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_item_product_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_product_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move_product_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move_product_mrp_area_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order_product_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order_product_mrp_area_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_product_id +#: model:ir.ui.view,arch_db:mrp_multi_level.mrp_inventory_search +msgid "Product" +msgstr "Produkt" + +#. module: mrp_multi_level +#: model:ir.model,name:mrp_multi_level.model_product_mrp_area +msgid "Product MRP Area" +msgstr "Produkt - Bereich" + +#. module: mrp_multi_level +#: model:ir.actions.act_window,name:mrp_multi_level.product_mrp_area_action +#: model:ir.ui.menu,name:mrp_multi_level.menu_product_mrp_area_parameters +msgid "Product MRP Area Parameters" +msgstr "Produkt-Bereich-Parameter" + +#. module: mrp_multi_level +#: model:ir.ui.view,arch_db:mrp_multi_level.product_mrp_area_form +#: model:ir.ui.view,arch_db:mrp_multi_level.product_mrp_area_search +#: model:ir.ui.view,arch_db:mrp_multi_level.product_mrp_area_tree +msgid "Product MRP Area parameters" +msgstr "Produkt-Bereich-Parameter" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_product_mrp_area_id +msgid "Product Parameters" +msgstr "Produkt-Parameter" + +#. module: mrp_multi_level +#: model:ir.model,name:mrp_multi_level.model_product_template +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_product_tmpl_id +msgid "Product Template" +msgstr "Produktvorlage" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_uom_id +msgid "Product UoM" +msgstr "Produkt ME" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move_purchase_order_id +#: selection:mrp.move,mrp_origin:0 selection:mrp.planned.order,mrp_action:0 +msgid "Purchase Order" +msgstr "Einkaufsbestellung" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move_purchase_line_id +msgid "Purchase Order Line" +msgstr "Bestellpositionen" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_product_purchase_order_line_ids +msgid "Purchase Orders" +msgstr "Einkaufsbestellungen" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_mrp_qty_multiple +msgid "Qty Multiple" +msgstr "Mengenfaktor" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order_qty_released +msgid "Qty Released" +msgstr "Freigegebene Menge" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_item_qty +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order_mrp_qty +msgid "Quantity" +msgstr "Menge" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_qty_available +msgid "Quantity Available" +msgstr "Verfügbare Menge" + +#. module: mrp_multi_level +#: code:addons/mrp_multi_level/wizards/mrp_inventory_procure.py:75 +#, python-format +msgid "Quantity must be positive." +msgstr "Die Menge muss größer als 0 sein." + +#. module: mrp_multi_level +#: selection:mrp.move,state:0 +msgid "Ready" +msgstr "Bereit" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order_order_release_date +msgid "Release Date" +msgstr "Freigabe-Datum" + +#. module: mrp_multi_level +#: model:ir.model.fields,help:mrp_multi_level.field_stock_location_mrp_area_id +msgid "" +"Requirements for a particular MRP area are combined for the purposes of " +"procurement by the MRP." +msgstr "" +"Nachfragen für einen bestimmten MRP-Bereich werden zum Zweck der Beschaffung " +"gruppiert." + +#. module: mrp_multi_level +#: model:ir.actions.act_window,name:mrp_multi_level.action_mrp_multi_level +#: model:ir.ui.view,arch_db:mrp_multi_level.view_run_mrp_multi_level_wizard +msgid "Run MRP" +msgstr "Ressourcenplanung (MRP) ausführen" + +#. module: mrp_multi_level +#: model:ir.ui.menu,name:mrp_multi_level.menu_mrp_multi_level +#: model:ir.ui.view,arch_db:mrp_multi_level.view_run_mrp_multi_level_wizard +msgid "Run MRP Multi Level" +msgstr "Mehrstufige Ressourcenplanung (MRP) ausführen" + +#. module: mrp_multi_level +#: model:product.product,name:mrp_multi_level.product_product_sf_1 +#: model:product.template,name:mrp_multi_level.product_product_sf_1_product_template +msgid "SF-1" +msgstr "SF-1" + +#. module: mrp_multi_level +#: model:product.product,name:mrp_multi_level.product_product_sf_2 +#: model:product.template,name:mrp_multi_level.product_product_sf_2_product_template +#: model:stock.inventory.line,product_name:mrp_multi_level.stock_inventory_line_3 +msgid "SF-2" +msgstr "SF-2" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_mrp_minimum_stock +msgid "Safety Stock" +msgstr "Sicherheitsbestand" + +#. module: mrp_multi_level +#: model:ir.ui.view,arch_db:mrp_multi_level.mrp_inventory_search +msgid "Selection..." +msgstr "Auswahl..." + +#. module: mrp_multi_level +#: selection:mrp.move,state:0 +msgid "Sent" +msgstr "Gesendet" + +#. module: mrp_multi_level +#: model:ir.model.fields,help:mrp_multi_level.field_product_mrp_area_location_proc_id +msgid "" +"Set this if you need to procure from a different locationthan area's " +"location." +msgstr "" +"Setzen Sie hier einen Lagerort, wenn die Beschaffung von einem anderen " +"Lagerort stattfinden soll als im Bereich angegeben." + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_initial_on_hand_qty +msgid "Starting Inventory" +msgstr "Anfangsbestand" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move_state +msgid "State" +msgstr "Status" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move_stock_move_id +msgid "Stock Move" +msgstr "Lagerbewegung" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_main_supplierinfo_id +msgid "Supplier Info" +msgstr "Lieferanten-Information" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_supply_qty +#: selection:mrp.move,mrp_type:0 +msgid "Supply" +msgstr "Liefermenge" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_supply_method +msgid "Supply Method" +msgstr "Liefermethode" + +#. module: mrp_multi_level +#: sql_constraint:product.mrp.area:0 +msgid "The product/MRP Area parameters combination must be unique." +msgstr "Die Kombination der Produkt-/Bereich-Parameter muss einzigartig sein." + +#. module: mrp_multi_level +#: model:ir.model.fields,help:mrp_multi_level.field_mrp_inventory_running_availability +msgid "Theoretical inventory level if all planned orderswere released." +msgstr "" +"Dies ist der theoretische Lagerbestand, wenn alle geplanten Aufträge " +"freigegeben werden." + +#. module: mrp_multi_level +#: selection:mrp.move,state:0 +msgid "To Approve" +msgstr "Genehmigen" + +#. module: mrp_multi_level +#: model:ir.ui.view,arch_db:mrp_multi_level.mrp_inventory_search +msgid "To Procure" +msgstr "Beschaffen" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_to_procure +msgid "To procure" +msgstr "Beschaffen" + +#. module: mrp_multi_level +#: selection:mrp.planned.order,mrp_action:0 +#: selection:product.mrp.area,supply_method:0 +msgid "Transfer" +msgstr "Umbuchen" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_mrp_transit_delay +msgid "Transit Delay" +msgstr "Umbuchungsverzögerung" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move_mrp_type +msgid "Type" +msgstr "Typ" + +#. module: mrp_multi_level +#: selection:product.mrp.area,supply_method:0 +msgid "Undefined" +msgstr "Nicht definiert" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_item_uom_id +msgid "Unit of Measure" +msgstr "Mengeneinheit" + +#. module: mrp_multi_level +#: model:ir.ui.view,arch_db:mrp_multi_level.view_mrp_inventory_procure_wizard +msgid "" +"Use this assistant to procure for this product and date.\n" +" According to the product configuration,\n" +" this may trigger a draft purchase order, a " +"manufacturing\n" +" order or a transfer picking." +msgstr "" +"Verwenden Sie diesen Assistenten zur Beschaffung des Produktes und des " +"Datums.\n" +"Abhängig von der Produktkonfiguration wird entweder eine Einkaufsbestellung, " +"ein Fertigungsauftrag oder ein Lieferschein im Entwurf erstellt." + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_mrp_verified +msgid "Verified for MRP" +msgstr "für MRP verifiziert" + +#. module: mrp_multi_level +#: selection:mrp.move,state:0 +msgid "Waiting" +msgstr "Wartend" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_area_warehouse_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_item_warehouse_id +msgid "Warehouse" +msgstr "Lager" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_item_wiz_id +msgid "Wizard" +msgstr "Assistent" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_area_calendar_id +msgid "Working Hours" +msgstr "Arbeitsstunden" + +#. module: mrp_multi_level +#: code:addons/mrp_multi_level/models/product_mrp_area.py:124 +#, python-format +msgid "You cannot use a negative number." +msgstr "Es darf keine negative Zahl angegeben werden." + +#. module: mrp_multi_level +#: model:ir.model,name:mrp_multi_level.model_mrp_area +msgid "mrp.area" +msgstr "mrp.area" + +#. module: mrp_multi_level +#: model:ir.model,name:mrp_multi_level.model_mrp_inventory_procure_item +msgid "mrp.inventory.procure.item" +msgstr "mrp.inventory.procure.item" + +#. module: mrp_multi_level +#: model:ir.model,name:mrp_multi_level.model_mrp_move +msgid "mrp.move" +msgstr "mrp.move" + +#. module: mrp_multi_level +#: model:ir.model,name:mrp_multi_level.model_mrp_multi_level +msgid "mrp.multi.level" +msgstr "mrp.multi.level" + +#. module: mrp_multi_level +#: model:ir.ui.view,arch_db:mrp_multi_level.view_run_mrp_multi_level_wizard +msgid "or" +msgstr "oder" + +#~ msgid "" +#~ "Average delay in days to produce this product. In the case of multi-level " +#~ "BOM, the manufacturing lead times of the components will be added." +#~ msgstr "" +#~ "Durchschnittliche Dauer für die Produktion des Produktes. Im Fall einer " +#~ "mehrstufigen Stückliste wird die Fertigungsdurchlaufzeit der Komponenten " +#~ "addiert." + +#~ msgid "MRP Action Date" +#~ msgstr "Aktionsdatum" + +#~ msgid "MRP Move UP" +#~ msgstr "nach oben verschieben" + +#~ msgid "Minimum Stock" +#~ msgstr "Mindestbestand" + +#~ msgid "Processed" +#~ msgstr "Bearbeitet" + +#~ msgid "" +#~ "Current quantity of products.\n" +#~ "In a context with a single Stock Location, this includes goods stored at " +#~ "this Location, or any of its children.\n" +#~ "In a context with a single Warehouse, this includes goods stored in the " +#~ "Stock Location of this Warehouse, or any of its children.\n" +#~ "stored in the Stock Location of the Warehouse of this Shop, or any of its " +#~ "children.\n" +#~ "Otherwise, this includes goods stored in any Stock Location with " +#~ "'internal' type." +#~ msgstr "" +#~ "Aktuelle Menge der Produkte\n" +#~ "Im Kontext eines einzelnen Lagerortes enthält der Wert die Waren, die auf " +#~ "diesem Lagerort und all seiner Unterlagerorte liegen.\n" +#~ "Im Kontext eines einzelnen Lagers enthält der Wert die Waren, die auf dem " +#~ "Lagerort dieses Lagers und all seiner Unterlagerorte liegen.\n" +#~ "Ansonsten enthält der Wert alle Waren von alĺen 'internen' Lagerorten." + +#~ msgid "MRP Product" +#~ msgstr "Produkt" + +#~ msgid "MRP Product data" +#~ msgstr "Produktdaten" + +#~ msgid "MRP Products" +#~ msgstr "Produkte" + +#~ msgid "MRP Qty Available" +#~ msgstr "Verfügbare Menge (MRP)" + +#~ msgid "MRP Verified" +#~ msgstr "für MRP verifiziert" + +#~ msgid "Manufacture Actions" +#~ msgstr "Fertigungsaktionen" + +#~ msgid "Moves" +#~ msgstr "Lagerbewegungen" + +#~ msgid "Nbr Actions" +#~ msgstr "# Aktionen" + +#~ msgid "Nbr Actions 4 Weeks" +#~ msgstr "# Aktionen (4 Wochen)" + +#~ msgid "Purchase Actions" +#~ msgstr "Einkaufsaktionen" + +#~ msgid "Search Product" +#~ msgstr "Produkt suchen" + +#~ msgid "With Actions" +#~ msgstr "Mit Aktionen" + +#~ msgid "With Actions in Coming 4 Weeks" +#~ msgstr "Mit Aktionen in den kommenden 4 Wochen" + +#~ msgid "With Moves" +#~ msgstr "Mit Lagerbewegungen" + +#~ msgid "mrp.product" +#~ msgstr "mrp.product" diff --git a/mrp_multi_level/i18n/es.po b/mrp_multi_level/i18n/es.po new file mode 100644 index 000000000..03c155aec --- /dev/null +++ b/mrp_multi_level/i18n/es.po @@ -0,0 +1,945 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * mrp_multi_level +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 11.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2018-08-25 15:00+0000\n" +"Last-Translator: Lois Rilo \n" +"Language-Team: none\n" +"Language: es\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.1.1\n" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order_mrp_action +msgid "Action" +msgstr "Acción" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_area_active +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_active +msgid "Active" +msgstr "Activo" + +#. module: mrp_multi_level +#: selection:mrp.move,state:0 +msgid "Approved" +msgstr "Aprobado" + +#. module: mrp_multi_level +#: model:ir.ui.view,arch_db:mrp_multi_level.product_mrp_area_search +msgid "Archived" +msgstr "" + +#. module: mrp_multi_level +#: selection:mrp.move,state:0 +msgid "Assigned" +msgstr "Asignado" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order_mrp_inventory_id +#, fuzzy +#| msgid "Forecasted Inventory" +msgid "Associated MRP Inventory" +msgstr "Previsión de stock" + +#. module: mrp_multi_level +#: selection:product.mrp.area,supply_method:0 +msgid "Buy" +msgstr "Comprar" + +#. module: mrp_multi_level +#: model:ir.ui.view,arch_db:mrp_multi_level.view_mrp_inventory_procure_wizard +#: model:ir.ui.view,arch_db:mrp_multi_level.view_run_mrp_multi_level_wizard +msgid "Cancel" +msgstr "Cancelar" + +#. module: mrp_multi_level +#: model:res.groups,name:mrp_multi_level.group_change_mrp_procure_qty +msgid "Change procure quantity in MRP" +msgstr "Cambiar la cantidad de reaprovisionamiento de MRP" + +#. module: mrp_multi_level +#: selection:mrp.move,state:0 +msgid "Confirmed" +msgstr "Confirmado" + +#. module: mrp_multi_level +#: model:ir.ui.view,arch_db:mrp_multi_level.mrp_inventory_tree +msgid "Create Procurement" +msgstr "Crear Aprovisionamiento" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_area_create_uid +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_create_uid +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_create_uid +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_item_create_uid +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move_create_uid +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_multi_level_create_uid +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order_create_uid +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_create_uid +msgid "Created by" +msgstr "Creado por" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_area_create_date +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_create_date +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_create_date +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_item_create_date +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move_create_date +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_multi_level_create_date +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order_create_date +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_create_date +msgid "Created on" +msgstr "Creado en" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move_current_date +msgid "Current Date" +msgstr "Fecha actual" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move_current_qty +msgid "Current Qty" +msgstr "Ctd. actual" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_date +msgid "Date" +msgstr "Fecha" + +#. module: mrp_multi_level +#: model:ir.model.fields,help:mrp_multi_level.field_mrp_planned_order_due_date +msgid "Date in which the supply must have been completed." +msgstr "" + +#. module: mrp_multi_level +#: model:ir.ui.view,arch_db:mrp_multi_level.mrp_inventory_search +msgid "Date to Procure (By Day)" +msgstr "Fecha para reaprovisionar (por día)" + +#. module: mrp_multi_level +#: model:ir.ui.view,arch_db:mrp_multi_level.mrp_inventory_search +msgid "Date to Procure (By Month)" +msgstr "Fecha para reaprovisionar (por mes)" + +#. module: mrp_multi_level +#: model:ir.ui.view,arch_db:mrp_multi_level.mrp_inventory_search +msgid "Date to Procure (By Week)" +msgstr "Fecha para reaprovisionar (por semana)" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_demand_qty +#: selection:mrp.move,mrp_type:0 +msgid "Demand" +msgstr "Demanda" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move_name +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order_name +msgid "Description" +msgstr "Descripción" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_area_display_name +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_display_name +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_display_name +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_item_display_name +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move_display_name +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_multi_level_display_name +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order_display_name +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_display_name +msgid "Display Name" +msgstr "Nombre de Visualización" + +#. module: mrp_multi_level +#: selection:mrp.move,state:0 +msgid "Draft" +msgstr "Borrador" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order_due_date +#, fuzzy +#| msgid "Current Date" +msgid "Due Date" +msgstr "Fecha actual" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_mrp_exclude +msgid "Exclude from MRP" +msgstr "Excluir del MRP" + +#. module: mrp_multi_level +#: model:ir.ui.view,arch_db:mrp_multi_level.view_mrp_inventory_procure_wizard +msgid "Execute" +msgstr "Ejecutar" + +#. module: mrp_multi_level +#: model:product.product,name:mrp_multi_level.product_product_fp_1 +#: model:product.template,name:mrp_multi_level.product_product_fp_1_product_template +msgid "FP-1" +msgstr "FP-1" + +#. module: mrp_multi_level +#: model:product.product,name:mrp_multi_level.product_product_fp_2 +#: model:product.template,name:mrp_multi_level.product_product_fp_2_product_template +msgid "FP-2" +msgstr "FP-2" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order_fixed +msgid "Fixed" +msgstr "" + +#. module: mrp_multi_level +#: selection:mrp.move,mrp_origin:0 +msgid "Forecast" +msgstr "Previsión" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_final_on_hand_qty +msgid "Forecasted Inventory" +msgstr "Previsión de stock" + +#. module: mrp_multi_level +#: model:ir.ui.view,arch_db:mrp_multi_level.mrp_inventory_search +msgid "Group By..." +msgstr "Agrupar por..." + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_group_estimate_days +msgid "Group Days of Estimates" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_area_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_item_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_multi_level_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_id +msgid "ID" +msgstr "ID" + +#. module: mrp_multi_level +#: model:ir.model.fields,help:mrp_multi_level.field_product_mrp_area_mrp_verified +msgid "Identifies that this product has been verified to be valid for the MRP." +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,help:mrp_multi_level.field_mrp_multi_level_mrp_area_ids +msgid "If empty, all areas will be computed." +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_mrp_inspection_delay +msgid "Inspection Delay" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model,name:mrp_multi_level.model_stock_location +msgid "Inventory Locations" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_item_ids +#: model:ir.ui.view,arch_db:mrp_multi_level.view_mrp_inventory_procure_wizard +msgid "Items" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_area___last_update +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory___last_update +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure___last_update +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_item___last_update +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move___last_update +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_multi_level___last_update +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order___last_update +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area___last_update +msgid "Last Modified on" +msgstr "Última Modificación en" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_area_write_uid +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_item_write_uid +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_write_uid +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_write_uid +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move_write_uid +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_multi_level_write_uid +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order_write_uid +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_write_uid +msgid "Last Updated by" +msgstr "Última Modificación por" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_area_write_date +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_item_write_date +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_write_date +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_write_date +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move_write_date +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_multi_level_write_date +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order_write_date +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_write_date +msgid "Last Updated on" +msgstr "Última Actualización en" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_mrp_lead_time +msgid "Lead Time" +msgstr "Plazo de Entrega" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_area_location_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_item_location_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_location_id +msgid "Location" +msgstr "Ubicación" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_product_llc +msgid "Low Level Code" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.ui.menu,name:mrp_multi_level.menu_mrp_mrp +#: selection:mrp.move,mrp_origin:0 +#: model:product.category,name:mrp_multi_level.product_category_mrp +msgid "MRP" +msgstr "MRP" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_mrp_applicable +msgid "MRP Applicable" +msgstr "Aplicable a MRP" + +#. module: mrp_multi_level +#: model:ir.actions.act_window,name:mrp_multi_level.mrp_area_action +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_mrp_area_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move_mrp_area_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order_mrp_area_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_stock_location_mrp_area_id +#: model:ir.ui.view,arch_db:mrp_multi_level.mrp_area_form +#: model:ir.ui.view,arch_db:mrp_multi_level.mrp_area_tree +#: model:ir.ui.view,arch_db:mrp_multi_level.mrp_inventory_search +msgid "MRP Area" +msgstr "Area MRP" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_product_mrp_area_count +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_template_mrp_area_count +msgid "MRP Area Parameter Count" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_product_mrp_area_ids +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_template_mrp_area_ids +#, fuzzy +msgid "MRP Area parameters" +msgstr "Areas MRP" + +#. module: mrp_multi_level +#: model:ir.ui.menu,name:mrp_multi_level.menu_mrp_areas +#: model:ir.ui.view,arch_db:mrp_multi_level.product_template_only_form_view_mrp +#: model:ir.ui.view,arch_db:mrp_multi_level.view_mrp_product_product_form +msgid "MRP Areas" +msgstr "Areas MRP" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_multi_level_mrp_area_ids +#, fuzzy +#| msgid "MRP Areas" +msgid "MRP Areas to run" +msgstr "Areas MRP" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move_mrp_date +msgid "MRP Date" +msgstr "Fecha MRP" + +#. module: mrp_multi_level +#: model:ir.actions.act_window,name:mrp_multi_level.mrp_inventory_action +#: model:ir.ui.menu,name:mrp_multi_level.menu_mrp_inventory +#: model:ir.ui.view,arch_db:mrp_multi_level.mrp_inventory_form +#: model:ir.ui.view,arch_db:mrp_multi_level.mrp_inventory_search +#: model:ir.ui.view,arch_db:mrp_multi_level.mrp_inventory_tree +#: model:ir.ui.view,arch_db:mrp_multi_level.view_mrp_inventory_graph +#: model:ir.ui.view,arch_db:mrp_multi_level.view_mrp_inventory_pivot +msgid "MRP Inventory" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order_mrp_move_down_ids +msgid "MRP Move DOWN" +msgstr "Movimiento Abajo MRP" + +#. module: mrp_multi_level +#: model:ir.ui.view,arch_db:mrp_multi_level.product_mrp_area_form +msgid "MRP Moves" +msgstr "Movimientos MRP" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move_mrp_qty +msgid "MRP Quantity" +msgstr "Ctd. MRP" + +#. module: mrp_multi_level +#: model:ir.model,name:mrp_multi_level.model_mrp_inventory +msgid "MRP inventory projections" +msgstr "Proyección de Stock MRP" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_main_supplier_id +msgid "Main Supplier" +msgstr "Proveedor Principal" + +#. module: mrp_multi_level +#: model:ir.model,name:mrp_multi_level.model_mrp_inventory_procure +msgid "Make Procurements from MRP inventory projections" +msgstr "Crear Aprovisionamiento desde Proyecciones de Stock MRP" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move_production_id +#: selection:mrp.move,mrp_origin:0 selection:mrp.planned.order,mrp_action:0 +msgid "Manufacturing Order" +msgstr "Order de Fabricación" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_product_manufacturing_order_ids +msgid "Manufacturing Orders" +msgstr "Órdenes de Fabricación" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_mrp_maximum_order_qty +msgid "Maximum Order Qty" +msgstr "Ctd. Máxima de Pedido" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_mrp_minimum_order_qty +msgid "Minimum Order Qty" +msgstr "Ctd. Mínima de Pedido" + +#. module: mrp_multi_level +#: selection:mrp.move,mrp_origin:0 +msgid "Move" +msgstr "Movimiento" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_mrp_area_id +#, fuzzy +msgid "Mrp Area" +msgstr "Area MRP" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_item_mrp_inventory_id +msgid "Mrp Inventory" +msgstr "Stock MRP" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_mrp_move_ids +#, fuzzy +msgid "Mrp Move" +msgstr "Movimientos MRP" + +#. module: mrp_multi_level +#: model:ir.actions.server,name:mrp_multi_level.mrp_multi_level_cron_ir_actions_server +#: model:ir.cron,cron_name:mrp_multi_level.mrp_multi_level_cron +#: model:ir.cron,name:mrp_multi_level.mrp_multi_level_cron +msgid "Multi Level MRP" +msgstr "MRP Multi Nivel" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_area_name +msgid "Name" +msgstr "Nombre" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_mrp_nbr_days +msgid "Nbr. Days" +msgstr "" + +#. module: mrp_multi_level +#: code:addons/mrp_multi_level/wizards/mrp_multi_level.py:156 +#, python-format +msgid "No MRP product found" +msgstr "No se encontró producto MRP" + +#. module: mrp_multi_level +#: selection:mrp.planned.order,mrp_action:0 +msgid "None" +msgstr "Ninguno/a" + +#. module: mrp_multi_level +#: model:ir.model.fields,help:mrp_multi_level.field_product_mrp_area_mrp_nbr_days +msgid "" +"Number of days to group demand for this product during the MRP run, in order " +"to determine the quantity to order." +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move_mrp_order_number +msgid "Order Number" +msgstr "Número de Pedido" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_order_release_date +msgid "Order Release Date" +msgstr "Fecha de Lanzamiento de Orden" + +#. module: mrp_multi_level +#: model:ir.model.fields,help:mrp_multi_level.field_mrp_planned_order_order_release_date +#, fuzzy +#| msgid "Order Release Date" +msgid "Order release date planned by MRP." +msgstr "Fecha de Lanzamiento de Orden" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move_mrp_origin +msgid "Origin" +msgstr "Origen" + +#. module: mrp_multi_level +#: model:product.product,name:mrp_multi_level.product_product_pp_1 +#: model:product.template,name:mrp_multi_level.product_product_pp_1_product_template +#: model:stock.inventory.line,product_name:mrp_multi_level.stock_inventory_line_1 +msgid "PP-1" +msgstr "PP-1" + +#. module: mrp_multi_level +#: model:product.product,name:mrp_multi_level.product_product_pp_2 +#: model:product.template,name:mrp_multi_level.product_product_pp_2_product_template +#: model:stock.inventory.line,product_name:mrp_multi_level.stock_inventory_line_2 +msgid "PP-2" +msgstr "PP-2" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move_parent_product_id +msgid "Parent Product" +msgstr "Producto Padre" + +#. module: mrp_multi_level +#: selection:mrp.move,state:0 +msgid "Partially Available" +msgstr "Parcialmente Disponible" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_running_availability +#, fuzzy +#| msgid "Planned Date" +msgid "Planned Availability" +msgstr "Fecha Planificada" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_item_date_planned +msgid "Planned Date" +msgstr "Fecha Planificada" + +#. module: mrp_multi_level +#: model:ir.model,name:mrp_multi_level.model_mrp_planned_order +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_planned_order_ids +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_item_planned_order_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_planned_order_ids +#, fuzzy +#| msgid "Planned Date" +msgid "Planned Order" +msgstr "Fecha Planificada" + +#. module: mrp_multi_level +#: model:ir.ui.view,arch_db:mrp_multi_level.product_mrp_area_form +#, fuzzy +#| msgid "Planned Date" +msgid "Planned Orders" +msgstr "Fecha Planificada" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move_planned_order_up_ids +#, fuzzy +#| msgid "Purchase Orders" +msgid "Planned Orders UP" +msgstr "Órdenes de Compra" + +#. module: mrp_multi_level +#: model:ir.actions.act_window,name:mrp_multi_level.act_mrp_inventory_procure +msgid "Procure" +msgstr "Abastecer" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_location_proc_id +#, fuzzy +#| msgid "Location" +msgid "Procure Location" +msgstr "Ubicación" + +#. module: mrp_multi_level +#: model:ir.ui.view,arch_db:mrp_multi_level.view_mrp_inventory_procure_wizard +msgid "Procurement Request" +msgstr "Solicitud de Abastecimiento" + +#. module: mrp_multi_level +#: selection:product.mrp.area,supply_method:0 +msgid "Produce" +msgstr "Producir" + +#. module: mrp_multi_level +#: model:ir.model,name:mrp_multi_level.model_product_product +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_item_product_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_product_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move_product_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move_product_mrp_area_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order_product_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order_product_mrp_area_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_product_id +#: model:ir.ui.view,arch_db:mrp_multi_level.mrp_inventory_search +msgid "Product" +msgstr "Producto" + +#. module: mrp_multi_level +#: model:ir.model,name:mrp_multi_level.model_product_mrp_area +#, fuzzy +msgid "Product MRP Area" +msgstr "Area MRP" + +#. module: mrp_multi_level +#: model:ir.actions.act_window,name:mrp_multi_level.product_mrp_area_action +#: model:ir.ui.menu,name:mrp_multi_level.menu_product_mrp_area_parameters +msgid "Product MRP Area Parameters" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.ui.view,arch_db:mrp_multi_level.product_mrp_area_form +#: model:ir.ui.view,arch_db:mrp_multi_level.product_mrp_area_search +#: model:ir.ui.view,arch_db:mrp_multi_level.product_mrp_area_tree +#, fuzzy +msgid "Product MRP Area parameters" +msgstr "Producto Modelo" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_product_mrp_area_id +#, fuzzy +msgid "Product Parameters" +msgstr "Producto Modelo" + +#. module: mrp_multi_level +#: model:ir.model,name:mrp_multi_level.model_product_template +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_product_tmpl_id +msgid "Product Template" +msgstr "Producto Modelo" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_uom_id +msgid "Product UoM" +msgstr "UdM del Producto" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move_purchase_order_id +#: selection:mrp.move,mrp_origin:0 selection:mrp.planned.order,mrp_action:0 +msgid "Purchase Order" +msgstr "Orden de Compra" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move_purchase_line_id +msgid "Purchase Order Line" +msgstr "Línea de Orden de Compra" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_product_purchase_order_line_ids +msgid "Purchase Orders" +msgstr "Órdenes de Compra" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_mrp_qty_multiple +msgid "Qty Multiple" +msgstr "Múltiplo de Cantidad" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order_qty_released +msgid "Qty Released" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_item_qty +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order_mrp_qty +msgid "Quantity" +msgstr "Cantidad" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_qty_available +#, fuzzy +msgid "Quantity Available" +msgstr "Ctd. actual disponible" + +#. module: mrp_multi_level +#: code:addons/mrp_multi_level/wizards/mrp_inventory_procure.py:75 +#, python-format +msgid "Quantity must be positive." +msgstr "La cantidad debe ser positiva." + +#. module: mrp_multi_level +#: selection:mrp.move,state:0 +msgid "Ready" +msgstr "Listo" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order_order_release_date +#, fuzzy +#| msgid "Order Release Date" +msgid "Release Date" +msgstr "Fecha de Lanzamiento de Orden" + +#. module: mrp_multi_level +#: model:ir.model.fields,help:mrp_multi_level.field_stock_location_mrp_area_id +msgid "" +"Requirements for a particular MRP area are combined for the purposes of " +"procurement by the MRP." +msgstr "" + +#. module: mrp_multi_level +#: model:ir.actions.act_window,name:mrp_multi_level.action_mrp_multi_level +#: model:ir.ui.view,arch_db:mrp_multi_level.view_run_mrp_multi_level_wizard +msgid "Run MRP" +msgstr "Ejecutar MRP" + +#. module: mrp_multi_level +#: model:ir.ui.menu,name:mrp_multi_level.menu_mrp_multi_level +#: model:ir.ui.view,arch_db:mrp_multi_level.view_run_mrp_multi_level_wizard +msgid "Run MRP Multi Level" +msgstr "Ejecutar MRP Multi Nivel" + +#. module: mrp_multi_level +#: model:product.product,name:mrp_multi_level.product_product_sf_1 +#: model:product.template,name:mrp_multi_level.product_product_sf_1_product_template +msgid "SF-1" +msgstr "SF-1" + +#. module: mrp_multi_level +#: model:product.product,name:mrp_multi_level.product_product_sf_2 +#: model:product.template,name:mrp_multi_level.product_product_sf_2_product_template +#: model:stock.inventory.line,product_name:mrp_multi_level.stock_inventory_line_3 +msgid "SF-2" +msgstr "SF-2" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_mrp_minimum_stock +msgid "Safety Stock" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.ui.view,arch_db:mrp_multi_level.mrp_inventory_search +msgid "Selection..." +msgstr "Selección..." + +#. module: mrp_multi_level +#: selection:mrp.move,state:0 +msgid "Sent" +msgstr "Enviado" + +#. module: mrp_multi_level +#: model:ir.model.fields,help:mrp_multi_level.field_product_mrp_area_location_proc_id +msgid "" +"Set this if you need to procure from a different locationthan area's " +"location." +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_initial_on_hand_qty +msgid "Starting Inventory" +msgstr "Stock Inicial" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move_state +msgid "State" +msgstr "Estado" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move_stock_move_id +msgid "Stock Move" +msgstr "Movimiento de Stock" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_main_supplierinfo_id +msgid "Supplier Info" +msgstr "Información de Proveedor" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_supply_qty +#: selection:mrp.move,mrp_type:0 +msgid "Supply" +msgstr "Suministro" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_supply_method +msgid "Supply Method" +msgstr "Método de Suministro" + +#. module: mrp_multi_level +#: sql_constraint:product.mrp.area:0 +msgid "The product/MRP Area parameters combination must be unique." +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,help:mrp_multi_level.field_mrp_inventory_running_availability +msgid "Theoretical inventory level if all planned orderswere released." +msgstr "" + +#. module: mrp_multi_level +#: selection:mrp.move,state:0 +msgid "To Approve" +msgstr "Por Aprobar" + +#. module: mrp_multi_level +#: model:ir.ui.view,arch_db:mrp_multi_level.mrp_inventory_search +msgid "To Procure" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_to_procure +msgid "To procure" +msgstr "" + +#. module: mrp_multi_level +#: selection:mrp.planned.order,mrp_action:0 +#: selection:product.mrp.area,supply_method:0 +msgid "Transfer" +msgstr "Transfer" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_mrp_transit_delay +msgid "Transit Delay" +msgstr "Retraso de Tránsito" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move_mrp_type +msgid "Type" +msgstr "Tipo" + +#. module: mrp_multi_level +#: selection:product.mrp.area,supply_method:0 +msgid "Undefined" +msgstr "Indefinido" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_item_uom_id +msgid "Unit of Measure" +msgstr "Unidad de Medida" + +#. module: mrp_multi_level +#: model:ir.ui.view,arch_db:mrp_multi_level.view_mrp_inventory_procure_wizard +msgid "" +"Use this assistant to procure for this product and date.\n" +" According to the product configuration,\n" +" this may trigger a draft purchase order, a " +"manufacturing\n" +" order or a transfer picking." +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area_mrp_verified +msgid "Verified for MRP" +msgstr "Verificado para MRP" + +#. module: mrp_multi_level +#: selection:mrp.move,state:0 +msgid "Waiting" +msgstr "Esperando" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_area_warehouse_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_item_warehouse_id +msgid "Warehouse" +msgstr "Almacén" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_item_wiz_id +msgid "Wizard" +msgstr "Asistente" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_area_calendar_id +msgid "Working Hours" +msgstr "Horario de Trabajo" + +#. module: mrp_multi_level +#: code:addons/mrp_multi_level/models/product_mrp_area.py:124 +#, python-format +msgid "You cannot use a negative number." +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model,name:mrp_multi_level.model_mrp_area +msgid "mrp.area" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model,name:mrp_multi_level.model_mrp_inventory_procure_item +msgid "mrp.inventory.procure.item" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model,name:mrp_multi_level.model_mrp_move +msgid "mrp.move" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model,name:mrp_multi_level.model_mrp_multi_level +msgid "mrp.multi.level" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.ui.view,arch_db:mrp_multi_level.view_run_mrp_multi_level_wizard +msgid "or" +msgstr "o" + +#~ msgid "MRP Action Date" +#~ msgstr "Fecha de acción MRP" + +#~ msgid "MRP Move UP" +#~ msgstr "Movimiento Arriba MRP" + +#~ msgid "Minimum Stock" +#~ msgstr "Stock Mínimo" + +#~ msgid "Processed" +#~ msgstr "Procesado" + +#~ msgid "MRP Product" +#~ msgstr "Producto MRP" + +#~ msgid "MRP Product data" +#~ msgstr "Datos Producto MRP" + +#~ msgid "MRP Products" +#~ msgstr "Productos MRP" + +#~ msgid "MRP Qty Available" +#~ msgstr "Ctd. Disponible MRP" + +#~ msgid "MRP Verified" +#~ msgstr "Verificado para MRP" + +#~ msgid "Manufacture Actions" +#~ msgstr "Acciones de Fabricación" + +#~ msgid "Moves" +#~ msgstr "Movimientos" + +#~ msgid "Purchase Actions" +#~ msgstr "Acciones de Compra" + +#~ msgid "Search Product" +#~ msgstr "Buscar Producto" + +#~ msgid "With Actions" +#~ msgstr "Con Acciones" + +#~ msgid "With Actions in Coming 4 Weeks" +#~ msgstr "Con Acciones en las Próximas 4 Semanas" + +#~ msgid "With Moves" +#~ msgstr "Con Movimientos" diff --git a/mrp_multi_level/i18n/mrp_multi_level.pot b/mrp_multi_level/i18n/mrp_multi_level.pot new file mode 100644 index 000000000..299bcd7be --- /dev/null +++ b/mrp_multi_level/i18n/mrp_multi_level.pot @@ -0,0 +1,908 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * mrp_multi_level +# +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_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order__mrp_action +msgid "Action" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_area__active +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area__active +msgid "Active" +msgstr "" + +#. module: mrp_multi_level +#: selection:mrp.move,state:0 +msgid "Approved" +msgstr "" + +#. module: mrp_multi_level +#: model_terms:ir.ui.view,arch_db:mrp_multi_level.product_mrp_area_search +msgid "Archived" +msgstr "" + +#. module: mrp_multi_level +#: selection:mrp.move,state:0 +msgid "Assigned" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order__mrp_inventory_id +msgid "Associated MRP Inventory" +msgstr "" + +#. module: mrp_multi_level +#: selection:product.mrp.area,supply_method:0 +msgid "Buy" +msgstr "" + +#. module: mrp_multi_level +#: model_terms:ir.ui.view,arch_db:mrp_multi_level.view_mrp_inventory_procure_wizard +#: model_terms:ir.ui.view,arch_db:mrp_multi_level.view_run_mrp_multi_level_wizard +msgid "Cancel" +msgstr "" + +#. module: mrp_multi_level +#: model:res.groups,name:mrp_multi_level.group_change_mrp_procure_qty +msgid "Change procure quantity in MRP" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_area__company_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory__company_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move__company_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order__company_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area__company_id +msgid "Company" +msgstr "" + +#. module: mrp_multi_level +#: selection:mrp.move,state:0 +msgid "Confirmed" +msgstr "" + +#. module: mrp_multi_level +#: model_terms:ir.ui.view,arch_db:mrp_multi_level.mrp_inventory_tree +msgid "Create Procurement" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_area__create_uid +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory__create_uid +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure__create_uid +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_item__create_uid +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move__create_uid +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_multi_level__create_uid +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order__create_uid +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area__create_uid +msgid "Created by" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_area__create_date +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory__create_date +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure__create_date +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_item__create_date +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move__create_date +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_multi_level__create_date +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order__create_date +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area__create_date +msgid "Created on" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move__current_date +msgid "Current Date" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move__current_qty +msgid "Current Qty" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory__date +msgid "Date" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,help:mrp_multi_level.field_mrp_planned_order__due_date +msgid "Date in which the supply must have been completed." +msgstr "" + +#. module: mrp_multi_level +#: model_terms:ir.ui.view,arch_db:mrp_multi_level.mrp_inventory_search +msgid "Date to Procure (By Day)" +msgstr "" + +#. module: mrp_multi_level +#: model_terms:ir.ui.view,arch_db:mrp_multi_level.mrp_inventory_search +msgid "Date to Procure (By Month)" +msgstr "" + +#. module: mrp_multi_level +#: model_terms:ir.ui.view,arch_db:mrp_multi_level.mrp_inventory_search +msgid "Date to Procure (By Week)" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory__demand_qty +#: selection:mrp.move,mrp_type:0 +msgid "Demand" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move__name +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order__name +msgid "Description" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_area__display_name +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory__display_name +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure__display_name +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_item__display_name +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move__display_name +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_multi_level__display_name +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order__display_name +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area__display_name +msgid "Display Name" +msgstr "" + +#. module: mrp_multi_level +#: selection:mrp.move,state:0 +msgid "Draft" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order__due_date +msgid "Due Date" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area__mrp_exclude +msgid "Exclude from MRP" +msgstr "" + +#. module: mrp_multi_level +#: model_terms:ir.ui.view,arch_db:mrp_multi_level.view_mrp_inventory_procure_wizard +msgid "Execute" +msgstr "" + +#. module: mrp_multi_level +#: model:product.product,name:mrp_multi_level.product_product_fp_1 +#: model:product.template,name:mrp_multi_level.product_product_fp_1_product_template +msgid "FP-1" +msgstr "" + +#. module: mrp_multi_level +#: model:product.product,name:mrp_multi_level.product_product_fp_2 +#: model:product.template,name:mrp_multi_level.product_product_fp_2_product_template +msgid "FP-2" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order__fixed +msgid "Fixed" +msgstr "" + +#. module: mrp_multi_level +#: selection:mrp.move,mrp_origin:0 +msgid "Forecast" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory__final_on_hand_qty +msgid "Forecasted Inventory" +msgstr "" + +#. module: mrp_multi_level +#: model_terms:ir.ui.view,arch_db:mrp_multi_level.mrp_inventory_search +msgid "Group By..." +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_area__id +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory__id +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure__id +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_item__id +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move__id +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_multi_level__id +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order__id +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area__id +msgid "ID" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,help:mrp_multi_level.field_product_mrp_area__mrp_verified +msgid "Identifies that this product has been verified to be valid for the MRP." +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,help:mrp_multi_level.field_mrp_multi_level__mrp_area_ids +msgid "If empty, all areas will be computed." +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area__mrp_inspection_delay +msgid "Inspection Delay" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model,name:mrp_multi_level.model_stock_location +msgid "Inventory Locations" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure__item_ids +#: model_terms:ir.ui.view,arch_db:mrp_multi_level.view_mrp_inventory_procure_wizard +msgid "Items" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_area____last_update +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory____last_update +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure____last_update +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_item____last_update +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move____last_update +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_multi_level____last_update +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order____last_update +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area____last_update +msgid "Last Modified on" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_area__write_uid +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory__write_uid +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure__write_uid +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_item__write_uid +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move__write_uid +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_multi_level__write_uid +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order__write_uid +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_area__write_date +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory__write_date +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure__write_date +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_item__write_date +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move__write_date +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_multi_level__write_date +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order__write_date +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area__write_date +msgid "Last Updated on" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area__mrp_lead_time +msgid "Lead Time" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_area__location_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_item__location_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area__location_id +msgid "Location" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_product__llc +msgid "Low Level Code" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.ui.menu,name:mrp_multi_level.menu_mrp_mrp +#: selection:mrp.move,mrp_origin:0 +#: model:product.category,name:mrp_multi_level.product_category_mrp +msgid "MRP" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area__mrp_applicable +msgid "MRP Applicable" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.actions.act_window,name:mrp_multi_level.mrp_area_action +#: model:ir.model,name:mrp_multi_level.model_mrp_area +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory__mrp_area_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move__mrp_area_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order__mrp_area_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_stock_location__mrp_area_id +#: model_terms:ir.ui.view,arch_db:mrp_multi_level.mrp_area_form +#: model_terms:ir.ui.view,arch_db:mrp_multi_level.mrp_area_tree +#: model_terms:ir.ui.view,arch_db:mrp_multi_level.mrp_inventory_search +msgid "MRP Area" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_product__mrp_area_count +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_template__mrp_area_count +msgid "MRP Area Parameter Count" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_product__mrp_area_ids +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_template__mrp_area_ids +msgid "MRP Area parameters" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.ui.menu,name:mrp_multi_level.menu_mrp_areas +#: model_terms:ir.ui.view,arch_db:mrp_multi_level.product_template_only_form_view_mrp +#: model_terms:ir.ui.view,arch_db:mrp_multi_level.view_mrp_product_product_form +msgid "MRP Areas" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_multi_level__mrp_area_ids +msgid "MRP Areas to run" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move__mrp_date +msgid "MRP Date" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.actions.act_window,name:mrp_multi_level.mrp_inventory_action +#: model:ir.ui.menu,name:mrp_multi_level.menu_mrp_inventory +#: model_terms:ir.ui.view,arch_db:mrp_multi_level.mrp_inventory_form +#: model_terms:ir.ui.view,arch_db:mrp_multi_level.mrp_inventory_search +#: model_terms:ir.ui.view,arch_db:mrp_multi_level.mrp_inventory_tree +#: model_terms:ir.ui.view,arch_db:mrp_multi_level.view_mrp_inventory_graph +#: model_terms:ir.ui.view,arch_db:mrp_multi_level.view_mrp_inventory_pivot +msgid "MRP Inventory" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model,name:mrp_multi_level.model_mrp_inventory_procure_item +msgid "MRP Inventory procure item" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model,name:mrp_multi_level.model_mrp_move +msgid "MRP Move" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order__mrp_move_down_ids +msgid "MRP Move DOWN" +msgstr "" + +#. module: mrp_multi_level +#: model_terms:ir.ui.view,arch_db:mrp_multi_level.product_mrp_area_form +msgid "MRP Moves" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move__mrp_qty +msgid "MRP Quantity" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model,name:mrp_multi_level.model_mrp_inventory +msgid "MRP inventory projections" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area__main_supplier_id +msgid "Main Supplier" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model,name:mrp_multi_level.model_mrp_inventory_procure +msgid "Make Procurements from MRP inventory projections" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move__production_id +#: selection:mrp.move,mrp_origin:0 +#: selection:mrp.planned.order,mrp_action:0 +msgid "Manufacturing Order" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_product__manufacturing_order_ids +msgid "Manufacturing Orders" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area__mrp_maximum_order_qty +msgid "Maximum Order Qty" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area__mrp_minimum_order_qty +msgid "Minimum Order Qty" +msgstr "" + +#. module: mrp_multi_level +#: selection:mrp.move,mrp_origin:0 +msgid "Move" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area__mrp_area_id +msgid "Mrp Area" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_item__mrp_inventory_id +msgid "Mrp Inventory" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area__mrp_move_ids +msgid "Mrp Move" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.actions.server,name:mrp_multi_level.mrp_multi_level_cron_ir_actions_server +#: model:ir.cron,cron_name:mrp_multi_level.mrp_multi_level_cron +#: model:ir.cron,name:mrp_multi_level.mrp_multi_level_cron +#: model:ir.model,name:mrp_multi_level.model_mrp_multi_level +msgid "Multi Level MRP" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_area__name +msgid "Name" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area__mrp_nbr_days +msgid "Nbr. Days" +msgstr "" + +#. module: mrp_multi_level +#: code:addons/mrp_multi_level/wizards/mrp_multi_level.py:121 +#, python-format +msgid "No MRP product found" +msgstr "" + +#. module: mrp_multi_level +#: selection:mrp.planned.order,mrp_action:0 +msgid "None" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,help:mrp_multi_level.field_product_mrp_area__mrp_nbr_days +msgid "Number of days to group demand for this product during the MRP run, in order to determine the quantity to order." +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move__mrp_order_number +msgid "Order Number" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory__order_release_date +msgid "Order Release Date" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,help:mrp_multi_level.field_mrp_planned_order__order_release_date +msgid "Order release date planned by MRP." +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move__mrp_origin +msgid "Origin" +msgstr "" + +#. module: mrp_multi_level +#: model:product.product,name:mrp_multi_level.product_product_pp_1 +#: model:product.template,name:mrp_multi_level.product_product_pp_1_product_template +msgid "PP-1" +msgstr "" + +#. module: mrp_multi_level +#: model:product.product,name:mrp_multi_level.product_product_pp_2 +#: model:product.template,name:mrp_multi_level.product_product_pp_2_product_template +msgid "PP-2" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move__parent_product_id +msgid "Parent Product" +msgstr "" + +#. module: mrp_multi_level +#: selection:mrp.move,state:0 +msgid "Partially Available" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory__running_availability +msgid "Planned Availability" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_item__date_planned +msgid "Planned Date" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model,name:mrp_multi_level.model_mrp_planned_order +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory__planned_order_ids +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_item__planned_order_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area__planned_order_ids +msgid "Planned Order" +msgstr "" + +#. module: mrp_multi_level +#: model_terms:ir.ui.view,arch_db:mrp_multi_level.product_mrp_area_form +msgid "Planned Orders" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move__planned_order_up_ids +msgid "Planned Orders UP" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.actions.act_window,name:mrp_multi_level.act_mrp_inventory_procure +msgid "Procure" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area__location_proc_id +msgid "Procure Location" +msgstr "" + +#. module: mrp_multi_level +#: model_terms:ir.ui.view,arch_db:mrp_multi_level.view_mrp_inventory_procure_wizard +msgid "Procurement Request" +msgstr "" + +#. module: mrp_multi_level +#: selection:product.mrp.area,supply_method:0 +msgid "Produce" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model,name:mrp_multi_level.model_product_product +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory__product_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_item__product_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move__product_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order__product_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area__product_id +#: model_terms:ir.ui.view,arch_db:mrp_multi_level.mrp_inventory_search +msgid "Product" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model,name:mrp_multi_level.model_product_mrp_area +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move__product_mrp_area_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order__product_mrp_area_id +msgid "Product MRP Area" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.actions.act_window,name:mrp_multi_level.product_mrp_area_action +#: model:ir.ui.menu,name:mrp_multi_level.menu_product_mrp_area_parameters +msgid "Product MRP Area Parameters" +msgstr "" + +#. module: mrp_multi_level +#: model_terms:ir.ui.view,arch_db:mrp_multi_level.product_mrp_area_form +#: model_terms:ir.ui.view,arch_db:mrp_multi_level.product_mrp_area_search +#: model_terms:ir.ui.view,arch_db:mrp_multi_level.product_mrp_area_tree +msgid "Product MRP Area parameters" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory__product_mrp_area_id +msgid "Product Parameters" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model,name:mrp_multi_level.model_product_template +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area__product_tmpl_id +msgid "Product Template" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory__uom_id +msgid "Product UoM" +msgstr "" + +#. module: mrp_multi_level +#: selection:mrp.planned.order,mrp_action:0 +#: selection:product.mrp.area,supply_method:0 +msgid "Pull & Push" +msgstr "" + +#. module: mrp_multi_level +#: selection:mrp.planned.order,mrp_action:0 +#: selection:product.mrp.area,supply_method:0 +msgid "Pull From" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move__purchase_order_id +#: selection:mrp.move,mrp_origin:0 +#: selection:mrp.planned.order,mrp_action:0 +msgid "Purchase Order" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move__purchase_line_id +msgid "Purchase Order Line" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_product__purchase_order_line_ids +msgid "Purchase Orders" +msgstr "" + +#. module: mrp_multi_level +#: selection:mrp.planned.order,mrp_action:0 +#: selection:product.mrp.area,supply_method:0 +msgid "Push To" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area__mrp_qty_multiple +msgid "Qty Multiple" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order__qty_released +msgid "Qty Released" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_item__qty +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order__mrp_qty +msgid "Quantity" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area__qty_available +msgid "Quantity Available" +msgstr "" + +#. module: mrp_multi_level +#: code:addons/mrp_multi_level/wizards/mrp_inventory_procure.py:75 +#, python-format +msgid "Quantity must be positive." +msgstr "" + +#. module: mrp_multi_level +#: selection:mrp.move,state:0 +msgid "Ready" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_planned_order__order_release_date +msgid "Release Date" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,help:mrp_multi_level.field_stock_location__mrp_area_id +msgid "Requirements for a particular MRP area are combined for the purposes of procurement by the MRP." +msgstr "" + +#. module: mrp_multi_level +#: model:ir.actions.act_window,name:mrp_multi_level.action_mrp_multi_level +#: model_terms:ir.ui.view,arch_db:mrp_multi_level.view_run_mrp_multi_level_wizard +msgid "Run MRP" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.ui.menu,name:mrp_multi_level.menu_mrp_multi_level +#: model_terms:ir.ui.view,arch_db:mrp_multi_level.view_run_mrp_multi_level_wizard +msgid "Run MRP Multi Level" +msgstr "" + +#. module: mrp_multi_level +#: model:product.product,name:mrp_multi_level.product_product_sf_1 +#: model:product.template,name:mrp_multi_level.product_product_sf_1_product_template +msgid "SF-1" +msgstr "" + +#. module: mrp_multi_level +#: model:product.product,name:mrp_multi_level.product_product_sf_2 +#: model:product.template,name:mrp_multi_level.product_product_sf_2_product_template +msgid "SF-2" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area__mrp_minimum_stock +msgid "Safety Stock" +msgstr "" + +#. module: mrp_multi_level +#: model_terms:ir.ui.view,arch_db:mrp_multi_level.mrp_inventory_search +msgid "Selection..." +msgstr "" + +#. module: mrp_multi_level +#: selection:mrp.move,state:0 +msgid "Sent" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,help:mrp_multi_level.field_product_mrp_area__location_proc_id +msgid "Set this if you need to procure from a different locationthan area's location." +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory__initial_on_hand_qty +msgid "Starting Inventory" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move__state +msgid "State" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move__stock_move_id +msgid "Stock Move" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area__main_supplierinfo_id +msgid "Supplier Info" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory__supply_qty +#: selection:mrp.move,mrp_type:0 +msgid "Supply" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area__supply_method +msgid "Supply Method" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,help:mrp_multi_level.field_mrp_area__company_id +#: model:ir.model.fields,help:mrp_multi_level.field_mrp_inventory__company_id +#: model:ir.model.fields,help:mrp_multi_level.field_mrp_move__company_id +#: model:ir.model.fields,help:mrp_multi_level.field_mrp_planned_order__company_id +#: model:ir.model.fields,help:mrp_multi_level.field_product_mrp_area__company_id +msgid "The company is automatically set from your user preferences." +msgstr "" + +#. module: mrp_multi_level +#: sql_constraint:product.mrp.area:0 +msgid "The product/MRP Area parameters combination must be unique." +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,help:mrp_multi_level.field_mrp_inventory__running_availability +msgid "Theoretical inventory level if all planned orderswere released." +msgstr "" + +#. module: mrp_multi_level +#: selection:mrp.move,state:0 +msgid "To Approve" +msgstr "" + +#. module: mrp_multi_level +#: model_terms:ir.ui.view,arch_db:mrp_multi_level.mrp_inventory_search +msgid "To Procure" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory__to_procure +msgid "To procure" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area__mrp_transit_delay +msgid "Transit Delay" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_move__mrp_type +msgid "Type" +msgstr "" + +#. module: mrp_multi_level +#: selection:product.mrp.area,supply_method:0 +msgid "Undefined" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_item__uom_id +msgid "Unit of Measure" +msgstr "" + +#. module: mrp_multi_level +#: model:product.product,uom_name:mrp_multi_level.product_product_fp_1 +#: model:product.product,uom_name:mrp_multi_level.product_product_fp_2 +#: model:product.product,uom_name:mrp_multi_level.product_product_pp_1 +#: model:product.product,uom_name:mrp_multi_level.product_product_pp_2 +#: model:product.product,uom_name:mrp_multi_level.product_product_sf_1 +#: model:product.product,uom_name:mrp_multi_level.product_product_sf_2 +#: model:product.template,uom_name:mrp_multi_level.product_product_fp_1_product_template +#: model:product.template,uom_name:mrp_multi_level.product_product_fp_2_product_template +#: model:product.template,uom_name:mrp_multi_level.product_product_pp_1_product_template +#: model:product.template,uom_name:mrp_multi_level.product_product_pp_2_product_template +#: model:product.template,uom_name:mrp_multi_level.product_product_sf_1_product_template +#: model:product.template,uom_name:mrp_multi_level.product_product_sf_2_product_template +msgid "Unit(s)" +msgstr "" + +#. module: mrp_multi_level +#: model_terms:ir.ui.view,arch_db:mrp_multi_level.view_mrp_inventory_procure_wizard +msgid "Use this assistant to procure for this product and date.\n" +" According to the product configuration,\n" +" this may trigger a draft purchase order, a manufacturing\n" +" order or a transfer picking." +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_product_mrp_area__mrp_verified +msgid "Verified for MRP" +msgstr "" + +#. module: mrp_multi_level +#: selection:mrp.move,state:0 +msgid "Waiting" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_area__warehouse_id +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_item__warehouse_id +msgid "Warehouse" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_inventory_procure_item__wiz_id +msgid "Wizard" +msgstr "" + +#. module: mrp_multi_level +#: model:ir.model.fields,field_description:mrp_multi_level.field_mrp_area__calendar_id +msgid "Working Hours" +msgstr "" + +#. module: mrp_multi_level +#: code:addons/mrp_multi_level/models/product_mrp_area.py:126 +#, python-format +msgid "You cannot use a negative number." +msgstr "" + +#. module: mrp_multi_level +#: model:product.product,weight_uom_name:mrp_multi_level.product_product_fp_1 +#: model:product.product,weight_uom_name:mrp_multi_level.product_product_fp_2 +#: model:product.product,weight_uom_name:mrp_multi_level.product_product_pp_1 +#: model:product.product,weight_uom_name:mrp_multi_level.product_product_pp_2 +#: model:product.product,weight_uom_name:mrp_multi_level.product_product_sf_1 +#: model:product.product,weight_uom_name:mrp_multi_level.product_product_sf_2 +#: model:product.template,weight_uom_name:mrp_multi_level.product_product_fp_1_product_template +#: model:product.template,weight_uom_name:mrp_multi_level.product_product_fp_2_product_template +#: model:product.template,weight_uom_name:mrp_multi_level.product_product_pp_1_product_template +#: model:product.template,weight_uom_name:mrp_multi_level.product_product_pp_2_product_template +#: model:product.template,weight_uom_name:mrp_multi_level.product_product_sf_1_product_template +#: model:product.template,weight_uom_name:mrp_multi_level.product_product_sf_2_product_template +msgid "kg" +msgstr "" + +#. module: mrp_multi_level +#: model_terms:ir.ui.view,arch_db:mrp_multi_level.view_run_mrp_multi_level_wizard +msgid "or" +msgstr "" + diff --git a/mrp_multi_level/migrations/11.0.2.0.0/post-migration.py b/mrp_multi_level/migrations/11.0.2.0.0/post-migration.py new file mode 100644 index 000000000..afd5d1925 --- /dev/null +++ b/mrp_multi_level/migrations/11.0.2.0.0/post-migration.py @@ -0,0 +1,50 @@ +# Copyright 2019 Eficent Business and IT Consulting Services, S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). +import logging +from odoo import api, SUPERUSER_ID + +_logger = logging.getLogger(__name__) + +__name__ = "Upgrade to 11.0.2.0.0" + + +def _migrate_product_to_product_mrp_area(env): + _logger.info("Migrating product parameters to Product MRP Areas") + env.cr.execute(""" + SELECT DISTINCT mrp_area.id, pr.id, pr.mrp_applicable, pr.mrp_exclude, + pr.mrp_inspection_delay, pr.mrp_maximum_order_qty, + pr.mrp_minimum_order_qty, pr.mrp_minimum_stock, pr.mrp_nbr_days, + pr.mrp_qty_multiple, pr.mrp_transit_delay, pr.mrp_verified, pr.active + FROM product_product AS pr + CROSS JOIN mrp_area + LEFT JOIN product_template AS pt + ON pt.id = pr.product_tmpl_id + WHERE pr.mrp_exclude = False + AND pt.type = 'product' + """) + product_mrp_area_model = env['product.mrp.area'] + for mrp_area_id, product_id, mrp_applicable, mrp_exclude,\ + mrp_inspection_delay, mrp_maximum_order_qty, mrp_minimum_order_qty, \ + mrp_minimum_stock, mrp_nbr_days, mrp_qty_multiple, mrp_transit_delay,\ + mrp_verified, active in env.cr.fetchall(): + product_mrp_area_model.create({ + 'mrp_area_id': mrp_area_id, + 'product_id': product_id, + 'mrp_applicable': mrp_applicable, + 'mrp_exclude': mrp_exclude, + 'mrp_inspection_delay': mrp_inspection_delay, + 'mrp_maximum_order_qty': mrp_maximum_order_qty, + 'mrp_minimum_order_qty': mrp_minimum_order_qty, + 'mrp_minimum_stock': mrp_minimum_stock, + 'mrp_nbr_days': mrp_nbr_days, + 'mrp_qty_multiple': mrp_qty_multiple, + 'mrp_transit_delay': mrp_transit_delay, + 'mrp_verified': mrp_verified, + 'active': active, + }) + + +def migrate(cr, version): + with api.Environment.manage(): + env = api.Environment(cr, SUPERUSER_ID, {}) + _migrate_product_to_product_mrp_area(env) diff --git a/mrp_multi_level/models/__init__.py b/mrp_multi_level/models/__init__.py new file mode 100644 index 000000000..486079907 --- /dev/null +++ b/mrp_multi_level/models/__init__.py @@ -0,0 +1,8 @@ +from . import mrp_area +from . import stock_location +from . import product_product +from . import product_template +from . import mrp_move +from . import mrp_planned_order +from . import mrp_inventory +from . import product_mrp_area diff --git a/mrp_multi_level/models/mrp_area.py b/mrp_multi_level/models/mrp_area.py new file mode 100644 index 000000000..b7c426e2d --- /dev/null +++ b/mrp_multi_level/models/mrp_area.py @@ -0,0 +1,39 @@ +# © 2016 Ucamco - Wim Audenaert +# © 2016-19 Eficent Business and IT Consulting Services S.L. +# - Jordi Ballester Alomar +# - Lois Rilo Antelo +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). + +from odoo import api, fields, models + + +class MrpArea(models.Model): + _name = 'mrp.area' + _description = "MRP Area" + + name = fields.Char(required=True) + warehouse_id = fields.Many2one( + comodel_name='stock.warehouse', string='Warehouse', + required=True, + ) + company_id = fields.Many2one( + comodel_name='res.company', + related='warehouse_id.company_id', + store=True, + ) + location_id = fields.Many2one( + comodel_name='stock.location', string='Location', + required=True, + ) + active = fields.Boolean(default=True) + calendar_id = fields.Many2one( + comodel_name='resource.calendar', + string='Working Hours', + related='warehouse_id.calendar_id', + ) + + @api.multi + def _get_locations(self): + self.ensure_one() + return self.env['stock.location'].search([ + ('id', 'child_of', self.location_id.id)]) diff --git a/mrp_multi_level/models/mrp_inventory.py b/mrp_multi_level/models/mrp_inventory.py new file mode 100644 index 000000000..75ae6b023 --- /dev/null +++ b/mrp_multi_level/models/mrp_inventory.py @@ -0,0 +1,102 @@ +# © 2016 Ucamco - Wim Audenaert +# Copyright 2016-19 Eficent Business and IT Consulting Services S.L. +# - Jordi Ballester Alomar +# - Lois Rilo Antelo +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). + +from odoo import api, fields, models + +from datetime import timedelta, date + + +class MrpInventory(models.Model): + _name = 'mrp.inventory' + _order = 'product_mrp_area_id, date' + _description = 'MRP inventory projections' + _rec_name = 'product_mrp_area_id' + + # TODO: name to pass to procurements? + # TODO: compute procurement_date to pass to the wizard? not needed for + # PO at least. Check for MO and moves + + mrp_area_id = fields.Many2one( + comodel_name='mrp.area', string='MRP Area', + related='product_mrp_area_id.mrp_area_id', store=True, + ) + product_mrp_area_id = fields.Many2one( + comodel_name='product.mrp.area', string='Product Parameters', + index=True, + required=True, + ) + company_id = fields.Many2one( + comodel_name='res.company', + related='product_mrp_area_id.mrp_area_id.warehouse_id.company_id', + store=True, + ) + product_id = fields.Many2one( + comodel_name='product.product', + related='product_mrp_area_id.product_id', + store=True, + ) + uom_id = fields.Many2one( + comodel_name='uom.uom', string='Product UoM', + compute='_compute_uom_id', + ) + date = fields.Date(string='Date') + demand_qty = fields.Float(string='Demand') + supply_qty = fields.Float(string='Supply') + initial_on_hand_qty = fields.Float(string='Starting Inventory') + final_on_hand_qty = fields.Float(string='Forecasted Inventory') + to_procure = fields.Float( + string="To procure", + compute="_compute_to_procure", + store=True, + ) + running_availability = fields.Float( + string="Planned Availability", + help="Theoretical inventory level if all planned orders" + "were released.", + ) + order_release_date = fields.Date( + string="Order Release Date", + compute="_compute_order_release_date", + store=True, + ) + planned_order_ids = fields.One2many( + comodel_name="mrp.planned.order", + inverse_name="mrp_inventory_id", + readonly=True, + ) + + @api.multi + def _compute_uom_id(self): + for rec in self: + rec.uom_id = rec.product_mrp_area_id.product_id.uom_id + + @api.depends("planned_order_ids", "planned_order_ids.qty_released") + def _compute_to_procure(self): + for rec in self: + rec.to_procure = sum(rec.planned_order_ids.mapped('mrp_qty')) - \ + sum(rec.planned_order_ids.mapped('qty_released')) + + @api.multi + @api.depends('product_mrp_area_id', + 'product_mrp_area_id.main_supplierinfo_id', + 'product_mrp_area_id.mrp_lead_time', + 'product_mrp_area_id.mrp_area_id.calendar_id') + def _compute_order_release_date(self): + today = date.today() + for rec in self.filtered(lambda r: r.date): + delay = rec.product_mrp_area_id.mrp_lead_time + if delay and rec.mrp_area_id.calendar_id: + dt_date = fields.Datetime.to_datetime(rec.date) + # dt_date is at the beginning of the day (00:00), + # so we can subtract the delay straight forward. + order_release_date = rec.mrp_area_id.calendar_id.plan_days( + -delay, dt_date).date() + else: + order_release_date = fields.Date.from_string( + rec.date) - timedelta(days=delay) + if order_release_date < today: + order_release_date = today + rec.order_release_date = order_release_date diff --git a/mrp_multi_level/models/mrp_move.py b/mrp_multi_level/models/mrp_move.py new file mode 100644 index 000000000..059cd0416 --- /dev/null +++ b/mrp_multi_level/models/mrp_move.py @@ -0,0 +1,94 @@ +# © 2016 Ucamco - Wim Audenaert +# © 2016-18 Eficent Business and IT Consulting Services S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). + +from odoo import models, fields + + +class MrpMove(models.Model): + _name = 'mrp.move' + _description = "MRP Move" + _order = 'product_mrp_area_id, mrp_date, mrp_type desc, id' + + # TODO: too many indexes... + + product_mrp_area_id = fields.Many2one( + comodel_name="product.mrp.area", + string="Product MRP Area", + index=True, + required=True, + ) + mrp_area_id = fields.Many2one( + comodel_name="mrp.area", + related="product_mrp_area_id.mrp_area_id", + string="MRP Area", + store=True, + index=True, + ) + company_id = fields.Many2one( + comodel_name='res.company', + related='product_mrp_area_id.mrp_area_id.warehouse_id.company_id', + store=True, + ) + product_id = fields.Many2one( + comodel_name='product.product', + related='product_mrp_area_id.product_id', + store=True, + ) + + current_date = fields.Date(string='Current Date') + current_qty = fields.Float(string='Current Qty') + mrp_date = fields.Date(string='MRP Date') + planned_order_up_ids = fields.Many2many( + comodel_name="mrp.planned.order", + relation="mrp_move_planned_order_rel", + column1="move_down_id", + column2="order_id", + string="Planned Orders UP", + ) + mrp_order_number = fields.Char(string='Order Number') + mrp_origin = fields.Selection( + selection=[('mo', 'Manufacturing Order'), + ('po', 'Purchase Order'), + ('mv', 'Move'), + ('fc', 'Forecast'), + ('mrp', 'MRP')], + string='Origin') + mrp_qty = fields.Float(string='MRP Quantity') + mrp_type = fields.Selection( + selection=[('s', 'Supply'), ('d', 'Demand')], + string='Type', + ) + name = fields.Char(string='Description') + parent_product_id = fields.Many2one( + comodel_name="product.product", + string="Parent Product", index=True, + ) + production_id = fields.Many2one( + comodel_name='mrp.production', + string='Manufacturing Order', index=True, + ) + purchase_line_id = fields.Many2one( + comodel_name='purchase.order.line', + string='Purchase Order Line', index=True, + ) + purchase_order_id = fields.Many2one( + comodel_name='purchase.order', + string='Purchase Order', index=True, + ) + state = fields.Selection( + selection=[('draft', 'Draft'), + ('assigned', 'Assigned'), + ('confirmed', 'Confirmed'), + ('waiting', 'Waiting'), + ('partially_available', 'Partially Available'), + ('ready', 'Ready'), + ('sent', 'Sent'), + ('to approve', 'To Approve'), + ('approved', 'Approved')], + string='State', + ) + stock_move_id = fields.Many2one( + comodel_name='stock.move', + string='Stock Move', index=True, + ) diff --git a/mrp_multi_level/models/mrp_planned_order.py b/mrp_multi_level/models/mrp_planned_order.py new file mode 100644 index 000000000..9959788c5 --- /dev/null +++ b/mrp_multi_level/models/mrp_planned_order.py @@ -0,0 +1,70 @@ +# Copyright 2019 Eficent Business and IT Consulting Services S.L. +# - Lois Rilo Antelo +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). + +from odoo import models, fields + + +class MrpPlannedOrder(models.Model): + _name = "mrp.planned.order" + _description = "Planned Order" + _order = "due_date, id" + + name = fields.Char(string="Description") + product_mrp_area_id = fields.Many2one( + comodel_name="product.mrp.area", + string="Product MRP Area", + index=True, + required=True, + ) + mrp_area_id = fields.Many2one( + comodel_name="mrp.area", + related="product_mrp_area_id.mrp_area_id", + string="MRP Area", + store=True, + index=True, + readonly=True, + ) + company_id = fields.Many2one( + comodel_name='res.company', + related='product_mrp_area_id.mrp_area_id.warehouse_id.company_id', + store=True, + ) + product_id = fields.Many2one( + comodel_name="product.product", + related="product_mrp_area_id.product_id", + store=True, + readonly=True, + ) + order_release_date = fields.Date( + string="Release Date", + help="Order release date planned by MRP.", + ) + due_date = fields.Date( + string="Due Date", + help="Date in which the supply must have been completed.", + ) + qty_released = fields.Float() + fixed = fields.Boolean() + mrp_qty = fields.Float(string="Quantity") + mrp_move_down_ids = fields.Many2many( + comodel_name="mrp.move", + relation="mrp_move_planned_order_rel", + column1="order_id", + column2="move_down_id", + string="MRP Move DOWN", + ) + mrp_action = fields.Selection( + selection=[("manufacture", "Manufacturing Order"), + ("buy", "Purchase Order"), + ('pull', 'Pull From'), + ('push', 'Push To'), + ('pull_push', 'Pull & Push'), + ("none", "None")], + string="Action", + ) + mrp_inventory_id = fields.Many2one( + string="Associated MRP Inventory", + comodel_name="mrp.inventory", + ondelete="set null", + ) diff --git a/mrp_multi_level/models/product_mrp_area.py b/mrp_multi_level/models/product_mrp_area.py new file mode 100644 index 000000000..792279cb4 --- /dev/null +++ b/mrp_multi_level/models/product_mrp_area.py @@ -0,0 +1,192 @@ +# Copyright 2016 Ucamco - Wim Audenaert +# Copyright 2016-19 Eficent Business and IT Consulting Services S.L. +# - Jordi Ballester Alomar +# - Lois Rilo Antelo +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). + +from math import ceil + +from odoo import api, fields, models, _ +from odoo.exceptions import ValidationError + + +class ProductMRPArea(models.Model): + _name = 'product.mrp.area' + _description = 'Product MRP Area' + + active = fields.Boolean(default=True) + mrp_area_id = fields.Many2one( + comodel_name='mrp.area', + required=True, + ) + company_id = fields.Many2one( + comodel_name='res.company', + related='mrp_area_id.warehouse_id.company_id', + store=True, + ) + product_id = fields.Many2one( + comodel_name='product.product', + required=True, + string='Product', + ) + product_tmpl_id = fields.Many2one( + comodel_name='product.template', + readonly=True, + related='product_id.product_tmpl_id', + store=True, + ) + location_id = fields.Many2one( + related="mrp_area_id.location_id", + ) + location_proc_id = fields.Many2one( + string="Procure Location", + comodel_name="stock.location", + domain="[('location_id', 'child_of', location_id)]", + help="Set this if you need to procure from a different location" + "than area's location.", + ) + # TODO: applicable and exclude... redundant?? + mrp_applicable = fields.Boolean(string='MRP Applicable') + mrp_exclude = fields.Boolean(string='Exclude from MRP') + mrp_inspection_delay = fields.Integer(string='Inspection Delay') + mrp_maximum_order_qty = fields.Float( + string='Maximum Order Qty', default=0.0, + ) + mrp_minimum_order_qty = fields.Float( + string='Minimum Order Qty', default=0.0, + ) + mrp_minimum_stock = fields.Float(string="Safety Stock") + mrp_nbr_days = fields.Integer( + string='Nbr. Days', default=0, + help="Number of days to group demand for this product during the " + "MRP run, in order to determine the quantity to order.", + ) + mrp_qty_multiple = fields.Float(string='Qty Multiple', default=1.00) + mrp_transit_delay = fields.Integer(string='Transit Delay', default=0) + mrp_verified = fields.Boolean( + string='Verified for MRP', + help="Identifies that this product has been verified " + "to be valid for the MRP.", + ) + mrp_lead_time = fields.Float( + string='Lead Time', + compute='_compute_mrp_lead_time', + ) + main_supplier_id = fields.Many2one( + comodel_name='res.partner', string='Main Supplier', + compute='_compute_main_supplier', store=True, + index=True, + ) + main_supplierinfo_id = fields.Many2one( + comodel_name='product.supplierinfo', string='Supplier Info', + compute='_compute_main_supplier', store=True, + ) + supply_method = fields.Selection( + selection=[('buy', 'Buy'), + ('none', 'Undefined'), + ('manufacture', 'Produce'), + ('pull', 'Pull From'), + ('push', 'Push To'), + ('pull_push', 'Pull & Push')], + string='Supply Method', + compute='_compute_supply_method', + ) + qty_available = fields.Float( + string="Quantity Available", + compute="_compute_qty_available", + ) + mrp_move_ids = fields.One2many( + comodel_name='mrp.move', + inverse_name='product_mrp_area_id', + readonly=True, + ) + planned_order_ids = fields.One2many( + comodel_name="mrp.planned.order", + inverse_name="product_mrp_area_id", + readonly=True, + ) + + _sql_constraints = [ + ('product_mrp_area_uniq', 'unique(product_id, mrp_area_id)', + 'The product/MRP Area parameters combination must be unique.'), + ] + + @api.multi + @api.constrains( + "mrp_minimum_order_qty", "mrp_maximum_order_qty", "mrp_qty_multiple", + "mrp_minimum_stock", "mrp_nbr_days", + ) + def _check_negatives(self): + values = self.read([ + "mrp_minimum_order_qty", "mrp_maximum_order_qty", + "mrp_qty_multiple", "mrp_minimum_stock", "mrp_nbr_days", + ]) + for rec in values: + if any(v < 0 for v in rec.values()): + raise ValidationError(_("You cannot use a negative number.")) + + @api.multi + def name_get(self): + return [(area.id, '[%s] %s' % ( + area.mrp_area_id.name, + area.product_id.display_name)) for area in self] + + @api.multi + def _compute_mrp_lead_time(self): + produced = self.filtered(lambda r: r.supply_method == "manufacture") + purchased = self.filtered(lambda r: r.supply_method == "buy") + for rec in produced: + rec.mrp_lead_time = rec.product_id.produce_delay + for rec in purchased: + rec.mrp_lead_time = rec.main_supplierinfo_id.delay + # TODO: 'move' supply method. + for rec in (self - produced - purchased): + rec.mrp_lead_time = 0 + + @api.multi + def _compute_qty_available(self): + for rec in self: + rec.qty_available = rec.product_id.with_context( + {'location': rec.mrp_area_id.location_id.id}).qty_available + + @api.multi + def _compute_supply_method(self): + group_obj = self.env['procurement.group'] + for rec in self: + proc_loc = rec.location_proc_id or rec.mrp_area_id.location_id + values = { + 'warehouse_id': rec.mrp_area_id.warehouse_id, + 'company_id': self.env.user.company_id.id, + # TODO: better way to get company + } + rule = group_obj._get_rule(rec.product_id, proc_loc, values) + rec.supply_method = rule.action if rule else 'none' + + @api.multi + @api.depends('supply_method', 'product_id.route_ids', + 'product_id.seller_ids') + def _compute_main_supplier(self): + """Simplified and similar to procurement.rule logic.""" + for rec in self.filtered(lambda r: r.supply_method == 'buy'): + suppliers = rec.product_id.seller_ids.filtered( + lambda r: (not r.product_id or r.product_id == rec.product_id)) + if not suppliers: + continue + rec.main_supplierinfo_id = suppliers[0] + rec.main_supplier_id = suppliers[0].name + + @api.multi + def _adjust_qty_to_order(self, qty_to_order): + self.ensure_one() + if (not self.mrp_maximum_order_qty and not + self.mrp_minimum_order_qty and self.mrp_qty_multiple == 1.0): + return qty_to_order + if qty_to_order < self.mrp_minimum_order_qty: + return self.mrp_minimum_order_qty + if self.mrp_qty_multiple: + multiplier = ceil(qty_to_order / self.mrp_qty_multiple) + qty_to_order = multiplier * self.mrp_qty_multiple + if self.mrp_maximum_order_qty and qty_to_order > \ + self.mrp_maximum_order_qty: + return self.mrp_maximum_order_qty + return qty_to_order diff --git a/mrp_multi_level/models/product_product.py b/mrp_multi_level/models/product_product.py new file mode 100644 index 000000000..b52802067 --- /dev/null +++ b/mrp_multi_level/models/product_product.py @@ -0,0 +1,59 @@ +# Copyright 2016 Ucamco - Wim Audenaert +# Copyright 2016-18 Eficent Business and IT Consulting Services S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). +import ast +from odoo import api, fields, models + + +class Product(models.Model): + _inherit = 'product.product' + + llc = fields.Integer(string='Low Level Code', default=0) + manufacturing_order_ids = fields.One2many( + comodel_name='mrp.production', + inverse_name='product_id', + string='Manufacturing Orders', + domain=[('state', '=', 'draft')], + ) + purchase_order_line_ids = fields.One2many( + comodel_name='purchase.order.line', + inverse_name='product_id', + string='Purchase Orders', + ) + mrp_area_ids = fields.One2many( + comodel_name='product.mrp.area', + inverse_name='product_id', + string='MRP Area parameters' + ) + mrp_area_count = fields.Integer( + string='MRP Area Parameter Count', + readonly=True, + compute='_compute_mrp_area_count', + ) + + @api.multi + def _compute_mrp_area_count(self): + for rec in self: + rec.mrp_area_count = len(rec.mrp_area_ids) + + @api.multi + def action_view_mrp_area_parameters(self): + self.ensure_one() + action = self.env.ref('mrp_multi_level.product_mrp_area_action') + result = action.read()[0] + ctx = ast.literal_eval(result.get('context')) + if not ctx: + ctx = {} + mrp_areas = self.env['mrp.area'].search([]) + if len(mrp_areas) == 1: + ctx.update({'default_mrp_area_id': mrp_areas[0].id}) + area_ids = self.mrp_area_ids.ids + ctx.update({'default_product_id': self.id}) + if self.mrp_area_count != 1: + result['domain'] = [('id', 'in', area_ids)] + else: + res = self.env.ref('mrp_multi_level.product_mrp_area_form', False) + result['views'] = [(res and res.id or False, 'form')] + result['res_id'] = area_ids[0] + result['context'] = ctx + return result diff --git a/mrp_multi_level/models/product_template.py b/mrp_multi_level/models/product_template.py new file mode 100644 index 000000000..bcea26a27 --- /dev/null +++ b/mrp_multi_level/models/product_template.py @@ -0,0 +1,49 @@ +# Copyright 2018 Eficent Business and IT Consulting Services S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). +import ast +from odoo import api, fields, models + + +class ProductTemplate(models.Model): + _inherit = 'product.template' + + mrp_area_ids = fields.One2many( + comodel_name='product.mrp.area', + inverse_name='product_tmpl_id', + string='MRP Area parameters', + ) + mrp_area_count = fields.Integer( + string='MRP Area Parameter Count', + readonly=True, + compute='_compute_mrp_area_count', + ) + + @api.multi + def _compute_mrp_area_count(self): + for rec in self: + rec.mrp_area_count = len(rec.mrp_area_ids) + + @api.multi + def action_view_mrp_area_parameters(self): + self.ensure_one() + action = self.env.ref('mrp_multi_level.product_mrp_area_action') + result = action.read()[0] + ctx = ast.literal_eval(result.get('context')) + mrp_areas = self.env['mrp.area'].search([]) + if 'context' not in result: + result['context'] = {} + if len(mrp_areas) == 1: + ctx.update({'default_mrp_area_id': mrp_areas[0].id}) + mrp_area_ids = self.with_context( + active_test=False).mrp_area_ids.ids + if len(self.product_variant_ids) == 1: + variant = self.product_variant_ids[0] + ctx.update({'default_product_id': variant.id}) + if len(mrp_area_ids) != 1: + result['domain'] = [('id', 'in', mrp_area_ids)] + else: + res = self.env.ref('mrp_multi_level.product_mrp_area_form', False) + result['views'] = [(res and res.id or False, 'form')] + result['res_id'] = mrp_area_ids[0] + result['context'] = ctx + return result diff --git a/mrp_multi_level/models/stock_location.py b/mrp_multi_level/models/stock_location.py new file mode 100644 index 000000000..3c574443c --- /dev/null +++ b/mrp_multi_level/models/stock_location.py @@ -0,0 +1,16 @@ +# © 2016 Ucamco - Wim Audenaert +# © 2016 Eficent Business and IT Consulting Services S.L. +# - Jordi Ballester Alomar +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). + +from odoo import fields, models + + +class StockLocation(models.Model): + _inherit = 'stock.location' + + mrp_area_id = fields.Many2one( + comodel_name='mrp.area', string='MRP Area', + help="Requirements for a particular MRP area are combined for the " + "purposes of procurement by the MRP.", + ) diff --git a/mrp_multi_level/readme/CONFIGURE.rst b/mrp_multi_level/readme/CONFIGURE.rst new file mode 100644 index 000000000..3825da541 --- /dev/null +++ b/mrp_multi_level/readme/CONFIGURE.rst @@ -0,0 +1,11 @@ +MRP Areas +~~~~~~~~~ + +* Go to *Manufacturing > Configuration > MRP Areas* and define or edit + any existing area. You can specify the working hours for every area. + +Product MRP Area Parameters +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +* Go to *Manufacturing > Master Data > Product MRP Area Parameters* and set + the MRP parameters for a given product and area. diff --git a/mrp_multi_level/readme/CONTRIBUTORS.rst b/mrp_multi_level/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..63a6a5199 --- /dev/null +++ b/mrp_multi_level/readme/CONTRIBUTORS.rst @@ -0,0 +1,3 @@ +* Wim Audenaert +* Jordi Ballester +* Lois Rilo diff --git a/mrp_multi_level/readme/DESCRIPTION.rst b/mrp_multi_level/readme/DESCRIPTION.rst new file mode 100644 index 000000000..07e004779 --- /dev/null +++ b/mrp_multi_level/readme/DESCRIPTION.rst @@ -0,0 +1,17 @@ +This module allows you to calculate, based in known inventory, demand, and +supply, and based on parameters set at product variant level, the new +procurements for each product. + +To do this, the calculation starts at top level of the bill of material +and explodes this down to the lowest level. + +Key Features +------------ + +* MRP parameters set by product variant MRP area pairs. +* Cron job to calculate the MRP demand. +* Manually calculate the MRP demand. +* Confirm the calculated MRP demand and create PO's, or MO's. +* Able to see the products for which action is needed throught Planned Orders. +* Integration with `Stock Demand Estimates `_ system. + Note: You need to install `mrp_multi_level_estimate module `_. diff --git a/mrp_multi_level/readme/HISTORY.rst b/mrp_multi_level/readme/HISTORY.rst new file mode 100644 index 000000000..c1596d26c --- /dev/null +++ b/mrp_multi_level/readme/HISTORY.rst @@ -0,0 +1,58 @@ +12.0.1.0.0 (2019-08-05) +~~~~~~~~~~~~~~~~~~~~~~~ + +* [MIG] Migration to v12: + + * Estimates as a forecasting mechanism is moved to a new module + (mrp_multi_level_estimate). + +11.0.3.0.0 (2019-05-22) +~~~~~~~~~~~~~~~~~~~~~~~ + +* [REW/IMP] Rework to include Planned Orders. + (`#365 `_). +* [IMP] Able to procure from a different location than the area's location. + +11.0.2.2.0 (2019-05-02) +~~~~~~~~~~~~~~~~~~~~~~~ + +* [IMP] Able to run MRP only for selected areas. + (`#360 `_). + +11.0.2.1.0 (2019-04-02) +~~~~~~~~~~~~~~~~~~~~~~~ + +* [IMP] Implement *Nbr. Days* functionality to be able to group demand when + generating supply proposals. + (`#345 `_). + +11.0.2.0.0 (2018-11-20) +~~~~~~~~~~~~~~~~~~~~~~~ + +* [REW] Refactor MRP Area. + (`#322 `_): + + * MRP product concept dropped in favor of *Product MRP Area Parameters*. + This allow to set different MRP parameters for the same product in + different areas. + * Menu items reordering. + +11.0.1.1.0 (2018-08-30) +~~~~~~~~~~~~~~~~~~~~~~~ + +* [FIX] Consider *Qty Multiple* on product to propose the quantity to procure. + (`#297 `_) + +11.0.1.0.1 (2018-08-03) +~~~~~~~~~~~~~~~~~~~~~~~ + +* [FIX] User and system locales doesn't break MRP calculation. + (`#290 `_) +* [FIX] Working Hours are now defined only at Warehouse level and displayed + as a related on MRP Areas. + (`#290 `__) + +11.0.1.0.0 (2018-07-09) +~~~~~~~~~~~~~~~~~~~~~~~ + +* Start of the history. diff --git a/mrp_multi_level/readme/USAGE.rst b/mrp_multi_level/readme/USAGE.rst new file mode 100644 index 000000000..6e28dce46 --- /dev/null +++ b/mrp_multi_level/readme/USAGE.rst @@ -0,0 +1,12 @@ +To manually run the MRP scheduler: + +#. Go to *Manufacturing > Operations > Run MRP Multi Level*. +#. On the wizard click *Run MRP*. + +To launch replenishment orders (moves, purchases, production orders...): + +#. Go to *Manufacturing > Operations > MRP Inventory*. +#. Filter with *To procure*. +#. Select multiple records and click on *Action > Procure* or click the right + hand side gears in any record. +#. On the wizard, check everything is ok and click *Execute*. diff --git a/mrp_multi_level/security/ir.model.access.csv b/mrp_multi_level/security/ir.model.access.csv new file mode 100644 index 000000000..e709cbec1 --- /dev/null +++ b/mrp_multi_level/security/ir.model.access.csv @@ -0,0 +1,11 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_mrp_inventory_user,mrp.inventory user,model_mrp_inventory,mrp.group_mrp_user,1,0,0,0 +access_mrp_inventory_manager,mrp.inventory manager,model_mrp_inventory,mrp.group_mrp_manager,1,1,1,1 +access_mrp_move_user,mrp.move user,model_mrp_move,mrp.group_mrp_user,1,0,0,0 +access_mrp_move_manager,mrp.move manager,model_mrp_move,mrp.group_mrp_manager,1,1,1,1 +access_mrp_area_user,mrp.area user,model_mrp_area,mrp.group_mrp_user,1,0,0,0 +access_mrp_area_manager,mrp.area manager,model_mrp_area,mrp.group_mrp_manager,1,1,1,1 +access_product_mrp_area_user,product.mrp.area user,model_product_mrp_area,mrp.group_mrp_user,1,1,1,0 +access_product_mrp_area_manager,product.mrp.area manager,model_product_mrp_area,mrp.group_mrp_manager,1,1,1,1 +access_mrp_planned_order_user,mrp.planned.order user,model_mrp_planned_order,mrp.group_mrp_user,1,0,0,0 +access_mrp_planned_order_manager,mrp.planned.order manager,model_mrp_planned_order,mrp.group_mrp_manager,1,1,1,1 diff --git a/mrp_multi_level/security/mrp_multi_level_security.xml b/mrp_multi_level/security/mrp_multi_level_security.xml new file mode 100644 index 000000000..075492f63 --- /dev/null +++ b/mrp_multi_level/security/mrp_multi_level_security.xml @@ -0,0 +1,45 @@ + + + + + Change procure quantity in MRP + + + + + + MRP Area multi-company rule + + + ['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])] + + + + Product MRP Area multi-company rule + + + ['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])] + + + + MRP Inventory multi-company rule + + + ['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])] + + + + MRP Move multi-company rule + + + ['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])] + + + + MRP Planned Order multi-company rule + + + ['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])] + + + diff --git a/mrp_multi_level/static/description/icon.png b/mrp_multi_level/static/description/icon.png new file mode 100644 index 000000000..b1cef6c4c Binary files /dev/null and b/mrp_multi_level/static/description/icon.png differ diff --git a/mrp_multi_level/static/description/index.html b/mrp_multi_level/static/description/index.html new file mode 100644 index 000000000..493ebe4f0 --- /dev/null +++ b/mrp_multi_level/static/description/index.html @@ -0,0 +1,562 @@ + + + + + + +MRP Multi Level + + + +
+

MRP Multi Level

+ + +

Beta License: LGPL-3 OCA/manufacture Translate me on Weblate Try me on Runbot

+

This module allows you to calculate, based in known inventory, demand, and +supply, and based on parameters set at product variant level, the new +procurements for each product.

+

To do this, the calculation starts at top level of the bill of material +and explodes this down to the lowest level.

+
+

Key Features

+
    +
  • MRP parameters set by product variant MRP area pairs.
  • +
  • Cron job to calculate the MRP demand.
  • +
  • Manually calculate the MRP demand.
  • +
  • Confirm the calculated MRP demand and create PO’s, or MO’s.
  • +
  • Able to see the products for which action is needed throught Planned Orders.
  • +
  • Integration with Stock Demand Estimates system. +Note: You need to install mrp_multi_level_estimate module.
  • +
+

Table of contents

+ +
+

Configuration

+
+

MRP Areas

+
    +
  • Go to Manufacturing > Configuration > MRP Areas and define or edit +any existing area. You can specify the working hours for every area.
  • +
+
+
+

Product MRP Area Parameters

+
    +
  • Go to Manufacturing > Master Data > Product MRP Area Parameters and set +the MRP parameters for a given product and area.
  • +
+
+
+
+

Usage

+

To manually run the MRP scheduler:

+
    +
  1. Go to Manufacturing > Operations > Run MRP Multi Level.
  2. +
  3. On the wizard click Run MRP.
  4. +
+

To launch replenishment orders (moves, purchases, production orders…):

+
    +
  1. Go to Manufacturing > Operations > MRP Inventory.
  2. +
  3. Filter with To procure.
  4. +
  5. Select multiple records and click on Action > Procure or click the right +hand side gears in any record.
  6. +
  7. On the wizard, check everything is ok and click Execute.
  8. +
+
+
+

Changelog

+
+

12.0.1.0.0 (2019-08-05)

+
    +
  • [MIG] Migration to v12:
      +
    • Estimates as a forecasting mechanism is moved to a new module +(mrp_multi_level_estimate).
    • +
    +
  • +
+
+
+

11.0.3.0.0 (2019-05-22)

+
    +
  • [REW/IMP] Rework to include Planned Orders. +(#365).
  • +
  • [IMP] Able to procure from a different location than the area’s location.
  • +
+
+
+

11.0.2.2.0 (2019-05-02)

+
    +
  • [IMP] Able to run MRP only for selected areas. +(#360).
  • +
+
+
+

11.0.2.1.0 (2019-04-02)

+
    +
  • [IMP] Implement Nbr. Days functionality to be able to group demand when +generating supply proposals. +(#345).
  • +
+
+
+

11.0.2.0.0 (2018-11-20)

+
    +
  • [REW] Refactor MRP Area. +(#322):
      +
    • MRP product concept dropped in favor of Product MRP Area Parameters. +This allow to set different MRP parameters for the same product in +different areas.
    • +
    • Menu items reordering.
    • +
    +
  • +
+
+
+

11.0.1.1.0 (2018-08-30)

+
    +
  • [FIX] Consider Qty Multiple on product to propose the quantity to procure. +(#297)
  • +
+
+
+

11.0.1.0.1 (2018-08-03)

+
    +
  • [FIX] User and system locales doesn’t break MRP calculation. +(#290)
  • +
  • [FIX] Working Hours are now defined only at Warehouse level and displayed +as a related on MRP Areas. +(#290)
  • +
+
+
+

11.0.1.0.0 (2018-07-09)

+
    +
  • Start of the history.
  • +
+
+
+
+

Bug Tracker

+

Bugs are tracked on GitHub 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.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Ucamco
  • +
  • Eficent
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

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.

+

Current maintainers:

+

jbeficent lreficent

+

This module is part of the OCA/manufacture project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+
+ + diff --git a/mrp_multi_level/static/src/img/icon.png b/mrp_multi_level/static/src/img/icon.png new file mode 100644 index 000000000..3a0328b51 Binary files /dev/null and b/mrp_multi_level/static/src/img/icon.png differ diff --git a/mrp_multi_level/tests/__init__.py b/mrp_multi_level/tests/__init__.py new file mode 100644 index 000000000..c27acfad0 --- /dev/null +++ b/mrp_multi_level/tests/__init__.py @@ -0,0 +1 @@ +from . import test_mrp_multi_level diff --git a/mrp_multi_level/tests/common.py b/mrp_multi_level/tests/common.py new file mode 100644 index 000000000..a64cb1fc3 --- /dev/null +++ b/mrp_multi_level/tests/common.py @@ -0,0 +1,284 @@ +# Copyright 2018-19 Eficent Business and IT Consulting Services S.L. +# (http://www.eficent.com) +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). + +from datetime import datetime + +from odoo.tests.common import SavepointCase + + +class TestMrpMultiLevelCommon(SavepointCase): + + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.mo_obj = cls.env['mrp.production'] + cls.po_obj = cls.env['purchase.order'] + cls.product_obj = cls.env['product.product'] + cls.loc_obj = cls.env['stock.location'] + cls.mrp_area_obj = cls.env['mrp.area'] + cls.product_mrp_area_obj = cls.env['product.mrp.area'] + cls.partner_obj = cls.env['res.partner'] + cls.res_users = cls.env['res.users'] + cls.stock_picking_obj = cls.env['stock.picking'] + cls.mrp_multi_level_wiz = cls.env['mrp.multi.level'] + cls.mrp_inventory_procure_wiz = cls.env['mrp.inventory.procure'] + cls.mrp_inventory_obj = cls.env['mrp.inventory'] + cls.mrp_move_obj = cls.env['mrp.move'] + cls.planned_order_obj = cls.env['mrp.planned.order'] + + cls.fp_1 = cls.env.ref('mrp_multi_level.product_product_fp_1') + cls.fp_2 = cls.env.ref('mrp_multi_level.product_product_fp_2') + cls.sf_1 = cls.env.ref('mrp_multi_level.product_product_sf_1') + cls.sf_2 = cls.env.ref('mrp_multi_level.product_product_sf_2') + cls.pp_1 = cls.env.ref('mrp_multi_level.product_product_pp_1') + cls.pp_2 = cls.env.ref('mrp_multi_level.product_product_pp_2') + cls.company = cls.env.ref('base.main_company') + cls.mrp_area = cls.env.ref('mrp_multi_level.mrp_area_stock_wh0') + cls.vendor = cls.env.ref('mrp_multi_level.res_partner_lazer_tech') + cls.wh = cls.env.ref('stock.warehouse0') + cls.stock_location = cls.wh.lot_stock_id + cls.customer_location = cls.env.ref( + 'stock.stock_location_customers') + cls.calendar = cls.env.ref('resource.resource_calendar_std') + # Add calendar to WH: + cls.wh.calendar_id = cls.calendar + + # Partner: + vendor1 = cls.partner_obj.create({'name': 'Vendor 1'}) + + # Create user: + group_mrp_manager = cls.env.ref('mrp.group_mrp_manager') + group_user = cls.env.ref('base.group_user') + group_stock_manager = cls.env.ref('stock.group_stock_manager') + cls.mrp_manager = cls._create_user( + 'Test User', + [group_mrp_manager, group_user, group_stock_manager], + cls.company, + ) + + # Create secondary location and MRP Area: + cls.sec_loc = cls.loc_obj.create({ + 'name': 'Test location', + 'usage': 'internal', + 'location_id': cls.wh.view_location_id.id, + }) + cls.secondary_area = cls.mrp_area_obj.create({ + 'name': 'Test', + 'warehouse_id': cls.wh.id, + 'location_id': cls.sec_loc.id, + }) + + # Create products: + route_buy = cls.env.ref('purchase_stock.route_warehouse0_buy').id + cls.prod_test = cls.product_obj.create({ + 'name': 'Test Top Seller', + 'type': 'product', + 'list_price': 150.0, + 'produce_delay': 5.0, + 'route_ids': [(6, 0, [route_buy])], + 'seller_ids': [(0, 0, {'name': vendor1.id, 'price': 20.0})], + }) + cls.product_mrp_area_obj.create({ + 'product_id': cls.prod_test.id, + 'mrp_area_id': cls.mrp_area.id, + }) + # Parameters in secondary area with nbr_days set. + cls.product_mrp_area_obj.create({ + 'product_id': cls.prod_test.id, + 'mrp_area_id': cls.secondary_area.id, + 'mrp_nbr_days': 7, + }) + cls.prod_min = cls.product_obj.create({ + 'name': 'Product with minimum order qty', + 'type': 'product', + 'list_price': 50.0, + 'route_ids': [(6, 0, [route_buy])], + 'seller_ids': [(0, 0, {'name': vendor1.id, 'price': 10.0})], + }) + cls.product_mrp_area_obj.create({ + 'product_id': cls.prod_min.id, + 'mrp_area_id': cls.mrp_area.id, + 'mrp_minimum_order_qty': 50.0, + 'mrp_maximum_order_qty': 0.0, + 'mrp_qty_multiple': 1.0, + }) + + cls.prod_max = cls.product_obj.create({ + 'name': 'Product with maximum order qty', + 'type': 'product', + 'list_price': 50.0, + 'route_ids': [(6, 0, [route_buy])], + 'seller_ids': [(0, 0, {'name': vendor1.id, 'price': 10.0})], + }) + cls.product_mrp_area_obj.create({ + 'product_id': cls.prod_max.id, + 'mrp_area_id': cls.mrp_area.id, + 'mrp_minimum_order_qty': 50.0, + 'mrp_maximum_order_qty': 100.0, + 'mrp_qty_multiple': 1.0, + }) + cls.prod_multiple = cls.product_obj.create({ + 'name': 'Product with qty multiple', + 'type': 'product', + 'list_price': 50.0, + 'route_ids': [(6, 0, [route_buy])], + 'seller_ids': [(0, 0, {'name': vendor1.id, 'price': 10.0})], + }) + cls.product_mrp_area_obj.create({ + 'product_id': cls.prod_multiple.id, + 'mrp_area_id': cls.mrp_area.id, + 'mrp_minimum_order_qty': 50.0, + 'mrp_maximum_order_qty': 500.0, + 'mrp_qty_multiple': 25.0, + }) + # Create test picking for FP-1 and FP-2: + res = cls.calendar.plan_days(7 + 1, datetime.today().replace(hour=0)) + date_move = res.date() + cls.picking_1 = cls.stock_picking_obj.create({ + 'picking_type_id': cls.env.ref('stock.picking_type_out').id, + 'location_id': cls.stock_location.id, + 'location_dest_id': cls.customer_location.id, + 'move_lines': [ + (0, 0, { + 'name': 'Test move fp-1', + 'product_id': cls.fp_1.id, + 'date_expected': date_move, + 'date': date_move, + 'product_uom': cls.fp_1.uom_id.id, + 'product_uom_qty': 100, + 'location_id': cls.stock_location.id, + 'location_dest_id': cls.customer_location.id + }), + (0, 0, { + 'name': 'Test move fp-2', + 'product_id': cls.fp_2.id, + 'date_expected': date_move, + 'date': date_move, + 'product_uom': cls.fp_2.uom_id.id, + 'product_uom_qty': 15, + 'location_id': cls.stock_location.id, + 'location_dest_id': cls.customer_location.id + })] + }) + cls.picking_1.action_confirm() + + # Create test picking for procure qty adjustment tests: + cls.picking_2 = cls.stock_picking_obj.create({ + 'picking_type_id': cls.env.ref('stock.picking_type_out').id, + 'location_id': cls.stock_location.id, + 'location_dest_id': cls.customer_location.id, + 'move_lines': [ + (0, 0, { + 'name': 'Test move prod_min', + 'product_id': cls.prod_min.id, + 'date_expected': date_move, + 'date': date_move, + 'product_uom': cls.prod_min.uom_id.id, + 'product_uom_qty': 16, + 'location_id': cls.stock_location.id, + 'location_dest_id': cls.customer_location.id + }), + (0, 0, { + 'name': 'Test move prod_max', + 'product_id': cls.prod_max.id, + 'date_expected': date_move, + 'date': date_move, + 'product_uom': cls.prod_max.uom_id.id, + 'product_uom_qty': 140, + 'location_id': cls.stock_location.id, + 'location_dest_id': cls.customer_location.id + }), + (0, 0, { + 'name': 'Test move prod_multiple', + 'product_id': cls.prod_multiple.id, + 'date_expected': date_move, + 'date': date_move, + 'product_uom': cls.prod_multiple.uom_id.id, + 'product_uom_qty': 112, + 'location_id': cls.stock_location.id, + 'location_dest_id': cls.customer_location.id + })] + }) + cls.picking_2.action_confirm() + + # Create Test PO: + date_po = cls.calendar.plan_days( + 1+1, datetime.today().replace(hour=0)).date() + cls.po = cls.po_obj.create({ + 'name': 'Test PO-001', + 'partner_id': cls.vendor.id, + 'order_line': [ + (0, 0, { + 'name': 'Test PP-2 line', + 'product_id': cls.pp_2.id, + 'date_planned': date_po, + 'product_qty': 5.0, + 'product_uom': cls.pp_2.uom_id.id, + 'price_unit': 25.0, + })], + }) + + # Create test MO: + date_mo = cls.calendar.plan_days( + 9 + 1, datetime.today().replace(hour=0)).date() + bom_fp_2 = cls.env.ref('mrp_multi_level.mrp_bom_fp_2') + cls.mo = cls.mo_obj.create({ + 'product_id': cls.fp_2.id, + 'bom_id': bom_fp_2.id, + 'product_qty': 12.0, + 'product_uom_id': cls.fp_2.uom_id.id, + 'date_planned_start': date_mo, + }) + + # Dates: + today = datetime.today().replace(hour=0) + cls.date_3 = cls.calendar.plan_days(3 + 1, today).date() + cls.date_5 = cls.calendar.plan_days(5 + 1, today).date() + cls.date_6 = cls.calendar.plan_days(6 + 1, today).date() + cls.date_7 = cls.calendar.plan_days(7 + 1, today).date() + cls.date_8 = cls.calendar.plan_days(8 + 1, today).date() + cls.date_9 = cls.calendar.plan_days(9 + 1, today).date() + cls.date_10 = cls.calendar.plan_days(10 + 1, today).date() + cls.date_20 = cls.calendar.plan_days(20 + 1, today).date() + cls.date_22 = cls.calendar.plan_days(22 + 1, today).date() + + # Create movements in secondary area: + cls.create_demand_sec_loc(cls.date_8, 80.0) + cls.create_demand_sec_loc(cls.date_9, 50.0) + cls.create_demand_sec_loc(cls.date_10, 70.0) + cls.create_demand_sec_loc(cls.date_20, 46.0) + cls.create_demand_sec_loc(cls.date_22, 33.0) + + cls.mrp_multi_level_wiz.create({}).run_mrp_multi_level() + + @classmethod + def create_demand_sec_loc(cls, date_move, qty): + return cls.stock_picking_obj.create({ + "picking_type_id": cls.env.ref("stock.picking_type_out").id, + "location_id": cls.sec_loc.id, + "location_dest_id": cls.customer_location.id, + "move_lines": [ + (0, 0, { + "name": "Test move", + "product_id": cls.prod_test.id, + "date_expected": date_move, + "date": date_move, + "product_uom": cls.prod_test.uom_id.id, + "product_uom_qty": qty, + "location_id": cls.sec_loc.id, + "location_dest_id": cls.customer_location.id, + })], + }) + + @classmethod + def _create_user(cls, login, groups, company): + user = cls.res_users.create({ + 'name': login, + 'login': login, + 'password': 'demo', + 'email': 'example@yourcompany.com', + 'company_id': company.id, + 'groups_id': [(6, 0, [group.id for group in groups])] + }) + return user diff --git a/mrp_multi_level/tests/test_mrp_multi_level.py b/mrp_multi_level/tests/test_mrp_multi_level.py new file mode 100644 index 000000000..558ed486c --- /dev/null +++ b/mrp_multi_level/tests/test_mrp_multi_level.py @@ -0,0 +1,252 @@ +# Copyright 2018-19 Eficent Business and IT Consulting Services S.L. +# (http://www.eficent.com) +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). + +from odoo.addons.mrp_multi_level.tests.common import TestMrpMultiLevelCommon +from odoo import fields + + +class TestMrpMultiLevel(TestMrpMultiLevelCommon): + + def test_01_mrp_levels(self): + """Tests computation of MRP levels.""" + self.assertEqual(self.fp_1.llc, 0) + self.assertEqual(self.fp_2.llc, 0) + self.assertEqual(self.sf_1.llc, 1) + self.assertEqual(self.sf_2.llc, 1) + self.assertEqual(self.pp_1.llc, 2) + self.assertEqual(self.pp_2.llc, 2) + + def test_02_product_mrp_area(self): + """Tests that mrp products are generated correctly.""" + product_mrp_area = self.product_mrp_area_obj.search([ + ('product_id', '=', self.pp_1.id)]) + self.assertEqual(product_mrp_area.supply_method, 'buy') + self.assertEqual(product_mrp_area.main_supplier_id, self.vendor) + self.assertEqual(product_mrp_area.qty_available, 10.0) + product_mrp_area = self.product_mrp_area_obj.search([ + ('product_id', '=', self.sf_1.id)]) + self.assertEqual(product_mrp_area.supply_method, 'manufacture') + + def test_03_mrp_moves(self): + """Tests for mrp moves generated.""" + moves = self.mrp_move_obj.search([ + ('product_id', '=', self.pp_1.id), + ]) + self.assertEqual(len(moves), 3) + self.assertNotIn('s', moves.mapped('mrp_type')) + for move in moves: + self.assertTrue(move.planned_order_up_ids) + if move.planned_order_up_ids.product_mrp_area_id.product_id == \ + self.fp_1: + # Demand coming from FP-1 + self.assertEqual( + move.planned_order_up_ids.mrp_action, "manufacture") + self.assertEqual(move.mrp_qty, -200.0) + elif move.planned_order_up_ids.product_mrp_area_id.product_id == \ + self.sf_1: + # Demand coming from FP-2 -> SF-1 + self.assertEqual( + move.planned_order_up_ids.mrp_action, "manufacture") + if move.mrp_date == self.date_5: + self.assertEqual(move.mrp_qty, -90.0) + elif move.mrp_date == self.date_8: + self.assertEqual(move.mrp_qty, -72.0) + # Check actions: + planned_orders = self.planned_order_obj.search([ + ('product_id', '=', self.pp_1.id), + ]) + self.assertEqual(len(planned_orders), 3) + for plan in planned_orders: + self.assertEqual(plan.mrp_action, 'buy') + # Check PP-2 PO being accounted: + po_move = self.mrp_move_obj.search([ + ('product_id', '=', self.pp_2.id), + ('mrp_type', '=', 's'), + ]) + self.assertEqual(len(po_move), 1) + self.assertEqual(po_move.purchase_order_id, self.po) + self.assertEqual(po_move.purchase_line_id, self.po.order_line) + + def test_04_mrp_multi_level(self): + """Tests MRP inventories created.""" + # FP-1 + fp_1_inventory_lines = self.mrp_inventory_obj.search( + [('product_mrp_area_id.product_id', '=', self.fp_1.id)]) + self.assertEqual(len(fp_1_inventory_lines), 1) + self.assertEqual(fp_1_inventory_lines.date, self.date_7) + self.assertEqual(fp_1_inventory_lines.demand_qty, 100.0) + self.assertEqual(fp_1_inventory_lines.to_procure, 100.0) + # FP-2 + fp_2_line_1 = self.mrp_inventory_obj.search([ + ('product_mrp_area_id.product_id', '=', self.fp_2.id), + ('date', '=', self.date_7)]) + self.assertEqual(len(fp_2_line_1), 1) + self.assertEqual(fp_2_line_1.demand_qty, 15.0) + self.assertEqual(fp_2_line_1.to_procure, 15.0) + # TODO: ask odoo to fix it... should be date10 + fp_2_line_2 = self.mrp_inventory_obj.search([ + ('product_mrp_area_id.product_id', '=', self.fp_2.id), + ('date', '=', self.date_9)]) + self.assertEqual(len(fp_2_line_2), 1) + self.assertEqual(fp_2_line_2.demand_qty, 0.0) + self.assertEqual(fp_2_line_2.to_procure, 0.0) + self.assertEqual(fp_2_line_2.supply_qty, 12.0) + + # SF-1 + sf_1_line_1 = self.mrp_inventory_obj.search([ + ('product_mrp_area_id.product_id', '=', self.sf_1.id), + ('date', '=', self.date_6)]) + self.assertEqual(len(sf_1_line_1), 1) + self.assertEqual(sf_1_line_1.demand_qty, 30.0) + self.assertEqual(sf_1_line_1.to_procure, 30.0) + sf_1_line_2 = self.mrp_inventory_obj.search([ + ('product_mrp_area_id.product_id', '=', self.sf_1.id), + ('date', '=', self.date_9)]) + self.assertEqual(len(sf_1_line_2), 1) + self.assertEqual(sf_1_line_2.demand_qty, 24.0) + self.assertEqual(sf_1_line_2.to_procure, 24.0) + # SF-2 + sf_2_line_1 = self.mrp_inventory_obj.search([ + ('product_mrp_area_id.product_id', '=', self.sf_2.id), + ('date', '=', self.date_6)]) + self.assertEqual(len(sf_2_line_1), 1) + self.assertEqual(sf_2_line_1.demand_qty, 45.0) + self.assertEqual(sf_2_line_1.to_procure, 30.0) + sf_2_line_2 = self.mrp_inventory_obj.search([ + ('product_mrp_area_id.product_id', '=', self.sf_2.id), + ('date', '=', self.date_9)]) + self.assertEqual(len(sf_2_line_2), 1) + self.assertEqual(sf_2_line_2.demand_qty, 36.0) + self.assertEqual(sf_2_line_2.to_procure, 36.0) + + # PP-1 + pp_1_line_1 = self.mrp_inventory_obj.search([ + ('product_mrp_area_id.product_id', '=', self.pp_1.id), + ('date', '=', self.date_5)]) + self.assertEqual(len(pp_1_line_1), 1) + self.assertEqual(pp_1_line_1.demand_qty, 290.0) + self.assertEqual(pp_1_line_1.to_procure, 280.0) + pp_1_line_2 = self.mrp_inventory_obj.search([ + ('product_mrp_area_id.product_id', '=', self.pp_1.id), + ('date', '=', self.date_8)]) + self.assertEqual(len(pp_1_line_2), 1) + self.assertEqual(pp_1_line_2.demand_qty, 72.0) + self.assertEqual(pp_1_line_2.to_procure, 72.0) + # PP-2 + pp_2_line_1 = self.mrp_inventory_obj.search([ + ('product_mrp_area_id.product_id', '=', self.pp_2.id), + ('date', '=', self.date_3)]) + self.assertEqual(len(pp_2_line_1), 1) + self.assertEqual(pp_2_line_1.demand_qty, 90.0) + # 90.0 demand - 20.0 on hand - 5.0 on PO = 65.0 + self.assertEqual(pp_2_line_1.to_procure, 65.0) + pp_2_line_2 = self.mrp_inventory_obj.search([ + ('product_mrp_area_id.product_id', '=', self.pp_2.id), + ('date', '=', self.date_5)]) + self.assertEqual(len(pp_2_line_2), 1) + self.assertEqual(pp_2_line_2.demand_qty, 360.0) + self.assertEqual(pp_2_line_2.to_procure, 360.0) + pp_2_line_3 = self.mrp_inventory_obj.search([ + ('product_mrp_area_id.product_id', '=', self.pp_2.id), + ('date', '=', self.date_6)]) + self.assertEqual(len(pp_2_line_3), 1) + self.assertEqual(pp_2_line_3.demand_qty, 108.0) + self.assertEqual(pp_2_line_3.to_procure, 108.0) + pp_2_line_4 = self.mrp_inventory_obj.search([ + ('product_mrp_area_id.product_id', '=', self.pp_2.id), + ('date', '=', self.date_8)]) + self.assertEqual(len(pp_2_line_4), 1) + self.assertEqual(pp_2_line_4.demand_qty, 48.0) + self.assertEqual(pp_2_line_4.to_procure, 48.0) + + def test_05_planned_availability(self): + """Test planned availability computation.""" + # Running availability for PP-1: + invs = self.mrp_inventory_obj.search([ + ('product_id', '=', self.pp_1.id)], + order='date') + self.assertEqual(len(invs), 2) + expected = [0.0, 0.0] # No grouping, lot size nor safety stock. + self.assertEqual(invs.mapped('running_availability'), expected) + + def test_06_procure_mo(self): + """Test procurement wizard with MOs.""" + mos = self.mo_obj.search([ + ('product_id', '=', self.fp_1.id)]) + self.assertFalse(mos) + mrp_inv = self.mrp_inventory_obj.search([ + ('product_mrp_area_id.product_id', '=', self.fp_1.id)]) + self.mrp_inventory_procure_wiz.with_context({ + 'active_model': 'mrp.inventory', + 'active_ids': mrp_inv.ids, + 'active_id': mrp_inv.id, + }).create({}).make_procurement() + mos = self.mo_obj.search([ + ('product_id', '=', self.fp_1.id)]) + self.assertTrue(mos) + self.assertEqual(mos.product_qty, 100.0) + mo_date_start = fields.Date.to_date(mos.date_planned_start) + self.assertEqual(mo_date_start, self.date_5) + + def test_07_adjust_qty_to_order(self): + """Test the adjustments made to the qty to procure when minimum, + maximum order quantities and quantity multiple are set.""" + # minimum order quantity: + mrp_inv_min = self.mrp_inventory_obj.search([ + ('product_mrp_area_id.product_id', '=', self.prod_min.id)]) + self.assertEqual(mrp_inv_min.to_procure, 50.0) + # maximum order quantity: + mrp_inv_max = self.mrp_inventory_obj.search([ + ('product_mrp_area_id.product_id', '=', self.prod_max.id)]) + self.assertEqual(mrp_inv_max.to_procure, 150) + plans = self.planned_order_obj.search([ + ('product_id', '=', self.prod_max.id), + ]) + self.assertEqual(len(plans), 2) + self.assertIn(100.0, plans.mapped('mrp_qty')) + self.assertIn(50.0, plans.mapped('mrp_qty')) + # quantity multiple: + mrp_inv_multiple = self.mrp_inventory_obj.search([ + ('product_mrp_area_id.product_id', '=', self.prod_multiple.id)]) + self.assertEqual(mrp_inv_multiple.to_procure, 125) + + def test_08_group_demand(self): + """Test demand grouping functionality, `nbr_days`.""" + pickings = self.stock_picking_obj.search([ + ('product_id', '=', self.prod_test.id), + ('location_id', '=', self.sec_loc.id)]) + self.assertEqual(len(pickings), 5) + moves = self.mrp_move_obj.search([ + ('product_id', '=', self.prod_test.id), + ('mrp_area_id', '=', self.secondary_area.id), + ]) + supply_plans = self.planned_order_obj.search([ + ('product_id', '=', self.prod_test.id), + ('mrp_area_id', '=', self.secondary_area.id), + ]) + moves_demand = moves.filtered(lambda m: m.mrp_type == 'd') + self.assertEqual(len(moves_demand), 5) + # two groups expected: + # 1. days 8, 9 and 10. + # 2. days 20, and 22. + self.assertEqual(len(supply_plans), 2) + quantities = supply_plans.mapped('mrp_qty') + week_1_expected = sum(moves_demand[0:3].mapped('mrp_qty')) + self.assertIn(abs(week_1_expected), quantities) + week_2_expected = sum(moves_demand[3:].mapped('mrp_qty')) + self.assertIn(abs(week_2_expected), quantities) + + def test_09_isolated_mrp_area_run(self): + """Test running MRP for just one area.""" + self.mrp_multi_level_wiz.sudo(self.mrp_manager).create({ + 'mrp_area_ids': [(6, 0, self.secondary_area.ids)], + }).run_mrp_multi_level() + this = self.mrp_inventory_obj.search([ + ('mrp_area_id', '=', self.secondary_area.id)], limit=1) + self.assertTrue(this) + # Only recently exectued areas should have been created by test user: + self.assertEqual(this.create_uid, self.mrp_manager) + prev = self.mrp_inventory_obj.search([ + ('mrp_area_id', '!=', self.secondary_area.id)], limit=1) + self.assertNotEqual(this.create_uid, prev.create_uid) diff --git a/mrp_multi_level/views/mrp_area_views.xml b/mrp_multi_level/views/mrp_area_views.xml new file mode 100644 index 000000000..d43633dab --- /dev/null +++ b/mrp_multi_level/views/mrp_area_views.xml @@ -0,0 +1,59 @@ + + + + + mrp.area.tree + mrp.area + tree + + + + + + + + + + + + + mrp.area.form + mrp.area + form + +
+ +
+ +
+
+
+
+
+ + + MRP Area + mrp.area + ir.actions.act_window + form + tree,form + + + +
diff --git a/mrp_multi_level/views/mrp_inventory_views.xml b/mrp_multi_level/views/mrp_inventory_views.xml new file mode 100644 index 000000000..3a096d448 --- /dev/null +++ b/mrp_multi_level/views/mrp_inventory_views.xml @@ -0,0 +1,130 @@ + + + + + mrp.inventory.form + mrp.inventory + form + +
+ + + + + + + + + + + + + + + + + + + +
+
+
+ + + mrp.inventory.tree + mrp.inventory + tree + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product.mrp.area.search + product.mrp.area + search + + + + + + + + + + + + Product MRP Area Parameters + product.mrp.area + ir.actions.act_window + form + tree,form + + + + +
diff --git a/mrp_multi_level/views/product_product_views.xml b/mrp_multi_level/views/product_product_views.xml new file mode 100644 index 000000000..c296c5434 --- /dev/null +++ b/mrp_multi_level/views/product_product_views.xml @@ -0,0 +1,22 @@ + + + + + view.product.mrp.area.product.form + product.product + + form + +
+ +
+
+
+
diff --git a/mrp_multi_level/views/product_template_views.xml b/mrp_multi_level/views/product_template_views.xml new file mode 100644 index 000000000..8527a11c6 --- /dev/null +++ b/mrp_multi_level/views/product_template_views.xml @@ -0,0 +1,22 @@ + + + + + product.template.product.form.mrp + product.template + + +
+ +
+
+
+ +
diff --git a/mrp_multi_level/views/stock_location_views.xml b/mrp_multi_level/views/stock_location_views.xml new file mode 100644 index 000000000..59144adeb --- /dev/null +++ b/mrp_multi_level/views/stock_location_views.xml @@ -0,0 +1,38 @@ + + + + + stock.location.form + stock.location + + + + + + + + + + stock.location.search + stock.location + + + + + + + + + + + stock.location.tree + stock.location + + + + + + + + + diff --git a/mrp_multi_level/wizards/__init__.py b/mrp_multi_level/wizards/__init__.py new file mode 100644 index 000000000..6e1a7350a --- /dev/null +++ b/mrp_multi_level/wizards/__init__.py @@ -0,0 +1,2 @@ +from . import mrp_multi_level +from . import mrp_inventory_procure diff --git a/mrp_multi_level/wizards/mrp_inventory_procure.py b/mrp_multi_level/wizards/mrp_inventory_procure.py new file mode 100644 index 000000000..e107a6ba6 --- /dev/null +++ b/mrp_multi_level/wizards/mrp_inventory_procure.py @@ -0,0 +1,144 @@ +# Copyright 2018-19 Eficent Business and IT Consulting Services S.L. +# (http://www.eficent.com) +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). + +from odoo import api, fields, models, _ +from odoo.exceptions import UserError, ValidationError + + +class MrpInventoryProcure(models.TransientModel): + _name = 'mrp.inventory.procure' + _description = 'Make Procurements from MRP inventory projections' + + item_ids = fields.One2many( + comodel_name='mrp.inventory.procure.item', + inverse_name='wiz_id', + string='Items', + ) + + @api.model + def _prepare_item(self, planned_order): + return { + 'planned_order_id': planned_order.id, + 'qty': planned_order.mrp_qty - planned_order.qty_released, + 'uom_id': planned_order.mrp_inventory_id.uom_id.id, + 'date_planned': planned_order.due_date, + 'mrp_inventory_id': planned_order.mrp_inventory_id.id, + 'product_id': planned_order.product_id.id, + 'warehouse_id': planned_order.mrp_area_id.warehouse_id.id, + 'location_id': + planned_order.product_mrp_area_id.location_proc_id.id or + planned_order.mrp_area_id.location_id.id, + } + + @api.model + def fields_view_get(self, view_id=None, view_type='form', toolbar=False, + submenu=False): + if self.user_has_groups( + "mrp_multi_level.group_change_mrp_procure_qty"): + view_id = self.env.ref( + 'mrp_multi_level.' + 'view_mrp_inventory_procure_wizard').id + else: + view_id = self.env.ref( + 'mrp_multi_level.' + 'view_mrp_inventory_procure_without_security').id + return super(MrpInventoryProcure, self).fields_view_get( + view_id=view_id, view_type=view_type, toolbar=toolbar, + submenu=submenu) + + @api.model + def default_get(self, fields): + res = super(MrpInventoryProcure, self).default_get(fields) + mrp_inventory_obj = self.env['mrp.inventory'] + mrp_inventory_ids = self.env.context['active_ids'] or [] + active_model = self.env.context['active_model'] + if not mrp_inventory_ids or 'item_ids' not in fields: + return res + + assert active_model == 'mrp.inventory', 'Bad context propagation' + + items = item_obj = self.env['mrp.inventory.procure.item'] + for line in mrp_inventory_obj.browse(mrp_inventory_ids).mapped( + 'planned_order_ids'): + if line.qty_released < line.mrp_qty: + items += item_obj.create(self._prepare_item(line)) + res['item_ids'] = [(6, 0, items.ids)] + return res + + @api.multi + def make_procurement(self): + self.ensure_one() + errors = [] + for item in self.item_ids: + if not item.qty: + raise ValidationError(_("Quantity must be positive.")) + values = item._prepare_procurement_values() + # Run procurement + try: + self.env['procurement.group'].run( + item.product_id, + item.qty, + item.uom_id, + item.location_id, + 'INT: ' + str(self.env.user.login), # name? + 'INT: ' + str(self.env.user.login), # origin? + values + ) + item.planned_order_id.qty_released += item.qty + except UserError as error: + errors.append(error.name) + if errors: + raise UserError('\n'.join(errors)) + return {'type': 'ir.actions.act_window_close'} + + +class MrpInventoryProcureItem(models.TransientModel): + _name = 'mrp.inventory.procure.item' + _description = "MRP Inventory procure item" + + wiz_id = fields.Many2one( + comodel_name='mrp.inventory.procure', string='Wizard', + ondelete='cascade', readonly=True, + ) + qty = fields.Float(string='Quantity') + uom_id = fields.Many2one( + string='Unit of Measure', + comodel_name='uom.uom', + ) + date_planned = fields.Date(string='Planned Date', required=False) + mrp_inventory_id = fields.Many2one( + string='Mrp Inventory', + comodel_name='mrp.inventory', + ) + planned_order_id = fields.Many2one( + comodel_name='mrp.planned.order', + ) + product_id = fields.Many2one( + string='Product', + comodel_name='product.product', + ) + warehouse_id = fields.Many2one( + string='Warehouse', + comodel_name='stock.warehouse', + ) + location_id = fields.Many2one( + string='Location', + comodel_name='stock.location', + ) + + def _prepare_procurement_values(self, group=False): + return { + 'date_planned': fields.Datetime.to_string( + fields.Date.from_string(self.date_planned)), + 'warehouse_id': self.warehouse_id, + # 'company_id': self.company_id, # TODO: consider company + 'group_id': group, + } + + @api.multi + @api.onchange('uom_id') + def onchange_uom_id(self): + for rec in self: + rec.qty = rec.mrp_inventory_id.uom_id._compute_quantity( + rec.mrp_inventory_id.to_procure, rec.uom_id) diff --git a/mrp_multi_level/wizards/mrp_inventory_procure_views.xml b/mrp_multi_level/wizards/mrp_inventory_procure_views.xml new file mode 100644 index 000000000..482bf5dc8 --- /dev/null +++ b/mrp_multi_level/wizards/mrp_inventory_procure_views.xml @@ -0,0 +1,59 @@ + + + + + + mrp.inventory.procure.form + mrp.inventory.procure + +
+

+ Use this assistant to procure for this product and date. + According to the product configuration, + this may trigger a draft purchase order, a manufacturing + order or a transfer picking. +

+ + + + + + + + + + + + + +
+
+
+
+
+ + + + mrp.inventory.procure.form - readonly qty + mrp.inventory.procure + + primary + + + 1 + + + + + + Procure + mrp.inventory.procure + form + new + + + +
diff --git a/mrp_multi_level/wizards/mrp_multi_level.py b/mrp_multi_level/wizards/mrp_multi_level.py new file mode 100644 index 000000000..e46eca453 --- /dev/null +++ b/mrp_multi_level/wizards/mrp_multi_level.py @@ -0,0 +1,712 @@ +# Copyright 2016 Ucamco - Wim Audenaert +# Copyright 2016-19 Eficent Business and IT Consulting Services S.L. +# - Jordi Ballester Alomar +# - Lois Rilo +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). + +from odoo import api, fields, models, exceptions, _ +from datetime import date, timedelta +import logging +logger = logging.getLogger(__name__) + + +class MultiLevelMrp(models.TransientModel): + _name = 'mrp.multi.level' + _description = "Multi Level MRP" + + mrp_area_ids = fields.Many2many( + comodel_name="mrp.area", + string="MRP Areas to run", + help="If empty, all areas will be computed.", + ) + + # TODO: dates are not being correctly computed for supply... + + @api.model + def _prepare_product_mrp_area_data(self, product_mrp_area): + qty_available = 0.0 + product_obj = self.env['product.product'] + location_ids = product_mrp_area.mrp_area_id._get_locations() + for location in location_ids: + product_l = product_obj.with_context( + {'location': location.id}).browse( + product_mrp_area.product_id.id) + qty_available += product_l.qty_available + + return { + 'product_mrp_area_id': product_mrp_area.id, + 'mrp_qty_available': qty_available, + 'mrp_llc': product_mrp_area.product_id.llc, + } + + @api.model + def _prepare_mrp_move_data_from_stock_move( + self, product_mrp_area, move, direction='in'): + if direction == 'out': + mrp_type = 'd' + product_qty = -move.product_qty + else: + mrp_type = 's' + product_qty = move.product_qty + po = po_line = None + mo = origin = order_number = parent_product_id = None + if move.purchase_line_id: + order_number = move.purchase_line_id.order_id.name + origin = 'po' + po = move.purchase_line_id.order_id.id + po_line = move.purchase_line_id.id + if move.production_id: + order_number = move.production_id.name + origin = 'mo' + mo = move.production_id.id + else: + if move.move_dest_ids: + # move_dest_id = move.move_dest_ids[:1] + for move_dest_id in move.move_dest_ids: + if move_dest_id.production_id: + order_number = move_dest_id.production_id.name + origin = 'mo' + mo = move_dest_id.production_id.id + if move_dest_id.production_id.product_id: + parent_product_id = \ + move_dest_id.production_id.product_id.id + else: + parent_product_id = move_dest_id.product_id.id + if order_number is None: + order_number = move.name + mrp_date = date.today() + if move.date_expected.date() > date.today(): + mrp_date = move.date_expected.date() + return { + 'product_id': move.product_id.id, + 'product_mrp_area_id': product_mrp_area.id, + 'production_id': mo, + 'purchase_order_id': po, + 'purchase_line_id': po_line, + 'stock_move_id': move.id, + 'mrp_qty': product_qty, + 'current_qty': product_qty, + 'mrp_date': mrp_date, + 'current_date': move.date_expected, + 'mrp_type': mrp_type, + 'mrp_origin': origin, + 'mrp_order_number': order_number, + 'parent_product_id': parent_product_id, + 'name': order_number, + 'state': move.state, + } + + @api.model + def _prepare_planned_order_data( + self, product_mrp_area, qty, mrp_date_supply, + mrp_action_date, name + ): + return { + 'product_mrp_area_id': product_mrp_area.id, + 'mrp_qty': qty, + 'due_date': mrp_date_supply, + 'order_release_date': mrp_action_date, + 'mrp_action': product_mrp_area.supply_method, + 'qty_released': 0.0, + 'name': 'Supply: ' + name, + } + + @api.model + def _prepare_mrp_move_data_bom_explosion( + self, product, bomline, qty, mrp_date_demand_2, bom, name): + product_mrp_area = self._get_product_mrp_area_from_product_and_area( + bomline.product_id, product.mrp_area_id) + if not product_mrp_area: + raise exceptions.Warning( + _("No MRP product found")) + + return { + 'mrp_area_id': product.mrp_area_id.id, + 'product_id': bomline.product_id.id, + 'product_mrp_area_id': product_mrp_area.id, + 'production_id': None, + 'purchase_order_id': None, + 'purchase_line_id': None, + 'stock_move_id': None, + 'mrp_qty': -(qty * bomline.product_qty), # TODO: review with UoM + 'current_qty': None, + 'mrp_date': mrp_date_demand_2, + 'current_date': None, + 'mrp_type': 'd', + 'mrp_origin': 'mrp', + 'mrp_order_number': None, + 'parent_product_id': bom.product_id.id, + 'name': + ('Demand Bom Explosion: ' + name).replace( + 'Demand Bom Explosion: Demand Bom ' + 'Explosion: ', + 'Demand Bom Explosion: '), + } + + @api.model + def _get_action_and_supply_dates(self, product_mrp_area, mrp_date): + if not isinstance(mrp_date, date): + mrp_date = fields.Date.from_string(mrp_date) + + if mrp_date < date.today(): + mrp_date_supply = date.today() + else: + mrp_date_supply = mrp_date + + calendar = product_mrp_area.mrp_area_id.calendar_id + if calendar and product_mrp_area.mrp_lead_time: + date_str = fields.Date.to_string(mrp_date) + dt = fields.Datetime.from_string(date_str) + # dt is at the beginning of the day (00:00) + res = calendar.plan_days( + -1 * product_mrp_area.mrp_lead_time, dt) + mrp_action_date = res.date() + else: + mrp_action_date = mrp_date - timedelta( + days=product_mrp_area.mrp_lead_time) + return mrp_action_date, mrp_date_supply + + @api.model + def explode_action( + self, product_mrp_area_id, mrp_action_date, name, qty, action + ): + """Explode requirements.""" + mrp_date_demand = mrp_action_date + if mrp_date_demand < date.today(): + mrp_date_demand = date.today() + if not product_mrp_area_id.product_id.bom_ids: + return False + bomcount = 0 + for bom in product_mrp_area_id.product_id.bom_ids: + if not bom.active or not bom.bom_line_ids: + continue + bomcount += 1 + if bomcount != 1: + continue + for bomline in bom.bom_line_ids: + if bomline.product_qty <= 0.00 or \ + bomline.product_id.type != 'product': + continue + if self.with_context(mrp_explosion=True)._exclude_from_mrp( + bomline.product_id, + product_mrp_area_id.mrp_area_id): + # Stop explosion. + continue + # TODO: review: mrp_transit_delay, mrp_inspection_delay + mrp_date_demand_2 = mrp_date_demand - timedelta( + days=(product_mrp_area_id.mrp_transit_delay + + product_mrp_area_id.mrp_inspection_delay)) + move_data = \ + self._prepare_mrp_move_data_bom_explosion( + product_mrp_area_id, bomline, qty, + mrp_date_demand_2, + bom, name) + mrpmove_id2 = self.env['mrp.move'].create(move_data) + if hasattr(action, "mrp_move_down_ids"): + action.mrp_move_down_ids = [(4, mrpmove_id2.id)] + return True + + @api.model + def create_action( + self, product_mrp_area_id, mrp_date, mrp_qty, name, values=None, + ): + if not values: + values = {} + if not isinstance(mrp_date, date): + mrp_date = fields.Date.from_string(mrp_date) + action_date, date_supply = \ + self._get_action_and_supply_dates(product_mrp_area_id, mrp_date) + return self.create_planned_order( + product_mrp_area_id, mrp_qty, name, date_supply, + action_date, values=values) + + @api.model + def create_planned_order( + self, product_mrp_area_id, mrp_qty, + name, mrp_date_supply, mrp_action_date, values=None, + ): + self = self.with_context(auditlog_disabled=True) + + qty_ordered = values.get("qty_ordered", 0.0) if values else 0.0 + qty_to_order = mrp_qty + while qty_ordered < mrp_qty: + qty = product_mrp_area_id._adjust_qty_to_order(qty_to_order) + qty_to_order -= qty + order_data = self._prepare_planned_order_data( + product_mrp_area_id, qty, mrp_date_supply, mrp_action_date, + name) + planned_order = self.env['mrp.planned.order'].create(order_data) + qty_ordered = qty_ordered + qty + + if product_mrp_area_id.supply_method == 'manufacture': + self.explode_action( + product_mrp_area_id, mrp_action_date, + name, qty, planned_order) + + values['qty_ordered'] = qty_ordered + log_msg = '[%s] %s: qty_ordered = %s' % ( + product_mrp_area_id.mrp_area_id.name, + product_mrp_area_id.product_id.default_code or + product_mrp_area_id.product_id.name, + qty_ordered, + ) + logger.debug(log_msg) + return values + + @api.model + def _mrp_cleanup(self, mrp_areas): + logger.info('Start MRP Cleanup') + domain = [] + if mrp_areas: + domain += [('mrp_area_id', 'in', mrp_areas.ids)] + self.env['mrp.move'].search(domain).unlink() + self.env['mrp.inventory'].search(domain).unlink() + domain += [('fixed', '=', False)] + self.env['mrp.planned.order'].search(domain).unlink() + logger.info('End MRP Cleanup') + return True + + @api.model + def _low_level_code_calculation(self): + logger.info('Start low level code calculation') + counter = 999999 + llc = 0 + self.env['product.product'].search([]).write({'llc': llc}) + products = self.env['product.product'].search([('llc', '=', llc)]) + if products: + counter = len(products) + log_msg = 'Low level code 0 finished - Nbr. products: %s' % counter + logger.info(log_msg) + + while counter: + llc += 1 + products = self.env['product.product'].search( + [('llc', '=', llc - 1)]) + p_templates = products.mapped('product_tmpl_id') + bom_lines = self.env['mrp.bom.line'].search( + [('product_id.llc', '=', llc - 1), + ('bom_id.product_tmpl_id', 'in', p_templates.ids)]) + products = bom_lines.mapped('product_id') + products.write({'llc': llc}) + products = self.env['product.product'].search([('llc', '=', llc)]) + counter = len(products) + log_msg = 'Low level code %s finished - Nbr. products: %s' % ( + llc, counter) + logger.info(log_msg) + + mrp_lowest_llc = llc + logger.info('End low level code calculation') + return mrp_lowest_llc + + @api.model + def _adjust_mrp_applicable(self, mrp_areas): + """This method is meant to modify the products that are applicable + to MRP Multi level calculation + """ + return True + + @api.model + def _calculate_mrp_applicable(self, mrp_areas): + logger.info('Start Calculate MRP Applicable') + domain = [] + if mrp_areas: + domain += [('mrp_area_id', 'in', mrp_areas.ids)] + self.env['product.mrp.area'].search(domain).write( + {'mrp_applicable': False}) + domain += [('product_id.type', '=', 'product')] + self.env['product.mrp.area'].search(domain).write( + {'mrp_applicable': True}) + self._adjust_mrp_applicable(mrp_areas) + count_domain = [('mrp_applicable', '=', True)] + if mrp_areas: + count_domain += [('mrp_area_id', 'in', mrp_areas.ids)] + counter = self.env['product.mrp.area'].search(count_domain, count=True) + log_msg = 'End Calculate MRP Applicable: %s' % counter + logger.info(log_msg) + return True + + @api.model + def _init_mrp_move_from_forecast(self, product_mrp_area): + """This method is meant to be inherited to add a forecast mechanism.""" + return True + + # TODO: move this methods to product_mrp_area?? to be able to + # show moves with an action + @api.model + def _in_stock_moves_domain(self, product_mrp_area): + locations = product_mrp_area.mrp_area_id._get_locations() + return [ + ('product_id', '=', product_mrp_area.product_id.id), + ('state', 'not in', ['done', 'cancel']), + ('product_qty', '>', 0.00), + ('location_id', 'not in', locations.ids), + ('location_dest_id', 'in', locations.ids), + ] + + @api.model + def _out_stock_moves_domain(self, product_mrp_area): + locations = product_mrp_area.mrp_area_id._get_locations() + return [ + ('product_id', '=', product_mrp_area.product_id.id), + ('state', 'not in', ['done', 'cancel']), + ('product_qty', '>', 0.00), + ('location_id', 'in', locations.ids), + ('location_dest_id', 'not in', locations.ids), + ] + + @api.model + def _init_mrp_move_from_stock_move(self, product_mrp_area): + move_obj = self.env['stock.move'] + mrp_move_obj = self.env['mrp.move'] + in_domain = self._in_stock_moves_domain(product_mrp_area) + in_moves = move_obj.search(in_domain) + out_domain = self._out_stock_moves_domain(product_mrp_area) + out_moves = move_obj.search(out_domain) + if in_moves: + for move in in_moves: + move_data = self._prepare_mrp_move_data_from_stock_move( + product_mrp_area, move, direction='in') + mrp_move_obj.create(move_data) + if out_moves: + for move in out_moves: + move_data = self._prepare_mrp_move_data_from_stock_move( + product_mrp_area, move, direction='out') + mrp_move_obj.create(move_data) + return True + + @api.model + def _prepare_mrp_move_data_from_purchase_order( + self, poline, product_mrp_area): + mrp_date = date.today() + if fields.Date.from_string(poline.date_planned) > date.today(): + mrp_date = fields.Date.from_string(poline.date_planned) + return { + 'product_id': poline.product_id.id, + 'product_mrp_area_id': product_mrp_area.id, + 'production_id': None, + 'purchase_order_id': poline.order_id.id, + 'purchase_line_id': poline.id, + 'stock_move_id': None, + 'mrp_qty': poline.product_qty, + 'current_qty': poline.product_qty, + 'mrp_date': mrp_date, + 'current_date': poline.date_planned, + 'mrp_type': 's', + 'mrp_origin': 'po', + 'mrp_order_number': poline.order_id.name, + 'parent_product_id': None, + 'name': poline.order_id.name, + 'state': poline.order_id.state, + } + + @api.model + def _init_mrp_move_from_purchase_order(self, product_mrp_area): + location_ids = product_mrp_area.mrp_area_id._get_locations() + picking_types = self.env['stock.picking.type'].search( + [('default_location_dest_id', 'in', + location_ids.ids)]) + picking_type_ids = [ptype.id for ptype in picking_types] + orders = self.env['purchase.order'].search( + [('picking_type_id', 'in', picking_type_ids), + ('state', 'in', ['draft', 'sent', 'to approve'])]) + po_lines = self.env['purchase.order.line'].search( + [('order_id', 'in', orders.ids), + ('product_qty', '>', 0.0), + ('product_id', '=', product_mrp_area.product_id.id)]) + + for line in po_lines: + mrp_move_data = \ + self._prepare_mrp_move_data_from_purchase_order( + line, product_mrp_area) + self.env['mrp.move'].create(mrp_move_data) + + @api.model + def _get_product_mrp_area_from_product_and_area(self, product, mrp_area): + return self.env['product.mrp.area'].search([ + ('product_id', '=', product.id), + ('mrp_area_id', '=', mrp_area.id), + ], limit=1) + + @api.model + def _init_mrp_move(self, product_mrp_area): + self._init_mrp_move_from_forecast(product_mrp_area) + self._init_mrp_move_from_stock_move(product_mrp_area) + self._init_mrp_move_from_purchase_order(product_mrp_area) + + @api.model + def _exclude_from_mrp(self, product, mrp_area): + """ To extend with various logic where needed. """ + product_mrp_area = self.env['product.mrp.area'].search( + [('product_id', '=', product.id), + ('mrp_area_id', '=', mrp_area.id)], limit=1) + if not product_mrp_area: + return True + return product_mrp_area.mrp_exclude + + @api.model + def _mrp_initialisation(self, mrp_areas): + logger.info('Start MRP initialisation') + if not mrp_areas: + mrp_areas = self.env['mrp.area'].search([]) + product_mrp_areas = self.env['product.mrp.area'].search([ + ('mrp_area_id', 'in', mrp_areas.ids), + ('mrp_applicable', '=', True), + ]) + init_counter = 0 + for mrp_area in mrp_areas: + for product_mrp_area in product_mrp_areas.filtered( + lambda a: a.mrp_area_id == mrp_area): + if self._exclude_from_mrp( + product_mrp_area.product_id, mrp_area): + continue + init_counter += 1 + log_msg = 'MRP Init: %s - %s ' % ( + init_counter, product_mrp_area.display_name) + logger.info(log_msg) + self._init_mrp_move(product_mrp_area) + logger.info('End MRP initialisation') + + @api.model + def _init_mrp_move_grouped_demand(self, nbr_create, product_mrp_area): + last_date = None + last_qty = 0.00 + onhand = product_mrp_area.qty_available + grouping_delta = product_mrp_area.mrp_nbr_days + for move in product_mrp_area.mrp_move_ids: + if self._exclude_move(move): + continue + if last_date and ( + fields.Date.from_string(move.mrp_date) + >= last_date + timedelta(days=grouping_delta)) and ( + (onhand + last_qty + move.mrp_qty) + < product_mrp_area.mrp_minimum_stock + or (onhand + last_qty) + < product_mrp_area.mrp_minimum_stock): + name = 'Grouped Demand for %d Days' % grouping_delta + qtytoorder = product_mrp_area.mrp_minimum_stock - last_qty + cm = self.create_action( + product_mrp_area_id=product_mrp_area, + mrp_date=last_date, + mrp_qty=qtytoorder, + name=name) + qty_ordered = cm.get('qty_ordered', 0.0) + onhand = onhand + last_qty + qty_ordered + last_date = None + last_qty = 0.00 + nbr_create += 1 + if (onhand + last_qty + move.mrp_qty) < \ + product_mrp_area.mrp_minimum_stock or \ + (onhand + last_qty) < \ + product_mrp_area.mrp_minimum_stock: + if not last_date or last_qty == 0.0: + last_date = fields.Date.from_string(move.mrp_date) + last_qty = move.mrp_qty + else: + last_qty += move.mrp_qty + else: + last_date = fields.Date.from_string(move.mrp_date) + onhand += move.mrp_qty + + if last_date and last_qty != 0.00: + name = 'Grouped Demand for %d Days' % grouping_delta + qtytoorder = product_mrp_area.mrp_minimum_stock - onhand - last_qty + cm = self.create_action( + product_mrp_area_id=product_mrp_area, mrp_date=last_date, + mrp_qty=qtytoorder, name=name) + qty_ordered = cm.get('qty_ordered', 0.0) + onhand += qty_ordered + nbr_create += 1 + return nbr_create + + @api.model + def _exclude_move(self, move): + """Improve extensibility being able to exclude special moves.""" + return False + + @api.model + def _mrp_calculation(self, mrp_lowest_llc, mrp_areas): + logger.info('Start MRP calculation') + product_mrp_area_obj = self.env['product.mrp.area'] + counter = 0 + if not mrp_areas: + mrp_areas = self.env['mrp.area'].search([]) + for mrp_area in mrp_areas: + llc = 0 + while mrp_lowest_llc > llc: + product_mrp_areas = product_mrp_area_obj.search( + [('product_id.llc', '=', llc), + ('mrp_area_id', '=', mrp_area.id)]) + llc += 1 + + for product_mrp_area in product_mrp_areas: + nbr_create = 0 + onhand = product_mrp_area.qty_available + if product_mrp_area.mrp_nbr_days == 0: + for move in product_mrp_area.mrp_move_ids: + if self._exclude_move(move): + continue + qtytoorder = product_mrp_area.mrp_minimum_stock - \ + onhand - move.mrp_qty + if qtytoorder > 0.0: + cm = self.create_action( + product_mrp_area_id=product_mrp_area, + mrp_date=move.mrp_date, + mrp_qty=qtytoorder, name=move.name) + qty_ordered = cm['qty_ordered'] + onhand += move.mrp_qty + qty_ordered + nbr_create += 1 + else: + onhand += move.mrp_qty + else: + nbr_create = self._init_mrp_move_grouped_demand( + nbr_create, product_mrp_area) + + if onhand < product_mrp_area.mrp_minimum_stock and \ + nbr_create == 0: + qtytoorder = \ + product_mrp_area.mrp_minimum_stock - onhand + cm = self.create_action( + product_mrp_area_id=product_mrp_area, + mrp_date=date.today(), + mrp_qty=qtytoorder, + name='Minimum Stock') + qty_ordered = cm['qty_ordered'] + onhand += qty_ordered + counter += 1 + + log_msg = 'MRP Calculation LLC %s Finished - Nbr. products: %s' % ( + llc - 1, counter) + logger.info(log_msg) + + logger.info('Enb MRP calculation') + + @api.model + def _get_demand_groups(self, product_mrp_area): + query = """ + SELECT mrp_date, sum(mrp_qty) + FROM mrp_move + WHERE product_mrp_area_id = %(mrp_product)s + AND mrp_type = 'd' + GROUP BY mrp_date + """ + params = { + 'mrp_product': product_mrp_area.id + } + return query, params + + @api.model + def _get_supply_groups(self, product_mrp_area): + query = """ + SELECT mrp_date, sum(mrp_qty) + FROM mrp_move + WHERE product_mrp_area_id = %(mrp_product)s + AND mrp_type = 's' + GROUP BY mrp_date + """ + params = { + 'mrp_product': product_mrp_area.id, + } + return query, params + + @api.model + def _get_planned_order_groups(self, product_mrp_area): + query = """ + SELECT due_date, sum(mrp_qty) + FROM mrp_planned_order + WHERE product_mrp_area_id = %(mrp_product)s + GROUP BY due_date + """ + params = { + 'mrp_product': product_mrp_area.id + } + return query, params + + @api.model + def _init_mrp_inventory(self, product_mrp_area): + mrp_move_obj = self.env['mrp.move'] + planned_order_obj = self.env['mrp.planned.order'] + # Read Demand + demand_qty_by_date = {} + query, params = self._get_demand_groups(product_mrp_area) + self.env.cr.execute(query, params) + for mrp_date, qty in self.env.cr.fetchall(): + demand_qty_by_date[mrp_date] = qty + # Read Supply + supply_qty_by_date = {} + query, params = self._get_supply_groups(product_mrp_area) + self.env.cr.execute(query, params) + for mrp_date, qty in self.env.cr.fetchall(): + supply_qty_by_date[mrp_date] = qty + # Read planned orders: + planned_qty_by_date = {} + query, params = self._get_planned_order_groups(product_mrp_area) + self.env.cr.execute(query, params) + for mrp_date, qty in self.env.cr.fetchall(): + planned_qty_by_date[mrp_date] = qty + # Dates + moves_dates = mrp_move_obj.search([ + ('product_mrp_area_id', '=', product_mrp_area.id)], + order='mrp_date').mapped('mrp_date') + action_dates = planned_order_obj.search([ + ('product_mrp_area_id', '=', product_mrp_area.id)], + order='due_date').mapped('due_date') + mrp_dates = set(moves_dates + action_dates) + on_hand_qty = product_mrp_area.product_id.with_context( + location=product_mrp_area.mrp_area_id.location_id.id + )._product_available()[ + product_mrp_area.product_id.id]['qty_available'] + running_availability = on_hand_qty + for mdt in sorted(mrp_dates): + mrp_inventory_data = { + 'product_mrp_area_id': product_mrp_area.id, + 'date': mdt, + } + demand_qty = demand_qty_by_date.get(mdt, 0.0) + mrp_inventory_data['demand_qty'] = abs(demand_qty) + supply_qty = supply_qty_by_date.get(mdt, 0.0) + mrp_inventory_data['supply_qty'] = abs(supply_qty) + mrp_inventory_data['initial_on_hand_qty'] = on_hand_qty + on_hand_qty += (supply_qty + demand_qty) + mrp_inventory_data['final_on_hand_qty'] = on_hand_qty + # Consider that MRP plan is followed exactly: + running_availability += supply_qty \ + + demand_qty + planned_qty_by_date.get(mdt, 0.0) + mrp_inventory_data['running_availability'] = running_availability + + inv_id = self.env['mrp.inventory'].create(mrp_inventory_data) + # attach planned orders to inventory + planned_order_obj.search([ + ('due_date', '=', mdt), + ('product_mrp_area_id', '=', product_mrp_area.id), + ]).write( + {'mrp_inventory_id': inv_id.id}) + + @api.model + def _mrp_final_process(self, mrp_areas): + logger.info('Start MRP final process') + domain = [('product_id.llc', '<', 9999)] + if mrp_areas: + domain += [('mrp_area_id', 'in', mrp_areas.ids)] + product_mrp_area_ids = self.env['product.mrp.area'].search(domain) + + for product_mrp_area in product_mrp_area_ids: + # Build the time-phased inventory + if self._exclude_from_mrp( + product_mrp_area.product_id, + product_mrp_area.mrp_area_id): + continue + self._init_mrp_inventory(product_mrp_area) + logger.info('End MRP final process') + + @api.multi + def run_mrp_multi_level(self): + self._mrp_cleanup(self.mrp_area_ids) + mrp_lowest_llc = self._low_level_code_calculation() + self._calculate_mrp_applicable(self.mrp_area_ids) + self._mrp_initialisation(self.mrp_area_ids) + self._mrp_calculation(mrp_lowest_llc, self.mrp_area_ids) + self._mrp_final_process(self.mrp_area_ids) + # Open MRP inventory screen to show result if manually run: + action = self.env.ref("mrp_multi_level.mrp_inventory_action") + result = action.read()[0] + return result diff --git a/mrp_multi_level/wizards/mrp_multi_level_views.xml b/mrp_multi_level/wizards/mrp_multi_level_views.xml new file mode 100644 index 000000000..3685ab597 --- /dev/null +++ b/mrp_multi_level/wizards/mrp_multi_level_views.xml @@ -0,0 +1,29 @@ + + + + + Run MRP + mrp.multi.level + +
+ + + +
+
+
+
+
+ + + +
diff --git a/setup/_metapackage/VERSION.txt b/setup/_metapackage/VERSION.txt index ea60b1adb..ee5cb59f6 100644 --- a/setup/_metapackage/VERSION.txt +++ b/setup/_metapackage/VERSION.txt @@ -1 +1 @@ -12.0.20190731.0 \ No newline at end of file +12.0.20190902.0 \ No newline at end of file diff --git a/setup/_metapackage/setup.py b/setup/_metapackage/setup.py index 3c8b76550..4804c0119 100644 --- a/setup/_metapackage/setup.py +++ b/setup/_metapackage/setup.py @@ -12,6 +12,7 @@ setuptools.setup( 'odoo12-addon-mrp_bom_component_menu', 'odoo12-addon-mrp_bom_location', 'odoo12-addon-mrp_bom_tracking', + 'odoo12-addon-mrp_multi_level', 'odoo12-addon-mrp_production_grouped_by_product', 'odoo12-addon-mrp_production_putaway_strategy', 'odoo12-addon-mrp_stock_orderpoint_manual_procurement', diff --git a/setup/mrp_multi_level/odoo/addons/mrp_multi_level b/setup/mrp_multi_level/odoo/addons/mrp_multi_level new file mode 120000 index 000000000..619fe2157 --- /dev/null +++ b/setup/mrp_multi_level/odoo/addons/mrp_multi_level @@ -0,0 +1 @@ +../../../../mrp_multi_level \ No newline at end of file diff --git a/setup/mrp_multi_level/setup.py b/setup/mrp_multi_level/setup.py new file mode 100644 index 000000000..28c57bb64 --- /dev/null +++ b/setup/mrp_multi_level/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +)