mirror of
https://github.com/bringout/oca-technical.git
synced 2026-04-18 05:52:06 +02:00
Initial commit: OCA Technical packages (595 packages)
This commit is contained in:
commit
2cc02aac6e
24950 changed files with 2318079 additions and 0 deletions
50
odoo-bringout-oca-ddmrp-ddmrp/README.md
Normal file
50
odoo-bringout-oca-ddmrp-ddmrp/README.md
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
# DDMRP
|
||||
|
||||
Odoo addon: ddmrp
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
pip install odoo-bringout-oca-ddmrp-ddmrp
|
||||
```
|
||||
|
||||
## Dependencies
|
||||
|
||||
This addon depends on:
|
||||
- purchase_stock
|
||||
- stock_demand_estimate
|
||||
- web_widget_bokeh_chart
|
||||
- mrp_multi_level
|
||||
- base_cron_exclusion
|
||||
- stock_warehouse_calendar
|
||||
- stock_helper
|
||||
|
||||
## Manifest Information
|
||||
|
||||
- **Name**: DDMRP
|
||||
- **Version**: 16.0.1.12.0
|
||||
- **Category**: Warehouse
|
||||
- **License**: LGPL-3
|
||||
- **Installable**: True
|
||||
|
||||
## Source
|
||||
|
||||
Based on [OCA/ddmrp](https://github.com/OCA/ddmrp) branch 16.0, addon `ddmrp`.
|
||||
|
||||
## License
|
||||
|
||||
This package maintains the original LGPL-3 license from the upstream Odoo project.
|
||||
|
||||
## Documentation
|
||||
|
||||
- Overview: doc/OVERVIEW.md
|
||||
- Architecture: doc/ARCHITECTURE.md
|
||||
- Models: doc/MODELS.md
|
||||
- Controllers: doc/CONTROLLERS.md
|
||||
- Wizards: doc/WIZARDS.md
|
||||
- Install: doc/INSTALL.md
|
||||
- Usage: doc/USAGE.md
|
||||
- Configuration: doc/CONFIGURATION.md
|
||||
- Dependencies: doc/DEPENDENCIES.md
|
||||
- Troubleshooting: doc/TROUBLESHOOTING.md
|
||||
- FAQ: doc/FAQ.md
|
||||
341
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/README.rst
Normal file
341
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/README.rst
Normal file
|
|
@ -0,0 +1,341 @@
|
|||
.. image:: https://odoo-community.org/readme-banner-image
|
||||
:target: https://odoo-community.org/get-involved?utm_source=readme
|
||||
:alt: Odoo Community Association
|
||||
|
||||
=====
|
||||
DDMRP
|
||||
=====
|
||||
|
||||
..
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
!! This file is generated by oca-gen-addon-readme !!
|
||||
!! changes will be overwritten. !!
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
!! source digest: sha256:f43055b32a5e8e104d8a45da35fc5716767773214054bbfe54da0c23dd8be731
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
.. |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/license-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%2Fddmrp-lightgray.png?logo=github
|
||||
:target: https://github.com/OCA/ddmrp/tree/16.0/ddmrp
|
||||
:alt: OCA/ddmrp
|
||||
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
|
||||
:target: https://translation.odoo-community.org/projects/ddmrp-16-0/ddmrp-16-0-ddmrp
|
||||
:alt: Translate me on Weblate
|
||||
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
|
||||
:target: https://runboat.odoo-community.org/builds?repo=OCA/ddmrp&target_branch=16.0
|
||||
:alt: Try me on Runboat
|
||||
|
||||
|badge1| |badge2| |badge3| |badge4| |badge5|
|
||||
|
||||
Demand Driven Material Requirements Planning is a formal multi-echelon
|
||||
planning and execution method developed by Ms. Carol Ptak and Mr. Chad Smith.
|
||||
|
||||
DDMRP combines blended aspects of Material Requirements Planning (MRP),
|
||||
Distribution Requirements Planning (DRP) with the pull and visibility
|
||||
emphases found in Lean and the Theory of Constraints and the variability
|
||||
reduction emphasis of Six Sigma.
|
||||
|
||||
This method has five sequential components:
|
||||
|
||||
#. *Strategic Inventory Positioning*. Answers the question "Given our system
|
||||
and environment, where should we place inventory to have the best
|
||||
protection?" and determines where should decoupling points of inventory be
|
||||
placed.
|
||||
|
||||
#. *Buffer Profiles and Levels*. Determine the amount of protection at those
|
||||
decoupling points.
|
||||
|
||||
#. *Dynamic Adjustments*. Allow the company to adapt buffers to group and
|
||||
individual part trait changes over time through the use of several types
|
||||
of adjustments.
|
||||
|
||||
#. *Demand Driven Planning*. Allow to launch purchase orders (POs),
|
||||
manufacturing orders (MOs) and Transfer Orders (TOs) based on the priority
|
||||
dictated by the buffers.
|
||||
|
||||
#. *Visible and Collaborative Execution*. These POs, MOs and TOs have to be
|
||||
effectively managed to synchronize with the changes that often occur within
|
||||
the "execution horizon."
|
||||
|
||||
These five components work together to greatly dampen, if not eliminate,
|
||||
the nervousness of traditional MRP systems and the bullwhip effect in
|
||||
complex and challenging environments.
|
||||
|
||||
This approach provides real information about those parts that are
|
||||
truly at risk of negatively impacting the planned availability of inventory.
|
||||
|
||||
DDMRP sorts the significant few items that require attention from
|
||||
the many parts that are being managed. Under the DDMRP approach,
|
||||
fewer planners can make better decisions more quickly. That means companies
|
||||
will be better able to leverage their working and human capital.
|
||||
|
||||
Demand Driven Material Requirements Planning is quickly being adopted
|
||||
by a wide variety of leading companies across the world.
|
||||
|
||||
Some of the benefits reported by the DDMRP method include:
|
||||
|
||||
* High fill rate performance
|
||||
* Lead time reductions
|
||||
* Inventory reductions, while improving customer service
|
||||
* Eliminate costs related to expedite
|
||||
* Planners see priorities instead of constantly fighting the conflicting
|
||||
messages of MRP
|
||||
|
||||
It is highly recommended to read the book 'Demand Driven Material
|
||||
Requirements Planning (DDMRP)' by Carol Ptak and Chad Smith.
|
||||
|
||||
**Table of contents**
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
We strongly recommend to modify the configuration of the reservation method
|
||||
to manual in the outgoing operation types (so deliveries
|
||||
related to Sales Orders aren't automatically reserved) and to avoid to
|
||||
reserve stock for specific moves, buffers are in fact a reservation of stock.
|
||||
However, while **reservation is discouraged**, it is still available to be
|
||||
used, in case of reserved stock be aware that the buffer will be blind to this
|
||||
transfers and stock and you are bypassing the DDMRP reordering flow.
|
||||
|
||||
Configuration
|
||||
=============
|
||||
|
||||
Scheduled actions
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Go to *Settings > Technical*.
|
||||
* 'DDMRP Buffer ADU calculation'. Computes the Average Daily Usage for all
|
||||
Buffers.
|
||||
* 'Reordering Rule DDMRP calculation'. Computes the Qualified Demand, Net
|
||||
Flow Position, Planning and Execution priorities for all Buffers.
|
||||
|
||||
Decoupled Lead Time computation
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The DLT is automatically computed by the system.
|
||||
|
||||
For manufactured products' buffers just remember to provide and
|
||||
set properly the following information:
|
||||
|
||||
* The *Manufacturing Lead Time* for the manufactured product. It can be found
|
||||
at the product form view under the tab *Sales*.
|
||||
* The *Delivery Lead Time* for the preferred vendor of a product. This is
|
||||
important for the products which are purchased and are components in any
|
||||
Bill of Materials.
|
||||
|
||||
For purchased/distributed products' buffers the logic is simpler.
|
||||
|
||||
* In the first place the system will look if there are Vendors for the product,
|
||||
if so it will use the *Delivery Lead Time* of the preferred one.
|
||||
* In case of absence of vendors, the *Lead Time* at the bottom of the Buffer
|
||||
form view will be used.
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
To easily identify were are you maintaining buffers in your Bill of
|
||||
Materials, you will need to first provide location information on the Bills
|
||||
of Materials.
|
||||
|
||||
* Go to *Manufacturing / Products / Bill of Materials* and update the
|
||||
'Location' in all the Bill of Materials and associated lines,
|
||||
indicating where will the parts be placed/used during the manufacturing
|
||||
process.
|
||||
|
||||
* Print the report 'BOM Structure' to display where in your BOM are you
|
||||
maintaining buffers, and to identify the Lead Time (LT) of each product, and
|
||||
Decouple Lead Time (DLT).
|
||||
|
||||
|
||||
Buffers
|
||||
~~~~~~~
|
||||
|
||||
To list the list of inventory buffers, go to one of the following:
|
||||
* *Inventory / Master Data / Stock Buffer Planning*
|
||||
* *Inventory / Master Data / Reordering Rules*
|
||||
|
||||
|
||||
Buffer Profiles
|
||||
~~~~~~~~~~~~~~~
|
||||
Buffer profiles make maintenance of buffers easier by grouping them in
|
||||
profiles. Changes applied to the profiles will be applicable in the
|
||||
associated buffer calculations.
|
||||
|
||||
* Go to *Inventory / Configuration / Buffer Profiles*.
|
||||
|
||||
The Buffer Profile Lead Time Factor influences the size of the Buffer Green
|
||||
zone. Items with longer lead times will usually have smaller green zones, which
|
||||
will translate in more frequent supply order generation.
|
||||
|
||||
* Go to *Inventory / Configuration / Buffer Profile Lead Time Factor* to
|
||||
chan
|
||||
|
||||
The Buffer Profile Variability Factor influences the size of the Buffer Red
|
||||
Safety zone. Items with longer lead times will usually have smaller green
|
||||
zones, which will translate in more frequent supply order generation.
|
||||
|
||||
* Go to *Inventory / Configuration / Buffer Profile Lead Time Factor*.
|
||||
|
||||
Usual factors should range from 0.2 (long lead time) to 0.8 (short lead time).
|
||||
|
||||
|
||||
Product attributes
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* For manufactured products, go to *Manufacturing / Products* and
|
||||
update the 'Manufacturing Lead Time' field, available in the tab *Inventory*.
|
||||
* For purchased products, go to go to *Purchasing / Products* and update the
|
||||
*Delivery Lead Time* for each vendor, available in tab *Purchase* and section
|
||||
*Vendors*.
|
||||
|
||||
|
||||
ADU Calculation Methods
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The Average Daily Usage (ADU) defines the frequency of demand of a product in a
|
||||
certain location. It can be computed in different ways, which you can configure
|
||||
with ADU calculation methods as follows:
|
||||
|
||||
#. Go to *Inventory / Configuration / DDMRP / ADU calculation methods*.
|
||||
#. Indicate a name, a calculation method (fixed, past-looking,
|
||||
future-looking or blended).
|
||||
#. Fill the corresponding period (past, future or both for blended method) to
|
||||
specify the length of period consideration (in days).
|
||||
#. Indicate the source of information: stock moves or demand estimates.
|
||||
#. If you use the blended method fill also the *Past Factor* and
|
||||
*Future Factor*.
|
||||
|
||||
If you do not have prior history of stock moves in your system, it is advised
|
||||
to use fixed method or start to work on future estimates. If you have
|
||||
past-history of stock moves, best use past-looking method or blended method.
|
||||
|
||||
The ADU is computed every day by default in a background job independently
|
||||
from the other buffer fields. This computation can be done with less frequency
|
||||
but it is not recommended to run it less than weekly or more than daily.
|
||||
Circumstantially, If you need to force the calculation of the ADU go to
|
||||
*Inventory / Configuration / DDMRP / Run DDMRP* and click on
|
||||
*Run ADU calculation*.
|
||||
|
||||
Known issues / Roadmap
|
||||
======================
|
||||
|
||||
The DDMRP `roadmap <https://github.com/OCA/ddmrp/issues?q=is%3Aopen+is%3Aissue+label%3Aenhancement>`_
|
||||
and `known issues <https://github.com/OCA/ddmrp/issues?q=is%3Aopen+is%3Aissue+label%3Abug>`_ can
|
||||
be found on GitHub.
|
||||
|
||||
Changelog
|
||||
=========
|
||||
|
||||
13.0.1.1.0 (2020-07-01)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
**Features**
|
||||
|
||||
- - New setting *Update NFP on Stock Buffers on relevant events*.
|
||||
- New dedicated settings block. (`#50 <https://github.com/OCA/ddmrp/issues/50>`_)
|
||||
|
||||
|
||||
13.0.1.0.0 (2020-06-11)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* [MIG/REF] Migration of module to v13 and refactor (added new dedicated model
|
||||
for stock buffer).
|
||||
|
||||
11.0.1.3.0 (2019-02-21)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* [ADD] New chart that depict information about the supply and demand (
|
||||
displaying also de order spike threshold and horizon) for a buffer.
|
||||
(`#40 <https://github.com/OCA/ddmrp/pull/40>`_)
|
||||
|
||||
11.0.1.2.0 (2019-01-29)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* [IMP] Performance improvement of execution priority calculation and ADU.
|
||||
(`#36 <https://github.com/OCA/ddmrp/pull/36>`_)
|
||||
* [IMP] Use the minimum quantity to adjust the procure recommendation.
|
||||
(`#37 <https://github.com/OCA/ddmrp/pull/37>`_)
|
||||
|
||||
11.0.1.1.0 (2018-08-31)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* [IMP] Implemented Blended ADU calculation method.
|
||||
(`#23 <https://github.com/OCA/ddmrp/pull/23>`_)
|
||||
|
||||
11.0.1.0.0 (2018-07-16)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Start of the history
|
||||
|
||||
Bug Tracker
|
||||
===========
|
||||
|
||||
Bugs are tracked on `GitHub Issues <https://github.com/OCA/ddmrp/issues>`_.
|
||||
In case of trouble, please check there if your issue has already been reported.
|
||||
If you spotted it first, help us to smash it by providing a detailed and welcomed
|
||||
`feedback <https://github.com/OCA/ddmrp/issues/new?body=module:%20ddmrp%0Aversion:%2016.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
|
||||
|
||||
Do not contact contributors directly about support or help with technical issues.
|
||||
|
||||
Credits
|
||||
=======
|
||||
|
||||
Authors
|
||||
~~~~~~~
|
||||
|
||||
* ForgeFlow
|
||||
|
||||
Contributors
|
||||
~~~~~~~~~~~~
|
||||
|
||||
* Jordi Ballester Alomar <jordi.ballester@forgeflow.com>
|
||||
* Lois Rilo Antelo <lois.rilo@forgeflow.com>
|
||||
* Guewen Baconnier <guewen.baconnier@camptocamp.com>
|
||||
* Adria Gil Sorribes <adria.gil@forgeflow.com>
|
||||
* Christopher Ormaza <chris.ormaza@forgeflow.com>
|
||||
|
||||
Other credits
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
The initial development of this module has been financially supported by:
|
||||
|
||||
* Aleph Objects, Inc.
|
||||
|
||||
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-JordiBForgeFlow| image:: https://github.com/JordiBForgeFlow.png?size=40px
|
||||
:target: https://github.com/JordiBForgeFlow
|
||||
:alt: JordiBForgeFlow
|
||||
.. |maintainer-LoisRForgeFlow| image:: https://github.com/LoisRForgeFlow.png?size=40px
|
||||
:target: https://github.com/LoisRForgeFlow
|
||||
:alt: LoisRForgeFlow
|
||||
.. |maintainer-ChrisOForgeFlow| image:: https://github.com/ChrisOForgeFlow.png?size=40px
|
||||
:target: https://github.com/ChrisOForgeFlow
|
||||
:alt: ChrisOForgeFlow
|
||||
|
||||
Current `maintainers <https://odoo-community.org/page/maintainer-role>`__:
|
||||
|
||||
|maintainer-JordiBForgeFlow| |maintainer-LoisRForgeFlow| |maintainer-ChrisOForgeFlow|
|
||||
|
||||
This module is part of the `OCA/ddmrp <https://github.com/OCA/ddmrp/tree/16.0/ddmrp>`_ project on GitHub.
|
||||
|
||||
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
|
||||
3
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/__init__.py
Normal file
3
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/__init__.py
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
from . import models
|
||||
from . import wizards
|
||||
from . import report
|
||||
73
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/__manifest__.py
Normal file
73
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/__manifest__.py
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
# Copyright 2016-20 ForgeFlow S.L. (https://www.forgeflow.com)
|
||||
# Copyright 2016 Aleph Objects, Inc. (https://www.alephobjects.com/)
|
||||
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
|
||||
|
||||
{
|
||||
"name": "DDMRP",
|
||||
"summary": "Demand Driven Material Requirements Planning",
|
||||
"version": "16.0.1.12.0",
|
||||
"license": "LGPL-3",
|
||||
"development_status": "Beta",
|
||||
"author": "ForgeFlow, " "Odoo Community Association (OCA)",
|
||||
"maintainers": ["JordiBForgeFlow", "LoisRForgeFlow", "ChrisOForgeFlow"],
|
||||
"website": "https://github.com/OCA/ddmrp",
|
||||
"category": "Warehouse",
|
||||
"depends": [
|
||||
"purchase_stock",
|
||||
"stock_demand_estimate",
|
||||
"web_widget_bokeh_chart",
|
||||
"mrp_multi_level",
|
||||
"base_cron_exclusion",
|
||||
"stock_warehouse_calendar",
|
||||
"stock_helper",
|
||||
],
|
||||
"data": [
|
||||
"data/product_adu_calculation_method_data.xml",
|
||||
"data/stock_buffer_profile_variability_data.xml",
|
||||
"data/stock_buffer_profile_lead_time_data.xml",
|
||||
"data/stock_buffer_profile_data.xml",
|
||||
"data/ir_sequence.xml",
|
||||
"data/decimal_precision_data.xml",
|
||||
"report/mrp_report_bom_structure.xml",
|
||||
"security/ddmrp_groups.xml",
|
||||
"security/ddmrp_rules.xml",
|
||||
"security/ir.model.access.csv",
|
||||
"wizards/make_procurement_buffer_view.xml",
|
||||
"views/stock_buffer_profile_view.xml",
|
||||
"views/stock_buffer_profile_variability_view.xml",
|
||||
"views/stock_buffer_profile_lead_time_view.xml",
|
||||
"views/product_adu_calculation_method_view.xml",
|
||||
"views/stock_warehouse_views.xml",
|
||||
"views/mrp_production_view.xml",
|
||||
"views/purchase_order_view.xml",
|
||||
"views/purchase_order_line_view.xml",
|
||||
"views/product_view.xml",
|
||||
"views/mrp_bom_view.xml",
|
||||
"views/stock_move_views.xml",
|
||||
"views/stock_buffer_view.xml",
|
||||
"views/stock_picking.xml",
|
||||
"data/ir_cron.xml",
|
||||
"wizards/ddmrp_duplicate_buffer.xml",
|
||||
"wizards/ddmrp_run_view.xml",
|
||||
"wizards/mrp_bom_change_location.xml",
|
||||
"wizards/res_config_settings_views.xml",
|
||||
],
|
||||
"demo": [
|
||||
"demo/ddmrp_demo_user.xml",
|
||||
"demo/res_partner_demo.xml",
|
||||
"demo/product_category_demo.xml",
|
||||
"demo/product_product_demo.xml",
|
||||
"demo/product_supplierinfo_demo.xml",
|
||||
"demo/mrp_bom_demo.xml",
|
||||
"demo/stock_buffer_demo.xml",
|
||||
],
|
||||
"assets": {
|
||||
"web.assets_backend": [
|
||||
"ddmrp/static/src/**/*.js",
|
||||
"ddmrp/static/src/**/*.scss",
|
||||
"ddmrp/static/src/**/*.xml",
|
||||
],
|
||||
},
|
||||
"installable": True,
|
||||
"application": True,
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo noupdate="1">
|
||||
<record
|
||||
forcecreate="True"
|
||||
id="lead_time_decimal_precision"
|
||||
model="decimal.precision"
|
||||
>
|
||||
<field name="name">Lead Time</field>
|
||||
<field name="digits" eval="0" />
|
||||
</record>
|
||||
<record
|
||||
forcecreate="True"
|
||||
id="average_daily_usage_decimal_precision"
|
||||
model="decimal.precision"
|
||||
>
|
||||
<field name="name">Average Daily Usage</field>
|
||||
<field name="digits" eval="3" />
|
||||
</record>
|
||||
</odoo>
|
||||
39
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/data/ir_cron.xml
Normal file
39
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/data/ir_cron.xml
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo noupdate="1">
|
||||
<record
|
||||
id="ir_cron_ddmrp_calculation_scheduler_action"
|
||||
model="ir.cron"
|
||||
forcecreate="True"
|
||||
>
|
||||
<field name="name">DDMRP Buffer calculation</field>
|
||||
<field name="state">code</field>
|
||||
<field name="user_id" ref="base.user_root" />
|
||||
<field name="interval_number">8</field>
|
||||
<field name="interval_type">hours</field>
|
||||
<field name="numbercall">-1</field>
|
||||
<field name="priority">6</field>
|
||||
<field eval="False" name="doall" />
|
||||
<field name="model_id" ref="model_stock_buffer" />
|
||||
<field name="code">model.cron_ddmrp(True)</field>
|
||||
</record>
|
||||
<record
|
||||
id="ir_cron_ddmrp_adu_calculation_scheduler_action"
|
||||
model="ir.cron"
|
||||
forcecreate="True"
|
||||
>
|
||||
<field name="name">DDMRP Buffer ADU calculation</field>
|
||||
<field name="state">code</field>
|
||||
<field name="user_id" ref="base.user_root" />
|
||||
<field name="interval_number">1</field>
|
||||
<field name="interval_type">days</field>
|
||||
<field name="numbercall">-1</field>
|
||||
<field name="priority">3</field>
|
||||
<field
|
||||
name="mutually_exclusive_cron_ids"
|
||||
eval="[(6, 0, [ref('ir_cron_ddmrp_calculation_scheduler_action'),])]"
|
||||
/>
|
||||
<field eval="False" name="doall" />
|
||||
<field name="model_id" ref="model_stock_buffer" />
|
||||
<field name="code">model.cron_ddmrp_adu(True)</field>
|
||||
</record>
|
||||
</odoo>
|
||||
12
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/data/ir_sequence.xml
Normal file
12
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/data/ir_sequence.xml
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo noupdate="1">
|
||||
<record id="sequence_mrp_op" model="ir.sequence">
|
||||
<field name="name">Stock Buffer</field>
|
||||
<field name="code">stock.buffer</field>
|
||||
<field name="prefix">SB/</field>
|
||||
<field name="padding">5</field>
|
||||
<field name="number_next">1</field>
|
||||
<field name="number_increment">1</field>
|
||||
<field name="company_id" eval="False" />
|
||||
</record>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo noupdate="1">
|
||||
<record id="adu_calculation_method_fixed" model="product.adu.calculation.method">
|
||||
<field name="name">Fixed</field>
|
||||
<field name="method">fixed</field>
|
||||
</record>
|
||||
<record id="adu_calculation_method_past_120" model="product.adu.calculation.method">
|
||||
<field name="name">Past (120 days)</field>
|
||||
<field name="method">past</field>
|
||||
<field name="source_past">actual</field>
|
||||
<field name="horizon_past">120</field>
|
||||
</record>
|
||||
<record
|
||||
id="adu_calculation_method_future_120"
|
||||
model="product.adu.calculation.method"
|
||||
>
|
||||
<field name="name">Future (120 days)</field>
|
||||
<field name="method">future</field>
|
||||
<field name="source_future">estimates</field>
|
||||
<field name="horizon_future">120</field>
|
||||
</record>
|
||||
<record
|
||||
id="adu_calculation_method_future_120_estimates_mrp"
|
||||
model="product.adu.calculation.method"
|
||||
>
|
||||
<field name="name">Future (Direct + Indirect)(120 days)</field>
|
||||
<field name="method">future</field>
|
||||
<field name="source_future">estimates_mrp</field>
|
||||
<field name="horizon_future">120</field>
|
||||
</record>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,894 @@
|
|||
<?xml version="1.0" ?>
|
||||
<odoo noupdate="1">
|
||||
<record
|
||||
id="stock_buffer_profile_replenish_purchased_short_low"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">replenish</field>
|
||||
<field name="variability_id" ref="ddmrp.stock_buffer_profile_variability_low" />
|
||||
<field name="item_type">purchased</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_short" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_replenish_manufactured_short_low"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">replenish</field>
|
||||
<field name="variability_id" ref="ddmrp.stock_buffer_profile_variability_low" />
|
||||
<field name="item_type">manufactured</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_short" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_replenish_distributed_short_low"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">replenish</field>
|
||||
<field name="variability_id" ref="ddmrp.stock_buffer_profile_variability_low" />
|
||||
<field name="item_type">distributed</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_short" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_replenish_purchased_short_medium"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">replenish</field>
|
||||
<field
|
||||
name="variability_id"
|
||||
ref="ddmrp.stock_buffer_profile_variability_medium"
|
||||
/>
|
||||
<field name="item_type">purchased</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_short" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_replenish_manufactured_short_medium"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">replenish</field>
|
||||
<field
|
||||
name="variability_id"
|
||||
ref="ddmrp.stock_buffer_profile_variability_medium"
|
||||
/>
|
||||
<field name="item_type">manufactured</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_short" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_replenish_distributed_short_medium"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">replenish</field>
|
||||
<field
|
||||
name="variability_id"
|
||||
ref="ddmrp.stock_buffer_profile_variability_medium"
|
||||
/>
|
||||
<field name="item_type">distributed</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_short" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_replenish_purchased_short_high"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">replenish</field>
|
||||
<field
|
||||
name="variability_id"
|
||||
ref="ddmrp.stock_buffer_profile_variability_high"
|
||||
/>
|
||||
<field name="item_type">purchased</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_short" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_replenish_manufactured_short_high"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">replenish</field>
|
||||
<field
|
||||
name="variability_id"
|
||||
ref="ddmrp.stock_buffer_profile_variability_high"
|
||||
/>
|
||||
<field name="item_type">manufactured</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_short" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_replenish_distributed_short_high"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">replenish</field>
|
||||
<field
|
||||
name="variability_id"
|
||||
ref="ddmrp.stock_buffer_profile_variability_high"
|
||||
/>
|
||||
<field name="item_type">distributed</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_short" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_replenish_purchased_medium_low"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">replenish</field>
|
||||
<field name="variability_id" ref="ddmrp.stock_buffer_profile_variability_low" />
|
||||
<field name="item_type">purchased</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_medium" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_replenish_manufactured_medium_low"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">replenish</field>
|
||||
<field name="variability_id" ref="ddmrp.stock_buffer_profile_variability_low" />
|
||||
<field name="item_type">manufactured</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_medium" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_replenish_distributed_medium_low"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">replenish</field>
|
||||
<field name="variability_id" ref="ddmrp.stock_buffer_profile_variability_low" />
|
||||
<field name="item_type">distributed</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_medium" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_replenish_purchased_medium_medium"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">replenish</field>
|
||||
<field
|
||||
name="variability_id"
|
||||
ref="ddmrp.stock_buffer_profile_variability_medium"
|
||||
/>
|
||||
<field name="item_type">purchased</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_medium" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_replenish_manufactured_medium_medium"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">replenish</field>
|
||||
<field
|
||||
name="variability_id"
|
||||
ref="ddmrp.stock_buffer_profile_variability_medium"
|
||||
/>
|
||||
<field name="item_type">manufactured</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_medium" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_replenish_distributed_medium_medium"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">replenish</field>
|
||||
<field
|
||||
name="variability_id"
|
||||
ref="ddmrp.stock_buffer_profile_variability_medium"
|
||||
/>
|
||||
<field name="item_type">distributed</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_medium" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_replenish_purchased_medium_high"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">replenish</field>
|
||||
<field
|
||||
name="variability_id"
|
||||
ref="ddmrp.stock_buffer_profile_variability_high"
|
||||
/>
|
||||
<field name="item_type">purchased</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_medium" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_replenish_manufactured_medium_high"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">replenish</field>
|
||||
<field
|
||||
name="variability_id"
|
||||
ref="ddmrp.stock_buffer_profile_variability_high"
|
||||
/>
|
||||
<field name="item_type">manufactured</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_medium" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_replenish_distributed_medium_high"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">replenish</field>
|
||||
<field
|
||||
name="variability_id"
|
||||
ref="ddmrp.stock_buffer_profile_variability_high"
|
||||
/>
|
||||
<field name="item_type">distributed</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_medium" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_replenish_purchased_long_low"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">replenish</field>
|
||||
<field name="variability_id" ref="ddmrp.stock_buffer_profile_variability_low" />
|
||||
<field name="item_type">purchased</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_long" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_replenish_manufactured_long_low"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">replenish</field>
|
||||
<field name="variability_id" ref="ddmrp.stock_buffer_profile_variability_low" />
|
||||
<field name="item_type">manufactured</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_long" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_replenish_distributed_long_low"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">replenish</field>
|
||||
<field name="variability_id" ref="ddmrp.stock_buffer_profile_variability_low" />
|
||||
<field name="item_type">distributed</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_long" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_replenish_purchased_long_medium"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">replenish</field>
|
||||
<field
|
||||
name="variability_id"
|
||||
ref="ddmrp.stock_buffer_profile_variability_medium"
|
||||
/>
|
||||
<field name="item_type">purchased</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_long" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_replenish_manufactured_long_medium"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">replenish</field>
|
||||
<field
|
||||
name="variability_id"
|
||||
ref="ddmrp.stock_buffer_profile_variability_medium"
|
||||
/>
|
||||
<field name="item_type">manufactured</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_long" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_replenish_distributed_long_medium"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">replenish</field>
|
||||
<field
|
||||
name="variability_id"
|
||||
ref="ddmrp.stock_buffer_profile_variability_medium"
|
||||
/>
|
||||
<field name="item_type">distributed</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_long" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_replenish_purchased_long_high"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">replenish</field>
|
||||
<field
|
||||
name="variability_id"
|
||||
ref="ddmrp.stock_buffer_profile_variability_high"
|
||||
/>
|
||||
<field name="item_type">purchased</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_long" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_replenish_manufactured_long_high"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">replenish</field>
|
||||
<field
|
||||
name="variability_id"
|
||||
ref="ddmrp.stock_buffer_profile_variability_high"
|
||||
/>
|
||||
<field name="item_type">manufactured</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_long" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_replenish_distributed_long_high"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">replenish</field>
|
||||
<field
|
||||
name="variability_id"
|
||||
ref="ddmrp.stock_buffer_profile_variability_high"
|
||||
/>
|
||||
<field name="item_type">distributed</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_long" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_min_max_purchased_short_low"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">min_max</field>
|
||||
<field name="variability_id" ref="ddmrp.stock_buffer_profile_variability_low" />
|
||||
<field name="item_type">purchased</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_short" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_min_max_manufactured_short_low"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">min_max</field>
|
||||
<field name="variability_id" ref="ddmrp.stock_buffer_profile_variability_low" />
|
||||
<field name="item_type">manufactured</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_short" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_min_max_distributed_short_low"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">min_max</field>
|
||||
<field name="variability_id" ref="ddmrp.stock_buffer_profile_variability_low" />
|
||||
<field name="item_type">distributed</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_short" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_min_max_purchased_short_medium"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">min_max</field>
|
||||
<field
|
||||
name="variability_id"
|
||||
ref="ddmrp.stock_buffer_profile_variability_medium"
|
||||
/>
|
||||
<field name="item_type">purchased</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_short" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_min_max_manufactured_short_medium"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">min_max</field>
|
||||
<field
|
||||
name="variability_id"
|
||||
ref="ddmrp.stock_buffer_profile_variability_medium"
|
||||
/>
|
||||
<field name="item_type">manufactured</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_short" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_min_max_distributed_short_medium"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">min_max</field>
|
||||
<field
|
||||
name="variability_id"
|
||||
ref="ddmrp.stock_buffer_profile_variability_medium"
|
||||
/>
|
||||
<field name="item_type">distributed</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_short" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_min_max_purchased_short_high"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">min_max</field>
|
||||
<field
|
||||
name="variability_id"
|
||||
ref="ddmrp.stock_buffer_profile_variability_high"
|
||||
/>
|
||||
<field name="item_type">purchased</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_short" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_min_max_manufactured_short_high"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">min_max</field>
|
||||
<field
|
||||
name="variability_id"
|
||||
ref="ddmrp.stock_buffer_profile_variability_high"
|
||||
/>
|
||||
<field name="item_type">manufactured</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_short" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_min_max_distributed_short_high"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">min_max</field>
|
||||
<field
|
||||
name="variability_id"
|
||||
ref="ddmrp.stock_buffer_profile_variability_high"
|
||||
/>
|
||||
<field name="item_type">distributed</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_short" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_min_max_purchased_medium_low"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">min_max</field>
|
||||
<field name="variability_id" ref="ddmrp.stock_buffer_profile_variability_low" />
|
||||
<field name="item_type">purchased</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_medium" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_min_max_manufactured_medium_low"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">min_max</field>
|
||||
<field name="variability_id" ref="ddmrp.stock_buffer_profile_variability_low" />
|
||||
<field name="item_type">manufactured</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_medium" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_min_max_distributed_medium_low"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">min_max</field>
|
||||
<field name="variability_id" ref="ddmrp.stock_buffer_profile_variability_low" />
|
||||
<field name="item_type">distributed</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_medium" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_min_max_purchased_medium_medium"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">min_max</field>
|
||||
<field
|
||||
name="variability_id"
|
||||
ref="ddmrp.stock_buffer_profile_variability_medium"
|
||||
/>
|
||||
<field name="item_type">purchased</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_medium" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_min_max_manufactured_medium_medium"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">min_max</field>
|
||||
<field
|
||||
name="variability_id"
|
||||
ref="ddmrp.stock_buffer_profile_variability_medium"
|
||||
/>
|
||||
<field name="item_type">manufactured</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_medium" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_min_max_distributed_medium_medium"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">min_max</field>
|
||||
<field
|
||||
name="variability_id"
|
||||
ref="ddmrp.stock_buffer_profile_variability_medium"
|
||||
/>
|
||||
<field name="item_type">distributed</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_medium" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_min_max_purchased_medium_high"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">min_max</field>
|
||||
<field
|
||||
name="variability_id"
|
||||
ref="ddmrp.stock_buffer_profile_variability_high"
|
||||
/>
|
||||
<field name="item_type">purchased</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_medium" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_min_max_manufactured_medium_high"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">min_max</field>
|
||||
<field
|
||||
name="variability_id"
|
||||
ref="ddmrp.stock_buffer_profile_variability_high"
|
||||
/>
|
||||
<field name="item_type">manufactured</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_medium" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_min_max_distributed_medium_high"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">min_max</field>
|
||||
<field
|
||||
name="variability_id"
|
||||
ref="ddmrp.stock_buffer_profile_variability_high"
|
||||
/>
|
||||
<field name="item_type">distributed</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_medium" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_min_max_purchased_long_low"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">min_max</field>
|
||||
<field name="variability_id" ref="ddmrp.stock_buffer_profile_variability_low" />
|
||||
<field name="item_type">purchased</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_long" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_min_max_manufactured_long_low"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">min_max</field>
|
||||
<field name="variability_id" ref="ddmrp.stock_buffer_profile_variability_low" />
|
||||
<field name="item_type">manufactured</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_long" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_min_max_distributed_long_low"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">min_max</field>
|
||||
<field name="variability_id" ref="ddmrp.stock_buffer_profile_variability_low" />
|
||||
<field name="item_type">distributed</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_long" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_min_max_purchased_long_medium"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">min_max</field>
|
||||
<field
|
||||
name="variability_id"
|
||||
ref="ddmrp.stock_buffer_profile_variability_medium"
|
||||
/>
|
||||
<field name="item_type">purchased</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_long" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_min_max_manufactured_long_medium"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">min_max</field>
|
||||
<field
|
||||
name="variability_id"
|
||||
ref="ddmrp.stock_buffer_profile_variability_medium"
|
||||
/>
|
||||
<field name="item_type">manufactured</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_long" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_min_max_distributed_long_medium"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">min_max</field>
|
||||
<field
|
||||
name="variability_id"
|
||||
ref="ddmrp.stock_buffer_profile_variability_medium"
|
||||
/>
|
||||
<field name="item_type">distributed</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_long" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_min_max_purchased_long_high"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">min_max</field>
|
||||
<field
|
||||
name="variability_id"
|
||||
ref="ddmrp.stock_buffer_profile_variability_high"
|
||||
/>
|
||||
<field name="item_type">purchased</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_long" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_min_max_manufactured_long_high"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">min_max</field>
|
||||
<field
|
||||
name="variability_id"
|
||||
ref="ddmrp.stock_buffer_profile_variability_high"
|
||||
/>
|
||||
<field name="item_type">manufactured</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_long" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_min_max_distributed_long_high"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">min_max</field>
|
||||
<field
|
||||
name="variability_id"
|
||||
ref="ddmrp.stock_buffer_profile_variability_high"
|
||||
/>
|
||||
<field name="item_type">distributed</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_long" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_replenish_override_purchased_short_low"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">replenish_override</field>
|
||||
<field name="variability_id" ref="ddmrp.stock_buffer_profile_variability_low" />
|
||||
<field name="item_type">purchased</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_short" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_replenish_override_manufactured_short_low"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">replenish_override</field>
|
||||
<field name="variability_id" ref="ddmrp.stock_buffer_profile_variability_low" />
|
||||
<field name="item_type">manufactured</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_short" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_replenish_override_distributed_short_low"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">replenish_override</field>
|
||||
<field name="variability_id" ref="ddmrp.stock_buffer_profile_variability_low" />
|
||||
<field name="item_type">distributed</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_short" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_replenish_override_purchased_short_medium"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">replenish_override</field>
|
||||
<field
|
||||
name="variability_id"
|
||||
ref="ddmrp.stock_buffer_profile_variability_medium"
|
||||
/>
|
||||
<field name="item_type">purchased</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_short" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_replenish_override_manufactured_short_medium"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">replenish_override</field>
|
||||
<field
|
||||
name="variability_id"
|
||||
ref="ddmrp.stock_buffer_profile_variability_medium"
|
||||
/>
|
||||
<field name="item_type">manufactured</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_short" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_replenish_override_distributed_short_medium"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">replenish_override</field>
|
||||
<field
|
||||
name="variability_id"
|
||||
ref="ddmrp.stock_buffer_profile_variability_medium"
|
||||
/>
|
||||
<field name="item_type">distributed</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_short" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_replenish_override_purchased_short_high"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">replenish_override</field>
|
||||
<field
|
||||
name="variability_id"
|
||||
ref="ddmrp.stock_buffer_profile_variability_high"
|
||||
/>
|
||||
<field name="item_type">purchased</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_short" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_replenish_override_manufactured_short_high"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">replenish_override</field>
|
||||
<field
|
||||
name="variability_id"
|
||||
ref="ddmrp.stock_buffer_profile_variability_high"
|
||||
/>
|
||||
<field name="item_type">manufactured</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_short" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_replenish_override_distributed_short_high"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">replenish_override</field>
|
||||
<field
|
||||
name="variability_id"
|
||||
ref="ddmrp.stock_buffer_profile_variability_high"
|
||||
/>
|
||||
<field name="item_type">distributed</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_short" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_replenish_override_purchased_medium_low"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">replenish_override</field>
|
||||
<field name="variability_id" ref="ddmrp.stock_buffer_profile_variability_low" />
|
||||
<field name="item_type">purchased</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_medium" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_replenish_override_manufactured_medium_low"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">replenish_override</field>
|
||||
<field name="variability_id" ref="ddmrp.stock_buffer_profile_variability_low" />
|
||||
<field name="item_type">manufactured</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_medium" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_replenish_override_distributed_medium_low"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">replenish_override</field>
|
||||
<field name="variability_id" ref="ddmrp.stock_buffer_profile_variability_low" />
|
||||
<field name="item_type">distributed</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_medium" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_replenish_override_purchased_medium_medium"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">replenish_override</field>
|
||||
<field
|
||||
name="variability_id"
|
||||
ref="ddmrp.stock_buffer_profile_variability_medium"
|
||||
/>
|
||||
<field name="item_type">purchased</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_medium" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_replenish_override_manufactured_medium_medium"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">replenish_override</field>
|
||||
<field
|
||||
name="variability_id"
|
||||
ref="ddmrp.stock_buffer_profile_variability_medium"
|
||||
/>
|
||||
<field name="item_type">manufactured</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_medium" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_replenish_override_distributed_medium_medium"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">replenish_override</field>
|
||||
<field
|
||||
name="variability_id"
|
||||
ref="ddmrp.stock_buffer_profile_variability_medium"
|
||||
/>
|
||||
<field name="item_type">distributed</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_medium" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_replenish_override_purchased_medium_high"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">replenish_override</field>
|
||||
<field
|
||||
name="variability_id"
|
||||
ref="ddmrp.stock_buffer_profile_variability_high"
|
||||
/>
|
||||
<field name="item_type">purchased</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_medium" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_replenish_override_manufactured_medium_high"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">replenish_override</field>
|
||||
<field
|
||||
name="variability_id"
|
||||
ref="ddmrp.stock_buffer_profile_variability_high"
|
||||
/>
|
||||
<field name="item_type">manufactured</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_medium" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_replenish_override_distributed_medium_high"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">replenish_override</field>
|
||||
<field
|
||||
name="variability_id"
|
||||
ref="ddmrp.stock_buffer_profile_variability_high"
|
||||
/>
|
||||
<field name="item_type">distributed</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_medium" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_replenish_override_purchased_long_low"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">replenish_override</field>
|
||||
<field name="variability_id" ref="ddmrp.stock_buffer_profile_variability_low" />
|
||||
<field name="item_type">purchased</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_long" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_replenish_override_manufactured_long_low"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">replenish_override</field>
|
||||
<field name="variability_id" ref="ddmrp.stock_buffer_profile_variability_low" />
|
||||
<field name="item_type">manufactured</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_long" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_replenish_override_distributed_long_low"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">replenish_override</field>
|
||||
<field name="variability_id" ref="ddmrp.stock_buffer_profile_variability_low" />
|
||||
<field name="item_type">distributed</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_long" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_replenish_override_purchased_long_medium"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">replenish_override</field>
|
||||
<field
|
||||
name="variability_id"
|
||||
ref="ddmrp.stock_buffer_profile_variability_medium"
|
||||
/>
|
||||
<field name="item_type">purchased</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_long" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_replenish_override_manufactured_long_medium"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">replenish_override</field>
|
||||
<field
|
||||
name="variability_id"
|
||||
ref="ddmrp.stock_buffer_profile_variability_medium"
|
||||
/>
|
||||
<field name="item_type">manufactured</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_long" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_replenish_override_distributed_long_medium"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">replenish_override</field>
|
||||
<field
|
||||
name="variability_id"
|
||||
ref="ddmrp.stock_buffer_profile_variability_medium"
|
||||
/>
|
||||
<field name="item_type">distributed</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_long" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_replenish_override_purchased_long_high"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">replenish_override</field>
|
||||
<field
|
||||
name="variability_id"
|
||||
ref="ddmrp.stock_buffer_profile_variability_high"
|
||||
/>
|
||||
<field name="item_type">purchased</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_long" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_replenish_override_manufactured_long_high"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">replenish_override</field>
|
||||
<field
|
||||
name="variability_id"
|
||||
ref="ddmrp.stock_buffer_profile_variability_high"
|
||||
/>
|
||||
<field name="item_type">manufactured</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_long" />
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_replenish_override_distributed_long_high"
|
||||
model="stock.buffer.profile"
|
||||
>
|
||||
<field name="replenish_method">replenish_override</field>
|
||||
<field
|
||||
name="variability_id"
|
||||
ref="ddmrp.stock_buffer_profile_variability_high"
|
||||
/>
|
||||
<field name="item_type">distributed</field>
|
||||
<field name="lead_time_id" ref="ddmrp.stock_buffer_profile_lead_time_long" />
|
||||
</record>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo noupdate="1">
|
||||
<record
|
||||
id="stock_buffer_profile_lead_time_short"
|
||||
model="stock.buffer.profile.lead.time"
|
||||
>
|
||||
<field name="name">Short</field>
|
||||
<field name="factor">0.75</field>
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_lead_time_medium"
|
||||
model="stock.buffer.profile.lead.time"
|
||||
>
|
||||
<field name="name">Medium</field>
|
||||
<field name="factor">0.5</field>
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_lead_time_long"
|
||||
model="stock.buffer.profile.lead.time"
|
||||
>
|
||||
<field name="name">Long</field>
|
||||
<field name="factor">0.25</field>
|
||||
</record>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo noupdate="1">
|
||||
<record
|
||||
id="stock_buffer_profile_variability_low"
|
||||
model="stock.buffer.profile.variability"
|
||||
>
|
||||
<field name="name">Low</field>
|
||||
<field name="factor">0.25</field>
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_variability_medium"
|
||||
model="stock.buffer.profile.variability"
|
||||
>
|
||||
<field name="name">Medium</field>
|
||||
<field name="factor">0.5</field>
|
||||
</record>
|
||||
<record
|
||||
id="stock_buffer_profile_variability_high"
|
||||
model="stock.buffer.profile.variability"
|
||||
>
|
||||
<field name="name">High</field>
|
||||
<field name="factor">0.75</field>
|
||||
</record>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo noupdate="1">
|
||||
|
||||
<record id="base.user_demo" model="res.users">
|
||||
<field eval="[(4, ref('group_stock_buffer_maintainer'))]" name="groups_id" />
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
36
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/demo/mrp_bom_demo.xml
Normal file
36
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/demo/mrp_bom_demo.xml
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo noupdate="1">
|
||||
<!-- FP-01 -->
|
||||
<record id="mrp_bom_fp01" model="mrp.bom">
|
||||
<field name="product_tmpl_id" ref="product_product_fp01_product_template" />
|
||||
<field name="product_uom_id" ref="uom.product_uom_unit" />
|
||||
<field name="sequence">5</field>
|
||||
</record>
|
||||
<record id="mrp_bom_fp01_line_as01" model="mrp.bom.line">
|
||||
<field name="product_id" ref="product_product_as01" />
|
||||
<field name="product_qty">1</field>
|
||||
<field name="product_uom_id" ref="uom.product_uom_unit" />
|
||||
<field name="sequence">5</field>
|
||||
<field name="bom_id" ref="mrp_bom_fp01" />
|
||||
</record>
|
||||
<!-- AS-01 -->
|
||||
<record id="mrp_bom_as01" model="mrp.bom">
|
||||
<field name="product_tmpl_id" ref="product_product_as01_product_template" />
|
||||
<field name="product_uom_id" ref="uom.product_uom_unit" />
|
||||
<field name="sequence">5</field>
|
||||
</record>
|
||||
<record id="mrp_bom_as01_line_rm01" model="mrp.bom.line">
|
||||
<field name="product_id" ref="product_product_rm01" />
|
||||
<field name="product_qty">1</field>
|
||||
<field name="product_uom_id" ref="uom.product_uom_unit" />
|
||||
<field name="sequence">5</field>
|
||||
<field name="bom_id" ref="mrp_bom_as01" />
|
||||
</record>
|
||||
<record id="mrp_bom_as01_line_rm02" model="mrp.bom.line">
|
||||
<field name="product_id" ref="product_product_rm02" />
|
||||
<field name="product_qty">1</field>
|
||||
<field name="product_uom_id" ref="uom.product_uom_unit" />
|
||||
<field name="sequence">10</field>
|
||||
<field name="bom_id" ref="mrp_bom_as01" />
|
||||
</record>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<record id="product_category_ddmrp" model="product.category">
|
||||
<field name="name">DDMRP</field>
|
||||
</record>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo noupdate="1">
|
||||
<record id="product_product_fp01" model="product.product">
|
||||
<field name="name">FP-01</field>
|
||||
<field name="categ_id" ref="product_category_ddmrp" />
|
||||
<field name="type">product</field>
|
||||
<field name="uom_id" ref="uom.product_uom_unit" />
|
||||
<field name="uom_po_id" ref="uom.product_uom_unit" />
|
||||
<field name="produce_delay">2</field>
|
||||
<field
|
||||
name="route_ids"
|
||||
eval="[(6, 0, [ref('mrp.route_warehouse0_manufacture')])]"
|
||||
/>
|
||||
</record>
|
||||
<record id="product_product_as01" model="product.product">
|
||||
<field name="name">AS-01</field>
|
||||
<field name="categ_id" ref="product_category_ddmrp" />
|
||||
<field name="type">product</field>
|
||||
<field name="uom_id" ref="uom.product_uom_unit" />
|
||||
<field name="uom_po_id" ref="uom.product_uom_unit" />
|
||||
<field name="produce_delay">6</field>
|
||||
<field
|
||||
name="route_ids"
|
||||
eval="[(6, 0, [ref('mrp.route_warehouse0_manufacture')])]"
|
||||
/>
|
||||
</record>
|
||||
<record id="product_product_rm01" model="product.product">
|
||||
<field name="name">RM-01</field>
|
||||
<field name="categ_id" ref="product_category_ddmrp" />
|
||||
<field name="type">product</field>
|
||||
<field name="uom_id" ref="uom.product_uom_unit" />
|
||||
<field name="uom_po_id" ref="uom.product_uom_unit" />
|
||||
<field
|
||||
name="route_ids"
|
||||
eval="[(6, 0, [ref('purchase_stock.route_warehouse0_buy')])]"
|
||||
/>
|
||||
</record>
|
||||
<record id="product_product_rm02" model="product.product">
|
||||
<field name="name">RM-02</field>
|
||||
<field name="categ_id" ref="product_category_ddmrp" />
|
||||
<field name="type">product</field>
|
||||
<field name="uom_id" ref="uom.product_uom_unit" />
|
||||
<field name="uom_po_id" ref="uom.product_uom_unit" />
|
||||
<field
|
||||
name="route_ids"
|
||||
eval="[(6, 0, [ref('purchase_stock.route_warehouse0_buy')])]"
|
||||
/>
|
||||
</record>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo noupdate="1">
|
||||
<record id="product_supplierinfo_rm01" model="product.supplierinfo">
|
||||
<field name="product_tmpl_id" ref="product_product_rm01_product_template" />
|
||||
<field name="partner_id" ref="res_partner_forgeflow" />
|
||||
<field name="delay">25</field>
|
||||
<field name="min_qty">50</field>
|
||||
<field name="price">100</field>
|
||||
</record>
|
||||
<record id="product_supplierinfo_rm02" model="product.supplierinfo">
|
||||
<field name="product_tmpl_id" ref="product_product_rm02_product_template" />
|
||||
<field name="partner_id" ref="res_partner_forgeflow" />
|
||||
<field name="delay">14</field>
|
||||
<field name="min_qty">10</field>
|
||||
<field name="price">100</field>
|
||||
</record>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo noupdate="1">
|
||||
<record id="res_partner_forgeflow" model="res.partner">
|
||||
<field name="name">ForgeFlow</field>
|
||||
<field name="is_company">1</field>
|
||||
<field name="company_id" ref="base.main_company" />
|
||||
<field name="email">forgeflow@yourcompany.example.com</field>
|
||||
<field name="street">Rambla de Catalunya</field>
|
||||
<field name="city">Barcelona</field>
|
||||
<field name="zip">08008</field>
|
||||
<field name="website">https://www.forgeflow.com</field>
|
||||
<field name="country_id" ref="base.es" />
|
||||
<field
|
||||
name="image_1920"
|
||||
type="base64"
|
||||
file="ddmrp/static/img/res_partner_forgeflow-image.png"
|
||||
/>
|
||||
</record>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo noupdate="1">
|
||||
<record id="stock_buffer_fp01" model="stock.buffer">
|
||||
<field name="product_id" ref="product_product_fp01" />
|
||||
<field
|
||||
name="buffer_profile_id"
|
||||
ref="ddmrp.stock_buffer_profile_replenish_manufactured_medium_medium"
|
||||
/>
|
||||
<field name="adu_calculation_method" ref="ddmrp.adu_calculation_method_fixed" />
|
||||
<field name="adu_fixed">60</field>
|
||||
<field name="order_spike_horizon">15</field>
|
||||
<field name="warehouse_id" ref="stock.warehouse0" />
|
||||
<field name="location_id" ref="stock.stock_location_stock" />
|
||||
<field name="minimum_order_quantity">5</field>
|
||||
</record>
|
||||
<record id="stock_buffer_rm01" model="stock.buffer">
|
||||
<field name="product_id" ref="product_product_rm01" />
|
||||
<field
|
||||
name="buffer_profile_id"
|
||||
ref="ddmrp.stock_buffer_profile_replenish_purchased_medium_medium"
|
||||
/>
|
||||
<field name="adu_calculation_method" ref="ddmrp.adu_calculation_method_fixed" />
|
||||
<field name="adu_fixed">50</field>
|
||||
<field name="order_spike_horizon">30</field>
|
||||
<field name="warehouse_id" ref="stock.warehouse0" />
|
||||
<field name="location_id" ref="stock.stock_location_stock" />
|
||||
<field name="minimum_order_quantity">50</field>
|
||||
</record>
|
||||
</odoo>
|
||||
2047
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/i18n/bs.po
Normal file
2047
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/i18n/bs.po
Normal file
File diff suppressed because it is too large
Load diff
2047
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/i18n/ddmrp.pot
Normal file
2047
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/i18n/ddmrp.pot
Normal file
File diff suppressed because it is too large
Load diff
2285
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/i18n/es.po
Normal file
2285
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/i18n/es.po
Normal file
File diff suppressed because it is too large
Load diff
2263
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/i18n/es_AR.po
Normal file
2263
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/i18n/es_AR.po
Normal file
File diff suppressed because it is too large
Load diff
2082
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/i18n/fr.po
Normal file
2082
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/i18n/fr.po
Normal file
File diff suppressed because it is too large
Load diff
2075
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/i18n/id.po
Normal file
2075
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/i18n/id.po
Normal file
File diff suppressed because it is too large
Load diff
2235
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/i18n/it.po
Normal file
2235
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/i18n/it.po
Normal file
File diff suppressed because it is too large
Load diff
2162
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/i18n/zh_Hans.po
Normal file
2162
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/i18n/zh_Hans.po
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,20 @@
|
|||
# Copyright 2021 ForgeFlow <http://www.forgeflow.com>
|
||||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
import logging
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def migrate(cr, version):
|
||||
_logger.info("Set buffer profile data as no-update.")
|
||||
cr.execute(
|
||||
"""
|
||||
UPDATE ir_model_data imd
|
||||
SET noupdate = true
|
||||
WHERE "module" = 'ddmrp' AND (
|
||||
name ILIKE 'stock_buffer_profile_replenish_%'
|
||||
OR name ILIKE 'stock_buffer_profile_min_max%'
|
||||
);
|
||||
"""
|
||||
)
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
from odoo import SUPERUSER_ID, api
|
||||
|
||||
|
||||
def migrate(cr, version):
|
||||
env = api.Environment(cr, SUPERUSER_ID, {})
|
||||
buffers = env["stock.buffer"].search(
|
||||
[("buffer_profile_id.item_type", "=", "distributed")]
|
||||
)
|
||||
if buffers:
|
||||
buffers._calc_distributed_source_location()
|
||||
18
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/models/__init__.py
Normal file
18
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/models/__init__.py
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
from . import mrp_bom
|
||||
from . import mrp_production
|
||||
from . import procurement_group
|
||||
from . import product_adu_calculation_method
|
||||
from . import purchase_order
|
||||
from . import stock_buffer_profile
|
||||
from . import stock_buffer_profile_lead_time
|
||||
from . import stock_buffer_profile_variability
|
||||
from . import stock_rule
|
||||
from . import stock_warehouse
|
||||
from . import stock_buffer
|
||||
from . import product_template
|
||||
from . import stock_move
|
||||
from . import stock_move_line
|
||||
from . import stock_picking
|
||||
from . import res_company
|
||||
from . import product_product
|
||||
from . import stock_warehouse_orderpoint
|
||||
198
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/models/mrp_bom.py
Normal file
198
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/models/mrp_bom.py
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
# Copyright 2017-24 ForgeFlow S.L. (http://www.forgeflow.com)
|
||||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).
|
||||
|
||||
import logging
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class MrpBom(models.Model):
|
||||
_inherit = "mrp.bom"
|
||||
|
||||
is_buffered = fields.Boolean(
|
||||
string="Buffered?",
|
||||
compute="_compute_is_buffered",
|
||||
help="True when the product has an DDMRP buffer associated.",
|
||||
)
|
||||
buffer_id = fields.Many2one(
|
||||
comodel_name="stock.buffer",
|
||||
string="Stock Buffer",
|
||||
compute="_compute_buffer",
|
||||
)
|
||||
dlt = fields.Float(
|
||||
string="Decoupled Lead Time (days)",
|
||||
compute="_compute_dlt",
|
||||
)
|
||||
context_location_id = fields.Many2one(
|
||||
comodel_name="stock.location",
|
||||
string="Stock Location",
|
||||
compute="_compute_context_location",
|
||||
)
|
||||
# This is a legacy field that can be removed in v17
|
||||
location_id = fields.Many2one(related="context_location_id")
|
||||
|
||||
def _get_search_buffer_domain(self):
|
||||
product = self.product_id
|
||||
if not product and self.product_tmpl_id.product_variant_ids:
|
||||
product = self.product_tmpl_id.product_variant_ids[0]
|
||||
domain = [
|
||||
("product_id", "=", product.id),
|
||||
("location_id", "=", self.context_location_id.id),
|
||||
]
|
||||
if self.company_id:
|
||||
domain.append(("company_id", "=", self.company_id.id))
|
||||
return domain
|
||||
|
||||
@api.depends("product_id", "product_tmpl_id", "context_location_id")
|
||||
def _compute_buffer(self):
|
||||
for record in self:
|
||||
domain = record._get_search_buffer_domain()
|
||||
# NOTE: It can be possible to find multiple buffers.
|
||||
# For example if the BoM has no location set, and there
|
||||
# are buffers with the same product_id and buffer_profile_id
|
||||
# You do not know which one the search function finds.
|
||||
buffer = self.env["stock.buffer"].search(domain, limit=1)
|
||||
record.buffer_id = buffer
|
||||
|
||||
@api.depends("buffer_id")
|
||||
def _compute_is_buffered(self):
|
||||
for bom in self:
|
||||
bom.is_buffered = True if bom.buffer_id else False
|
||||
|
||||
@api.depends_context("location_id")
|
||||
def _compute_context_location(self):
|
||||
warehouse_model = self.env["stock.warehouse"]
|
||||
for rec in self:
|
||||
if self.env.context.get("location_id", None):
|
||||
rec.context_location_id = self.env.context.get("location_id")
|
||||
elif self.env.context.get("warehouse", None):
|
||||
warehouse_id = self.env.context.get("warehouse")
|
||||
rec.context_location_id = warehouse_model.browse(
|
||||
warehouse_id
|
||||
).lot_stock_id.id
|
||||
else:
|
||||
company_id = rec.company_id or self.env.company
|
||||
warehouse_id = warehouse_model.search(
|
||||
[("company_id", "=", company_id.id)], limit=1
|
||||
)
|
||||
rec.context_location_id = warehouse_id.lot_stock_id.id
|
||||
|
||||
def _get_produce_delay(self):
|
||||
self.ensure_one()
|
||||
return self.product_id.produce_delay or self.product_tmpl_id.produce_delay
|
||||
|
||||
def _get_longest_path(self):
|
||||
if not self.bom_line_ids:
|
||||
return 0.0
|
||||
paths = [0] * len(self.bom_line_ids)
|
||||
i = 0
|
||||
for line in self.bom_line_ids:
|
||||
if line.is_buffered:
|
||||
i += 1
|
||||
elif line.product_id.bom_ids:
|
||||
# If the a component is manufactured we continue exploding.
|
||||
location = line.context_location_id
|
||||
line_boms = line.product_id.bom_ids
|
||||
bom = line_boms.filtered(
|
||||
lambda bom: bom.context_location_id == location
|
||||
) or line_boms.filtered(lambda bom: not bom.context_location_id)
|
||||
if bom:
|
||||
paths[i] += bom[0]._get_produce_delay()
|
||||
paths[i] += bom[0]._get_longest_path()
|
||||
else:
|
||||
_logger.info(
|
||||
"ddmrp (dlt): Product %s has no BOM for location "
|
||||
"%s." % (line.product_id.name, location.name)
|
||||
)
|
||||
i += 1
|
||||
else:
|
||||
# assuming they are purchased,
|
||||
if line.product_id.seller_ids:
|
||||
paths[i] = line.product_id.seller_ids[0].delay
|
||||
else:
|
||||
_logger.info(
|
||||
"ddmrp (dlt): Product %s has no seller set."
|
||||
% line.product_id.name
|
||||
)
|
||||
i += 1
|
||||
return max(paths)
|
||||
|
||||
def _get_manufactured_dlt(self):
|
||||
"""Computes the Decoupled Lead Time exploding all the branches of the
|
||||
BOM until a buffered position and then selecting the greatest."""
|
||||
self.ensure_one()
|
||||
dlt = self._get_produce_delay()
|
||||
dlt += self._get_longest_path()
|
||||
return dlt
|
||||
|
||||
@api.depends("context_location_id")
|
||||
@api.depends_context("location_id")
|
||||
def _compute_dlt(self):
|
||||
for rec in self:
|
||||
rec.dlt = rec._get_manufactured_dlt()
|
||||
|
||||
def action_change_context_location(self):
|
||||
return {
|
||||
"type": "ir.actions.act_window",
|
||||
"name": _("Change MRP BoM Location"),
|
||||
"res_model": "mrp.bom.change.location",
|
||||
"view_mode": "form",
|
||||
"target": "new",
|
||||
}
|
||||
|
||||
|
||||
class MrpBomLine(models.Model):
|
||||
_inherit = "mrp.bom.line"
|
||||
|
||||
is_buffered = fields.Boolean(
|
||||
string="Buffered?",
|
||||
compute="_compute_is_buffered",
|
||||
help="True when the product has an DDMRP buffer associated.",
|
||||
)
|
||||
buffer_id = fields.Many2one(
|
||||
comodel_name="stock.buffer",
|
||||
string="Stock Buffer",
|
||||
compute="_compute_is_buffered",
|
||||
)
|
||||
dlt = fields.Float(
|
||||
string="Decoupled Lead Time (days)",
|
||||
compute="_compute_dlt",
|
||||
)
|
||||
context_location_id = fields.Many2one(related="bom_id.context_location_id")
|
||||
# This is a legacy field that can be removed in v17
|
||||
location_id = fields.Many2one(related="context_location_id")
|
||||
|
||||
def _get_search_buffer_domain(self):
|
||||
product = self.product_id
|
||||
if not product and self.product_tmpl_id.product_variant_ids:
|
||||
product = self.product_tmpl_id.product_variant_ids[0]
|
||||
domain = [
|
||||
("product_id", "=", product.id),
|
||||
("location_id", "=", self.context_location_id.id),
|
||||
]
|
||||
if self.company_id:
|
||||
domain.append(("company_id", "=", self.company_id.id))
|
||||
return domain
|
||||
|
||||
@api.depends("context_location_id")
|
||||
@api.depends_context("location_id")
|
||||
def _compute_is_buffered(self):
|
||||
for line in self:
|
||||
domain = line._get_search_buffer_domain()
|
||||
buffer = self.env["stock.buffer"].search(domain, limit=1)
|
||||
line.buffer_id = buffer
|
||||
line.is_buffered = True if buffer else False
|
||||
|
||||
@api.depends("product_id")
|
||||
def _compute_dlt(self):
|
||||
for rec in self:
|
||||
if rec.product_id.bom_ids:
|
||||
rec.dlt = rec.product_id.bom_ids[0].dlt
|
||||
else:
|
||||
rec.dlt = (
|
||||
rec.product_id.seller_ids
|
||||
and rec.product_id.seller_ids[0].delay
|
||||
or 0.0
|
||||
)
|
||||
75
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/models/mrp_production.py
Normal file
75
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/models/mrp_production.py
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
# Copyright 2016-20 ForgeFlow S.L. (http://www.forgeflow.com)
|
||||
# Copyright 2016 Aleph Objects, Inc. (https://www.alephobjects.com/)
|
||||
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
|
||||
|
||||
from odoo import api, fields, models
|
||||
|
||||
from .stock_buffer import _PRIORITY_LEVEL
|
||||
|
||||
|
||||
class MrpProduction(models.Model):
|
||||
_inherit = "mrp.production"
|
||||
|
||||
buffer_id = fields.Many2one(
|
||||
comodel_name="stock.buffer",
|
||||
index=True,
|
||||
string="Stock Buffer",
|
||||
)
|
||||
execution_priority_level = fields.Selection(
|
||||
string="Buffer On-Hand Alert Level",
|
||||
selection=_PRIORITY_LEVEL,
|
||||
readonly=True,
|
||||
)
|
||||
on_hand_percent = fields.Float(
|
||||
string="On Hand/TOR (%)",
|
||||
)
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
records = super().create(vals_list)
|
||||
records._calc_execution_priority()
|
||||
return records
|
||||
|
||||
def _calc_execution_priority(self):
|
||||
"""Technical note: this method cannot be decorated with api.depends,
|
||||
otherwise it would generate a infinite recursion."""
|
||||
prods = self.filtered(
|
||||
lambda r: r.buffer_id and r.state not in ["done", "cancel"]
|
||||
)
|
||||
for rec in prods:
|
||||
rec.execution_priority_level = rec.buffer_id.execution_priority_level
|
||||
rec.on_hand_percent = rec.buffer_id.on_hand_percent
|
||||
to_update = (self - prods).filtered(
|
||||
lambda r: r.execution_priority_level or r.on_hand_percent
|
||||
)
|
||||
if to_update:
|
||||
to_update.write({"execution_priority_level": None, "on_hand_percent": None})
|
||||
|
||||
def _search_execution_priority(self, operator, value):
|
||||
"""Search on the execution priority by evaluating on all
|
||||
open manufacturing orders."""
|
||||
all_records = self.search([("state", "not in", ["done", "cancel"])])
|
||||
|
||||
if operator == "=":
|
||||
found_ids = [
|
||||
a.id for a in all_records if a.execution_priority_level == value
|
||||
]
|
||||
elif operator == "in" and isinstance(value, list):
|
||||
found_ids = [
|
||||
a.id for a in all_records if a.execution_priority_level in value
|
||||
]
|
||||
elif operator in ("!=", "<>"):
|
||||
found_ids = [
|
||||
a.id for a in all_records if a.execution_priority_level != value
|
||||
]
|
||||
elif operator == "not in" and isinstance(value, list):
|
||||
found_ids = [
|
||||
a.id for a in all_records if a.execution_priority_level not in value
|
||||
]
|
||||
else:
|
||||
raise NotImplementedError(
|
||||
"Search operator {} not implemented for value {}".format(
|
||||
operator, value
|
||||
)
|
||||
)
|
||||
return [("id", "in", found_ids)]
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
# Copyright 2016-20 ForgeFlow S.L. (http://www.forgeflow.com)
|
||||
# Copyright 2016 Aleph Objects, Inc. (https://www.alephobjects.com/)
|
||||
# Copyright 2018 Camptocamp SA https://www.camptocamp.com
|
||||
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
|
||||
|
||||
from odoo import api, models
|
||||
|
||||
|
||||
class ProcurementGroup(models.Model):
|
||||
_inherit = "procurement.group"
|
||||
|
||||
# UOM: (stock_orderpoint_uom):
|
||||
@api.model
|
||||
def run(self, procurements, raise_user_error=True):
|
||||
Proc = self.env["procurement.group"].Procurement
|
||||
indexes_to_pop = []
|
||||
new_procs = []
|
||||
for i, procurement in enumerate(procurements):
|
||||
if "buffer_id" in procurement.values:
|
||||
buffer = procurement.values.get("buffer_id")
|
||||
if (
|
||||
buffer.procure_uom_id
|
||||
and procurement.product_uom != buffer.procure_uom_id
|
||||
):
|
||||
new_product_qty = procurement.product_uom._compute_quantity(
|
||||
procurement.product_qty, buffer.procure_uom_id
|
||||
)
|
||||
new_product_uom = buffer.procure_uom_id
|
||||
new_procs.append(
|
||||
Proc(
|
||||
procurement.product_id,
|
||||
new_product_qty,
|
||||
new_product_uom,
|
||||
procurement.location_id,
|
||||
procurement.name,
|
||||
procurement.origin,
|
||||
procurement.company_id,
|
||||
procurement.values,
|
||||
)
|
||||
)
|
||||
indexes_to_pop.append(i)
|
||||
if new_procs:
|
||||
indexes_to_pop.reverse()
|
||||
for index in indexes_to_pop:
|
||||
procurements.pop(index)
|
||||
procurements.extend(new_procs)
|
||||
|
||||
return super(ProcurementGroup, self).run(
|
||||
procurements, raise_user_error=raise_user_error
|
||||
)
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
# Copyright 2016-20 ForgeFlow S.L. (http://www.forgeflow.com)
|
||||
# Copyright 2016 Aleph Objects, Inc. (https://www.alephobjects.com/)
|
||||
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
|
||||
class ProductAduCalculationMethod(models.Model):
|
||||
_name = "product.adu.calculation.method"
|
||||
_description = "Product Average Daily Usage calculation method"
|
||||
|
||||
@api.model
|
||||
def _get_calculation_method(self):
|
||||
return [
|
||||
("fixed", _("Fixed ADU")),
|
||||
("past", _("Past-looking")),
|
||||
("future", _("Future-looking")),
|
||||
("blended", _("Blended")),
|
||||
]
|
||||
|
||||
@api.model
|
||||
def _get_source_selection(self):
|
||||
return [
|
||||
("actual", "Use actual Stock Moves"),
|
||||
("estimates", "Use Demand Estimates"),
|
||||
("estimates_mrp", "Use Demand Estimates + Indirect Demand from MRP Moves"),
|
||||
]
|
||||
|
||||
name = fields.Char(required=True)
|
||||
method = fields.Selection(
|
||||
selection="_get_calculation_method",
|
||||
string="Calculation method",
|
||||
)
|
||||
source_past = fields.Selection(
|
||||
selection="_get_source_selection",
|
||||
string="Past Source",
|
||||
help="Information source used for past calculation.",
|
||||
)
|
||||
horizon_past = fields.Float(
|
||||
string="Past Horizon",
|
||||
help="Length-of-period horizon in days looking past.",
|
||||
)
|
||||
factor_past = fields.Float(
|
||||
string="Past Factor",
|
||||
help="When using a blended method, this is the relative weight "
|
||||
"assigned to the past part of the combination.",
|
||||
default=0.5,
|
||||
)
|
||||
source_future = fields.Selection(
|
||||
selection="_get_source_selection",
|
||||
string="Future Source",
|
||||
help="Information source used for future calculation.",
|
||||
)
|
||||
horizon_future = fields.Float(
|
||||
string="Future Horizon",
|
||||
help="Length-of-period horizon in days looking forward.",
|
||||
)
|
||||
factor_future = fields.Float(
|
||||
string="Future Factor",
|
||||
help="When using a blended method, this is the relative weight "
|
||||
"assigned to the future part of the combination.",
|
||||
default=0.5,
|
||||
)
|
||||
company_id = fields.Many2one(
|
||||
comodel_name="res.company",
|
||||
string="Company",
|
||||
)
|
||||
|
||||
@api.constrains("method", "horizon_past", "horizon_future")
|
||||
def _check_horizon(self):
|
||||
for rec in self:
|
||||
if rec.method in ["past", "blended"] and not rec.horizon_past:
|
||||
raise ValidationError(_("Please indicate a Past Horizon."))
|
||||
if rec.method in ["blended", "future"] and not rec.horizon_future:
|
||||
raise ValidationError(_("Please indicate a Future Horizon."))
|
||||
|
||||
@api.constrains("method", "source_past", "source_future")
|
||||
def _check_source(self):
|
||||
for rec in self:
|
||||
if rec.method in ["past", "blended"] and not rec.source_past:
|
||||
raise ValidationError(_("Please indicate a Past Source."))
|
||||
if rec.method in ["blended", "future"] and not rec.source_future:
|
||||
raise ValidationError(_("Please indicate a Future Source."))
|
||||
|
||||
@api.constrains("method", "factor_past", "factor_future")
|
||||
def _check_factor(self):
|
||||
for rec in self.filtered(lambda r: r.method == "blended"):
|
||||
if (
|
||||
rec.factor_past + rec.factor_future != 1.0
|
||||
or rec.factor_future < 0.0
|
||||
or rec.factor_past < 0.0
|
||||
):
|
||||
raise ValidationError(
|
||||
_(
|
||||
"In blended method, past and future factors must be "
|
||||
"positive and sum exactly 1,0."
|
||||
)
|
||||
)
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
# Copyright 2020 ForgeFlow S.L. (http://www.forgeflow.com)
|
||||
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class Product(models.Model):
|
||||
_inherit = "product.product"
|
||||
|
||||
buffer_ids = fields.One2many(
|
||||
comodel_name="stock.buffer",
|
||||
string="Stock Buffers",
|
||||
inverse_name="product_id",
|
||||
)
|
||||
|
||||
buffer_count = fields.Integer(compute="_compute_buffer_count")
|
||||
|
||||
def write(self, values):
|
||||
res = super().write(values)
|
||||
if values.get("active") is False:
|
||||
buffers = (
|
||||
self.env["stock.buffer"].sudo().search([("product_id", "in", self.ids)])
|
||||
)
|
||||
buffers.write({"active": False})
|
||||
return res
|
||||
|
||||
def _compute_buffer_count(self):
|
||||
for rec in self:
|
||||
rec.buffer_count = len(rec.buffer_ids)
|
||||
|
||||
def action_view_stock_buffers(self):
|
||||
action = self.env["ir.actions.actions"]._for_xml_id("ddmrp.action_stock_buffer")
|
||||
action["context"] = {}
|
||||
action["domain"] = [("id", "in", self.buffer_ids.ids)]
|
||||
return action
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
# Copyright 2019-20 ForgeFlow S.L. (http://www.forgeflow.com)
|
||||
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
|
||||
class ProductTemplate(models.Model):
|
||||
_inherit = "product.template"
|
||||
|
||||
buffer_count = fields.Integer(compute="_compute_buffer_count")
|
||||
|
||||
def _compute_buffer_count(self):
|
||||
for rec in self:
|
||||
rec.buffer_count = sum(
|
||||
variant.buffer_count for variant in rec.product_variant_ids
|
||||
)
|
||||
|
||||
# UOM: (stock_orderpoint_uom):
|
||||
@api.constrains("uom_id")
|
||||
def _check_buffer_procure_uom(self):
|
||||
for rec in self:
|
||||
buffer = self.env["stock.buffer"].search(
|
||||
[
|
||||
("procure_uom_id.category_id", "!=", rec.uom_id.category_id.id),
|
||||
("product_id", "in", rec.product_variant_ids.ids),
|
||||
],
|
||||
limit=1,
|
||||
)
|
||||
if buffer:
|
||||
raise ValidationError(
|
||||
_(
|
||||
"At least one stock buffer for this product has a "
|
||||
"different Procurement unit of measure category."
|
||||
)
|
||||
)
|
||||
|
||||
def action_view_stock_buffers(self):
|
||||
return self.product_variant_ids.action_view_stock_buffers()
|
||||
107
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/models/purchase_order.py
Normal file
107
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/models/purchase_order.py
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
# Copyright 2017-20 ForgeFlow S.L. (http://www.forgeflow.com)
|
||||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
from .stock_buffer import _PRIORITY_LEVEL
|
||||
|
||||
|
||||
class PurchaseOrder(models.Model):
|
||||
_inherit = "purchase.order"
|
||||
|
||||
ddmrp_comment = fields.Text(string="Follow-up Notes")
|
||||
|
||||
|
||||
class PurchaseOrderLine(models.Model):
|
||||
_inherit = "purchase.order.line"
|
||||
|
||||
buffer_ids = fields.Many2many(
|
||||
comodel_name="stock.buffer",
|
||||
string="Stock Buffers",
|
||||
copy=False,
|
||||
readonly=True,
|
||||
)
|
||||
execution_priority_level = fields.Selection(
|
||||
string="Buffer On-Hand Status Level",
|
||||
selection=_PRIORITY_LEVEL,
|
||||
readonly=True,
|
||||
)
|
||||
on_hand_percent = fields.Float(
|
||||
string="On Hand/TOR (%)",
|
||||
readonly=True,
|
||||
)
|
||||
ddmrp_comment = fields.Text(related="order_id.ddmrp_comment", readonly=False)
|
||||
|
||||
def create(self, vals):
|
||||
record = super().create(vals)
|
||||
if record.product_id:
|
||||
record._find_buffer_link()
|
||||
record._calc_execution_priority()
|
||||
return record
|
||||
|
||||
def write(self, vals):
|
||||
res = super().write(vals)
|
||||
for rec in self:
|
||||
if rec.product_id:
|
||||
rec._find_buffer_link()
|
||||
return res
|
||||
|
||||
def _product_id_change(self):
|
||||
res = super()._product_id_change()
|
||||
if self.product_id:
|
||||
self._find_buffer_link()
|
||||
return res
|
||||
|
||||
def _calc_execution_priority(self):
|
||||
# TODO: handle serveral buffers? worst scenario, average?
|
||||
to_compute = self.filtered(
|
||||
lambda r: r.buffer_ids and r.state not in ["done", "cancel"]
|
||||
)
|
||||
for rec in to_compute:
|
||||
rec.execution_priority_level = rec.buffer_ids[0].execution_priority_level
|
||||
rec.on_hand_percent = rec.buffer_ids[0].on_hand_percent
|
||||
(self - to_compute).write(
|
||||
{"execution_priority_level": None, "on_hand_percent": None}
|
||||
)
|
||||
|
||||
def _get_domain_buffer_link(self):
|
||||
self.ensure_one()
|
||||
if not self.product_id:
|
||||
# Return impossible domain -> no buffer.
|
||||
return [(0, "=", 1)]
|
||||
return [
|
||||
("product_id", "=", self.product_id.id),
|
||||
("company_id", "=", self.order_id.company_id.id),
|
||||
("buffer_profile_id.item_type", "=", "purchased"),
|
||||
("warehouse_id", "=", self.order_id.picking_type_id.warehouse_id.id),
|
||||
]
|
||||
|
||||
def _find_buffer_link(self):
|
||||
buffer_model = self.env["stock.buffer"]
|
||||
move_model = self.env["stock.move"]
|
||||
for rec in self.filtered(lambda r: not r.buffer_ids):
|
||||
mto_move = move_model.search(
|
||||
[("created_purchase_line_id", "=", rec.id)], limit=1
|
||||
)
|
||||
if mto_move:
|
||||
# MTO lines are not accounted in MTS stock buffers.
|
||||
continue
|
||||
domain = rec._get_domain_buffer_link()
|
||||
buffer = buffer_model.search(domain, limit=1)
|
||||
if buffer:
|
||||
rec.buffer_ids = buffer
|
||||
rec._calc_execution_priority()
|
||||
|
||||
def _prepare_purchase_order_line_from_procurement(
|
||||
self, product_id, product_qty, product_uom, company_id, values, po
|
||||
):
|
||||
vals = super()._prepare_purchase_order_line_from_procurement(
|
||||
product_id, product_qty, product_uom, company_id, values, po
|
||||
)
|
||||
# If the procurement was run directly by a reordering rule.
|
||||
if "buffer_id" in values:
|
||||
vals["buffer_ids"] = [(4, values["buffer_id"].id)]
|
||||
# If the procurement was run by a stock move.
|
||||
elif "buffer_ids" in values:
|
||||
vals["buffer_ids"] = [(4, o.id) for o in values["buffer_ids"]]
|
||||
return vals
|
||||
21
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/models/res_company.py
Normal file
21
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/models/res_company.py
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
# Copyright 2020 ForgeFlow S.L. (http://www.forgeflow.com)
|
||||
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
|
||||
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class ResCompany(models.Model):
|
||||
_inherit = "res.company"
|
||||
|
||||
ddmrp_auto_update_nfp = fields.Boolean(
|
||||
string="Update NFP on Stock Buffers on relevant events.",
|
||||
help="Transfer status changes can trigger the update of relevant "
|
||||
"buffer's NFP.",
|
||||
)
|
||||
ddmrp_adu_calc_include_scrap = fields.Boolean(
|
||||
string="Include scrap locations in ADU calculation",
|
||||
)
|
||||
ddmrp_qty_multiple_tolerance = fields.Float(
|
||||
string="Qty Multiple Tolerance",
|
||||
)
|
||||
2127
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/models/stock_buffer.py
Normal file
2127
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/models/stock_buffer.py
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,77 @@
|
|||
# Copyright 2016-20 ForgeFlow S.L. (http://www.forgeflow.com)
|
||||
# Copyright 2016 Aleph Objects, Inc. (https://www.alephobjects.com/)
|
||||
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
|
||||
|
||||
from odoo import api, fields, models
|
||||
|
||||
_REPLENISH_METHODS = [
|
||||
("replenish", "Replenished"),
|
||||
("replenish_override", "Replenished Override"),
|
||||
("min_max", "Min-max"),
|
||||
]
|
||||
_ITEM_TYPES = [
|
||||
("manufactured", "Manufactured"),
|
||||
("purchased", "Purchased"),
|
||||
("distributed", "Distributed"),
|
||||
]
|
||||
|
||||
|
||||
class StockBufferProfile(models.Model):
|
||||
_name = "stock.buffer.profile"
|
||||
_description = "Stock Buffer Profile"
|
||||
|
||||
@api.depends(
|
||||
"item_type",
|
||||
"lead_time_id",
|
||||
"lead_time_id.name",
|
||||
"lead_time_id.factor",
|
||||
"variability_id",
|
||||
"variability_id.name",
|
||||
"variability_id.factor",
|
||||
"distributed_reschedule_max_proc_time",
|
||||
)
|
||||
def _compute_name(self):
|
||||
"""Get the right summary for this job."""
|
||||
for rec in self:
|
||||
name = "{} {}, {}({}), {}({})".format(
|
||||
rec.replenish_method,
|
||||
rec.item_type,
|
||||
rec.lead_time_id.name,
|
||||
rec.lead_time_id.factor,
|
||||
rec.variability_id.name,
|
||||
rec.variability_id.factor,
|
||||
)
|
||||
if rec.distributed_reschedule_max_proc_time > 0.0:
|
||||
name += ", {}min".format(rec.distributed_reschedule_max_proc_time)
|
||||
rec.name = name
|
||||
|
||||
name = fields.Char(compute="_compute_name", store=True)
|
||||
replenish_method = fields.Selection(
|
||||
string="Replenishment method", selection=_REPLENISH_METHODS, required=True
|
||||
)
|
||||
item_type = fields.Selection(selection=_ITEM_TYPES, required=True)
|
||||
lead_time_id = fields.Many2one(
|
||||
comodel_name="stock.buffer.profile.lead.time", string="Lead Time Factor"
|
||||
)
|
||||
variability_id = fields.Many2one(
|
||||
comodel_name="stock.buffer.profile.variability", string="Variability Factor"
|
||||
)
|
||||
company_id = fields.Many2one(
|
||||
"res.company",
|
||||
"Company",
|
||||
)
|
||||
|
||||
replenish_distributed_limit_to_free_qty = fields.Boolean(
|
||||
string="Limit replenishment to free quantity",
|
||||
default=False,
|
||||
help="When activated, the recommended quantity will be maxed at "
|
||||
"the quantity available in the replenishment source location.",
|
||||
)
|
||||
distributed_reschedule_max_proc_time = fields.Float(
|
||||
string="Re-Schedule Procurement Max Proc. Time (minutes)",
|
||||
default=0.0,
|
||||
help="When you request procurement from a buffer, their scheduled"
|
||||
" date is rescheduled to now + this procurement time (in minutes)."
|
||||
" Their scheduled date represents the latest the transfers should"
|
||||
" be done, and therefore, past this timestamp, considered late.",
|
||||
)
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
# Copyright 2016-20 ForgeFlow S.L. (http://www.forgeflow.com)
|
||||
# Copyright 2016 Aleph Objects, Inc. (https://www.alephobjects.com/)
|
||||
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class StockBufferProfileLeadTime(models.Model):
|
||||
_name = "stock.buffer.profile.lead.time"
|
||||
_description = "Stock Buffer Profile Lead Time Factor"
|
||||
|
||||
name = fields.Char(required=True)
|
||||
factor = fields.Float(string="Lead Time Factor", required=True)
|
||||
company_id = fields.Many2one(
|
||||
"res.company",
|
||||
"Company",
|
||||
)
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
# Copyright 2016-20 ForgeFlow S.L. (http://www.forgeflow.com)
|
||||
# Copyright 2016 Aleph Objects, Inc. (https://www.alephobjects.com/)
|
||||
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class StockBufferProfileVariability(models.Model):
|
||||
_name = "stock.buffer.profile.variability"
|
||||
_description = "Stock Buffer Profile Variability Factor"
|
||||
|
||||
name = fields.Char(required=True)
|
||||
factor = fields.Float(string="Variability Factor", required=True)
|
||||
company_id = fields.Many2one(
|
||||
"res.company",
|
||||
"Company",
|
||||
)
|
||||
152
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/models/stock_move.py
Normal file
152
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/models/stock_move.py
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
# Copyright 2019-20 ForgeFlow S.L. (http://www.forgeflow.com)
|
||||
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
|
||||
|
||||
class StockMove(models.Model):
|
||||
_inherit = "stock.move"
|
||||
|
||||
buffer_ids = fields.Many2many(
|
||||
comodel_name="stock.buffer",
|
||||
string="Linked Stock Buffers",
|
||||
)
|
||||
# Add an index as '_find_buffer_link' method is using it as search criteria
|
||||
created_purchase_line_id = fields.Many2one(index=True)
|
||||
|
||||
def _prepare_procurement_values(self):
|
||||
res = super(StockMove, self)._prepare_procurement_values()
|
||||
if self.buffer_ids:
|
||||
res["buffer_ids"] = self.buffer_ids
|
||||
return res
|
||||
|
||||
def _merge_moves_fields(self):
|
||||
res = super(StockMove, self)._merge_moves_fields()
|
||||
res["buffer_ids"] = [(4, m.id) for m in self.mapped("buffer_ids")]
|
||||
return res
|
||||
|
||||
def write(self, vals):
|
||||
res = super(StockMove, self).write(vals)
|
||||
if self and self.env.company.ddmrp_auto_update_nfp:
|
||||
# Stock moves changes can be triggered by users without
|
||||
# access to write stock buffers, thus we do it with sudo.
|
||||
if "state" in vals:
|
||||
self.sudo()._update_ddmrp_nfp()
|
||||
elif "location_id" in vals or "location_dest_id" in vals:
|
||||
self.sudo().filtered(
|
||||
lambda m: m.state
|
||||
in ("confirmed", "partially_available", "assigned")
|
||||
)._update_ddmrp_nfp()
|
||||
return res
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
moves = super(StockMove, self).create(vals_list)
|
||||
# TODO should we use @api.model_create_single instead?
|
||||
moves_to_update_ids = []
|
||||
for vals, move in zip(vals_list, moves):
|
||||
if (
|
||||
"state" in vals
|
||||
and move.state not in ("draft", "cancel")
|
||||
and self.env.company.ddmrp_auto_update_nfp
|
||||
):
|
||||
moves_to_update_ids.append(move.id)
|
||||
# Stock moves state changes can be triggered by users without
|
||||
# access to write stock buffers, thus we do it with sudo.
|
||||
if moves_to_update_ids:
|
||||
self.browse(moves_to_update_ids).sudo()._update_ddmrp_nfp()
|
||||
return moves
|
||||
|
||||
def _find_buffers_to_update_nfp(self):
|
||||
# Find buffers that can be affected. `out_buffers` will see the move as
|
||||
# outgoing and `in_buffers` as incoming.
|
||||
out_buffers = in_buffers = self.env["stock.buffer"]
|
||||
for move in self:
|
||||
out_buffers |= move.mapped("product_id.buffer_ids").filtered(
|
||||
lambda buffer: (
|
||||
move.location_id.is_sublocation_of(buffer.location_id)
|
||||
and not move.location_dest_id.is_sublocation_of(buffer.location_id)
|
||||
)
|
||||
)
|
||||
in_buffers |= move.mapped("product_id.buffer_ids").filtered(
|
||||
lambda buffer: (
|
||||
not move.location_id.is_sublocation_of(buffer.location_id)
|
||||
and move.location_dest_id.is_sublocation_of(buffer.location_id)
|
||||
)
|
||||
)
|
||||
return out_buffers, in_buffers
|
||||
|
||||
def _update_ddmrp_nfp(self):
|
||||
if self.env.context.get("no_ddmrp_auto_update_nfp"):
|
||||
return True
|
||||
out_buffers, in_buffers = self._find_buffers_to_update_nfp()
|
||||
for buffer in out_buffers.with_context(no_ddmrp_history=True):
|
||||
buffer.cron_actions(only_nfp="out")
|
||||
for buffer in in_buffers.with_context(no_ddmrp_history=True):
|
||||
buffer.cron_actions(only_nfp="in")
|
||||
|
||||
def _get_all_linked_moves(self):
|
||||
"""Retrieve all linked moves both origin and destination recursively."""
|
||||
|
||||
def get_moves(move_set, attr):
|
||||
new_moves = move_set.mapped(attr)
|
||||
while new_moves:
|
||||
move_set |= new_moves
|
||||
new_moves = new_moves.mapped(attr)
|
||||
return move_set
|
||||
|
||||
all_moves = (
|
||||
self | get_moves(self, "move_orig_ids") | get_moves(self, "move_dest_ids")
|
||||
)
|
||||
return all_moves
|
||||
|
||||
def _get_source_field_candidates(self):
|
||||
"""Extend for more source field candidates."""
|
||||
return [
|
||||
"sale_line_id.order_id",
|
||||
"purchase_line_id.order_id",
|
||||
"production_id",
|
||||
"raw_material_production_id",
|
||||
"unbuild_id",
|
||||
"repair_id",
|
||||
"rma_line_id",
|
||||
"picking_id",
|
||||
]
|
||||
|
||||
def _has_nested_field(self, field):
|
||||
"""Check if an object has a nested chain of fields."""
|
||||
current_object = self
|
||||
try:
|
||||
for field in field.split("."):
|
||||
current_object = getattr(current_object, field)
|
||||
return True
|
||||
except AttributeError:
|
||||
return False
|
||||
|
||||
def _get_source_record(self):
|
||||
"""Find the first source record in the field candidates linked with the moves,
|
||||
prioritizing the order of field candidates."""
|
||||
moves = self._get_all_linked_moves()
|
||||
field_candidates = self._get_source_field_candidates()
|
||||
# Iterate over the prioritized list of candidate fields
|
||||
for field in field_candidates:
|
||||
if self._has_nested_field(field):
|
||||
for move in moves:
|
||||
record = move.mapped(field)
|
||||
if record:
|
||||
return record
|
||||
return False
|
||||
|
||||
def action_open_stock_move_source(self):
|
||||
"""Open the source record of the stock move, if it exists."""
|
||||
self.ensure_one()
|
||||
record = self._get_source_record()
|
||||
if record:
|
||||
return {
|
||||
"name": getattr(record, "name", _("Stock Move Source")),
|
||||
"view_mode": "form",
|
||||
"res_model": record._name,
|
||||
"type": "ir.actions.act_window",
|
||||
"res_id": record.id,
|
||||
}
|
||||
return False
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
# Copyright 2021 Camptocamp SA
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class StockMoveLine(models.Model):
|
||||
_inherit = "stock.move.line"
|
||||
|
||||
# Override to make '_calc_product_available_qty' method of
|
||||
# 'stock.buffer' more efficient.
|
||||
state = fields.Selection(index=True)
|
||||
20
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/models/stock_picking.py
Normal file
20
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/models/stock_picking.py
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
# Copyright 2020 Camptocamp SA
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)
|
||||
|
||||
from odoo import models
|
||||
|
||||
|
||||
class StockPicking(models.Model):
|
||||
_inherit = "stock.picking"
|
||||
|
||||
def action_stock_buffer_open(self):
|
||||
"""Open a stock.buffer list related to products of the stock.picking."""
|
||||
self.ensure_one()
|
||||
domain = [
|
||||
("product_id", "in", self.mapped("move_ids.product_id.id")),
|
||||
("company_id", "=", self.company_id.id),
|
||||
]
|
||||
action = self.env["ir.actions.actions"]._for_xml_id("ddmrp.action_stock_buffer")
|
||||
action["domain"] = domain
|
||||
action["context"] = {"search_default_procure_recommended": 1}
|
||||
return action
|
||||
92
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/models/stock_rule.py
Normal file
92
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/models/stock_rule.py
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
# Copyright 2018 Camptocamp (https://www.camptocamp.com)
|
||||
# Copyright 2019-20 ForgeFlow S.L. (http://www.forgeflow.com)
|
||||
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
|
||||
|
||||
from odoo import models
|
||||
|
||||
|
||||
class StockRule(models.Model):
|
||||
_inherit = "stock.rule"
|
||||
|
||||
def _prepare_mo_vals(
|
||||
self,
|
||||
product_id,
|
||||
product_qty,
|
||||
product_uom,
|
||||
location_id,
|
||||
name,
|
||||
origin,
|
||||
company_id,
|
||||
values,
|
||||
bom,
|
||||
):
|
||||
result = super(StockRule, self)._prepare_mo_vals(
|
||||
product_id,
|
||||
product_qty,
|
||||
product_uom,
|
||||
location_id,
|
||||
name,
|
||||
origin,
|
||||
company_id,
|
||||
values,
|
||||
bom,
|
||||
)
|
||||
# TODO: stock_orderpoint_mrp_link: tests!
|
||||
if "buffer_id" in values:
|
||||
result["buffer_id"] = values["buffer_id"].id
|
||||
elif "buffer_ids" in values:
|
||||
# We take the always first value as in case of chain procurements,
|
||||
# the procurements are resolved first and then the moves are
|
||||
# merged. Thus here we are going to have only one buffer in
|
||||
# in buffer_ids.
|
||||
result["buffer_id"] = values["buffer_ids"][0].id
|
||||
return result
|
||||
|
||||
def _run_manufacture(self, procurements):
|
||||
super()._run_manufacture(procurements)
|
||||
for procurement, _rule in procurements:
|
||||
buffer = procurement.values.get("buffer_id")
|
||||
if buffer:
|
||||
buffer.sudo().cron_actions()
|
||||
return True
|
||||
|
||||
# TODO: stock_orderpoint_move_link: tests!
|
||||
def _get_stock_move_values(
|
||||
self,
|
||||
product_id,
|
||||
product_qty,
|
||||
product_uom,
|
||||
location_id,
|
||||
name,
|
||||
origin,
|
||||
company_id,
|
||||
values,
|
||||
):
|
||||
vals = super()._get_stock_move_values(
|
||||
product_id,
|
||||
product_qty,
|
||||
product_uom,
|
||||
location_id,
|
||||
name,
|
||||
origin,
|
||||
company_id,
|
||||
values,
|
||||
)
|
||||
if "buffer_id" in values:
|
||||
vals["buffer_ids"] = [(4, values["buffer_id"].id)]
|
||||
elif "buffer_ids" in values:
|
||||
vals["buffer_ids"] = [(4, o.id) for o in values["buffer_ids"]]
|
||||
return vals
|
||||
|
||||
def _update_purchase_order_line(
|
||||
self, product_id, product_qty, product_uom, company_id, values, line
|
||||
):
|
||||
vals = super()._update_purchase_order_line(
|
||||
product_id, product_qty, product_uom, company_id, values, line
|
||||
)
|
||||
if "buffer_id" in values:
|
||||
vals["buffer_ids"] = [(4, values["buffer_id"].id)]
|
||||
# If the procurement was run by a stock move.
|
||||
elif "buffer_ids" in values:
|
||||
vals["buffer_ids"] = [(4, o.id) for o in values["buffer_ids"]]
|
||||
return vals
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
# Copyright 2018-20 ForgeFlow S.L. (http://www.forgeflow.com)
|
||||
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class StockWarehouse(models.Model):
|
||||
_inherit = "stock.warehouse"
|
||||
|
||||
nfp_incoming_safety_factor = fields.Float(
|
||||
"Net Flow Position Incoming Safety Factor",
|
||||
help="Factor used to compute the number of days to look into the "
|
||||
"future for incoming shipments for the purposes of the Net "
|
||||
"Flow position calculation.",
|
||||
)
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
# Copyright 2024 ForgeFlow S.L. (http://www.forgeflow.com)
|
||||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).
|
||||
|
||||
from odoo import api, models
|
||||
|
||||
|
||||
class StockWarehouseOrderpoint(models.Model):
|
||||
_inherit = "stock.warehouse.orderpoint"
|
||||
|
||||
def _get_orderpoint_action(self):
|
||||
return super(
|
||||
StockWarehouseOrderpoint, self.with_context(_from_get_op_action=True)
|
||||
)._get_orderpoint_action()
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
if self.env.context.get("_from_get_op_action"):
|
||||
new_vals_list = []
|
||||
for vals in vals_list:
|
||||
buffer = self.env["stock.buffer"].search(
|
||||
[
|
||||
("product_id", "=", vals.get("product_id")),
|
||||
("location_id", "=", vals.get("location_id")),
|
||||
],
|
||||
limit=1,
|
||||
)
|
||||
if not buffer:
|
||||
new_vals_list.append(vals)
|
||||
vals_list = new_vals_list
|
||||
return super().create(vals_list)
|
||||
29
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/readme/CONFIGURE.rst
Normal file
29
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/readme/CONFIGURE.rst
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
Scheduled actions
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Go to *Settings > Technical*.
|
||||
* 'DDMRP Buffer ADU calculation'. Computes the Average Daily Usage for all
|
||||
Buffers.
|
||||
* 'Reordering Rule DDMRP calculation'. Computes the Qualified Demand, Net
|
||||
Flow Position, Planning and Execution priorities for all Buffers.
|
||||
|
||||
Decoupled Lead Time computation
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The DLT is automatically computed by the system.
|
||||
|
||||
For manufactured products' buffers just remember to provide and
|
||||
set properly the following information:
|
||||
|
||||
* The *Manufacturing Lead Time* for the manufactured product. It can be found
|
||||
at the product form view under the tab *Sales*.
|
||||
* The *Delivery Lead Time* for the preferred vendor of a product. This is
|
||||
important for the products which are purchased and are components in any
|
||||
Bill of Materials.
|
||||
|
||||
For purchased/distributed products' buffers the logic is simpler.
|
||||
|
||||
* In the first place the system will look if there are Vendors for the product,
|
||||
if so it will use the *Delivery Lead Time* of the preferred one.
|
||||
* In case of absence of vendors, the *Lead Time* at the bottom of the Buffer
|
||||
form view will be used.
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
* Jordi Ballester Alomar <jordi.ballester@forgeflow.com>
|
||||
* Lois Rilo Antelo <lois.rilo@forgeflow.com>
|
||||
* Guewen Baconnier <guewen.baconnier@camptocamp.com>
|
||||
* Adria Gil Sorribes <adria.gil@forgeflow.com>
|
||||
* Christopher Ormaza <chris.ormaza@forgeflow.com>
|
||||
3
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/readme/CREDITS.rst
Normal file
3
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/readme/CREDITS.rst
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
The initial development of this module has been financially supported by:
|
||||
|
||||
* Aleph Objects, Inc.
|
||||
56
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/readme/DESCRIPTION.rst
Normal file
56
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/readme/DESCRIPTION.rst
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
Demand Driven Material Requirements Planning is a formal multi-echelon
|
||||
planning and execution method developed by Ms. Carol Ptak and Mr. Chad Smith.
|
||||
|
||||
DDMRP combines blended aspects of Material Requirements Planning (MRP),
|
||||
Distribution Requirements Planning (DRP) with the pull and visibility
|
||||
emphases found in Lean and the Theory of Constraints and the variability
|
||||
reduction emphasis of Six Sigma.
|
||||
|
||||
This method has five sequential components:
|
||||
|
||||
#. *Strategic Inventory Positioning*. Answers the question "Given our system
|
||||
and environment, where should we place inventory to have the best
|
||||
protection?" and determines where should decoupling points of inventory be
|
||||
placed.
|
||||
|
||||
#. *Buffer Profiles and Levels*. Determine the amount of protection at those
|
||||
decoupling points.
|
||||
|
||||
#. *Dynamic Adjustments*. Allow the company to adapt buffers to group and
|
||||
individual part trait changes over time through the use of several types
|
||||
of adjustments.
|
||||
|
||||
#. *Demand Driven Planning*. Allow to launch purchase orders (POs),
|
||||
manufacturing orders (MOs) and Transfer Orders (TOs) based on the priority
|
||||
dictated by the buffers.
|
||||
|
||||
#. *Visible and Collaborative Execution*. These POs, MOs and TOs have to be
|
||||
effectively managed to synchronize with the changes that often occur within
|
||||
the "execution horizon."
|
||||
|
||||
These five components work together to greatly dampen, if not eliminate,
|
||||
the nervousness of traditional MRP systems and the bullwhip effect in
|
||||
complex and challenging environments.
|
||||
|
||||
This approach provides real information about those parts that are
|
||||
truly at risk of negatively impacting the planned availability of inventory.
|
||||
|
||||
DDMRP sorts the significant few items that require attention from
|
||||
the many parts that are being managed. Under the DDMRP approach,
|
||||
fewer planners can make better decisions more quickly. That means companies
|
||||
will be better able to leverage their working and human capital.
|
||||
|
||||
Demand Driven Material Requirements Planning is quickly being adopted
|
||||
by a wide variety of leading companies across the world.
|
||||
|
||||
Some of the benefits reported by the DDMRP method include:
|
||||
|
||||
* High fill rate performance
|
||||
* Lead time reductions
|
||||
* Inventory reductions, while improving customer service
|
||||
* Eliminate costs related to expedite
|
||||
* Planners see priorities instead of constantly fighting the conflicting
|
||||
messages of MRP
|
||||
|
||||
It is highly recommended to read the book 'Demand Driven Material
|
||||
Requirements Planning (DDMRP)' by Carol Ptak and Chad Smith.
|
||||
40
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/readme/HISTORY.rst
Normal file
40
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/readme/HISTORY.rst
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
13.0.1.1.0 (2020-07-01)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
**Features**
|
||||
|
||||
- - New setting *Update NFP on Stock Buffers on relevant events*.
|
||||
- New dedicated settings block. (`#50 <https://github.com/OCA/ddmrp/issues/50>`_)
|
||||
|
||||
|
||||
13.0.1.0.0 (2020-06-11)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* [MIG/REF] Migration of module to v13 and refactor (added new dedicated model
|
||||
for stock buffer).
|
||||
|
||||
11.0.1.3.0 (2019-02-21)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* [ADD] New chart that depict information about the supply and demand (
|
||||
displaying also de order spike threshold and horizon) for a buffer.
|
||||
(`#40 <https://github.com/OCA/ddmrp/pull/40>`_)
|
||||
|
||||
11.0.1.2.0 (2019-01-29)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* [IMP] Performance improvement of execution priority calculation and ADU.
|
||||
(`#36 <https://github.com/OCA/ddmrp/pull/36>`_)
|
||||
* [IMP] Use the minimum quantity to adjust the procure recommendation.
|
||||
(`#37 <https://github.com/OCA/ddmrp/pull/37>`_)
|
||||
|
||||
11.0.1.1.0 (2018-08-31)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* [IMP] Implemented Blended ADU calculation method.
|
||||
(`#23 <https://github.com/OCA/ddmrp/pull/23>`_)
|
||||
|
||||
11.0.1.0.0 (2018-07-16)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Start of the history
|
||||
7
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/readme/INSTALL.rst
Normal file
7
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/readme/INSTALL.rst
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
We strongly recommend to modify the configuration of the reservation method
|
||||
to manual in the outgoing operation types (so deliveries
|
||||
related to Sales Orders aren't automatically reserved) and to avoid to
|
||||
reserve stock for specific moves, buffers are in fact a reservation of stock.
|
||||
However, while **reservation is discouraged**, it is still available to be
|
||||
used, in case of reserved stock be aware that the buffer will be blind to this
|
||||
transfers and stock and you are bypassing the DDMRP reordering flow.
|
||||
3
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/readme/ROADMAP.rst
Normal file
3
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/readme/ROADMAP.rst
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
The DDMRP `roadmap <https://github.com/OCA/ddmrp/issues?q=is%3Aopen+is%3Aissue+label%3Aenhancement>`_
|
||||
and `known issues <https://github.com/OCA/ddmrp/issues?q=is%3Aopen+is%3Aissue+label%3Abug>`_ can
|
||||
be found on GitHub.
|
||||
82
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/readme/USAGE.rst
Normal file
82
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/readme/USAGE.rst
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
To easily identify were are you maintaining buffers in your Bill of
|
||||
Materials, you will need to first provide location information on the Bills
|
||||
of Materials.
|
||||
|
||||
* Go to *Manufacturing / Products / Bill of Materials* and update the
|
||||
'Location' in all the Bill of Materials and associated lines,
|
||||
indicating where will the parts be placed/used during the manufacturing
|
||||
process.
|
||||
|
||||
* Print the report 'BOM Structure' to display where in your BOM are you
|
||||
maintaining buffers, and to identify the Lead Time (LT) of each product, and
|
||||
Decouple Lead Time (DLT).
|
||||
|
||||
|
||||
Buffers
|
||||
~~~~~~~
|
||||
|
||||
To list the list of inventory buffers, go to one of the following:
|
||||
* *Inventory / Master Data / Stock Buffer Planning*
|
||||
* *Inventory / Master Data / Reordering Rules*
|
||||
|
||||
|
||||
Buffer Profiles
|
||||
~~~~~~~~~~~~~~~
|
||||
Buffer profiles make maintenance of buffers easier by grouping them in
|
||||
profiles. Changes applied to the profiles will be applicable in the
|
||||
associated buffer calculations.
|
||||
|
||||
* Go to *Inventory / Configuration / Buffer Profiles*.
|
||||
|
||||
The Buffer Profile Lead Time Factor influences the size of the Buffer Green
|
||||
zone. Items with longer lead times will usually have smaller green zones, which
|
||||
will translate in more frequent supply order generation.
|
||||
|
||||
* Go to *Inventory / Configuration / Buffer Profile Lead Time Factor* to
|
||||
chan
|
||||
|
||||
The Buffer Profile Variability Factor influences the size of the Buffer Red
|
||||
Safety zone. Items with longer lead times will usually have smaller green
|
||||
zones, which will translate in more frequent supply order generation.
|
||||
|
||||
* Go to *Inventory / Configuration / Buffer Profile Lead Time Factor*.
|
||||
|
||||
Usual factors should range from 0.2 (long lead time) to 0.8 (short lead time).
|
||||
|
||||
|
||||
Product attributes
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* For manufactured products, go to *Manufacturing / Products* and
|
||||
update the 'Manufacturing Lead Time' field, available in the tab *Inventory*.
|
||||
* For purchased products, go to go to *Purchasing / Products* and update the
|
||||
*Delivery Lead Time* for each vendor, available in tab *Purchase* and section
|
||||
*Vendors*.
|
||||
|
||||
|
||||
ADU Calculation Methods
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The Average Daily Usage (ADU) defines the frequency of demand of a product in a
|
||||
certain location. It can be computed in different ways, which you can configure
|
||||
with ADU calculation methods as follows:
|
||||
|
||||
#. Go to *Inventory / Configuration / DDMRP / ADU calculation methods*.
|
||||
#. Indicate a name, a calculation method (fixed, past-looking,
|
||||
future-looking or blended).
|
||||
#. Fill the corresponding period (past, future or both for blended method) to
|
||||
specify the length of period consideration (in days).
|
||||
#. Indicate the source of information: stock moves or demand estimates.
|
||||
#. If you use the blended method fill also the *Past Factor* and
|
||||
*Future Factor*.
|
||||
|
||||
If you do not have prior history of stock moves in your system, it is advised
|
||||
to use fixed method or start to work on future estimates. If you have
|
||||
past-history of stock moves, best use past-looking method or blended method.
|
||||
|
||||
The ADU is computed every day by default in a background job independently
|
||||
from the other buffer fields. This computation can be done with less frequency
|
||||
but it is not recommended to run it less than weekly or more than daily.
|
||||
Circumstantially, If you need to force the calculation of the ADU go to
|
||||
*Inventory / Configuration / DDMRP / Run DDMRP* and click on
|
||||
*Run ADU calculation*.
|
||||
1
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/report/__init__.py
Normal file
1
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/report/__init__.py
Normal file
|
|
@ -0,0 +1 @@
|
|||
from . import mrp_report_bom_structure
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
# Copyright 2017-23 ForgeFlow S.L. (http://www.forgeflow.com)
|
||||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).
|
||||
|
||||
from odoo import api, models
|
||||
|
||||
|
||||
class BomStructureReport(models.AbstractModel):
|
||||
_inherit = "report.mrp.report_bom_structure"
|
||||
|
||||
def _get_pdf_doc(self, bom_id, data, quantity, product_variant_id=None):
|
||||
doc = super()._get_pdf_doc(bom_id, data, quantity, product_variant_id)
|
||||
doc["show_buffered"] = (
|
||||
True if data and data.get("show_buffered") == "true" else False
|
||||
)
|
||||
return doc
|
||||
|
||||
@api.model
|
||||
def _get_bom_data(
|
||||
self,
|
||||
bom,
|
||||
warehouse,
|
||||
product=False,
|
||||
line_qty=False,
|
||||
bom_line=False,
|
||||
level=0,
|
||||
parent_bom=False,
|
||||
index=0,
|
||||
product_info=False,
|
||||
ignore_stock=False,
|
||||
):
|
||||
res = super(BomStructureReport, self)._get_bom_data(
|
||||
bom,
|
||||
warehouse,
|
||||
product=product,
|
||||
line_qty=line_qty,
|
||||
bom_line=bom_line,
|
||||
level=level,
|
||||
parent_bom=parent_bom,
|
||||
index=index,
|
||||
product_info=product_info,
|
||||
ignore_stock=ignore_stock,
|
||||
)
|
||||
res["is_buffered"] = bom.is_buffered
|
||||
res["dlt"] = bom.dlt
|
||||
return res
|
||||
|
||||
@api.model
|
||||
def _get_component_data(
|
||||
self,
|
||||
parent_bom,
|
||||
warehouse,
|
||||
bom_line,
|
||||
line_quantity,
|
||||
level,
|
||||
index,
|
||||
product_info,
|
||||
ignore_stock=False,
|
||||
):
|
||||
res = super(BomStructureReport, self)._get_component_data(
|
||||
parent_bom,
|
||||
warehouse,
|
||||
bom_line,
|
||||
line_quantity,
|
||||
level,
|
||||
index,
|
||||
product_info,
|
||||
ignore_stock=ignore_stock,
|
||||
)
|
||||
if bom_line.product_id.bom_ids:
|
||||
lead_time = bom_line.product_id.produce_delay
|
||||
else:
|
||||
lead_time = (
|
||||
bom_line.product_id.seller_ids
|
||||
and bom_line.product_id.seller_ids[0].delay
|
||||
or 0.0
|
||||
)
|
||||
res["is_buffered"] = bom_line.is_buffered
|
||||
res["lead_time"] = lead_time or False
|
||||
res["dlt"] = bom_line.dlt
|
||||
return res
|
||||
|
||||
def _get_bom_array_lines(
|
||||
self, data, level, unfolded_ids, unfolded, parent_unfolded
|
||||
):
|
||||
lines = super()._get_bom_array_lines(
|
||||
data, level, unfolded_ids, unfolded, parent_unfolded
|
||||
)
|
||||
for component in data.get("components", []):
|
||||
bom_line = next(
|
||||
filter(
|
||||
lambda line: line.get("bom_id", False) == component["bom_id"]
|
||||
and line.get("name", False) == component["name"]
|
||||
and line.get("level", False) == component["level"],
|
||||
lines,
|
||||
)
|
||||
)
|
||||
if bom_line:
|
||||
bom_line["is_buffered"] = component["is_buffered"]
|
||||
bom_line["dlt"] = component["dlt"]
|
||||
return lines
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
<odoo>
|
||||
<template id="report_mrp_bom_inherit_ddmrp" inherit_id="mrp.report_mrp_bom">
|
||||
<xpath expr="//th[@name='th_mrp_bom_h']" position="before">
|
||||
<th t-if="data['show_buffered']">Buffered</th>
|
||||
</xpath>
|
||||
|
||||
<xpath expr="//td[@name='td_mrp_bom']" position="before">
|
||||
<td t-if="data['show_buffered']">
|
||||
<span t-if="data['is_buffered']">
|
||||
<img
|
||||
src='/ddmrp/static/img/is_buffered.png'
|
||||
style="width:30px;height:30px;padding:5px"
|
||||
/>
|
||||
</span>
|
||||
</td>
|
||||
</xpath>
|
||||
|
||||
<xpath expr="//td[@name='td_mrp_bom_f']" position="before">
|
||||
<td t-if="data['show_buffered']" />
|
||||
</xpath>
|
||||
|
||||
<xpath expr="//td[@name='td_mrp_bom_byproducts_f']" position="before">
|
||||
<td t-if="data['show_buffered']" />
|
||||
</xpath>
|
||||
|
||||
</template>
|
||||
|
||||
<template
|
||||
id="report_mrp_bom_pdf_line_inherit_ddmrp"
|
||||
inherit_id="mrp.report_mrp_bom_pdf_line"
|
||||
>
|
||||
<xpath expr="//td[@name='td_mrp_code']" position="before">
|
||||
<td t-if="data['show_buffered']">
|
||||
<span t-if="l.get('is_buffered')">
|
||||
<img
|
||||
src='/ddmrp/static/img/is_buffered.png'
|
||||
style="width:30px;height:30px;padding:5px"
|
||||
/>
|
||||
</span>
|
||||
</td>
|
||||
</xpath>
|
||||
</template>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
<?xml version="1.0" ?>
|
||||
<odoo noupdate="1">
|
||||
|
||||
<record id="module_category_ddmrp" model="ir.module.category">
|
||||
<field name="name">DDMRP</field>
|
||||
<field name="sequence">40</field>
|
||||
</record>
|
||||
|
||||
<record id="group_change_buffer_procure_qty" model="res.groups">
|
||||
<field
|
||||
name="name"
|
||||
>Change quantity in manual procurements from Stock Buffers</field>
|
||||
<field name="implied_ids" eval="[(4, ref('base.group_user'))]" />
|
||||
<field name="category_id" ref="ddmrp.module_category_ddmrp" />
|
||||
</record>
|
||||
|
||||
<record id="group_stock_buffer_maintainer" model="res.groups">
|
||||
<field name="name">Stock Buffer Maintainer</field>
|
||||
<field name="category_id" ref="ddmrp.module_category_ddmrp" />
|
||||
<field name="implied_ids" eval="[(4, ref('stock.group_stock_user'))]" />
|
||||
</record>
|
||||
|
||||
<record id="group_ddmrp_manager" model="res.groups">
|
||||
<field name="name">DDMRP Manager</field>
|
||||
<field name="category_id" ref="ddmrp.module_category_ddmrp" />
|
||||
<field
|
||||
name="implied_ids"
|
||||
eval="[(4, ref('ddmrp.group_stock_buffer_maintainer'))]"
|
||||
/>
|
||||
<field
|
||||
name="users"
|
||||
eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"
|
||||
/>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
43
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/security/ddmrp_rules.xml
Normal file
43
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/security/ddmrp_rules.xml
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo noupdate="0">
|
||||
<record model="ir.rule" id="stock_buffer_profile_variability_comp_rule">
|
||||
<field name="name">Buffer Profile Variability multi-company</field>
|
||||
<field name="model_id" ref="model_stock_buffer_profile_variability" />
|
||||
<field name="global" eval="True" />
|
||||
<field
|
||||
name="domain_force"
|
||||
>['|',('company_id','=',False),('company_id', 'in', company_ids)]</field>
|
||||
</record>
|
||||
<record model="ir.rule" id="stock_buffer_profile_variability_lead_time_comp_rule">
|
||||
<field name="name">Buffer Profile Lead Time multi-company</field>
|
||||
<field name="model_id" ref="model_stock_buffer_profile_lead_time" />
|
||||
<field name="global" eval="True" />
|
||||
<field
|
||||
name="domain_force"
|
||||
>['|',('company_id','=',False),('company_id', 'in', company_ids)]</field>
|
||||
</record>
|
||||
<record model="ir.rule" id="stock_buffer_profile_comp_rule">
|
||||
<field name="name">Buffer Profile multi-company</field>
|
||||
<field name="model_id" ref="model_stock_buffer_profile" />
|
||||
<field name="global" eval="True" />
|
||||
<field
|
||||
name="domain_force"
|
||||
>['|',('company_id','=',False),('company_id', 'in', company_ids)]</field>
|
||||
</record>
|
||||
<record model="ir.rule" id="product_adu_calculation_method_comp_rule">
|
||||
<field name="name">Product ADU calculation method multi-company</field>
|
||||
<field name="model_id" ref="model_product_adu_calculation_method" />
|
||||
<field name="global" eval="True" />
|
||||
<field
|
||||
name="domain_force"
|
||||
>['|',('company_id','=',False),('company_id', 'in', company_ids)]</field>
|
||||
</record>
|
||||
<record model="ir.rule" id="stock_buffer_comp_rule">
|
||||
<field name="name">Stock Buffer multi-company</field>
|
||||
<field name="model_id" ref="model_stock_buffer" />
|
||||
<field name="global" eval="True" />
|
||||
<field
|
||||
name="domain_force"
|
||||
>['|',('company_id','=',False),('company_id', 'in', company_ids)]</field>
|
||||
</record>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_product_adu_calculation_method,product.adu.calculation.method,model_product_adu_calculation_method,stock.group_stock_user,1,0,0,0
|
||||
access_product_adu_calculation_method_system,product.adu.calculation.method system,model_product_adu_calculation_method,ddmrp.group_ddmrp_manager,1,1,1,1
|
||||
access_stock_buffer_profile,stock.buffer.profile,model_stock_buffer_profile,stock.group_stock_user,1,0,0,0
|
||||
access_stock_buffer_profile_system,stock.buffer.profile system,model_stock_buffer_profile,ddmrp.group_ddmrp_manager,1,1,1,1
|
||||
access_stock_buffer_profile_lead_time,stock.buffer.profile.lead.time stock user,model_stock_buffer_profile_lead_time,stock.group_stock_user,1,0,0,0
|
||||
access_stock_buffer_profile_lead_time_manager,stock.buffer.profile.lead.time stock user,model_stock_buffer_profile_lead_time,ddmrp.group_ddmrp_manager,1,1,1,1
|
||||
access_stock_buffer_profile_variability,stock.buffer.profile.variability stock user,model_stock_buffer_profile_variability,stock.group_stock_user,1,0,0,0
|
||||
access_stock_buffer_profile_variability_manager,stock.buffer.profile.variability stock manager,model_stock_buffer_profile_variability,ddmrp.group_ddmrp_manager,1,1,1,1
|
||||
access_stock_buffer,stock.buffer.user,model_stock_buffer,stock.group_stock_user,1,0,0,0
|
||||
access_stock_buffer_manager,stock.buffer.manager,model_stock_buffer,ddmrp.group_stock_buffer_maintainer,1,1,1,1
|
||||
access_stock_buffer_procurements,stock.buffer.procurements.user,model_make_procurement_buffer,stock.group_stock_user,1,0,0,0
|
||||
access_stock_buffer_procurements_manager,stock.buffer.procurements.manager,model_make_procurement_buffer,stock.group_stock_manager,1,1,1,1
|
||||
access_stock_buffer_procurements_item,stock.buffer.procurements.item.user,model_make_procurement_buffer_item,stock.group_stock_user,1,0,0,0
|
||||
access_stock_buffer_procurements_item_manager,stock.buffer.procurements.item.manager,model_make_procurement_buffer_item,stock.group_stock_manager,1,1,1,1
|
||||
access_ddmrp_duplicate_buffer,ddmrp.duplicate.buffer,model_ddmrp_duplicate_buffer,stock.group_stock_user,1,0,0,0
|
||||
access_ddmrp_duplicate_buffer_manager,ddmrp.duplicate.buffer,model_ddmrp_duplicate_buffer,ddmrp.group_stock_buffer_maintainer,1,1,1,1
|
||||
access_mrp_bom_change_location_manager,mrp.bom.change.location,model_mrp_bom_change_location,stock.group_stock_user,1,1,1,1
|
||||
ddmrp_access_run,ddmrp.run,model_ddmrp_run,stock.group_stock_user,1,0,0,0
|
||||
ddmrp_access_run_manager,ddmrp.run.manager,model_ddmrp_run,stock.group_stock_manager,1,1,1,1
|
||||
access_ddmrp_mrp_move,mrp.move ddmrp,mrp_multi_level.model_mrp_move,stock.group_stock_user,1,0,0,0
|
||||
|
BIN
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/static/description/icon.png
Normal file
BIN
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/static/description/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.8 KiB |
|
|
@ -0,0 +1,690 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="generator" content="Docutils: https://docutils.sourceforge.io/" />
|
||||
<title>README.rst</title>
|
||||
<style type="text/css">
|
||||
|
||||
/*
|
||||
:Author: David Goodger (goodger@python.org)
|
||||
:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $
|
||||
:Copyright: This stylesheet has been placed in the public domain.
|
||||
|
||||
Default cascading style sheet for the HTML output of Docutils.
|
||||
Despite the name, some widely supported CSS2 features are used.
|
||||
|
||||
See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to
|
||||
customize this style sheet.
|
||||
*/
|
||||
|
||||
/* used to remove borders from tables and images */
|
||||
.borderless, table.borderless td, table.borderless th {
|
||||
border: 0 }
|
||||
|
||||
table.borderless td, table.borderless th {
|
||||
/* Override padding for "table.docutils td" with "! important".
|
||||
The right padding separates the table cells. */
|
||||
padding: 0 0.5em 0 0 ! important }
|
||||
|
||||
.first {
|
||||
/* Override more specific margin styles with "! important". */
|
||||
margin-top: 0 ! important }
|
||||
|
||||
.last, .with-subtitle {
|
||||
margin-bottom: 0 ! important }
|
||||
|
||||
.hidden {
|
||||
display: none }
|
||||
|
||||
.subscript {
|
||||
vertical-align: sub;
|
||||
font-size: smaller }
|
||||
|
||||
.superscript {
|
||||
vertical-align: super;
|
||||
font-size: smaller }
|
||||
|
||||
a.toc-backref {
|
||||
text-decoration: none ;
|
||||
color: black }
|
||||
|
||||
blockquote.epigraph {
|
||||
margin: 2em 5em ; }
|
||||
|
||||
dl.docutils dd {
|
||||
margin-bottom: 0.5em }
|
||||
|
||||
object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Uncomment (and remove this text!) to get bold-faced definition list terms
|
||||
dl.docutils dt {
|
||||
font-weight: bold }
|
||||
*/
|
||||
|
||||
div.abstract {
|
||||
margin: 2em 5em }
|
||||
|
||||
div.abstract p.topic-title {
|
||||
font-weight: bold ;
|
||||
text-align: center }
|
||||
|
||||
div.admonition, div.attention, div.caution, div.danger, div.error,
|
||||
div.hint, div.important, div.note, div.tip, div.warning {
|
||||
margin: 2em ;
|
||||
border: medium outset ;
|
||||
padding: 1em }
|
||||
|
||||
div.admonition p.admonition-title, div.hint p.admonition-title,
|
||||
div.important p.admonition-title, div.note p.admonition-title,
|
||||
div.tip p.admonition-title {
|
||||
font-weight: bold ;
|
||||
font-family: sans-serif }
|
||||
|
||||
div.attention p.admonition-title, div.caution p.admonition-title,
|
||||
div.danger p.admonition-title, div.error p.admonition-title,
|
||||
div.warning p.admonition-title, .code .error {
|
||||
color: red ;
|
||||
font-weight: bold ;
|
||||
font-family: sans-serif }
|
||||
|
||||
/* Uncomment (and remove this text!) to get reduced vertical space in
|
||||
compound paragraphs.
|
||||
div.compound .compound-first, div.compound .compound-middle {
|
||||
margin-bottom: 0.5em }
|
||||
|
||||
div.compound .compound-last, div.compound .compound-middle {
|
||||
margin-top: 0.5em }
|
||||
*/
|
||||
|
||||
div.dedication {
|
||||
margin: 2em 5em ;
|
||||
text-align: center ;
|
||||
font-style: italic }
|
||||
|
||||
div.dedication p.topic-title {
|
||||
font-weight: bold ;
|
||||
font-style: normal }
|
||||
|
||||
div.figure {
|
||||
margin-left: 2em ;
|
||||
margin-right: 2em }
|
||||
|
||||
div.footer, div.header {
|
||||
clear: both;
|
||||
font-size: smaller }
|
||||
|
||||
div.line-block {
|
||||
display: block ;
|
||||
margin-top: 1em ;
|
||||
margin-bottom: 1em }
|
||||
|
||||
div.line-block div.line-block {
|
||||
margin-top: 0 ;
|
||||
margin-bottom: 0 ;
|
||||
margin-left: 1.5em }
|
||||
|
||||
div.sidebar {
|
||||
margin: 0 0 0.5em 1em ;
|
||||
border: medium outset ;
|
||||
padding: 1em ;
|
||||
background-color: #ffffee ;
|
||||
width: 40% ;
|
||||
float: right ;
|
||||
clear: right }
|
||||
|
||||
div.sidebar p.rubric {
|
||||
font-family: sans-serif ;
|
||||
font-size: medium }
|
||||
|
||||
div.system-messages {
|
||||
margin: 5em }
|
||||
|
||||
div.system-messages h1 {
|
||||
color: red }
|
||||
|
||||
div.system-message {
|
||||
border: medium outset ;
|
||||
padding: 1em }
|
||||
|
||||
div.system-message p.system-message-title {
|
||||
color: red ;
|
||||
font-weight: bold }
|
||||
|
||||
div.topic {
|
||||
margin: 2em }
|
||||
|
||||
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
|
||||
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
|
||||
margin-top: 0.4em }
|
||||
|
||||
h1.title {
|
||||
text-align: center }
|
||||
|
||||
h2.subtitle {
|
||||
text-align: center }
|
||||
|
||||
hr.docutils {
|
||||
width: 75% }
|
||||
|
||||
img.align-left, .figure.align-left, object.align-left, table.align-left {
|
||||
clear: left ;
|
||||
float: left ;
|
||||
margin-right: 1em }
|
||||
|
||||
img.align-right, .figure.align-right, object.align-right, table.align-right {
|
||||
clear: right ;
|
||||
float: right ;
|
||||
margin-left: 1em }
|
||||
|
||||
img.align-center, .figure.align-center, object.align-center {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
table.align-center {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.align-left {
|
||||
text-align: left }
|
||||
|
||||
.align-center {
|
||||
clear: both ;
|
||||
text-align: center }
|
||||
|
||||
.align-right {
|
||||
text-align: right }
|
||||
|
||||
/* reset inner alignment in figures */
|
||||
div.align-right {
|
||||
text-align: inherit }
|
||||
|
||||
/* div.align-center * { */
|
||||
/* text-align: left } */
|
||||
|
||||
.align-top {
|
||||
vertical-align: top }
|
||||
|
||||
.align-middle {
|
||||
vertical-align: middle }
|
||||
|
||||
.align-bottom {
|
||||
vertical-align: bottom }
|
||||
|
||||
ol.simple, ul.simple {
|
||||
margin-bottom: 1em }
|
||||
|
||||
ol.arabic {
|
||||
list-style: decimal }
|
||||
|
||||
ol.loweralpha {
|
||||
list-style: lower-alpha }
|
||||
|
||||
ol.upperalpha {
|
||||
list-style: upper-alpha }
|
||||
|
||||
ol.lowerroman {
|
||||
list-style: lower-roman }
|
||||
|
||||
ol.upperroman {
|
||||
list-style: upper-roman }
|
||||
|
||||
p.attribution {
|
||||
text-align: right ;
|
||||
margin-left: 50% }
|
||||
|
||||
p.caption {
|
||||
font-style: italic }
|
||||
|
||||
p.credits {
|
||||
font-style: italic ;
|
||||
font-size: smaller }
|
||||
|
||||
p.label {
|
||||
white-space: nowrap }
|
||||
|
||||
p.rubric {
|
||||
font-weight: bold ;
|
||||
font-size: larger ;
|
||||
color: maroon ;
|
||||
text-align: center }
|
||||
|
||||
p.sidebar-title {
|
||||
font-family: sans-serif ;
|
||||
font-weight: bold ;
|
||||
font-size: larger }
|
||||
|
||||
p.sidebar-subtitle {
|
||||
font-family: sans-serif ;
|
||||
font-weight: bold }
|
||||
|
||||
p.topic-title {
|
||||
font-weight: bold }
|
||||
|
||||
pre.address {
|
||||
margin-bottom: 0 ;
|
||||
margin-top: 0 ;
|
||||
font: inherit }
|
||||
|
||||
pre.literal-block, pre.doctest-block, pre.math, pre.code {
|
||||
margin-left: 2em ;
|
||||
margin-right: 2em }
|
||||
|
||||
pre.code .ln { color: gray; } /* line numbers */
|
||||
pre.code, code { background-color: #eeeeee }
|
||||
pre.code .comment, code .comment { color: #5C6576 }
|
||||
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
|
||||
pre.code .literal.string, code .literal.string { color: #0C5404 }
|
||||
pre.code .name.builtin, code .name.builtin { color: #352B84 }
|
||||
pre.code .deleted, code .deleted { background-color: #DEB0A1}
|
||||
pre.code .inserted, code .inserted { background-color: #A3D289}
|
||||
|
||||
span.classifier {
|
||||
font-family: sans-serif ;
|
||||
font-style: oblique }
|
||||
|
||||
span.classifier-delimiter {
|
||||
font-family: sans-serif ;
|
||||
font-weight: bold }
|
||||
|
||||
span.interpreted {
|
||||
font-family: sans-serif }
|
||||
|
||||
span.option {
|
||||
white-space: nowrap }
|
||||
|
||||
span.pre {
|
||||
white-space: pre }
|
||||
|
||||
span.problematic, pre.problematic {
|
||||
color: red }
|
||||
|
||||
span.section-subtitle {
|
||||
/* font-size relative to parent (h1..h6 element) */
|
||||
font-size: 80% }
|
||||
|
||||
table.citation {
|
||||
border-left: solid 1px gray;
|
||||
margin-left: 1px }
|
||||
|
||||
table.docinfo {
|
||||
margin: 2em 4em }
|
||||
|
||||
table.docutils {
|
||||
margin-top: 0.5em ;
|
||||
margin-bottom: 0.5em }
|
||||
|
||||
table.footnote {
|
||||
border-left: solid 1px black;
|
||||
margin-left: 1px }
|
||||
|
||||
table.docutils td, table.docutils th,
|
||||
table.docinfo td, table.docinfo th {
|
||||
padding-left: 0.5em ;
|
||||
padding-right: 0.5em ;
|
||||
vertical-align: top }
|
||||
|
||||
table.docutils th.field-name, table.docinfo th.docinfo-name {
|
||||
font-weight: bold ;
|
||||
text-align: left ;
|
||||
white-space: nowrap ;
|
||||
padding-left: 0 }
|
||||
|
||||
/* "booktabs" style (no vertical lines) */
|
||||
table.docutils.booktabs {
|
||||
border: 0px;
|
||||
border-top: 2px solid;
|
||||
border-bottom: 2px solid;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
table.docutils.booktabs * {
|
||||
border: 0px;
|
||||
}
|
||||
table.docutils.booktabs th {
|
||||
border-bottom: thin solid;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
|
||||
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
|
||||
font-size: 100% }
|
||||
|
||||
ul.auto-toc {
|
||||
list-style-type: none }
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="document">
|
||||
|
||||
|
||||
<a class="reference external image-reference" href="https://odoo-community.org/get-involved?utm_source=readme">
|
||||
<img alt="Odoo Community Association" src="https://odoo-community.org/readme-banner-image" />
|
||||
</a>
|
||||
<div class="section" id="ddmrp">
|
||||
<h1>DDMRP</h1>
|
||||
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
!! This file is generated by oca-gen-addon-readme !!
|
||||
!! changes will be overwritten. !!
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
!! source digest: sha256:f43055b32a5e8e104d8a45da35fc5716767773214054bbfe54da0c23dd8be731
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
|
||||
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/lgpl-3.0-standalone.html"><img alt="License: LGPL-3" src="https://img.shields.io/badge/license-LGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/ddmrp/tree/16.0/ddmrp"><img alt="OCA/ddmrp" src="https://img.shields.io/badge/github-OCA%2Fddmrp-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/ddmrp-16-0/ddmrp-16-0-ddmrp"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/ddmrp&target_branch=16.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
|
||||
<p>Demand Driven Material Requirements Planning is a formal multi-echelon
|
||||
planning and execution method developed by Ms. Carol Ptak and Mr. Chad Smith.</p>
|
||||
<p>DDMRP combines blended aspects of Material Requirements Planning (MRP),
|
||||
Distribution Requirements Planning (DRP) with the pull and visibility
|
||||
emphases found in Lean and the Theory of Constraints and the variability
|
||||
reduction emphasis of Six Sigma.</p>
|
||||
<p>This method has five sequential components:</p>
|
||||
<ol class="arabic simple">
|
||||
<li><em>Strategic Inventory Positioning</em>. Answers the question “Given our system
|
||||
and environment, where should we place inventory to have the best
|
||||
protection?” and determines where should decoupling points of inventory be
|
||||
placed.</li>
|
||||
<li><em>Buffer Profiles and Levels</em>. Determine the amount of protection at those
|
||||
decoupling points.</li>
|
||||
<li><em>Dynamic Adjustments</em>. Allow the company to adapt buffers to group and
|
||||
individual part trait changes over time through the use of several types
|
||||
of adjustments.</li>
|
||||
<li><em>Demand Driven Planning</em>. Allow to launch purchase orders (POs),
|
||||
manufacturing orders (MOs) and Transfer Orders (TOs) based on the priority
|
||||
dictated by the buffers.</li>
|
||||
<li><em>Visible and Collaborative Execution</em>. These POs, MOs and TOs have to be
|
||||
effectively managed to synchronize with the changes that often occur within
|
||||
the “execution horizon.”</li>
|
||||
</ol>
|
||||
<p>These five components work together to greatly dampen, if not eliminate,
|
||||
the nervousness of traditional MRP systems and the bullwhip effect in
|
||||
complex and challenging environments.</p>
|
||||
<p>This approach provides real information about those parts that are
|
||||
truly at risk of negatively impacting the planned availability of inventory.</p>
|
||||
<p>DDMRP sorts the significant few items that require attention from
|
||||
the many parts that are being managed. Under the DDMRP approach,
|
||||
fewer planners can make better decisions more quickly. That means companies
|
||||
will be better able to leverage their working and human capital.</p>
|
||||
<p>Demand Driven Material Requirements Planning is quickly being adopted
|
||||
by a wide variety of leading companies across the world.</p>
|
||||
<p>Some of the benefits reported by the DDMRP method include:</p>
|
||||
<ul class="simple">
|
||||
<li>High fill rate performance</li>
|
||||
<li>Lead time reductions</li>
|
||||
<li>Inventory reductions, while improving customer service</li>
|
||||
<li>Eliminate costs related to expedite</li>
|
||||
<li>Planners see priorities instead of constantly fighting the conflicting
|
||||
messages of MRP</li>
|
||||
</ul>
|
||||
<p>It is highly recommended to read the book ‘Demand Driven Material
|
||||
Requirements Planning (DDMRP)’ by Carol Ptak and Chad Smith.</p>
|
||||
<p><strong>Table of contents</strong></p>
|
||||
<div class="contents local topic" id="contents">
|
||||
<ul class="simple">
|
||||
<li><a class="reference internal" href="#installation" id="toc-entry-1">Installation</a></li>
|
||||
<li><a class="reference internal" href="#configuration" id="toc-entry-2">Configuration</a><ul>
|
||||
<li><a class="reference internal" href="#scheduled-actions" id="toc-entry-3">Scheduled actions</a></li>
|
||||
<li><a class="reference internal" href="#decoupled-lead-time-computation" id="toc-entry-4">Decoupled Lead Time computation</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#usage" id="toc-entry-5">Usage</a><ul>
|
||||
<li><a class="reference internal" href="#buffers" id="toc-entry-6">Buffers</a></li>
|
||||
<li><a class="reference internal" href="#buffer-profiles" id="toc-entry-7">Buffer Profiles</a></li>
|
||||
<li><a class="reference internal" href="#product-attributes" id="toc-entry-8">Product attributes</a></li>
|
||||
<li><a class="reference internal" href="#adu-calculation-methods" id="toc-entry-9">ADU Calculation Methods</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#known-issues-roadmap" id="toc-entry-10">Known issues / Roadmap</a></li>
|
||||
<li><a class="reference internal" href="#changelog" id="toc-entry-11">Changelog</a><ul>
|
||||
<li><a class="reference internal" href="#section-1" id="toc-entry-12">13.0.1.1.0 (2020-07-01)</a></li>
|
||||
<li><a class="reference internal" href="#section-2" id="toc-entry-13">13.0.1.0.0 (2020-06-11)</a></li>
|
||||
<li><a class="reference internal" href="#section-3" id="toc-entry-14">11.0.1.3.0 (2019-02-21)</a></li>
|
||||
<li><a class="reference internal" href="#section-4" id="toc-entry-15">11.0.1.2.0 (2019-01-29)</a></li>
|
||||
<li><a class="reference internal" href="#section-5" id="toc-entry-16">11.0.1.1.0 (2018-08-31)</a></li>
|
||||
<li><a class="reference internal" href="#section-6" id="toc-entry-17">11.0.1.0.0 (2018-07-16)</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#bug-tracker" id="toc-entry-18">Bug Tracker</a></li>
|
||||
<li><a class="reference internal" href="#credits" id="toc-entry-19">Credits</a><ul>
|
||||
<li><a class="reference internal" href="#authors" id="toc-entry-20">Authors</a></li>
|
||||
<li><a class="reference internal" href="#contributors" id="toc-entry-21">Contributors</a></li>
|
||||
<li><a class="reference internal" href="#other-credits" id="toc-entry-22">Other credits</a></li>
|
||||
<li><a class="reference internal" href="#maintainers" id="toc-entry-23">Maintainers</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="installation">
|
||||
<h2><a class="toc-backref" href="#toc-entry-1">Installation</a></h2>
|
||||
<p>We strongly recommend to modify the configuration of the reservation method
|
||||
to manual in the outgoing operation types (so deliveries
|
||||
related to Sales Orders aren’t automatically reserved) and to avoid to
|
||||
reserve stock for specific moves, buffers are in fact a reservation of stock.
|
||||
However, while <strong>reservation is discouraged</strong>, it is still available to be
|
||||
used, in case of reserved stock be aware that the buffer will be blind to this
|
||||
transfers and stock and you are bypassing the DDMRP reordering flow.</p>
|
||||
</div>
|
||||
<div class="section" id="configuration">
|
||||
<h2><a class="toc-backref" href="#toc-entry-2">Configuration</a></h2>
|
||||
<div class="section" id="scheduled-actions">
|
||||
<h3><a class="toc-backref" href="#toc-entry-3">Scheduled actions</a></h3>
|
||||
<ul class="simple">
|
||||
<li>Go to <em>Settings > Technical</em>.</li>
|
||||
<li>‘DDMRP Buffer ADU calculation’. Computes the Average Daily Usage for all
|
||||
Buffers.</li>
|
||||
<li>‘Reordering Rule DDMRP calculation’. Computes the Qualified Demand, Net
|
||||
Flow Position, Planning and Execution priorities for all Buffers.</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="decoupled-lead-time-computation">
|
||||
<h3><a class="toc-backref" href="#toc-entry-4">Decoupled Lead Time computation</a></h3>
|
||||
<p>The DLT is automatically computed by the system.</p>
|
||||
<p>For manufactured products’ buffers just remember to provide and
|
||||
set properly the following information:</p>
|
||||
<ul class="simple">
|
||||
<li>The <em>Manufacturing Lead Time</em> for the manufactured product. It can be found
|
||||
at the product form view under the tab <em>Sales</em>.</li>
|
||||
<li>The <em>Delivery Lead Time</em> for the preferred vendor of a product. This is
|
||||
important for the products which are purchased and are components in any
|
||||
Bill of Materials.</li>
|
||||
</ul>
|
||||
<p>For purchased/distributed products’ buffers the logic is simpler.</p>
|
||||
<ul class="simple">
|
||||
<li>In the first place the system will look if there are Vendors for the product,
|
||||
if so it will use the <em>Delivery Lead Time</em> of the preferred one.</li>
|
||||
<li>In case of absence of vendors, the <em>Lead Time</em> at the bottom of the Buffer
|
||||
form view will be used.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="usage">
|
||||
<h2><a class="toc-backref" href="#toc-entry-5">Usage</a></h2>
|
||||
<p>To easily identify were are you maintaining buffers in your Bill of
|
||||
Materials, you will need to first provide location information on the Bills
|
||||
of Materials.</p>
|
||||
<ul class="simple">
|
||||
<li>Go to <em>Manufacturing / Products / Bill of Materials</em> and update the
|
||||
‘Location’ in all the Bill of Materials and associated lines,
|
||||
indicating where will the parts be placed/used during the manufacturing
|
||||
process.</li>
|
||||
<li>Print the report ‘BOM Structure’ to display where in your BOM are you
|
||||
maintaining buffers, and to identify the Lead Time (LT) of each product, and
|
||||
Decouple Lead Time (DLT).</li>
|
||||
</ul>
|
||||
<div class="section" id="buffers">
|
||||
<h3><a class="toc-backref" href="#toc-entry-6">Buffers</a></h3>
|
||||
<p>To list the list of inventory buffers, go to one of the following:
|
||||
* <em>Inventory / Master Data / Stock Buffer Planning</em>
|
||||
* <em>Inventory / Master Data / Reordering Rules</em></p>
|
||||
</div>
|
||||
<div class="section" id="buffer-profiles">
|
||||
<h3><a class="toc-backref" href="#toc-entry-7">Buffer Profiles</a></h3>
|
||||
<p>Buffer profiles make maintenance of buffers easier by grouping them in
|
||||
profiles. Changes applied to the profiles will be applicable in the
|
||||
associated buffer calculations.</p>
|
||||
<ul class="simple">
|
||||
<li>Go to <em>Inventory / Configuration / Buffer Profiles</em>.</li>
|
||||
</ul>
|
||||
<p>The Buffer Profile Lead Time Factor influences the size of the Buffer Green
|
||||
zone. Items with longer lead times will usually have smaller green zones, which
|
||||
will translate in more frequent supply order generation.</p>
|
||||
<ul class="simple">
|
||||
<li>Go to <em>Inventory / Configuration / Buffer Profile Lead Time Factor</em> to
|
||||
chan</li>
|
||||
</ul>
|
||||
<p>The Buffer Profile Variability Factor influences the size of the Buffer Red
|
||||
Safety zone. Items with longer lead times will usually have smaller green
|
||||
zones, which will translate in more frequent supply order generation.</p>
|
||||
<ul class="simple">
|
||||
<li>Go to <em>Inventory / Configuration / Buffer Profile Lead Time Factor</em>.</li>
|
||||
</ul>
|
||||
<p>Usual factors should range from 0.2 (long lead time) to 0.8 (short lead time).</p>
|
||||
</div>
|
||||
<div class="section" id="product-attributes">
|
||||
<h3><a class="toc-backref" href="#toc-entry-8">Product attributes</a></h3>
|
||||
<ul class="simple">
|
||||
<li>For manufactured products, go to <em>Manufacturing / Products</em> and
|
||||
update the ‘Manufacturing Lead Time’ field, available in the tab <em>Inventory</em>.</li>
|
||||
<li>For purchased products, go to go to <em>Purchasing / Products</em> and update the
|
||||
<em>Delivery Lead Time</em> for each vendor, available in tab <em>Purchase</em> and section
|
||||
<em>Vendors</em>.</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="adu-calculation-methods">
|
||||
<h3><a class="toc-backref" href="#toc-entry-9">ADU Calculation Methods</a></h3>
|
||||
<p>The Average Daily Usage (ADU) defines the frequency of demand of a product in a
|
||||
certain location. It can be computed in different ways, which you can configure
|
||||
with ADU calculation methods as follows:</p>
|
||||
<ol class="arabic simple">
|
||||
<li>Go to <em>Inventory / Configuration / DDMRP / ADU calculation methods</em>.</li>
|
||||
<li>Indicate a name, a calculation method (fixed, past-looking,
|
||||
future-looking or blended).</li>
|
||||
<li>Fill the corresponding period (past, future or both for blended method) to
|
||||
specify the length of period consideration (in days).</li>
|
||||
<li>Indicate the source of information: stock moves or demand estimates.</li>
|
||||
<li>If you use the blended method fill also the <em>Past Factor</em> and
|
||||
<em>Future Factor</em>.</li>
|
||||
</ol>
|
||||
<p>If you do not have prior history of stock moves in your system, it is advised
|
||||
to use fixed method or start to work on future estimates. If you have
|
||||
past-history of stock moves, best use past-looking method or blended method.</p>
|
||||
<p>The ADU is computed every day by default in a background job independently
|
||||
from the other buffer fields. This computation can be done with less frequency
|
||||
but it is not recommended to run it less than weekly or more than daily.
|
||||
Circumstantially, If you need to force the calculation of the ADU go to
|
||||
<em>Inventory / Configuration / DDMRP / Run DDMRP</em> and click on
|
||||
<em>Run ADU calculation</em>.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="known-issues-roadmap">
|
||||
<h2><a class="toc-backref" href="#toc-entry-10">Known issues / Roadmap</a></h2>
|
||||
<p>The DDMRP <a class="reference external" href="https://github.com/OCA/ddmrp/issues?q=is%3Aopen+is%3Aissue+label%3Aenhancement">roadmap</a>
|
||||
and <a class="reference external" href="https://github.com/OCA/ddmrp/issues?q=is%3Aopen+is%3Aissue+label%3Abug">known issues</a> can
|
||||
be found on GitHub.</p>
|
||||
</div>
|
||||
<div class="section" id="changelog">
|
||||
<h2><a class="toc-backref" href="#toc-entry-11">Changelog</a></h2>
|
||||
<div class="section" id="section-1">
|
||||
<h3><a class="toc-backref" href="#toc-entry-12">13.0.1.1.0 (2020-07-01)</a></h3>
|
||||
<p><strong>Features</strong></p>
|
||||
<ul class="simple">
|
||||
<li><ul class="first">
|
||||
<li>New setting <em>Update NFP on Stock Buffers on relevant events</em>.</li>
|
||||
<li>New dedicated settings block. (<a class="reference external" href="https://github.com/OCA/ddmrp/issues/50">#50</a>)</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="section-2">
|
||||
<h3><a class="toc-backref" href="#toc-entry-13">13.0.1.0.0 (2020-06-11)</a></h3>
|
||||
<ul class="simple">
|
||||
<li>[MIG/REF] Migration of module to v13 and refactor (added new dedicated model
|
||||
for stock buffer).</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="section-3">
|
||||
<h3><a class="toc-backref" href="#toc-entry-14">11.0.1.3.0 (2019-02-21)</a></h3>
|
||||
<ul class="simple">
|
||||
<li>[ADD] New chart that depict information about the supply and demand (
|
||||
displaying also de order spike threshold and horizon) for a buffer.
|
||||
(<a class="reference external" href="https://github.com/OCA/ddmrp/pull/40">#40</a>)</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="section-4">
|
||||
<h3><a class="toc-backref" href="#toc-entry-15">11.0.1.2.0 (2019-01-29)</a></h3>
|
||||
<ul class="simple">
|
||||
<li>[IMP] Performance improvement of execution priority calculation and ADU.
|
||||
(<a class="reference external" href="https://github.com/OCA/ddmrp/pull/36">#36</a>)</li>
|
||||
<li>[IMP] Use the minimum quantity to adjust the procure recommendation.
|
||||
(<a class="reference external" href="https://github.com/OCA/ddmrp/pull/37">#37</a>)</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="section-5">
|
||||
<h3><a class="toc-backref" href="#toc-entry-16">11.0.1.1.0 (2018-08-31)</a></h3>
|
||||
<ul class="simple">
|
||||
<li>[IMP] Implemented Blended ADU calculation method.
|
||||
(<a class="reference external" href="https://github.com/OCA/ddmrp/pull/23">#23</a>)</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="section-6">
|
||||
<h3><a class="toc-backref" href="#toc-entry-17">11.0.1.0.0 (2018-07-16)</a></h3>
|
||||
<ul class="simple">
|
||||
<li>Start of the history</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="bug-tracker">
|
||||
<h2><a class="toc-backref" href="#toc-entry-18">Bug Tracker</a></h2>
|
||||
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/ddmrp/issues">GitHub Issues</a>.
|
||||
In case of trouble, please check there if your issue has already been reported.
|
||||
If you spotted it first, help us to smash it by providing a detailed and welcomed
|
||||
<a class="reference external" href="https://github.com/OCA/ddmrp/issues/new?body=module:%20ddmrp%0Aversion:%2016.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
|
||||
<p>Do not contact contributors directly about support or help with technical issues.</p>
|
||||
</div>
|
||||
<div class="section" id="credits">
|
||||
<h2><a class="toc-backref" href="#toc-entry-19">Credits</a></h2>
|
||||
<div class="section" id="authors">
|
||||
<h3><a class="toc-backref" href="#toc-entry-20">Authors</a></h3>
|
||||
<ul class="simple">
|
||||
<li>ForgeFlow</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="contributors">
|
||||
<h3><a class="toc-backref" href="#toc-entry-21">Contributors</a></h3>
|
||||
<ul class="simple">
|
||||
<li>Jordi Ballester Alomar <<a class="reference external" href="mailto:jordi.ballester@forgeflow.com">jordi.ballester@forgeflow.com</a>></li>
|
||||
<li>Lois Rilo Antelo <<a class="reference external" href="mailto:lois.rilo@forgeflow.com">lois.rilo@forgeflow.com</a>></li>
|
||||
<li>Guewen Baconnier <<a class="reference external" href="mailto:guewen.baconnier@camptocamp.com">guewen.baconnier@camptocamp.com</a>></li>
|
||||
<li>Adria Gil Sorribes <<a class="reference external" href="mailto:adria.gil@forgeflow.com">adria.gil@forgeflow.com</a>></li>
|
||||
<li>Christopher Ormaza <<a class="reference external" href="mailto:chris.ormaza@forgeflow.com">chris.ormaza@forgeflow.com</a>></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="other-credits">
|
||||
<h3><a class="toc-backref" href="#toc-entry-22">Other credits</a></h3>
|
||||
<p>The initial development of this module has been financially supported by:</p>
|
||||
<ul class="simple">
|
||||
<li>Aleph Objects, Inc.</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="maintainers">
|
||||
<h3><a class="toc-backref" href="#toc-entry-23">Maintainers</a></h3>
|
||||
<p>This module is maintained by the OCA.</p>
|
||||
<a class="reference external image-reference" href="https://odoo-community.org">
|
||||
<img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" />
|
||||
</a>
|
||||
<p>OCA, or the Odoo Community Association, is a nonprofit organization whose
|
||||
mission is to support the collaborative development of Odoo features and
|
||||
promote its widespread use.</p>
|
||||
<p>Current <a class="reference external" href="https://odoo-community.org/page/maintainer-role">maintainers</a>:</p>
|
||||
<p><a class="reference external image-reference" href="https://github.com/JordiBForgeFlow"><img alt="JordiBForgeFlow" src="https://github.com/JordiBForgeFlow.png?size=40px" /></a> <a class="reference external image-reference" href="https://github.com/LoisRForgeFlow"><img alt="LoisRForgeFlow" src="https://github.com/LoisRForgeFlow.png?size=40px" /></a> <a class="reference external image-reference" href="https://github.com/ChrisOForgeFlow"><img alt="ChrisOForgeFlow" src="https://github.com/ChrisOForgeFlow.png?size=40px" /></a></p>
|
||||
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/ddmrp/tree/16.0/ddmrp">OCA/ddmrp</a> project on GitHub.</p>
|
||||
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
BIN
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/static/img/has_mto_rule.png
Normal file
BIN
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/static/img/has_mto_rule.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.5 KiB |
BIN
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/static/img/is_buffered.png
Normal file
BIN
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/static/img/is_buffered.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.9 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 7.2 KiB |
|
|
@ -0,0 +1,29 @@
|
|||
/** @odoo-module **/
|
||||
|
||||
import {BomOverviewComponent} from "@mrp/components/bom_overview/mrp_bom_overview";
|
||||
import {patch} from "@web/core/utils/patch";
|
||||
|
||||
patch(BomOverviewComponent.prototype, "ddmrp", {
|
||||
setup() {
|
||||
this._super.apply();
|
||||
this.state.showOptions.is_buffered = true;
|
||||
this.state.showOptions.dlt = true;
|
||||
},
|
||||
|
||||
async getWarehouses() {
|
||||
await this._super.apply();
|
||||
if (this.props.action.context.warehouse_id) {
|
||||
this.state.currentWarehouse = this.warehouses.filter(
|
||||
(warehouse) => warehouse.id === this.props.action.context.warehouse_id
|
||||
)[0];
|
||||
}
|
||||
},
|
||||
|
||||
getReportName() {
|
||||
return (
|
||||
this._super.apply(this, arguments) +
|
||||
"&show_buffered=" +
|
||||
this.state.showOptions.is_buffered
|
||||
);
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
/** @odoo-module **/
|
||||
|
||||
import {BomOverviewDisplayFilter} from "@mrp/components/bom_overview_display_filter/mrp_bom_overview_display_filter";
|
||||
import {patch} from "@web/core/utils/patch";
|
||||
|
||||
patch(BomOverviewDisplayFilter.prototype, "ddmrp", {
|
||||
setup() {
|
||||
this._super.apply();
|
||||
this.displayOptions.is_buffered = this.env._t("Buffered");
|
||||
},
|
||||
});
|
||||
|
||||
patch(BomOverviewDisplayFilter, "ddmrp", {
|
||||
props: {
|
||||
...BomOverviewDisplayFilter.props,
|
||||
showOptions: {
|
||||
...BomOverviewDisplayFilter.showOptions,
|
||||
is_buffered: Boolean,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
/** @odoo-module **/
|
||||
|
||||
import {BomOverviewLine} from "@mrp/components/bom_overview_line/mrp_bom_overview_line";
|
||||
import {patch} from "@web/core/utils/patch";
|
||||
|
||||
patch(BomOverviewLine, "ddmrp", {
|
||||
props: {
|
||||
...BomOverviewLine.props,
|
||||
showOptions: {
|
||||
...BomOverviewLine.showOptions,
|
||||
is_buffered: Boolean,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<templates xml:space="preserve">
|
||||
|
||||
<t
|
||||
t-name="ddmrp.BomOverviewLine"
|
||||
t-inherit="mrp.BomOverviewLine"
|
||||
t-inherit-mode="extension"
|
||||
owl="1"
|
||||
>
|
||||
<xpath expr="//td[@name='td_mrp_bom']" position="before">
|
||||
<td
|
||||
t-if="props.showOptions.is_buffered and data.is_buffered"
|
||||
class="text-center"
|
||||
>
|
||||
<span>
|
||||
<img
|
||||
src='/ddmrp/static/img/is_buffered.png'
|
||||
style="width:30px;height:30px;padding:5px"
|
||||
/>
|
||||
</span>
|
||||
</td>
|
||||
<td t-if="props.showOptions.is_buffered and !data.is_buffered" />
|
||||
</xpath>
|
||||
<xpath expr="//td[@t-if='showLeadTimes']" position="after">
|
||||
<td t-if="showLeadTimes" class="text-end">
|
||||
<t
|
||||
t-esc="data.dlt"
|
||||
t-options='{"widget": "float", "decimal_precision": "Lead Time"}'
|
||||
/> Days
|
||||
</td>
|
||||
</xpath>
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
/** @odoo-module **/
|
||||
|
||||
import {BomOverviewSpecialLine} from "@mrp/components/bom_overview_special_line/mrp_bom_overview_special_line";
|
||||
import {patch} from "@web/core/utils/patch";
|
||||
|
||||
patch(BomOverviewSpecialLine, "ddmrp", {
|
||||
props: {
|
||||
...BomOverviewSpecialLine.props,
|
||||
showOptions: {
|
||||
...BomOverviewSpecialLine.showOptions,
|
||||
is_buffered: Boolean,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<templates xml:space="preserve">
|
||||
|
||||
<t
|
||||
t-name="ddmrp.BomOverviewSpecialLine"
|
||||
t-inherit="mrp.BomOverviewSpecialLine"
|
||||
t-inherit-mode="extension"
|
||||
owl="1"
|
||||
>
|
||||
<xpath expr="//td[@name='td_mrp_bom']" position="before">
|
||||
<td t-if="showBuffered" />
|
||||
</xpath>
|
||||
<xpath expr="//td[@t-if='showLeadTimes']" position="after">
|
||||
<td t-if="showLeadTimes" />
|
||||
</xpath>
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
/** @odoo-module **/
|
||||
|
||||
import {BomOverviewTable} from "@mrp/components/bom_overview_table/mrp_bom_overview_table";
|
||||
import {patch} from "@web/core/utils/patch";
|
||||
|
||||
patch(BomOverviewTable.prototype, "ddmrp", {
|
||||
// ---- Getters ----
|
||||
|
||||
get showBuffered() {
|
||||
return this.props.showOptions.is_buffered;
|
||||
},
|
||||
});
|
||||
|
||||
patch(BomOverviewTable, "ddmrp", {
|
||||
props: {
|
||||
...BomOverviewTable.props,
|
||||
showOptions: {
|
||||
...BomOverviewTable.showOptions,
|
||||
is_buffered: Boolean,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<templates xml:space="preserve">
|
||||
|
||||
<t
|
||||
t-name="ddmrp.BomOverviewTable"
|
||||
t-inherit="mrp.BomOverviewTable"
|
||||
t-inherit-mode="extension"
|
||||
owl="1"
|
||||
>
|
||||
<xpath expr="//th[@name='th_mrp_bom_h']" position="before">
|
||||
<th t-if="showBuffered" class="text-center">Buffered</th>
|
||||
</xpath>
|
||||
<xpath expr="//thead/tr/th[@t-if='showLeadTimes']" position="after">
|
||||
<th
|
||||
t-if="showLeadTimes"
|
||||
class="text-end"
|
||||
title="Decoupled Lead Time of the BoM."
|
||||
>DLT</th>
|
||||
</xpath>
|
||||
|
||||
<xpath expr="//td[@name='td_mrp_bom_f']" position="before">
|
||||
<td t-if="showBuffered" />
|
||||
</xpath>
|
||||
<xpath expr="//tfoot/tr/td[@t-if='showLeadTimes']" position="after">
|
||||
<td t-if="showLeadTimes" />
|
||||
</xpath>
|
||||
|
||||
<xpath expr="//td[@name='td_mrp_bom_b']" position="before">
|
||||
<td t-if="showBuffered" />
|
||||
</xpath>
|
||||
<xpath expr="//tfoot/t/tr/td[@t-if='showLeadTimes']" position="after">
|
||||
<td t-if="showLeadTimes" />
|
||||
</xpath>
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
.circle {
|
||||
padding: 0.3em 0.7em;
|
||||
border-radius: 25em;
|
||||
display: inline-cell;
|
||||
}
|
||||
.circle_dark_red {
|
||||
background-color: #8b0000;
|
||||
color: white;
|
||||
}
|
||||
.circle_red {
|
||||
background-color: #ff0000;
|
||||
color: white;
|
||||
}
|
||||
.circle_yellow {
|
||||
background-color: #ffff00;
|
||||
color: black;
|
||||
}
|
||||
.circle_green {
|
||||
background-color: #33cc33;
|
||||
color: white;
|
||||
}
|
||||
.popover {
|
||||
display: inline-table;
|
||||
}
|
||||
body.with-scrollbar {
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
/** @odoo-module **/
|
||||
|
||||
import {FloatField} from "@web/views/fields/float/float_field";
|
||||
import {loadBundle} from "@web/core/assets";
|
||||
import {registry} from "@web/core/registry";
|
||||
import {useService} from "@web/core/utils/hooks";
|
||||
import {useUniquePopover} from "@web/core/model_field_selector/unique_popover_hook";
|
||||
|
||||
const {Component, markup, onWillStart} = owl;
|
||||
|
||||
export class StockBufferPopover extends Component {
|
||||
setup() {
|
||||
this.actionService = useService("action");
|
||||
this.orm = useService("orm");
|
||||
onWillStart(async () => {
|
||||
await loadBundle({
|
||||
jsLibs: [
|
||||
"/web_widget_bokeh_chart/static/src/lib/bokeh/bokeh-3.1.1.min.js",
|
||||
"/web_widget_bokeh_chart/static/src/lib/bokeh/bokeh-api-3.1.1.min.js",
|
||||
"/web_widget_bokeh_chart/static/src/lib/bokeh/bokeh-widgets-3.1.1.min.js",
|
||||
"/web_widget_bokeh_chart/static/src/lib/bokeh/bokeh-tables-3.1.1.min.js",
|
||||
"/web_widget_bokeh_chart/static/src/lib/bokeh/bokeh-mathjax-3.1.1.min.js",
|
||||
"/web_widget_bokeh_chart/static/src/lib/bokeh/bokeh-gl-3.1.1.min.js",
|
||||
],
|
||||
});
|
||||
var bufferId = this.props.record.resId;
|
||||
var bufferField = this.props.buffer_id;
|
||||
if (bufferField && this.props.record.data[bufferField]) {
|
||||
if (
|
||||
("field" in this.props.record.data[bufferField] &&
|
||||
this.props.record.data[bufferField].field.type ==
|
||||
"many2many") ||
|
||||
bufferField.endsWith("_ids")
|
||||
) {
|
||||
if (this.props.record.data[bufferField].records.length > 0) {
|
||||
bufferId = this.props.record.data[bufferField].records[0].resId;
|
||||
} else {
|
||||
bufferId = 0; // Relation is blank, no buffer.
|
||||
}
|
||||
} else {
|
||||
// Assume m2o
|
||||
bufferId = this.props.record.data[bufferField][0];
|
||||
}
|
||||
} else if (bufferField) {
|
||||
bufferId = 0; // Relation is blank, no buffer.
|
||||
}
|
||||
if (bufferId == 0) {
|
||||
return;
|
||||
}
|
||||
this.bokeh_chart = await this.orm.read(
|
||||
"stock.buffer",
|
||||
[bufferId],
|
||||
[this.props.field]
|
||||
);
|
||||
});
|
||||
}
|
||||
get json_value() {
|
||||
try {
|
||||
var value = JSON.parse(this.bokeh_chart[0][this.props.field]);
|
||||
value.div = markup(value.div.trim());
|
||||
return value;
|
||||
} catch (error) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
}
|
||||
StockBufferPopover.template = "ddmrp.StockBufferPopover";
|
||||
|
||||
export class StockBufferInfoWidget extends FloatField {
|
||||
setup() {
|
||||
super.setup();
|
||||
this.popover = useUniquePopover();
|
||||
}
|
||||
|
||||
get classFromDecoration() {
|
||||
var decorationName = this.props.record.data[this.props.color_from];
|
||||
if (decorationName !== "" && decorationName.length > 1) {
|
||||
decorationName = "circle" + decorationName.slice(1);
|
||||
return `${decorationName}`;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
showPopup(ev) {
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
this.popover.add(
|
||||
ev.currentTarget,
|
||||
this.constructor.components.Popover,
|
||||
{
|
||||
bus: this.bus,
|
||||
record: this.props.record,
|
||||
field: this.props.field,
|
||||
color_from: this.props.color_from,
|
||||
buffer_id: this.props.buffer_id,
|
||||
},
|
||||
{
|
||||
position: "right",
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
StockBufferInfoWidget.components = {
|
||||
...StockBufferInfoWidget.components,
|
||||
Popover: StockBufferPopover,
|
||||
};
|
||||
StockBufferInfoWidget.template = "ddmrp.StockBufferInfoWidget";
|
||||
|
||||
StockBufferInfoWidget.props = {
|
||||
...StockBufferInfoWidget.props,
|
||||
color_from: {type: String, optional: true},
|
||||
field: {type: String, optional: true},
|
||||
buffer_id: {type: String, optional: true},
|
||||
};
|
||||
|
||||
const StockBufferInfoWidgetExtractProps = StockBufferInfoWidget.extractProps;
|
||||
StockBufferInfoWidget.extractProps = ({attrs, field}) => {
|
||||
return Object.assign(StockBufferInfoWidgetExtractProps({attrs, field}), {
|
||||
color_from: attrs.options.color_from,
|
||||
field: attrs.options.field,
|
||||
buffer_id: attrs.options.buffer_id,
|
||||
});
|
||||
};
|
||||
|
||||
registry.category("fields").add("stock_buffer_info", StockBufferInfoWidget);
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<template id="template" xml:space="preserve">
|
||||
|
||||
<!-- TODO: rename this to QtyAtDate in master version -->
|
||||
<t
|
||||
t-name="ddmrp.StockBufferInfoWidget"
|
||||
t-inherit="web.FloatField"
|
||||
owl="1"
|
||||
t-inherit-mode="primary"
|
||||
>
|
||||
<xpath expr="//span" position="attributes">
|
||||
<attribute name="t-on-click">showPopup</attribute>
|
||||
<attribute name="class">circle</attribute>
|
||||
<attribute name="t-att-class">classFromDecoration</attribute>
|
||||
</xpath>
|
||||
</t>
|
||||
<t t-name="ddmrp.StockBufferPopover" owl="1">
|
||||
<div>
|
||||
<t t-out="json_value.div" />
|
||||
<script type="text/javascript" t-out="json_value.script" />
|
||||
</div>
|
||||
</t>
|
||||
|
||||
</template>
|
||||
3
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/tests/__init__.py
Normal file
3
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/tests/__init__.py
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
from . import test_ddmrp
|
||||
from . import test_ddmrp_distributed_source_location
|
||||
from . import test_distributed_max_proc_time
|
||||
549
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/tests/common.py
Normal file
549
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/tests/common.py
Normal file
|
|
@ -0,0 +1,549 @@
|
|||
# Copyright 2016-20 ForgeFlow S.L. (http://www.forgeflow.com)
|
||||
# Copyright 2016 Aleph Objects, Inc. (https://www.alephobjects.com/)
|
||||
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
import odoo.tests.common as common
|
||||
|
||||
|
||||
class TestDdmrpCommon(common.TransactionCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
|
||||
cls.env = cls.env(
|
||||
context=dict(
|
||||
cls.env.context,
|
||||
tracking_disable=True,
|
||||
# compatibility with ddmrp_cron_actions_as_job,
|
||||
# that would delay calls to "cron_actions" in these tests
|
||||
test_queue_job_no_delay=True,
|
||||
)
|
||||
)
|
||||
|
||||
# Models
|
||||
cls.productModel = cls.env["product.product"]
|
||||
cls.templateModel = cls.env["product.template"]
|
||||
cls.bomModel = cls.env["mrp.bom"]
|
||||
cls.bomlineModel = cls.env["mrp.bom.line"]
|
||||
cls.bufferModel = cls.env["stock.buffer"]
|
||||
cls.pickingModel = cls.env["stock.picking"]
|
||||
cls.moveModel = cls.env["stock.move"]
|
||||
cls.quantModel = cls.env["stock.quant"]
|
||||
cls.estimateModel = cls.env["stock.demand.estimate"]
|
||||
cls.aducalcmethodModel = cls.env["product.adu.calculation.method"]
|
||||
cls.locationModel = cls.env["stock.location"]
|
||||
cls.make_procurement_wiz = cls.env["make.procurement.buffer"]
|
||||
cls.user_model = cls.env["res.users"]
|
||||
cls.partner_model = cls.env["res.partner"]
|
||||
cls.supinfo_model = cls.env["product.supplierinfo"]
|
||||
cls.pol_model = cls.env["purchase.order.line"]
|
||||
cls.wh_model = cls.env["stock.warehouse"]
|
||||
cls.orderpoint_model = cls.env["stock.warehouse.orderpoint"]
|
||||
|
||||
# Refs
|
||||
cls.main_company = cls.env.ref("base.main_company")
|
||||
cls.second_company = cls.env.ref("stock.res_company_1")
|
||||
cls.warehouse = cls.env.ref("stock.warehouse0")
|
||||
cls.warehouse2 = cls.wh_model.create(
|
||||
{
|
||||
"partner_id": cls.env.ref("base.main_partner").id,
|
||||
"name": "Warehouse 2",
|
||||
"code": "WH2",
|
||||
}
|
||||
)
|
||||
cls.warehouse_sc = cls.env.ref("stock.stock_warehouse_shop0")
|
||||
cls.stock_location = cls.env.ref("stock.stock_location_stock")
|
||||
cls.stock_location_sc = cls.warehouse_sc.lot_stock_id
|
||||
cls.location_shelf1 = cls.env.ref("stock.stock_location_components")
|
||||
cls.supplier_location = cls.env.ref("stock.stock_location_suppliers")
|
||||
cls.customer_location = cls.env.ref("stock.stock_location_customers")
|
||||
cls.inter_wh = cls.env.ref("stock.stock_location_inter_wh")
|
||||
cls.inventory_location = cls.env["stock.location"].search(
|
||||
[("usage", "=", "inventory"), ("company_id", "=", cls.main_company.id)],
|
||||
limit=1,
|
||||
)
|
||||
cls.picking_type_out = cls.env.ref("stock.picking_type_out").copy(
|
||||
{
|
||||
"reservation_method": "manual",
|
||||
"sequence_code": "DDMRP-OUT",
|
||||
}
|
||||
)
|
||||
cls.picking_type_in = cls.env.ref("stock.picking_type_in")
|
||||
cls.picking_type_internal = cls.env.ref("stock.picking_type_internal").copy(
|
||||
{
|
||||
"reservation_method": "manual",
|
||||
"sequence_code": "DDMRP-INTERNAL",
|
||||
}
|
||||
)
|
||||
cls.uom_unit = cls.env.ref("uom.product_uom_unit")
|
||||
cls.dozen_unit = cls.env.ref("uom.product_uom_dozen")
|
||||
cls.buffer_profile_pur = cls.env.ref(
|
||||
"ddmrp.stock_buffer_profile_replenish_purchased_medium_medium"
|
||||
)
|
||||
cls.buffer_profile_mmm = cls.env.ref(
|
||||
"ddmrp.stock_buffer_profile_replenish_manufactured_medium_medium"
|
||||
)
|
||||
cls.buffer_profile_distr = cls.env.ref(
|
||||
"ddmrp.stock_buffer_profile_replenish_distributed_medium_medium"
|
||||
)
|
||||
cls.buffer_profile_override = cls.env.ref(
|
||||
"ddmrp.stock_buffer_profile_replenish_override_purchased_short_low"
|
||||
)
|
||||
cls.adu_fixed = cls.env.ref("ddmrp.adu_calculation_method_fixed")
|
||||
cls.group_stock_manager = cls.env.ref("stock.group_stock_manager")
|
||||
cls.group_mrp_user = cls.env.ref("mrp.group_mrp_user")
|
||||
cls.group_change_procure_qty = cls.env.ref(
|
||||
"ddmrp.group_change_buffer_procure_qty"
|
||||
)
|
||||
cls.group_buffer_manager = cls.env.ref("ddmrp.group_stock_buffer_maintainer")
|
||||
cls.calendar = cls.env.ref("resource.resource_calendar_std")
|
||||
cls.warehouse.calendar_id = cls.calendar
|
||||
|
||||
# Create users
|
||||
cls.user = cls._create_user(
|
||||
"user_1",
|
||||
[
|
||||
cls.group_stock_manager,
|
||||
cls.group_mrp_user,
|
||||
cls.group_change_procure_qty,
|
||||
cls.group_buffer_manager,
|
||||
],
|
||||
)
|
||||
# Create Partners:
|
||||
vendor = cls.partner_model.create({"name": "Test Vendor 1"})
|
||||
|
||||
# Create products and BoM's:
|
||||
manufacture_route = cls.env.ref("mrp.route_warehouse0_manufacture")
|
||||
cls.productA = cls.productModel.create(
|
||||
{
|
||||
"name": "product A",
|
||||
"standard_price": 1,
|
||||
"type": "product",
|
||||
"uom_id": cls.uom_unit.id,
|
||||
"default_code": "A",
|
||||
"route_ids": [(6, 0, manufacture_route.ids)],
|
||||
"produce_delay": 10.0,
|
||||
}
|
||||
)
|
||||
cls.component_a1 = cls.productModel.create(
|
||||
{
|
||||
"name": "Component A-1",
|
||||
"standard_price": 1,
|
||||
"type": "product",
|
||||
"uom_id": cls.uom_unit.id,
|
||||
"default_code": "RM-test01",
|
||||
}
|
||||
)
|
||||
cls.bom_a = cls.bomModel.create(
|
||||
{
|
||||
"product_tmpl_id": cls.productA.product_tmpl_id.id,
|
||||
"product_id": cls.productA.id,
|
||||
}
|
||||
)
|
||||
cls.bomlineModel.create(
|
||||
{
|
||||
"product_id": cls.component_a1.id,
|
||||
"product_qty": 2.0,
|
||||
"bom_id": cls.bom_a.id,
|
||||
}
|
||||
)
|
||||
# Create locations:
|
||||
cls.binA = cls.locationModel.create(
|
||||
{
|
||||
"usage": "internal",
|
||||
"name": "Bin A",
|
||||
"location_id": cls.location_shelf1.id,
|
||||
"company_id": cls.main_company.id,
|
||||
}
|
||||
)
|
||||
|
||||
cls.binB = cls.locationModel.create(
|
||||
{
|
||||
"usage": "internal",
|
||||
"name": "Bin B",
|
||||
"location_id": cls.location_shelf1.id,
|
||||
"company_id": cls.main_company.id,
|
||||
}
|
||||
)
|
||||
cls.locationModel._parent_store_compute()
|
||||
|
||||
cls.quant = cls.quantModel.create(
|
||||
{
|
||||
"location_id": cls.binA.id,
|
||||
"company_id": cls.main_company.id,
|
||||
"product_id": cls.productA.id,
|
||||
"inventory_quantity": 200.0,
|
||||
}
|
||||
)
|
||||
cls.quant.action_apply_inventory()
|
||||
|
||||
# Product B (purchased):
|
||||
buy_route = cls.env.ref("purchase_stock.route_warehouse0_buy")
|
||||
cls.product_purchased = cls.productModel.create(
|
||||
{
|
||||
"name": "product Purchased",
|
||||
"standard_price": 1,
|
||||
"type": "product",
|
||||
"uom_id": cls.uom_unit.id,
|
||||
"default_code": "B",
|
||||
"route_ids": [(6, 0, buy_route.ids)],
|
||||
}
|
||||
)
|
||||
cls.product_purchased_2 = cls.productModel.create(
|
||||
{
|
||||
"name": "product Purchased 2",
|
||||
"standard_price": 1,
|
||||
"type": "product",
|
||||
"uom_id": cls.uom_unit.id,
|
||||
"default_code": "B",
|
||||
"route_ids": [(6, 0, buy_route.ids)],
|
||||
}
|
||||
)
|
||||
cls.supinfo_model.create(
|
||||
{
|
||||
"product_tmpl_id": cls.product_purchased.product_tmpl_id.id,
|
||||
"partner_id": vendor.id,
|
||||
"delay": 20.0,
|
||||
}
|
||||
)
|
||||
|
||||
# Product C (purchased and with variants):
|
||||
cls.template_c = cls.templateModel.create(
|
||||
{
|
||||
"name": "Product C",
|
||||
"type": "product",
|
||||
"uom_id": cls.uom_unit.id,
|
||||
"default_code": "C",
|
||||
"route_ids": [(6, 0, buy_route.ids)],
|
||||
}
|
||||
)
|
||||
cls.color_attribute = cls.env["product.attribute"].create(
|
||||
{"name": "Color", "sequence": 1}
|
||||
)
|
||||
cls.color_blue = cls.env["product.attribute.value"].create(
|
||||
{"name": "Blue", "attribute_id": cls.color_attribute.id, "sequence": 1}
|
||||
)
|
||||
cls.color_orange = cls.env["product.attribute.value"].create(
|
||||
{"name": "Orange", "attribute_id": cls.color_attribute.id, "sequence": 2}
|
||||
)
|
||||
cls.color_green = cls.env["product.attribute.value"].create(
|
||||
{"name": "Green", "attribute_id": cls.color_attribute.id, "sequence": 3}
|
||||
)
|
||||
cls.p_c_color_attribute_line = cls.env[
|
||||
"product.template.attribute.line"
|
||||
].create(
|
||||
{
|
||||
"product_tmpl_id": cls.template_c.id,
|
||||
"attribute_id": cls.color_attribute.id,
|
||||
"value_ids": [
|
||||
(6, 0, [cls.color_blue.id, cls.color_orange.id, cls.color_green.id])
|
||||
],
|
||||
}
|
||||
)
|
||||
cls.product_c_blue = cls.template_c.product_variant_ids[0]
|
||||
cls.product_c_orange = cls.template_c.product_variant_ids[1]
|
||||
cls.product_c_green = cls.template_c.product_variant_ids[2]
|
||||
cls.p_c_supinfo_blue = cls.supinfo_model.create(
|
||||
{
|
||||
"product_tmpl_id": cls.template_c.id,
|
||||
"product_id": cls.product_c_blue.id,
|
||||
"partner_id": vendor.id,
|
||||
"delay": 5.0,
|
||||
}
|
||||
)
|
||||
cls.p_c_supinfo_orange = cls.supinfo_model.create(
|
||||
{
|
||||
"product_tmpl_id": cls.template_c.id,
|
||||
"product_id": cls.product_c_orange.id,
|
||||
"partner_id": vendor.id,
|
||||
"delay": 10.0,
|
||||
}
|
||||
)
|
||||
cls.p_c_supinfo_no_variant = cls.supinfo_model.create(
|
||||
{
|
||||
"product_tmpl_id": cls.template_c.id,
|
||||
"partner_id": vendor.id,
|
||||
"delay": 8.0,
|
||||
}
|
||||
)
|
||||
# Product D (distributed):
|
||||
cls.product_distributed = cls.productModel.create(
|
||||
{
|
||||
"name": "product Distributed",
|
||||
"standard_price": 1,
|
||||
"type": "product",
|
||||
"uom_id": cls.uom_unit.id,
|
||||
"default_code": "D",
|
||||
# TODO: "route_ids": [(6, 0, distribution_route.id)],
|
||||
}
|
||||
)
|
||||
|
||||
# Create buffers:
|
||||
cls.buffer_a = cls.bufferModel.create(
|
||||
{
|
||||
"buffer_profile_id": cls.buffer_profile_mmm.id,
|
||||
"product_id": cls.productA.id,
|
||||
"location_id": cls.stock_location.id,
|
||||
"warehouse_id": cls.warehouse.id,
|
||||
"qty_multiple": 1.0,
|
||||
"adu_calculation_method": cls.adu_fixed.id,
|
||||
"adu_fixed": 4.0,
|
||||
"lead_days": 10.0,
|
||||
"order_spike_horizon": 10.0,
|
||||
}
|
||||
)
|
||||
cls.buffer_purchase = cls.bufferModel.create(
|
||||
{
|
||||
"buffer_profile_id": cls.buffer_profile_pur.id,
|
||||
"product_id": cls.product_purchased.id,
|
||||
"location_id": cls.stock_location.id,
|
||||
"warehouse_id": cls.warehouse.id,
|
||||
"qty_multiple": 1.0,
|
||||
"adu_calculation_method": cls.adu_fixed.id,
|
||||
"adu_fixed": 5.0,
|
||||
}
|
||||
)
|
||||
cls.buffer_c_blue = cls.bufferModel.create(
|
||||
{
|
||||
"buffer_profile_id": cls.buffer_profile_pur.id,
|
||||
"product_id": cls.product_c_blue.id,
|
||||
"location_id": cls.stock_location.id,
|
||||
"warehouse_id": cls.warehouse.id,
|
||||
"qty_multiple": 1.0,
|
||||
"adu_calculation_method": cls.adu_fixed.id,
|
||||
"adu_fixed": 5.0,
|
||||
}
|
||||
)
|
||||
cls.buffer_c_orange = cls.bufferModel.create(
|
||||
{
|
||||
"buffer_profile_id": cls.buffer_profile_pur.id,
|
||||
"product_id": cls.product_c_orange.id,
|
||||
"location_id": cls.stock_location.id,
|
||||
"warehouse_id": cls.warehouse.id,
|
||||
"qty_multiple": 1.0,
|
||||
"adu_calculation_method": cls.adu_fixed.id,
|
||||
"adu_fixed": 5.0,
|
||||
}
|
||||
)
|
||||
cls.buffer_distributed = cls.bufferModel.create(
|
||||
{
|
||||
"buffer_profile_id": cls.buffer_profile_distr.id,
|
||||
"product_id": cls.product_distributed.id,
|
||||
"location_id": cls.stock_location.id,
|
||||
"warehouse_id": cls.warehouse.id,
|
||||
"qty_multiple": 1.0,
|
||||
"adu_calculation_method": cls.adu_fixed.id,
|
||||
"adu_fixed": 5.0,
|
||||
"lead_days": 20,
|
||||
}
|
||||
)
|
||||
|
||||
# dates for a period of 120 days for estimates.
|
||||
cls.estimate_date_from = cls.calendar.plan_days(1, datetime.today()).date()
|
||||
days = 119
|
||||
dt = cls.calendar.plan_days(+1 * days + 1, datetime.today())
|
||||
cls.estimate_date_to = dt.date()
|
||||
|
||||
# Run cron jobs:
|
||||
cls.bufferModel.cron_ddmrp_adu()
|
||||
cls.bufferModel.cron_ddmrp()
|
||||
|
||||
@classmethod
|
||||
def _create_user(cls, login, groups):
|
||||
"""Create a user."""
|
||||
group_ids = [group.id for group in groups]
|
||||
user = cls.user_model.with_context(no_reset_password=True).create(
|
||||
{
|
||||
"name": "Test User",
|
||||
"login": login,
|
||||
"password": "demo",
|
||||
"email": "test@yourcompany.com",
|
||||
"groups_id": [(6, 0, group_ids)],
|
||||
}
|
||||
)
|
||||
return user
|
||||
|
||||
def create_pickingoutA(self, date_move, qty, uom=False, source_location=None):
|
||||
if not uom:
|
||||
uom = self.productA.uom_id
|
||||
if not source_location:
|
||||
source_location = self.binA
|
||||
picking = self.pickingModel.with_user(self.user).create(
|
||||
{
|
||||
"picking_type_id": self.picking_type_out.id,
|
||||
"location_id": source_location.id,
|
||||
"location_dest_id": self.customer_location.id,
|
||||
"scheduled_date": date_move,
|
||||
"move_ids": [
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"name": "Test move",
|
||||
"product_id": self.productA.id,
|
||||
"date": date_move,
|
||||
"product_uom": uom.id,
|
||||
"product_uom_qty": qty,
|
||||
"location_id": source_location.id,
|
||||
"location_dest_id": self.customer_location.id,
|
||||
},
|
||||
)
|
||||
],
|
||||
}
|
||||
)
|
||||
picking.action_confirm()
|
||||
return picking
|
||||
|
||||
def create_pickinginA(self, date_move, qty):
|
||||
picking = self.pickingModel.with_user(self.user).create(
|
||||
{
|
||||
"picking_type_id": self.picking_type_in.id,
|
||||
"location_id": self.supplier_location.id,
|
||||
"location_dest_id": self.binA.id,
|
||||
"scheduled_date": date_move,
|
||||
"move_ids": [
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"name": "Test move",
|
||||
"product_id": self.productA.id,
|
||||
"date": date_move,
|
||||
"date_deadline": date_move,
|
||||
"product_uom": self.productA.uom_id.id,
|
||||
"product_uom_qty": qty,
|
||||
"location_id": self.supplier_location.id,
|
||||
"location_dest_id": self.binA.id,
|
||||
},
|
||||
)
|
||||
],
|
||||
}
|
||||
)
|
||||
picking.action_confirm()
|
||||
return picking
|
||||
|
||||
def create_pickinginternalA(self, date_move, qty):
|
||||
picking = self.pickingModel.with_user(self.user).create(
|
||||
{
|
||||
"picking_type_id": self.picking_type_internal.id,
|
||||
"location_id": self.binA.id,
|
||||
"location_dest_id": self.binB.id,
|
||||
"scheduled_date": date_move,
|
||||
"move_ids": [
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"name": "Test move",
|
||||
"product_id": self.productA.id,
|
||||
"date": date_move,
|
||||
"product_uom": self.productA.uom_id.id,
|
||||
"product_uom_qty": qty,
|
||||
"location_id": self.binA.id,
|
||||
"location_dest_id": self.binB.id,
|
||||
},
|
||||
)
|
||||
],
|
||||
}
|
||||
)
|
||||
picking.action_confirm()
|
||||
return picking
|
||||
|
||||
def create_picking_out(self, product, date_move, qty, source_location=None):
|
||||
if not source_location:
|
||||
source_location = self.binA
|
||||
picking = self.pickingModel.with_user(self.user).create(
|
||||
{
|
||||
"picking_type_id": self.picking_type_out.id,
|
||||
"location_id": source_location.id,
|
||||
"location_dest_id": self.customer_location.id,
|
||||
"scheduled_date": date_move,
|
||||
"move_ids": [
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"name": "Test move",
|
||||
"product_id": product.id,
|
||||
"date": date_move,
|
||||
"product_uom": product.uom_id.id,
|
||||
"product_uom_qty": qty,
|
||||
"location_id": source_location.id,
|
||||
"location_dest_id": self.customer_location.id,
|
||||
},
|
||||
)
|
||||
],
|
||||
}
|
||||
)
|
||||
picking.action_confirm()
|
||||
return picking
|
||||
|
||||
def create_picking_in(self, product, date_move, qty):
|
||||
picking = self.pickingModel.with_user(self.user).create(
|
||||
{
|
||||
"picking_type_id": self.picking_type_in.id,
|
||||
"location_id": self.supplier_location.id,
|
||||
"location_dest_id": self.binA.id,
|
||||
"scheduled_date": date_move,
|
||||
"move_ids": [
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"name": "Test move",
|
||||
"product_id": product.id,
|
||||
"date": date_move,
|
||||
"product_uom": product.uom_id.id,
|
||||
"product_uom_qty": qty,
|
||||
"location_id": self.supplier_location.id,
|
||||
"location_dest_id": self.binA.id,
|
||||
},
|
||||
)
|
||||
],
|
||||
}
|
||||
)
|
||||
picking.action_confirm()
|
||||
return picking
|
||||
|
||||
def _do_picking(self, picking, date):
|
||||
"""Do picking with only one move on the given date."""
|
||||
picking.action_confirm()
|
||||
picking.move_ids.quantity_done = picking.move_ids.product_uom_qty
|
||||
picking._action_done()
|
||||
for move in picking.move_ids:
|
||||
move.date = date
|
||||
|
||||
def create_orderpoint_procurement(self, buffer, make_procurement=True):
|
||||
"""Make Procurement from Reordering Rule"""
|
||||
wizard = (
|
||||
self.make_procurement_wiz.with_user(self.user)
|
||||
.with_context(
|
||||
active_model="stock.buffer", active_ids=buffer.ids, active_id=buffer.id
|
||||
)
|
||||
.create({})
|
||||
)
|
||||
if make_procurement:
|
||||
wizard.make_procurement()
|
||||
return wizard
|
||||
|
||||
def create_inventorylossA(self, date_move, qty):
|
||||
move = self.moveModel.with_user(self.user).create(
|
||||
{
|
||||
"name": "Test inventory move",
|
||||
"product_id": self.productA.id,
|
||||
"date": date_move,
|
||||
"product_uom": self.productA.uom_id.id,
|
||||
"product_uom_qty": qty,
|
||||
"location_id": self.binA.id,
|
||||
"location_dest_id": self.inventory_location.id,
|
||||
},
|
||||
)
|
||||
return move
|
||||
|
||||
def _do_move(self, move, date):
|
||||
move._action_confirm()
|
||||
move.move_line_ids.qty_done = move.move_line_ids.reserved_uom_qty
|
||||
move._action_done()
|
||||
move.date = date
|
||||
1305
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/tests/test_ddmrp.py
Normal file
1305
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/tests/test_ddmrp.py
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,182 @@
|
|||
# Copyright 2020 Camptocamp (https://www.camptocamp.com)
|
||||
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
|
||||
|
||||
from .common import TestDdmrpCommon
|
||||
|
||||
|
||||
class TestDdmrpDistributedSourceLocation(TestDdmrpCommon):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
# we store goods in "Replenish" and make pull rules to
|
||||
# go through "Replenish Step" when we replenish Stock
|
||||
cls.replenish_location = cls.env["stock.location"].create(
|
||||
{
|
||||
"name": "Replenish",
|
||||
"location_id": cls.warehouse.view_location_id.id,
|
||||
"usage": "internal",
|
||||
"company_id": cls.main_company.id,
|
||||
}
|
||||
)
|
||||
replenish_step_location = cls.env["stock.location"].create(
|
||||
{
|
||||
"name": "Replenish Step",
|
||||
"location_id": cls.warehouse.view_location_id.id,
|
||||
"usage": "internal",
|
||||
"company_id": cls.main_company.id,
|
||||
}
|
||||
)
|
||||
|
||||
replenish_route = cls.env["stock.route"].create(
|
||||
{"name": "Replenish", "sequence": 1}
|
||||
)
|
||||
cls.env["stock.rule"].create(
|
||||
{
|
||||
"name": "Replenish",
|
||||
"route_id": replenish_route.id,
|
||||
"location_src_id": cls.replenish_location.id,
|
||||
"location_dest_id": replenish_step_location.id,
|
||||
"action": "pull",
|
||||
"picking_type_id": cls.warehouse.int_type_id.id,
|
||||
"procure_method": "make_to_stock",
|
||||
"warehouse_id": cls.warehouse.id,
|
||||
"company_id": cls.main_company.id,
|
||||
}
|
||||
)
|
||||
cls.env["stock.rule"].create(
|
||||
{
|
||||
"name": "Replenish Step",
|
||||
"route_id": replenish_route.id,
|
||||
"location_src_id": replenish_step_location.id,
|
||||
"location_dest_id": cls.warehouse.lot_stock_id.id,
|
||||
"action": "pull",
|
||||
"picking_type_id": cls.warehouse.int_type_id.id,
|
||||
"procure_method": "make_to_order",
|
||||
"warehouse_id": cls.warehouse.id,
|
||||
"company_id": cls.main_company.id,
|
||||
}
|
||||
)
|
||||
|
||||
# our product uses the replenishment route
|
||||
cls.product_c_green.route_ids = replenish_route
|
||||
|
||||
cls.buffer_dist = cls.bufferModel.create(
|
||||
{
|
||||
"buffer_profile_id": cls.buffer_profile_distr.id,
|
||||
"product_id": cls.product_c_green.id,
|
||||
"location_id": cls.stock_location.id,
|
||||
"warehouse_id": cls.warehouse.id,
|
||||
"qty_multiple": 1.0,
|
||||
"adu_calculation_method": cls.adu_fixed.id,
|
||||
"adu_fixed": 5.0,
|
||||
}
|
||||
)
|
||||
|
||||
cls.buffer_profile_distr.replenish_distributed_limit_to_free_qty = True
|
||||
|
||||
def test_distributed_source_location_id(self):
|
||||
# as we have a route to replenish from this location, we expect the
|
||||
# buffer to have this location set as source
|
||||
self.assertEqual(
|
||||
self.buffer_dist.distributed_source_location_id, self.replenish_location
|
||||
)
|
||||
self.assertEqual(self.buffer_dist.distributed_source_location_qty, 0)
|
||||
|
||||
def test_distributed_source_location_qty(self):
|
||||
self.env["stock.quant"]._update_available_quantity(
|
||||
self.product_c_green, self.replenish_location, 4000
|
||||
)
|
||||
|
||||
# Invalidate the computed quantities
|
||||
self.env["product.product"].invalidate_model()
|
||||
self.assertEqual(self.buffer_dist.distributed_source_location_qty, 4000)
|
||||
|
||||
self.env["stock.quant"]._update_reserved_quantity(
|
||||
self.product_c_green, self.replenish_location, 500
|
||||
)
|
||||
|
||||
# Invalidate the computed quantities to recompute free_qty
|
||||
self.env["product.product"].invalidate_model()
|
||||
self.assertEqual(self.buffer_dist.distributed_source_location_qty, 3500)
|
||||
|
||||
self.assertEqual(
|
||||
self.env["stock.buffer"].search(
|
||||
[("distributed_source_location_qty", "=", 3500)]
|
||||
),
|
||||
self.buffer_dist,
|
||||
)
|
||||
|
||||
def _set_qty_and_create_replenish_wizard(
|
||||
self, qty_in_replenish=4000, recommended_qty=10000
|
||||
):
|
||||
self.env["stock.quant"]._update_available_quantity(
|
||||
self.product_c_green, self.replenish_location, 4000
|
||||
)
|
||||
# lie about the recommended qty (we only want to test if the limit is
|
||||
# applied)
|
||||
self.buffer_dist.procure_recommended_qty = 10000
|
||||
|
||||
return self.create_orderpoint_procurement(
|
||||
self.buffer_dist, make_procurement=False
|
||||
)
|
||||
|
||||
def test_distributed_source_limit_replenish(self):
|
||||
wizard = self._set_qty_and_create_replenish_wizard()
|
||||
self.assertRecordValues(
|
||||
wizard.item_ids,
|
||||
[
|
||||
{
|
||||
"recommended_qty": 10000,
|
||||
# limited to the free qty
|
||||
"qty": 4000,
|
||||
}
|
||||
],
|
||||
)
|
||||
|
||||
def test_distributed_source_limit_replenish_with_batch_limit_max(self):
|
||||
self.buffer_dist.procure_max_qty = 1200
|
||||
wizard = self._set_qty_and_create_replenish_wizard()
|
||||
self.assertRecordValues(
|
||||
wizard.item_ids,
|
||||
# we expect lines to be per batch of 1200 but maxed to the free qty
|
||||
[
|
||||
{"recommended_qty": 10000, "qty": 1200},
|
||||
{"recommended_qty": 10000, "qty": 1200},
|
||||
{"recommended_qty": 10000, "qty": 1200},
|
||||
{"recommended_qty": 10000, "qty": 400},
|
||||
],
|
||||
)
|
||||
|
||||
def test_distributed_source_limit_replenish_with_batch_limit_min(self):
|
||||
self.buffer_dist.procure_min_qty = 5000
|
||||
wizard = self._set_qty_and_create_replenish_wizard()
|
||||
self.assertRecordValues(
|
||||
wizard.item_ids,
|
||||
# the 4000 in stock is below the min of 5000, nothing moved
|
||||
[{"recommended_qty": 10000, "qty": 0}],
|
||||
)
|
||||
|
||||
def test_distributed_source_limit_replenish_with_batch_limit_min_and_max(self):
|
||||
self.buffer_dist.procure_min_qty = 1000
|
||||
self.buffer_dist.procure_max_qty = 1200
|
||||
wizard = self._set_qty_and_create_replenish_wizard()
|
||||
self.assertRecordValues(
|
||||
wizard.item_ids,
|
||||
# the last batch would be 400 which is below the min limit,
|
||||
# ignore the remaining
|
||||
[
|
||||
{"recommended_qty": 10000, "qty": 1200},
|
||||
{"recommended_qty": 10000, "qty": 1200},
|
||||
{"recommended_qty": 10000, "qty": 1200},
|
||||
],
|
||||
)
|
||||
|
||||
def test_distributed_source_limit_disabled(self):
|
||||
self.buffer_profile_distr.replenish_distributed_limit_to_free_qty = False
|
||||
wizard = self._set_qty_and_create_replenish_wizard()
|
||||
self.assertRecordValues(
|
||||
wizard.item_ids,
|
||||
# normal behavior, apply the recommended qty when the option is set
|
||||
# to False on the profile
|
||||
[{"recommended_qty": 10000, "qty": 10000}],
|
||||
)
|
||||
|
|
@ -0,0 +1,143 @@
|
|||
# Copyright 2020 Camptocamp (https://www.camptocamp.com)
|
||||
# Copyright 2021 ForgeFlow S.L. (http://www.forgeflow.com)
|
||||
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
|
||||
|
||||
from freezegun import freeze_time
|
||||
|
||||
from odoo import fields
|
||||
|
||||
from .common import TestDdmrpCommon
|
||||
|
||||
|
||||
class TestDdmrpMaxProcTime(TestDdmrpCommon):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
# we store goods in "Replenish" and make pull rules to
|
||||
# go through "Replenish Step" when we replenish Stock
|
||||
cls.replenish_location = cls.env["stock.location"].create(
|
||||
{
|
||||
"name": "Replenish",
|
||||
"location_id": cls.warehouse.view_location_id.id,
|
||||
"usage": "internal",
|
||||
"company_id": cls.main_company.id,
|
||||
}
|
||||
)
|
||||
replenish_step_location = cls.env["stock.location"].create(
|
||||
{
|
||||
"name": "Replenish Step",
|
||||
"location_id": cls.warehouse.view_location_id.id,
|
||||
"usage": "internal",
|
||||
"company_id": cls.main_company.id,
|
||||
}
|
||||
)
|
||||
|
||||
replenish_route = cls.env["stock.route"].create(
|
||||
{"name": "Replenish", "sequence": 1}
|
||||
)
|
||||
cls.env["stock.rule"].create(
|
||||
{
|
||||
"name": "Replenish",
|
||||
"route_id": replenish_route.id,
|
||||
"location_src_id": cls.replenish_location.id,
|
||||
"location_dest_id": replenish_step_location.id,
|
||||
"action": "pull",
|
||||
"picking_type_id": cls.warehouse.int_type_id.id,
|
||||
"procure_method": "make_to_stock",
|
||||
"warehouse_id": cls.warehouse.id,
|
||||
"company_id": cls.main_company.id,
|
||||
}
|
||||
)
|
||||
cls.env["stock.rule"].create(
|
||||
{
|
||||
"name": "Replenish Step",
|
||||
"route_id": replenish_route.id,
|
||||
"location_src_id": replenish_step_location.id,
|
||||
"location_dest_id": cls.warehouse.lot_stock_id.id,
|
||||
"action": "pull",
|
||||
"picking_type_id": cls.warehouse.int_type_id.id,
|
||||
"procure_method": "make_to_order",
|
||||
"warehouse_id": cls.warehouse.id,
|
||||
"company_id": cls.main_company.id,
|
||||
}
|
||||
)
|
||||
|
||||
# our product uses the replenishment route
|
||||
cls.product_c_green.route_ids = replenish_route
|
||||
|
||||
cls.buffer_dist = cls.bufferModel.create(
|
||||
{
|
||||
"buffer_profile_id": cls.buffer_profile_distr.id,
|
||||
"product_id": cls.product_c_green.id,
|
||||
"location_id": cls.stock_location.id,
|
||||
"warehouse_id": cls.warehouse.id,
|
||||
"qty_multiple": 1.0,
|
||||
"adu_calculation_method": cls.adu_fixed.id,
|
||||
"adu_fixed": 5.0,
|
||||
}
|
||||
)
|
||||
|
||||
@freeze_time("2020-12-10 10:00:00")
|
||||
def test_reschedule_proc_time_no_calendar(self):
|
||||
"""Reschedule moves based on the proc time"""
|
||||
self.buffer_profile_distr.distributed_reschedule_max_proc_time = 180
|
||||
self.warehouse.calendar_id = False
|
||||
|
||||
self.env["stock.quant"]._update_available_quantity(
|
||||
self.product_c_green, self.replenish_location, 4000
|
||||
)
|
||||
# lie about the recommended qty to force creation of replenishment
|
||||
self.buffer_dist.procure_recommended_qty = 10000
|
||||
|
||||
self.create_orderpoint_procurement(self.buffer_dist)
|
||||
moves = self.env["stock.move"].search(
|
||||
[("product_id", "=", self.product_c_green.id)]
|
||||
)
|
||||
|
||||
self.assertRecordValues(
|
||||
moves,
|
||||
[
|
||||
{"date": fields.Datetime.to_datetime("2020-12-11 13:00:00")},
|
||||
{"date": fields.Datetime.to_datetime("2020-12-11 13:00:00")},
|
||||
],
|
||||
)
|
||||
|
||||
@freeze_time("2020-12-10 10:00:00")
|
||||
def test_reschedule_proc_time_with_calendar(self):
|
||||
"""Reschedule moves based on the proc time with calendar"""
|
||||
self.buffer_profile_distr.distributed_reschedule_max_proc_time = 90
|
||||
|
||||
self.env["stock.quant"]._update_available_quantity(
|
||||
self.product_c_green, self.replenish_location, 4000
|
||||
)
|
||||
# lie about the recommended qty to force creation of replenishment
|
||||
self.buffer_dist.procure_recommended_qty = 10000
|
||||
|
||||
self.create_orderpoint_procurement(self.buffer_dist)
|
||||
moves = self.env["stock.move"].search(
|
||||
[("product_id", "=", self.product_c_green.id)]
|
||||
)
|
||||
|
||||
self.assertRecordValues(
|
||||
moves,
|
||||
[
|
||||
# the start of the working hours is 7:00 (UTC), should be 8:00
|
||||
# + 1:30 hour = 8:30
|
||||
{"date": fields.Datetime.to_datetime("2020-12-11 08:30:00")},
|
||||
{"date": fields.Datetime.to_datetime("2020-12-11 08:30:00")},
|
||||
],
|
||||
)
|
||||
|
||||
@freeze_time("2020-12-10 23:00:00")
|
||||
def test_03_reschedule_to_next_day(self):
|
||||
self.buffer_profile_distr.distributed_reschedule_max_proc_time = 90
|
||||
self.warehouse.calendar_id = False
|
||||
buffer = self.buffer_dist
|
||||
self.assertEqual(buffer.dlt, 1)
|
||||
self.assertEqual(buffer.incoming_dlt_qty, 0)
|
||||
# Create a picking with date planned.
|
||||
date_move = buffer._get_date_planned()
|
||||
self.create_picking_in(buffer.product_id, date_move, 15.0)
|
||||
# Picking should be in the DLT window.
|
||||
buffer.cron_actions()
|
||||
self.assertEqual(buffer.incoming_dlt_qty, 15.0)
|
||||
50
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/views/mrp_bom_view.xml
Normal file
50
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/views/mrp_bom_view.xml
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<!-- Copyright 2017-20 ForgeFlow S.L. (http://www.forgeflow.com)
|
||||
License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl-3.0) -->
|
||||
<odoo>
|
||||
<record id="mrp_bom_form_view" model="ir.ui.view">
|
||||
<field name="name">mrp.bom.form - ddmrp</field>
|
||||
<field name="model">mrp.bom</field>
|
||||
<field name="inherit_id" ref="mrp.mrp_bom_form_view" />
|
||||
<field name="arch" type="xml">
|
||||
<field name="product_id" position="after">
|
||||
<field name="is_buffered" />
|
||||
<field name="buffer_id" />
|
||||
<label for="dlt" />
|
||||
<div class="o_row" style="width: 60% !important">
|
||||
<field name="dlt" />
|
||||
<field
|
||||
name="context_location_id"
|
||||
options="{'no_open': True}"
|
||||
style="text-align: right;"
|
||||
/>
|
||||
<button
|
||||
title="Change Location"
|
||||
name="action_change_context_location"
|
||||
icon="fa-exchange"
|
||||
type="object"
|
||||
/>
|
||||
</div>
|
||||
</field>
|
||||
<xpath
|
||||
expr="//field[@name='bom_line_ids']/tree/field[@name='product_uom_id']"
|
||||
position="after"
|
||||
>
|
||||
<field name="is_buffered" />
|
||||
<field name="buffer_id" />
|
||||
<field name="dlt" />
|
||||
<field name="context_location_id" />
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
<record id="mrp_bom_line_view_form" model="ir.ui.view">
|
||||
<field name="name">mrp.bom.line.form</field>
|
||||
<field name="model">mrp.bom.line</field>
|
||||
<field name="inherit_id" ref="mrp.mrp_bom_line_view_form" />
|
||||
<field name="arch" type="xml">
|
||||
<field name="parent_product_tmpl_id" position="after">
|
||||
<field name="buffer_id" />
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<record id="mrp_production_tree_view" model="ir.ui.view">
|
||||
<field name="name">mrp.production.tree</field>
|
||||
<field name="model">mrp.production</field>
|
||||
<field name="inherit_id" ref="mrp.mrp_production_tree_view" />
|
||||
<field name="arch" type="xml">
|
||||
<field name="date_planned_start" position="before">
|
||||
<field name="buffer_id" invisible="1" />
|
||||
<field name="execution_priority_level" invisible="1" />
|
||||
<field
|
||||
name="on_hand_percent"
|
||||
options='{"buffer_id": "buffer_id", "color_from": "execution_priority_level", "field": "ddmrp_chart_execution"}'
|
||||
widget="stock_buffer_info"
|
||||
/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
<record id="view_mrp_production_filter" model="ir.ui.view">
|
||||
<field name="name">mrp.production.select</field>
|
||||
<field name="model">mrp.production</field>
|
||||
<field name="inherit_id" ref="mrp.view_mrp_production_filter" />
|
||||
<field name="arch" type="xml">
|
||||
<field name="product_id" position="before">
|
||||
<field name="execution_priority_level" />
|
||||
<group name="execution_priority" string="On Hand Alert Zones">
|
||||
<filter
|
||||
name="execution_priority_level_red"
|
||||
string="Red"
|
||||
domain="[('execution_priority_level', '=', '1_red')]"
|
||||
/>
|
||||
<filter
|
||||
name="execution_priority_level_yellow"
|
||||
string="Yellow"
|
||||
domain="[('execution_priority_level', '=', '2_yellow')]"
|
||||
/>
|
||||
<filter
|
||||
name="execution_priority_level_green"
|
||||
string="Green"
|
||||
domain="[('execution_priority_level', '=', '3_green')]"
|
||||
/>
|
||||
</group>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<record model="ir.ui.view" id="view_product_adu_calculation_method_tree">
|
||||
<field name="name">product.adu.calculation.method.tree</field>
|
||||
<field name="model">product.adu.calculation.method</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree>
|
||||
<field name="name" />
|
||||
<field name="method" />
|
||||
<field name="company_id" groups="base.group_multi_company" />
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="view_product_adu_calculation_method_form">
|
||||
<field name="name">product.adu.calculation.method.form</field>
|
||||
<field name="model">product.adu.calculation.method</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<sheet>
|
||||
<group name="name">
|
||||
<field name="name" />
|
||||
<field name="method" />
|
||||
<field
|
||||
name="company_id"
|
||||
groups="base.group_multi_company"
|
||||
widget="selection"
|
||||
/>
|
||||
</group>
|
||||
<group name="configuration">
|
||||
<group name="past">
|
||||
<field name="source_past" />
|
||||
<label for="horizon_past" />
|
||||
<div name="horizon_past">
|
||||
<field name="horizon_past" class="oe_inline" /> days
|
||||
</div>
|
||||
<field
|
||||
name="factor_past"
|
||||
attrs="{'invisible': [('method', '!=', 'blended')]}"
|
||||
/>
|
||||
</group>
|
||||
<group name="future">
|
||||
<field name="source_future" />
|
||||
<label for="horizon_future" />
|
||||
<div name="horizon_future">
|
||||
<field name="horizon_future" class="oe_inline" /> days
|
||||
</div>
|
||||
<field
|
||||
name="factor_future"
|
||||
attrs="{'invisible': [('method', '!=', 'blended')]}"
|
||||
/>
|
||||
</group>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<record id="view_product_adu_calculation_method_search" model="ir.ui.view">
|
||||
<field name="name">product.adu.calculation.method.search</field>
|
||||
<field name="model">product.adu.calculation.method</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Search ADU Calculatiion methods">
|
||||
<field name="name" />
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
<record
|
||||
model="ir.actions.act_window"
|
||||
id="product_adu_calculation_method_form_action"
|
||||
>
|
||||
<field name="name">ADU calculation methods</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">product.adu.calculation.method</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="search_view_id" ref="view_product_adu_calculation_method_search" />
|
||||
</record>
|
||||
<menuitem
|
||||
id="menu_product_adu_calculation_method"
|
||||
parent="ddmrp.menu_ddmrp_config"
|
||||
action="product_adu_calculation_method_form_action"
|
||||
/>
|
||||
</odoo>
|
||||
55
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/views/product_view.xml
Normal file
55
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/views/product_view.xml
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
|
||||
<record id="product_normal_form_view_inherit" model="ir.ui.view">
|
||||
<field name="name">product.product.form.inherit</field>
|
||||
<field name="model">product.product</field>
|
||||
<field name="inherit_id" ref="product.product_normal_form_view" />
|
||||
<field name="arch" type="xml">
|
||||
<xpath
|
||||
expr="//div[@name='button_box']/button[@name='action_view_mrp_area_parameters']"
|
||||
position="after"
|
||||
>
|
||||
<button
|
||||
type="object"
|
||||
name="action_view_stock_buffers"
|
||||
class="oe_stat_button"
|
||||
icon="fa-flask"
|
||||
attrs="{'invisible': [('buffer_count', '=', 0)]}"
|
||||
>
|
||||
<field
|
||||
name="buffer_count"
|
||||
widget="statinfo"
|
||||
string="Stock Buffers"
|
||||
/>
|
||||
</button>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="product_template_only_form_view_inherit" model="ir.ui.view">
|
||||
<field name="name">product.template.product.form.inherit</field>
|
||||
<field name="model">product.template</field>
|
||||
<field name="inherit_id" ref="product.product_template_only_form_view" />
|
||||
<field name="arch" type="xml">
|
||||
<xpath
|
||||
expr="//div[@name='button_box']/button[@name='action_view_mrp_area_parameters']"
|
||||
position="after"
|
||||
>
|
||||
<button
|
||||
type="object"
|
||||
name="action_view_stock_buffers"
|
||||
class="oe_stat_button"
|
||||
icon="fa-flask"
|
||||
attrs="{'invisible': [('buffer_count', '=', 0)]}"
|
||||
>
|
||||
<field
|
||||
name="buffer_count"
|
||||
widget="statinfo"
|
||||
string="Stock Buffers"
|
||||
/>
|
||||
</button>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<!-- Copyright 2017-18 ForgeFlow S.L. (http://www.forgeflow.com)
|
||||
License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl-3.0) -->
|
||||
<odoo>
|
||||
<record id="purchase_order_line_execution_tree" model="ir.ui.view">
|
||||
<field name="name">purchase.order.line.tree - ddmrp</field>
|
||||
<field name="model">purchase.order.line</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree
|
||||
default_order='execution_priority_level,on_hand_percent'
|
||||
create="false"
|
||||
editable="top"
|
||||
delete="false"
|
||||
multi_edit="1"
|
||||
>
|
||||
<field name="order_id" widget="many2one" readonly="True" />
|
||||
<field name="partner_id" string="Vendor" />
|
||||
<field name="execution_priority_level" invisible="1" />
|
||||
<field
|
||||
name="on_hand_percent"
|
||||
options='{"buffer_id": "buffer_ids", "color_from": "execution_priority_level", "field": "ddmrp_chart_execution"}'
|
||||
widget="stock_buffer_info"
|
||||
/>
|
||||
<field name="product_qty" readonly="True" />
|
||||
<field name="product_id" readonly="True" />
|
||||
<field
|
||||
name="buffer_ids"
|
||||
string="Buffers"
|
||||
widget="many2many_tags"
|
||||
readonly="1"
|
||||
/>
|
||||
<field name="date_planned" />
|
||||
<field name="state" />
|
||||
<field name="ddmrp_comment" />
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
<record id="purchase_order_line_search" model="ir.ui.view">
|
||||
<field name="name">purchase.order.line.search - ddmrp</field>
|
||||
<field name="model">purchase.order.line</field>
|
||||
<field name="inherit_id" ref="purchase.purchase_order_line_search" />
|
||||
<field name="arch" type="xml">
|
||||
<filter name="hide_cancelled" position="after">
|
||||
<filter
|
||||
name="hide_no_buffer"
|
||||
string="Buffered"
|
||||
domain="[('buffer_ids','!=',False), ('execution_priority_level','!=',False)]"
|
||||
/>
|
||||
<separator />
|
||||
<group name="execution_priority" string="On Hand Alert Zones">
|
||||
<filter
|
||||
name="execution_priority_level_red"
|
||||
string="Red"
|
||||
domain="[('execution_priority_level', '=', '1_red')]"
|
||||
/>
|
||||
<filter
|
||||
name="execution_priority_level_yellow"
|
||||
string="Yellow"
|
||||
domain="[('execution_priority_level', '=', '2_yellow')]"
|
||||
/>
|
||||
<filter
|
||||
name="execution_priority_level_green"
|
||||
string="Green"
|
||||
domain="[('execution_priority_level', '=', '3_green')]"
|
||||
/>
|
||||
</group>
|
||||
</filter>
|
||||
</field>
|
||||
</record>
|
||||
<record id="po_line_execution_action" model="ir.actions.act_window">
|
||||
<field name="name">PO lines On-Hand Status</field>
|
||||
<field name="res_model">purchase.order.line</field>
|
||||
<field name="view_id" ref="purchase_order_line_execution_tree" />
|
||||
<field name="domain" />
|
||||
<field name="context">{"search_default_hide_no_buffer":1}</field>
|
||||
<field name="view_mode">tree</field>
|
||||
</record>
|
||||
<menuitem
|
||||
id="menu_pol_execution"
|
||||
action="po_line_execution_action"
|
||||
parent="purchase.menu_procurement_management"
|
||||
sequence="8"
|
||||
/>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
<?xml version="1.0" ?>
|
||||
<!-- Copyright 2017-20 ForgeFlow S.L. (http://www.forgeflow.com)
|
||||
License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl-3.0) -->
|
||||
<odoo>
|
||||
<record id="purchase_order_form" model="ir.ui.view">
|
||||
<field name="name">purchase.order.form - ddmrp</field>
|
||||
<field name="model">purchase.order</field>
|
||||
<field name="inherit_id" ref="purchase.purchase_order_form" />
|
||||
<field name="arch" type="xml">
|
||||
<xpath
|
||||
expr="//field[@name='order_line']//field[@name='date_planned']"
|
||||
position="after"
|
||||
>
|
||||
<field name="buffer_ids" invisible="1" />
|
||||
<field name="execution_priority_level" invisible="1" />
|
||||
<field
|
||||
name="on_hand_percent"
|
||||
options='{"buffer_id": "buffer_ids", "color_from": "execution_priority_level", "field": "ddmrp_chart_execution"}'
|
||||
widget="stock_buffer_info"
|
||||
/>
|
||||
</xpath>
|
||||
<xpath
|
||||
expr="//page[@name='purchase_delivery_invoice']/group/group"
|
||||
position="inside"
|
||||
>
|
||||
<field name="ddmrp_comment" />
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='order_line']/form//notebook" position="inside">
|
||||
<page
|
||||
name="buffers"
|
||||
string="Stock Buffers"
|
||||
groups="stock.group_stock_user"
|
||||
>
|
||||
<field name="buffer_ids" />
|
||||
</page>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
<record id="view_purchase_order_filter" model="ir.ui.view">
|
||||
<field name="name">request.quotation.select - ddmrp</field>
|
||||
<field name="model">purchase.order</field>
|
||||
<field name="inherit_id" ref="purchase.view_purchase_order_filter" />
|
||||
<field name="arch" type="xml">
|
||||
<filter name="order_date" position="before">
|
||||
<filter
|
||||
name="execution_priority_level_red"
|
||||
string="On-Hand Alert: Red"
|
||||
domain="[('order_line.execution_priority_level', '=', '1_red')]"
|
||||
/>
|
||||
<filter
|
||||
name="execution_priority_level_yellow"
|
||||
string="On-Hand Alert: Yellow"
|
||||
domain="[('order_line.execution_priority_level', '=', '2_yellow')]"
|
||||
/>
|
||||
<separator />
|
||||
</filter>
|
||||
</field>
|
||||
</record>
|
||||
<record id="purchase_order_line_form2" model="ir.ui.view">
|
||||
<field name="name">purchase.order.line.form2</field>
|
||||
<field name="model">purchase.order.line</field>
|
||||
<field name="inherit_id" ref="purchase.purchase_order_line_form2" />
|
||||
<field name="arch" type="xml">
|
||||
<field name="name" position="after">
|
||||
<separator string="Stock Buffers" />
|
||||
<field name="buffer_ids" />
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<record model="ir.ui.view" id="view_stock_buffer_profile_lead_time_form">
|
||||
<field name="name">stock.buffer.profile.lead.time.form</field>
|
||||
<field name="model">stock.buffer.profile.lead.time</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Buffer Profile Lead Time Factor">
|
||||
<sheet>
|
||||
<div class="oe_title">
|
||||
<label for="name" class="oe_edit_only" />
|
||||
<h1>
|
||||
<field name="name" class="oe_inline" />
|
||||
</h1>
|
||||
</div>
|
||||
<group>
|
||||
<group name="factor">
|
||||
<field name="factor" />
|
||||
</group>
|
||||
<group name="company" groups="base.group_multi_company">
|
||||
<field name="company_id" />
|
||||
</group>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="view_stock_buffer_profile_lead_time_tree">
|
||||
<field name="name">stock.buffer.profile.lead.time.tree</field>
|
||||
<field name="model">stock.buffer.profile.lead.time</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree>
|
||||
<field name="name" />
|
||||
<field name="factor" />
|
||||
<field name="company_id" groups="base.group_multi_company" />
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
<record id="view_stock_buffer_profile_lead_time_search" model="ir.ui.view">
|
||||
<field name="name">stock.buffer.profile.lead.time.search</field>
|
||||
<field name="model">stock.buffer.profile.lead.time</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Search Buffer Profile Lead Time">
|
||||
<field name="name" />
|
||||
<field name="factor" />
|
||||
<field name="company_id" groups="base.group_multi_company" />
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
<record
|
||||
model="ir.actions.act_window"
|
||||
id="stock_buffer_profile_lead_time_form_action"
|
||||
>
|
||||
<field name="name">Buffer Profile Lead Time Factor</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">stock.buffer.profile.lead.time</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="search_view_id" ref="view_stock_buffer_profile_lead_time_search" />
|
||||
<field name="help" type="html">
|
||||
<p class="oe_view_nocontent_create">
|
||||
Click to start a new buffer profile lead time factor
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
<menuitem
|
||||
id="menu_stock_buffer_profile_lead_time"
|
||||
parent="ddmrp.menu_ddmrp_config"
|
||||
action="stock_buffer_profile_lead_time_form_action"
|
||||
/>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<record model="ir.ui.view" id="view_stock_buffer_profile_variability_form">
|
||||
<field name="name">stock.buffer.profile.variability.form</field>
|
||||
<field name="model">stock.buffer.profile.variability</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Buffer Profile Variability Factor">
|
||||
<sheet>
|
||||
<div class="oe_title">
|
||||
<label for="name" class="oe_edit_only" />
|
||||
<h1>
|
||||
<field name="name" class="oe_inline" />
|
||||
</h1>
|
||||
</div>
|
||||
<group>
|
||||
<group name="factor">
|
||||
<field name="factor" />
|
||||
</group>
|
||||
<group name="company" groups="base.group_multi_company">
|
||||
<field name="company_id" />
|
||||
</group>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="view_stock_buffer_profile_variability_tree">
|
||||
<field name="name">stock.buffer.profile.variability.tree</field>
|
||||
<field name="model">stock.buffer.profile.variability</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree>
|
||||
<field name="name" />
|
||||
<field name="factor" />
|
||||
<field name="company_id" groups="base.group_multi_company" />
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
<record id="view_stock_buffer_profile_variability_search" model="ir.ui.view">
|
||||
<field name="name">stock.buffer.profile.variability.search</field>
|
||||
<field name="model">stock.buffer.profile.variability</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Search Buffer Profile Variability">
|
||||
<field name="name" />
|
||||
<field name="factor" />
|
||||
<field name="company_id" groups="base.group_multi_company" />
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
<record
|
||||
model="ir.actions.act_window"
|
||||
id="stock_buffer_profile_variability_form_action"
|
||||
>
|
||||
<field name="name">Buffer Profile Variability Factor</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">stock.buffer.profile.variability</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field
|
||||
name="search_view_id"
|
||||
ref="view_stock_buffer_profile_variability_search"
|
||||
/>
|
||||
<field name="help" type="html">
|
||||
<p class="oe_view_nocontent_create">
|
||||
Click to start a new buffer profile variability factor
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
<menuitem
|
||||
id="menu_stock_buffer_profile_variability"
|
||||
parent="ddmrp.menu_ddmrp_config"
|
||||
action="stock_buffer_profile_variability_form_action"
|
||||
/>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<record id="view_stock_buffer_profile_form" model="ir.ui.view">
|
||||
<field name="name">stock.buffer.profile.form</field>
|
||||
<field name="model">stock.buffer.profile</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Buffer Profile">
|
||||
<sheet>
|
||||
<div class="oe_edit_only">
|
||||
<label for="name" class="oe_inline" />
|
||||
<h1>
|
||||
<field name="name" />
|
||||
</h1>
|
||||
</div>
|
||||
<group>
|
||||
<group name="replenish_method">
|
||||
<field name="replenish_method" />
|
||||
</group>
|
||||
<group name="item_type">
|
||||
<field name="item_type" />
|
||||
</group>
|
||||
<group name="lead_time">
|
||||
<field name="lead_time_id" />
|
||||
</group>
|
||||
<group name="variability">
|
||||
<field name="variability_id" />
|
||||
</group>
|
||||
<group name="organization">
|
||||
<field
|
||||
name="company_id"
|
||||
groups="base.group_multi_company"
|
||||
options="{'no_create': True}"
|
||||
/>
|
||||
</group>
|
||||
<group
|
||||
name="distributed_options"
|
||||
attrs="{'invisible': [('item_type', '!=', 'distributed')]}"
|
||||
>
|
||||
<field name="replenish_distributed_limit_to_free_qty" />
|
||||
<field name="distributed_reschedule_max_proc_time" />
|
||||
</group>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<record id="view_stock_buffer_profile_tree" model="ir.ui.view">
|
||||
<field name="name">stock.buffer.profile.tree</field>
|
||||
<field name="model">stock.buffer.profile</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree>
|
||||
<field name="name" />
|
||||
<field name="replenish_method" />
|
||||
<field name="item_type" />
|
||||
<field name="lead_time_id" />
|
||||
<field name="variability_id" />
|
||||
<field name="company_id" groups="base.group_multi_company" />
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
<record id="view_stock_buffer_profile_search" model="ir.ui.view">
|
||||
<field name="name">stock.buffer.profile.search</field>
|
||||
<field name="model">stock.buffer.profile</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Search Buffer Profiles">
|
||||
<field name="name" />
|
||||
<separator />
|
||||
<field name="item_type" />
|
||||
<field name="replenish_method" />
|
||||
<field name="lead_time_id" />
|
||||
<field name="variability_id" />
|
||||
<field name="company_id" groups="base.group_multi_company" />
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
<record id="stock_buffer_profile_form_action" model="ir.actions.act_window">
|
||||
<field name="name">Buffer Profiles</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">stock.buffer.profile</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="search_view_id" ref="view_stock_buffer_profile_search" />
|
||||
<field name="help" type="html">
|
||||
<p class="oe_view_nocontent_create">
|
||||
Click to start a new buffer profile
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
<menuitem
|
||||
id="menu_ddmrp_config"
|
||||
name="DDMRP"
|
||||
parent="stock.menu_stock_config_settings"
|
||||
/>
|
||||
<menuitem
|
||||
id="menu_stock_buffer_profile_mgt"
|
||||
parent="ddmrp.menu_ddmrp_config"
|
||||
action="stock_buffer_profile_form_action"
|
||||
/>
|
||||
</odoo>
|
||||
739
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/views/stock_buffer_view.xml
Normal file
739
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/views/stock_buffer_view.xml
Normal file
|
|
@ -0,0 +1,739 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<record id="stock_buffer_view_tree" model="ir.ui.view">
|
||||
<field name="name">stock.buffer.tree</field>
|
||||
<field name="model">stock.buffer</field>
|
||||
<field name="priority">50</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree decoration-danger="procure_recommended_qty > 0">
|
||||
<header>
|
||||
<button
|
||||
name="action_request_procurement"
|
||||
type="object"
|
||||
string="Procure"
|
||||
/>
|
||||
</header>
|
||||
<field name="product_id" />
|
||||
<field name="product_vendor_code" optional="hide" />
|
||||
<field name="warehouse_id" optional="show" />
|
||||
<field name="location_id" groups="stock.group_stock_multi_locations" />
|
||||
<field
|
||||
name="product_uom"
|
||||
string="UoM"
|
||||
groups="uom.group_uom"
|
||||
optional="hide"
|
||||
/>
|
||||
<field name="planning_priority_level" invisible="1" />
|
||||
<field
|
||||
name="net_flow_position_percent"
|
||||
options='{"color_from": "planning_priority_level", "field": "ddmrp_chart"}'
|
||||
widget="stock_buffer_info"
|
||||
/>
|
||||
<field
|
||||
name="product_location_qty_available_not_res"
|
||||
string="On-Hand"
|
||||
optional="show"
|
||||
/>
|
||||
<field name="execution_priority_level" invisible="1" />
|
||||
<field
|
||||
name="on_hand_percent"
|
||||
options='{"color_from": "execution_priority_level", "field": "ddmrp_chart_execution"}'
|
||||
widget="stock_buffer_info"
|
||||
/>
|
||||
<button
|
||||
title="Refresh Buffer"
|
||||
name="refresh_buffer"
|
||||
icon="fa-refresh"
|
||||
type="object"
|
||||
/>
|
||||
<field name="incoming_dlt_qty" string="Incoming Within DLT" />
|
||||
<field
|
||||
name="incoming_outside_dlt_qty"
|
||||
string="Incoming Outside DLT"
|
||||
optional="hide"
|
||||
/>
|
||||
<field
|
||||
name="incoming_total_qty"
|
||||
string="Total Incoming"
|
||||
optional="show"
|
||||
/>
|
||||
<button
|
||||
title="Total Incoming"
|
||||
name="action_view_supply_moves"
|
||||
icon="fa-exchange"
|
||||
type="object"
|
||||
/>
|
||||
<field name="qualified_demand" />
|
||||
<field name="net_flow_position" />
|
||||
<field name="procure_recommended_qty" />
|
||||
<field name="procure_uom_id" groups="uom.group_uom" optional="show" />
|
||||
<button
|
||||
title="Create Procurement"
|
||||
name="%(ddmrp.act_make_procurement_from_buffer)d"
|
||||
icon="fa-cogs"
|
||||
type="action"
|
||||
/>
|
||||
<button
|
||||
title="Some incoming quantities are outside of the DLT Horizon and may require rescheduling. Press this button to display the involved supply orders"
|
||||
name="action_view_supply_moves_outside_dlt_window"
|
||||
icon="fa-warning"
|
||||
type="object"
|
||||
attrs="{'invisible':[('incoming_outside_dlt_qty', '=', 0)]}"
|
||||
/>
|
||||
<field name="rfq_total_qty" optional="hide" />
|
||||
<field name="rfq_outside_dlt_qty" invisible="1" />
|
||||
<button
|
||||
title="Some RFQ quantities are outside of the DLT Horizon and may require rescheduling.
|
||||
Press this button to display the involved RFQs"
|
||||
name="action_view_supply_rfq_outside_dlt_window"
|
||||
icon="fa-warning"
|
||||
type="object"
|
||||
attrs="{'invisible':[('rfq_outside_dlt_qty', '=', 0)]}"
|
||||
/>
|
||||
<field name="rfq_inside_dlt_qty" optional="hide" />
|
||||
<button
|
||||
title="Some RFQs are inside of the DLT Horizon and waiting validation to be accounted into the NFP.
|
||||
Press this button to display them."
|
||||
name="action_view_supply_rfq_inside_dlt_window"
|
||||
icon="fa-warning"
|
||||
type="object"
|
||||
attrs="{'invisible':[('rfq_inside_dlt_qty', '=', 0)]}"
|
||||
/>
|
||||
<button
|
||||
title="No stock available in source location for distributed buffer"
|
||||
name="action_dummy"
|
||||
icon="fa-warning"
|
||||
type="object"
|
||||
attrs="{'invisible':['|', ('distributed_source_location_id', '=', False), ('distributed_source_location_qty', '>', 0)]}"
|
||||
/>
|
||||
<field name="distributed_source_location_id" optional="hide" />
|
||||
<field name="distributed_source_location_qty" optional="hide" />
|
||||
<field name="item_type" optional="show" />
|
||||
<field name="main_supplier_id" optional="show" />
|
||||
<field name="adu" optional="hide" />
|
||||
<field name="dlt" optional="hide" />
|
||||
<field name="top_of_red" optional="hide" />
|
||||
<field name="top_of_yellow" optional="hide" />
|
||||
<field name="top_of_green" optional="hide" />
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
<record id="stock_buffer_view_form" model="ir.ui.view">
|
||||
<field name="name">stock.buffer.form</field>
|
||||
<field name="model">stock.buffer</field>
|
||||
<field name="arch" type="xml">
|
||||
<form duplicate="0">
|
||||
<header>
|
||||
<button
|
||||
string="Refresh Buffer"
|
||||
name="refresh_buffer"
|
||||
icon="fa-refresh"
|
||||
type="object"
|
||||
/>
|
||||
</header>
|
||||
<sheet>
|
||||
<div class="oe_button_box" name="button_box">
|
||||
<button
|
||||
type="object"
|
||||
name="action_view_yearly_consumption"
|
||||
class="oe_stat_button"
|
||||
string="Consumption"
|
||||
icon="fa-fire"
|
||||
/>
|
||||
<button
|
||||
type="object"
|
||||
name="action_view_stock_demand_estimates"
|
||||
class="oe_stat_button"
|
||||
string="Estimates"
|
||||
icon="fa-signal"
|
||||
attrs="{'invisible': [('adu_calculation_method_type', '!=', 'future')]}"
|
||||
/>
|
||||
<button
|
||||
type="object"
|
||||
name="action_view_bom"
|
||||
class="oe_stat_button"
|
||||
string="Bill of Materials"
|
||||
icon="fa-flask"
|
||||
attrs="{'invisible': [('item_type', '!=', 'manufactured')]}"
|
||||
/>
|
||||
<button
|
||||
type="object"
|
||||
name="action_view_mrp_productions"
|
||||
class="oe_stat_button"
|
||||
string="Manufacturing Orders"
|
||||
icon="fa-wrench"
|
||||
attrs="{'invisible': [('item_type', '!=', 'manufactured')]}"
|
||||
/>
|
||||
<button
|
||||
type="object"
|
||||
name="action_view_purchase"
|
||||
class="oe_stat_button"
|
||||
string="Purchase Orders"
|
||||
icon="fa-credit-card"
|
||||
attrs="{'invisible': [('item_type', '!=', 'purchased')]}"
|
||||
/>
|
||||
<button
|
||||
class="oe_stat_button"
|
||||
name="action_used_in_bom"
|
||||
type="object"
|
||||
attrs="{'invisible':['|',('product_type', 'not in', ['product', 'consu']), ('used_in_bom_count', '=', 0)]}"
|
||||
icon="fa-level-up"
|
||||
>
|
||||
<field
|
||||
string="Used In"
|
||||
name="used_in_bom_count"
|
||||
widget="statinfo"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
<widget
|
||||
name="web_ribbon"
|
||||
title="Archived"
|
||||
bg_color="bg-danger"
|
||||
attrs="{'invisible': [('active', '=', True)]}"
|
||||
/>
|
||||
<group>
|
||||
<group>
|
||||
<field name="active" invisible="1" />
|
||||
<field name="name" />
|
||||
<field name="product_id" />
|
||||
<field
|
||||
name="product_uom"
|
||||
options="{'no_open': True, 'no_create': True}"
|
||||
groups="uom.group_uom"
|
||||
/>
|
||||
<field name="product_type" invisible="1" />
|
||||
</group>
|
||||
<group>
|
||||
<field
|
||||
name="location_id"
|
||||
groups="stock.group_stock_multi_locations"
|
||||
/>
|
||||
<field
|
||||
name="warehouse_id"
|
||||
widget="selection"
|
||||
groups="stock.group_stock_multi_locations"
|
||||
/>
|
||||
<field
|
||||
name="company_id"
|
||||
groups="base.group_multi_company"
|
||||
options="{'no_create': True}"
|
||||
/>
|
||||
</group>
|
||||
<group name="buffer_size_factors">
|
||||
<group
|
||||
name="main_buffer_size_factors"
|
||||
string="Main Buffer size factors"
|
||||
colspan="2"
|
||||
>
|
||||
<field name="buffer_profile_id" />
|
||||
<field name="replenish_method" invisible="1" />
|
||||
<field name="item_type" invisible="1" />
|
||||
<field
|
||||
name="green_override"
|
||||
attrs="{'invisible': [('replenish_method', '!=', 'replenish_override')]}"
|
||||
/>
|
||||
<field
|
||||
name="yellow_override"
|
||||
attrs="{'invisible': [('replenish_method', '!=', 'replenish_override')]}"
|
||||
/>
|
||||
<field
|
||||
name="red_override"
|
||||
attrs="{'invisible': [('replenish_method', '!=', 'replenish_override')]}"
|
||||
/>
|
||||
<field name="adu_calculation_method" />
|
||||
<field
|
||||
name="adu_calculation_method_type"
|
||||
invisible="1"
|
||||
/>
|
||||
<field
|
||||
name="adu_fixed"
|
||||
attrs="{'invisible': [('adu_calculation_method_type', '!=', 'fixed')]}"
|
||||
/>
|
||||
<label for="adu" />
|
||||
<div name="adu" class="o_row">
|
||||
<field
|
||||
name="adu"
|
||||
force_save="1"
|
||||
class="oe_inline"
|
||||
/>
|
||||
<button
|
||||
title="View ADU (Past - Direct Demand)"
|
||||
name="action_view_past_adu_direct_demand"
|
||||
icon="fa-search"
|
||||
type="object"
|
||||
attrs="{'invisible': ['|', ('adu_calculation_method_type', 'in', ['fixed', 'future']), ('adu', '=', 0)]}"
|
||||
/>
|
||||
<button
|
||||
title="View ADU (Past - Indirect Demand)"
|
||||
name="action_view_past_adu_indirect_demand"
|
||||
icon="fa-search"
|
||||
type="object"
|
||||
attrs="{'invisible': ['|', '|', ('adu_calculation_method_type', 'in', ['fixed', 'future']), ('used_in_bom_count', '=', 0), ('adu', '=', 0)]}"
|
||||
/>
|
||||
<button
|
||||
title="View ADU (Future - Direct Demand)"
|
||||
name="action_view_future_adu_direct_demand"
|
||||
icon="fa-search"
|
||||
type="object"
|
||||
attrs="{'invisible': ['|', ('adu_calculation_method_type', 'in', ['fixed', 'past']), ('adu', '=', 0)]}"
|
||||
/>
|
||||
<button
|
||||
title="View ADU (Future - Indirect Demand)"
|
||||
name="action_view_future_adu_indirect_demand"
|
||||
icon="fa-search"
|
||||
type="object"
|
||||
attrs="{'invisible': ['|', '|', ('adu_calculation_method_type', 'in', ['fixed', 'past']), ('used_in_bom_count', '=', 0), ('adu', '=', 0)]}"
|
||||
/>
|
||||
</div>
|
||||
<field
|
||||
name="lead_days"
|
||||
attrs="{'invisible': [('item_type', '!=', 'distributed')]}"
|
||||
/>
|
||||
<label for="dlt" />
|
||||
<div name="dlt">
|
||||
<field name="dlt" class="oe_inline" /> days
|
||||
</div>
|
||||
</group>
|
||||
<group />
|
||||
<group
|
||||
name="secondary_buffer_size_factors"
|
||||
string="Secondary Buffer size factors"
|
||||
colspan="2"
|
||||
>
|
||||
<label for="extra_lead_time" />
|
||||
<div name="extra_lead_time">
|
||||
<field
|
||||
name="extra_lead_time"
|
||||
class="oe_inline"
|
||||
/> days
|
||||
</div>
|
||||
<field name="minimum_order_quantity" />
|
||||
<label for="order_cycle" />
|
||||
<div name="order_cycle">
|
||||
<field name="order_cycle" class="oe_inline" /> days
|
||||
</div>
|
||||
</group>
|
||||
</group>
|
||||
<group name="ddmrp_chart" string="Buffer summary">
|
||||
|
||||
<div colspan="2">
|
||||
<field
|
||||
name="ddmrp_chart"
|
||||
widget="bokeh_chart"
|
||||
nolabel="1"
|
||||
attrs="{'invisible': [('show_execution_chart', '=', True)]}"
|
||||
/>
|
||||
<field
|
||||
name="ddmrp_chart_execution"
|
||||
widget="bokeh_chart"
|
||||
nolabel="1"
|
||||
attrs="{'invisible': [('show_execution_chart', '=', False)]}"
|
||||
/>
|
||||
</div>
|
||||
<div cols="3">
|
||||
<label
|
||||
for="show_execution_chart"
|
||||
string="Planning"
|
||||
class="text-muted"
|
||||
attrs="{'invisible': [('show_execution_chart', '=', False)]}"
|
||||
/>
|
||||
<label
|
||||
for="show_execution_chart"
|
||||
string="Planning"
|
||||
style="font-weight: bold;"
|
||||
attrs="{'invisible': [('show_execution_chart', '=', True)]}"
|
||||
/>
|
||||
<field
|
||||
name="show_execution_chart"
|
||||
widget="boolean_toggle"
|
||||
nolabel="1"
|
||||
options="{'autosave': False}"
|
||||
/>
|
||||
<label
|
||||
for="show_execution_chart"
|
||||
string="Execution"
|
||||
class="text-muted"
|
||||
attrs="{'invisible': [('show_execution_chart', '=', True)]}"
|
||||
/>
|
||||
<label
|
||||
for="show_execution_chart"
|
||||
string="Execution"
|
||||
style="font-weight: bold;"
|
||||
attrs="{'invisible': [('show_execution_chart', '=', False)]}"
|
||||
/>
|
||||
</div>
|
||||
</group>
|
||||
<group name="execution_settings">
|
||||
<group
|
||||
name="qualified_demand"
|
||||
string="Qualified Demand"
|
||||
colspan="2"
|
||||
>
|
||||
<label for="order_spike_horizon" />
|
||||
<div name="order_spike_horizon">
|
||||
<field
|
||||
name="order_spike_horizon"
|
||||
class="oe_inline"
|
||||
/> days
|
||||
</div>
|
||||
<field name="order_spike_threshold" />
|
||||
</group>
|
||||
<group
|
||||
name="procurement_settings"
|
||||
string="Procurement Settings"
|
||||
colspan="2"
|
||||
>
|
||||
<field name="procure_uom_id" groups="uom.group_uom" />
|
||||
<field name="qty_multiple" />
|
||||
<field name="procure_min_qty" />
|
||||
<field name="procure_max_qty" />
|
||||
<field
|
||||
name="group_id"
|
||||
groups="stock.group_adv_location"
|
||||
/>
|
||||
<field
|
||||
name="distributed_source_location_id"
|
||||
attrs="{'invisible': ['|', ('item_type', '!=', 'distributed'), ('distributed_source_location_id', '=', False)]}"
|
||||
/>
|
||||
<field
|
||||
name="distributed_source_location_qty"
|
||||
attrs="{'invisible': ['|', ('item_type', '!=', 'distributed'), ('distributed_source_location_id', '=', False)]}"
|
||||
/>
|
||||
<field
|
||||
name="main_supplier_id"
|
||||
attrs="{'invisible': [('item_type', '!=', 'purchased')]}"
|
||||
/>
|
||||
<field
|
||||
name="product_vendor_code"
|
||||
attrs="{'invisible': [('product_vendor_code', '=', False)]}"
|
||||
/>
|
||||
<field name="auto_procure" />
|
||||
<field
|
||||
name="auto_procure_option"
|
||||
attrs="{'invisible': [('auto_procure', '=', False)]}"
|
||||
/>
|
||||
</group>
|
||||
</group>
|
||||
<group name="buffer_summary">
|
||||
<group
|
||||
name="buffer_information"
|
||||
string="Buffer Information"
|
||||
colspan="2"
|
||||
>
|
||||
<field name="product_location_qty_available_not_res" />
|
||||
<label for="incoming_dlt_qty" />
|
||||
<div name="incoming_dlt_qty" class="o_row">
|
||||
<field name="incoming_dlt_qty" class="oe_inline" />
|
||||
<button
|
||||
title="View Incoming Moves (Within DLT)"
|
||||
name="action_view_supply_moves_inside_dlt_window"
|
||||
icon="fa-search"
|
||||
type="object"
|
||||
attrs="{'invisible': [('incoming_dlt_qty', '=', 0)]}"
|
||||
/>
|
||||
</div>
|
||||
<label for="incoming_outside_dlt_qty" />
|
||||
<div name="incoming_outside_dlt_qty" class="o_row">
|
||||
<field
|
||||
name="incoming_outside_dlt_qty"
|
||||
class="oe_inline"
|
||||
/>
|
||||
<button
|
||||
title="Some incoming qty is outside of the DLT Horizon and may require rescheduling.
|
||||
Press this button to display the involved supply orders"
|
||||
name="action_view_supply_moves_outside_dlt_window"
|
||||
icon="fa-warning"
|
||||
type="object"
|
||||
attrs="{'invisible':[('incoming_outside_dlt_qty', '=', 0)]}"
|
||||
/>
|
||||
<field name="rfq_outside_dlt_qty" invisible="1" />
|
||||
<button
|
||||
title="Some incoming RFQs are outside of the DLT Horizon and may require rescheduling.
|
||||
Press this button to display the involved supply orders"
|
||||
name="action_view_supply_rfq_outside_dlt_window"
|
||||
icon="fa-warning"
|
||||
type="object"
|
||||
attrs="{'invisible':[('rfq_outside_dlt_qty', '=', 0)]}"
|
||||
/>
|
||||
</div>
|
||||
<label for="qualified_demand" />
|
||||
<div name="qualified_demand" class="o_row">
|
||||
<field name="qualified_demand" class="oe_inline" />
|
||||
<field
|
||||
name="qualified_demand_stock_move_ids"
|
||||
invisible="1"
|
||||
/>
|
||||
<field
|
||||
name="qualified_demand_mrp_move_ids"
|
||||
invisible="1"
|
||||
/>
|
||||
<button
|
||||
title="View Qualified Demand from Pickings"
|
||||
name="action_view_qualified_demand_moves"
|
||||
icon="fa-search"
|
||||
type="object"
|
||||
attrs="{'invisible': ['|', ('qualified_demand', '=', 0), ('qualified_demand_stock_move_ids', '=', [])]}"
|
||||
/>
|
||||
<button
|
||||
title="View Qualified Demand from MRP"
|
||||
name="action_view_qualified_demand_mrp"
|
||||
icon="fa-search"
|
||||
type="object"
|
||||
attrs="{'invisible': ['|', ('qualified_demand', '=', 0), ('qualified_demand_mrp_move_ids', '=', [])]}"
|
||||
/>
|
||||
<field name="rfq_inside_dlt_qty" invisible="1" />
|
||||
<button
|
||||
title="Some RFQs are inside of the DLT Horizon and waiting validation to be accounted into the NFP.
|
||||
Press this button to display them."
|
||||
name="action_view_supply_rfq_inside_dlt_window"
|
||||
icon="fa-warning"
|
||||
type="object"
|
||||
attrs="{'invisible':[('rfq_inside_dlt_qty', '=', 0)]}"
|
||||
/>
|
||||
</div>
|
||||
<field name="net_flow_position" />
|
||||
<label for="net_flow_position_percent" />
|
||||
<div name="net_flow_position_percent">
|
||||
<field
|
||||
name="net_flow_position_percent"
|
||||
class="oe_inline"
|
||||
/> %
|
||||
</div>
|
||||
</group>
|
||||
<group />
|
||||
<group
|
||||
name="buffer_target"
|
||||
string="On Hand Target"
|
||||
colspan="2"
|
||||
>
|
||||
<label for="on_hand_target_position" />
|
||||
<div name="on_hand_target_position_uom" class="o_row">
|
||||
<field name="on_hand_target_position" />
|
||||
</div>
|
||||
<label for="on_hand_target_min" />
|
||||
<div name="on_hand_target_range">
|
||||
<field
|
||||
name="on_hand_target_min"
|
||||
class="oe_inline"
|
||||
/> -
|
||||
<field
|
||||
name="on_hand_target_max"
|
||||
class="oe_inline"
|
||||
/>
|
||||
</div>
|
||||
</group>
|
||||
</group>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="Supply & Demand" name="demand_supply_bars">
|
||||
<group>
|
||||
<group string="Supply">
|
||||
<div style="margin-top: 1em;">
|
||||
<field
|
||||
name="ddmrp_supply_chart"
|
||||
style="height:400px"
|
||||
widget="bokeh_chart"
|
||||
nolabel="1"
|
||||
/>
|
||||
</div>
|
||||
</group>
|
||||
<group string="Demand">
|
||||
<div style="margin-top: 1em;">
|
||||
<field
|
||||
name="ddmrp_demand_chart"
|
||||
style="height:400px"
|
||||
widget="bokeh_chart"
|
||||
nolabel="1"
|
||||
/>
|
||||
</div>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
<page name="zones_info" string="Zones Information">
|
||||
<group col="3">
|
||||
<group name="green_zone" string="Green zone">
|
||||
<div class="no_print" colspan="2">
|
||||
<p
|
||||
class="oe_grey"
|
||||
>The green zone determines the average order frequency and the order size. It is determined as the maximum of the following three factors: Minimum Order Cycle, Lead Time Factor and Minimum Order Quantity.</p>
|
||||
</div>
|
||||
<field name="green_zone_oc" />
|
||||
<field name="green_zone_moq" />
|
||||
<field name="green_zone_lt_factor" />
|
||||
<field name="green_zone_qty" />
|
||||
</group>
|
||||
<group name="yellow_zone" string="Yellow zone">
|
||||
<div class="no_print" colspan="2">
|
||||
<p
|
||||
class="oe_grey"
|
||||
>The yellow zone represents the stock required to cover a full lead time.</p>
|
||||
</div>
|
||||
<field name="yellow_zone_qty" />
|
||||
</group>
|
||||
<group name="red_zone" string="Red zone">
|
||||
<div class="no_print" colspan="2">
|
||||
<p
|
||||
class="oe_grey"
|
||||
>The red zone is the embedded safety in the buffer. The larger the variability associated with the product, the larger the red zone will be. It is composed of two sub-zones: Red base and red safety.</p>
|
||||
</div>
|
||||
<field name="red_base_qty" />
|
||||
<field name="red_safety_qty" />
|
||||
<field name="red_zone_qty" />
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<record id="stock_buffer_search" model="ir.ui.view">
|
||||
<field name="name">stock.buffer.search</field>
|
||||
<field name="model">stock.buffer</field>
|
||||
<field name="arch" type="xml">
|
||||
<search>
|
||||
<field
|
||||
name="name"
|
||||
string="Buffer"
|
||||
filter_domain="[
|
||||
'|', '|',
|
||||
('name', 'ilike', self), ('product_id', 'ilike', self), ('location_id', 'ilike', self)]"
|
||||
/>
|
||||
<field name="buffer_profile_id" />
|
||||
<field
|
||||
name="warehouse_id"
|
||||
groups="stock.group_stock_multi_warehouses"
|
||||
/>
|
||||
<field name="location_id" groups="stock.group_stock_multi_locations" />
|
||||
<field name="main_supplier_id" />
|
||||
<field name="company_id" groups="base.group_multi_company" />
|
||||
<field name="product_id" />
|
||||
<field name="product_categ_id" />
|
||||
<field name="dlt" />
|
||||
<field name="order_cycle" />
|
||||
<field name="minimum_order_quantity" />
|
||||
<field name="planning_priority_level" />
|
||||
<field name="execution_priority_level" />
|
||||
<group name="planning_priority" string="Planning Priority Zones">
|
||||
<filter
|
||||
name="planning_priority_level_red"
|
||||
string="Red"
|
||||
domain="[('planning_priority_level', '=', '1_red')]"
|
||||
/>
|
||||
<filter
|
||||
name="planning_priority_level_yellow"
|
||||
string="Yellow"
|
||||
domain="[('planning_priority_level', '=', '2_yellow')]"
|
||||
/>
|
||||
<filter
|
||||
name="planning_priority_level_green"
|
||||
string="Green"
|
||||
domain="[('planning_priority_level', '=', '3_green')]"
|
||||
/>
|
||||
</group>
|
||||
<separator />
|
||||
<group name="execution_priority" string="On Hand Alert Zones">
|
||||
<filter
|
||||
name="execution_priority_level_red"
|
||||
string="Red"
|
||||
domain="[('execution_priority_level', '=', '1_red')]"
|
||||
/>
|
||||
<filter
|
||||
name="execution_priority_level_yellow"
|
||||
string="Yellow"
|
||||
domain="[('execution_priority_level', '=', '2_yellow')]"
|
||||
/>
|
||||
<filter
|
||||
name="execution_priority_level_green"
|
||||
string="Green"
|
||||
domain="[('execution_priority_level', '=', '3_green')]"
|
||||
/>
|
||||
</group>
|
||||
<separator />
|
||||
<group name="item_type" string="Type">
|
||||
<filter
|
||||
name="item_type_manufactured"
|
||||
string="Manufactured"
|
||||
domain="[('item_type', '=', 'manufactured')]"
|
||||
/>
|
||||
<filter
|
||||
name="item_type_purchased"
|
||||
string="Purchased"
|
||||
domain="[('item_type', '=', 'purchased')]"
|
||||
/>
|
||||
<filter
|
||||
name="item_type_distributed"
|
||||
string="Distributed"
|
||||
domain="[('item_type', '=', 'distributed')]"
|
||||
/>
|
||||
</group>
|
||||
<separator />
|
||||
<group name="procure_recommendation" string="Procurement">
|
||||
<filter
|
||||
name="procure_recommended"
|
||||
string="Procurement recommended"
|
||||
domain="[('procure_recommended_qty', '>', 0.0)]"
|
||||
/>
|
||||
</group>
|
||||
<separator />
|
||||
<filter
|
||||
name="has_long_term_supply"
|
||||
string="Has Long Term Supply"
|
||||
domain="['|', ('incoming_outside_dlt_qty', '>', 0), ('rfq_outside_dlt_qty', '>', 0)]"
|
||||
/>
|
||||
<separator />
|
||||
<filter
|
||||
name="has_distributed_source_location_qty"
|
||||
string="Has Stock In Source Location"
|
||||
domain="[('distributed_source_location_qty', '>', 0)]"
|
||||
/>
|
||||
<separator />
|
||||
<filter
|
||||
string="Archived"
|
||||
name="inactive"
|
||||
domain="[('active','=',False)]"
|
||||
/>
|
||||
<group expand="0" string="Group By">
|
||||
<filter
|
||||
string="Warehouse"
|
||||
name="warehouse"
|
||||
domain="[]"
|
||||
context="{'group_by':'warehouse_id'}"
|
||||
groups="stock.group_stock_multi_warehouses"
|
||||
/>
|
||||
<filter
|
||||
string="Location"
|
||||
name="location"
|
||||
domain="[]"
|
||||
context="{'group_by':'location_id'}"
|
||||
groups="stock.group_stock_multi_locations"
|
||||
/>
|
||||
<filter
|
||||
string="Main supplier"
|
||||
name="main_supplier_group_filter"
|
||||
domain="[]"
|
||||
context="{'group_by':'main_supplier_id'}"
|
||||
/>
|
||||
<filter
|
||||
string="Product Category"
|
||||
name="product_categ_id"
|
||||
domain="[]"
|
||||
context="{'group_by': 'product_categ_id'}"
|
||||
/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
<record id="action_stock_buffer" model="ir.actions.act_window">
|
||||
<field name="name">Stock Buffers</field>
|
||||
<field name="res_model">stock.buffer</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="context">{'location_id': False}</field>
|
||||
</record>
|
||||
<menuitem
|
||||
id="menu_stock_buffer"
|
||||
parent="stock.menu_stock_inventory_control"
|
||||
action="action_stock_buffer"
|
||||
/>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<!-- Copyright 2018-20 ForgeFlow S.L. (http://www.forgeflow.com)
|
||||
License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl-3.0) -->
|
||||
<odoo>
|
||||
<record id="view_move_tree" model="ir.ui.view">
|
||||
<field name="name">stock.move.tree</field>
|
||||
<field name="model">stock.move</field>
|
||||
<field name="inherit_id" ref="stock.view_move_tree" />
|
||||
<field name="arch" type="xml">
|
||||
<field name="state" position="after">
|
||||
<button
|
||||
title="Go to Source"
|
||||
name="action_open_stock_move_source"
|
||||
icon="fa-arrow-right"
|
||||
type="object"
|
||||
/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
<record id="view_move_form" model="ir.ui.view">
|
||||
<field name="name">stock.move.form</field>
|
||||
<field name="model">stock.move</field>
|
||||
<field name="inherit_id" ref="stock.view_move_form" />
|
||||
<field name="arch" type="xml">
|
||||
<field name="date" position="attributes">
|
||||
<attribute name="invisible">False</attribute>
|
||||
</field>
|
||||
<field name="move_dest_ids" position="after">
|
||||
<field name="buffer_ids" />
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
<record id="view_move_consumption_pivot" model="ir.ui.view">
|
||||
<field name="name">stock.move.consumption.pivot</field>
|
||||
<field name="model">stock.move</field>
|
||||
<field name="arch" type="xml">
|
||||
<pivot string="Stock Moves Yearly Consumption">
|
||||
<field name="date" interval="month" type="row" />
|
||||
<field name="location_dest_id" type="col" />
|
||||
<field name="product_uom_qty" type="measure" />
|
||||
</pivot>
|
||||
</field>
|
||||
</record>
|
||||
<record id="stock_move_year_consumption_action" model="ir.actions.act_window">
|
||||
<field name="name">Stock Move Last Year Consumption</field>
|
||||
<field name="res_model">stock.move</field>
|
||||
<field name="view_id" ref="ddmrp.view_move_consumption_pivot" />
|
||||
<field
|
||||
name="context"
|
||||
>{"time_ranges": {"field": "date", "range": "last_365_days"}}</field>
|
||||
<field name="domain" />
|
||||
<field name="view_mode">pivot</field>
|
||||
</record>
|
||||
</odoo>
|
||||
19
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/views/stock_picking.xml
Normal file
19
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/views/stock_picking.xml
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
<record id="view_picking_form" model="ir.ui.view">
|
||||
<field name="name">stock.picking.form.inherit</field>
|
||||
<field name="model">stock.picking</field>
|
||||
<field name="inherit_id" ref="stock.view_picking_form" />
|
||||
<field name="arch" type="xml">
|
||||
<div name="button_box" position="inside">
|
||||
<button
|
||||
name="action_stock_buffer_open"
|
||||
type="object"
|
||||
string="Product Buffers"
|
||||
class="oe_stat_button"
|
||||
icon="fa-tasks"
|
||||
/>
|
||||
</div>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<!-- Copyright 2018 ForgeFlow S.L. (http://www.forgeflow.com)
|
||||
License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). -->
|
||||
<odoo>
|
||||
<record id="view_warehouse" model="ir.ui.view">
|
||||
<field name="name">stock.warehouse</field>
|
||||
<field name="model">stock.warehouse</field>
|
||||
<field name="inherit_id" ref="stock.view_warehouse" />
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//page[@name='warehouse_config']/group" position="inside">
|
||||
<group name="ddmrp" string="DDMRP">
|
||||
<field name="nfp_incoming_safety_factor" />
|
||||
</group>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
6
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/wizards/__init__.py
Normal file
6
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/wizards/__init__.py
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
from . import multi_level_mrp
|
||||
from . import make_procurement_buffer
|
||||
from . import mrp_bom_change_location
|
||||
from . import ddmrp_duplicate_buffer
|
||||
from . import ddmrp_run
|
||||
from . import res_config_settings
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
# Copyright 2023 ForgeFlow S.L. (http://www.forgeflow.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
|
||||
|
||||
|
||||
class DdmrpDuplicateBuffer(models.TransientModel):
|
||||
_name = "ddmrp.duplicate.buffer"
|
||||
_description = "DDMRP Duplicate Buffer"
|
||||
|
||||
@api.model
|
||||
def default_get(self, fields_list):
|
||||
res = super().default_get(fields_list)
|
||||
buffer_obj = self.env["stock.buffer"]
|
||||
buffer_ids = self.env.context.get("active_ids", [])
|
||||
active_model = self.env.context["active_model"]
|
||||
|
||||
if not buffer_ids:
|
||||
return
|
||||
assert active_model == "stock.buffer", "Bad context propagation"
|
||||
|
||||
if len(buffer_ids) > 1:
|
||||
res.update(
|
||||
{
|
||||
"type": "location",
|
||||
}
|
||||
)
|
||||
else:
|
||||
buffer = buffer_obj.browse(buffer_ids)
|
||||
res.update(
|
||||
{
|
||||
"type": "both",
|
||||
"product_id": buffer.product_id.id,
|
||||
"location_id": buffer.location_id.id,
|
||||
}
|
||||
)
|
||||
return res
|
||||
|
||||
type = fields.Selection(
|
||||
string="Duplication Type",
|
||||
selection=[
|
||||
("both", "Change both values"),
|
||||
("product", "Change Product"),
|
||||
("location", "Change Location"),
|
||||
],
|
||||
required=True,
|
||||
)
|
||||
product_id = fields.Many2one(
|
||||
comodel_name="product.product",
|
||||
string="New Product",
|
||||
)
|
||||
location_id = fields.Many2one(
|
||||
comodel_name="stock.location",
|
||||
string="New Location",
|
||||
)
|
||||
|
||||
def action_duplicate_buffer(self):
|
||||
buffer_obj = self.env["stock.buffer"]
|
||||
buffer_ids = self.env.context["active_ids"] or []
|
||||
|
||||
if self.type in ["product", "both"] and not self.product_id:
|
||||
raise UserError(_("Please select a New Product."))
|
||||
if self.type in ["location", "both"] and not self.location_id:
|
||||
raise UserError(_("Please select a New Location."))
|
||||
|
||||
copy_buffers = self.env["stock.buffer"]
|
||||
for buffer in buffer_obj.browse(buffer_ids):
|
||||
default = {}
|
||||
if self.type in ["product", "both"]:
|
||||
default["product_id"] = self.product_id.id
|
||||
if self.type in ["location", "both"]:
|
||||
default["location_id"] = self.location_id.id
|
||||
default["warehouse_id"] = self.location_id.warehouse_id.id
|
||||
default["company_id"] = self.location_id.company_id.id
|
||||
copy_buffers |= buffer.copy(default)
|
||||
if len(copy_buffers) == 1:
|
||||
view_id = self.env.ref("ddmrp.stock_buffer_view_form").id
|
||||
return {
|
||||
"name": _("Duplicated Buffers"),
|
||||
"type": "ir.actions.act_window",
|
||||
"res_model": "stock.buffer",
|
||||
"res_id": copy_buffers.id,
|
||||
"view_mode": "form",
|
||||
"view_id": view_id,
|
||||
}
|
||||
else:
|
||||
xmlid = "ddmrp.action_stock_buffer"
|
||||
action = self.env["ir.actions.act_window"]._for_xml_id(xmlid)
|
||||
action.update(
|
||||
{
|
||||
"name": _("Duplicated Buffers"),
|
||||
"res_model": "stock.buffer",
|
||||
"view_mode": "tree,form",
|
||||
"domain": [("id", "in", copy_buffers.ids)],
|
||||
}
|
||||
)
|
||||
return action
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
|
||||
<record id="ddmrp_duplicate_buffer_wizard" model="ir.ui.view">
|
||||
<field name="name">Ddmrp Duplicate Buffer Wizard</field>
|
||||
<field name="model">ddmrp.duplicate.buffer</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Copy Ddmrp Stock Buffer">
|
||||
<group>
|
||||
<group>
|
||||
<field name="type" />
|
||||
<field
|
||||
name="product_id"
|
||||
attrs="{'invisible':[('type','=', 'location')]}"
|
||||
/>
|
||||
<field
|
||||
name="location_id"
|
||||
attrs="{'invisible':[('type','=', 'product')]}"
|
||||
/>
|
||||
</group>
|
||||
</group>
|
||||
<footer>
|
||||
<button
|
||||
name="action_duplicate_buffer"
|
||||
string="Duplicate"
|
||||
type="object"
|
||||
class="btn-primary"
|
||||
/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_server_ddmrp_duplicate_buffer" model="ir.actions.act_window">
|
||||
<field name="name">Duplicate Buffer</field>
|
||||
<field name="res_model">ddmrp.duplicate.buffer</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
<field name="binding_model_id" ref="ddmrp.model_stock_buffer" />
|
||||
<field name="view_id" ref="ddmrp.ddmrp_duplicate_buffer_wizard" />
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
15
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/wizards/ddmrp_run.py
Normal file
15
odoo-bringout-oca-ddmrp-ddmrp/ddmrp/wizards/ddmrp_run.py
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
# Copyright 2018-20 ForgeFlow S.L. (http://www.forgeflow.com)
|
||||
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
|
||||
|
||||
from odoo import models
|
||||
|
||||
|
||||
class DdmrpRun(models.TransientModel):
|
||||
_name = "ddmrp.run"
|
||||
_description = "DDMRP Manual Run Wizard"
|
||||
|
||||
def run_cron_ddmrp_adu(self):
|
||||
self.env["stock.buffer"].cron_ddmrp_adu(True)
|
||||
|
||||
def run_cron_ddmrp(self):
|
||||
self.env["stock.buffer"].cron_ddmrp(True)
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue