Merge PR #2041 into 17.0

Signed-off-by LoisRForgeFlow
This commit is contained in:
OCA-git-bot
2024-10-28 15:55:31 +00:00
25 changed files with 1963 additions and 0 deletions

View File

@@ -0,0 +1,105 @@
============================
Stock Demand Estimate Matrix
============================
..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:dd6235ad9f824ac586e403e2c2a17b00c6cb981efee47edf1409ed6693a44f61
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| image:: https://img.shields.io/badge/maturity-Production%2FStable-green.png
:target: https://odoo-community.org/page/development-status
:alt: Production/Stable
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fstock--logistics--warehouse-lightgray.png?logo=github
:target: https://github.com/OCA/stock-logistics-warehouse/tree/17.0/stock_demand_estimate_matrix
:alt: OCA/stock-logistics-warehouse
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/stock-logistics-warehouse-17-0/stock-logistics-warehouse-17-0-stock_demand_estimate_matrix
: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/stock-logistics-warehouse&target_branch=17.0
:alt: Try me on Runboat
|badge1| |badge2| |badge3| |badge4| |badge5|
This module allows to create demand estimates for a given product and
location, on configurable time periods.
The module does not provide in itself any specific usage of the
estimates.
**Table of contents**
.. contents::
:local:
Installation
============
This module relies on:
- The OCA module '2D matrix for x2many fields', and can be downloaded
from Github:
https://github.com/OCA/web/tree/13.0/web_widget_x2many_2d_matrix
- The OCA module 'Date Range', and can be downloaded from Github:
https://github.com/OCA/server-ux/tree/13.0/date_range
Usage
=====
Go to *Inventory > Configuration > Date Ranges* and define your
estimating periods.
Go to *Inventory > Demand Planning > Create Demand Estimates* to create
or update your demand estimates.
Go to *Inventory > Demand Planning > Demand Estimates* to review the
estimates created.
Bug Tracker
===========
Bugs are tracked on `GitHub Issues <https://github.com/OCA/stock-logistics-warehouse/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/stock-logistics-warehouse/issues/new?body=module:%20stock_demand_estimate_matrix%0Aversion:%2017.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 <lois.rilo@forgeflow.com>
- Pimolnat Suntian <pimolnats@ecosoft.co.th>
Maintainers
-----------
This module is maintained by the OCA.
.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org
OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.
This module is part of the `OCA/stock-logistics-warehouse <https://github.com/OCA/stock-logistics-warehouse/tree/17.0/stock_demand_estimate_matrix>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

View File

@@ -0,0 +1,2 @@
from . import models
from . import wizards

View File

@@ -0,0 +1,20 @@
# Copyright 2019 ForgeFlow S.L. (https://www.forgeflow.com)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
{
"name": "Stock Demand Estimate Matrix",
"summary": "Allows to create demand estimates.",
"version": "17.0.1.0.0",
"author": "ForgeFlow, Odoo Community Association (OCA)",
"development_status": "Production/Stable",
"website": "https://github.com/OCA/stock-logistics-warehouse",
"category": "Warehouse",
"depends": ["stock_demand_estimate", "web_widget_x2many_2d_matrix", "date_range"],
"data": [
"security/ir.model.access.csv",
"views/stock_demand_estimate_view.xml",
"views/date_range.xml",
"wizards/stock_demand_estimate_wizard_view.xml",
],
"license": "AGPL-3",
"installable": True,
}

View File

@@ -0,0 +1,258 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * stock_demand_estimate_matrix
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2023-12-29 14:36+0000\n"
"Last-Translator: mymage <stefano.consolaro@mymage.it>\n"
"Language-Team: none\n"
"Language: it\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 4.17\n"
#. module: stock_demand_estimate_matrix
#: model_terms:ir.ui.view,arch_db:stock_demand_estimate_matrix.demand_estimate_wizard_view_form
#: model_terms:ir.ui.view,arch_db:stock_demand_estimate_matrix.stock_demand_estimate_sheet_view_form
msgid "Cancel"
msgstr "Annulla"
#. module: stock_demand_estimate_matrix
#: model:ir.actions.act_window,name:stock_demand_estimate_matrix.stock_demand_estimate_wizard_action
#: model:ir.ui.menu,name:stock_demand_estimate_matrix.stock_demand_estimate_wizard_menu
msgid "Create Stock Demand Estimates"
msgstr "Crea stime richiesta giacenza"
#. module: stock_demand_estimate_matrix
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet__create_uid
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet_line__create_uid
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_wizard__create_uid
msgid "Created by"
msgstr "Creato da"
#. module: stock_demand_estimate_matrix
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet__create_date
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet_line__create_date
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_wizard__create_date
msgid "Created on"
msgstr "Creato il"
#. module: stock_demand_estimate_matrix
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet__date_start
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_wizard__date_start
msgid "Date From"
msgstr "Dalla data"
#. module: stock_demand_estimate_matrix
#: model:ir.model,name:stock_demand_estimate_matrix.model_date_range
msgid "Date Range"
msgstr "Intervallo data"
#. module: stock_demand_estimate_matrix
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet__date_range_type_id
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_wizard__date_range_type_id
msgid "Date Range Type"
msgstr "Tipo intervallo date"
#. module: stock_demand_estimate_matrix
#: model:ir.ui.menu,name:stock_demand_estimate_matrix.date_range_menu
msgid "Date Ranges"
msgstr "Intervalli data"
#. module: stock_demand_estimate_matrix
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_wizard__date_end
msgid "Date To"
msgstr "Alla data"
#. module: stock_demand_estimate_matrix
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet__date_end
msgid "Date to"
msgstr "Alla data"
#. module: stock_demand_estimate_matrix
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_date_range__days
msgid "Days between dates"
msgstr "Giorni tra le date"
#. module: stock_demand_estimate_matrix
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet__display_name
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet_line__display_name
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_wizard__display_name
msgid "Display Name"
msgstr "Nome visualizzato"
#. module: stock_demand_estimate_matrix
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet_line__estimate_id
msgid "Estimate"
msgstr "Stime"
#. module: stock_demand_estimate_matrix
#. odoo-python
#: code:addons/stock_demand_estimate_matrix/wizards/stock_demand_estimate_wizard.py:0
#, python-format
msgid "Estimate Sheet"
msgstr "Foglio stima"
#. module: stock_demand_estimate_matrix
#: model_terms:ir.ui.view,arch_db:stock_demand_estimate_matrix.stock_demand_estimate_sheet_view_form
msgid "Estimated quantity"
msgstr "Quantità stimata"
#. module: stock_demand_estimate_matrix
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet__line_ids
msgid "Estimates"
msgstr "Stime"
#. module: stock_demand_estimate_matrix
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate__date_range_id
msgid "Estimating Period"
msgstr "Valutazione periodo"
#. module: stock_demand_estimate_matrix
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet__id
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet_line__id
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_wizard__id
msgid "ID"
msgstr "ID"
#. module: stock_demand_estimate_matrix
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet____last_update
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet_line____last_update
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_wizard____last_update
msgid "Last Modified on"
msgstr "Ultima modifica il"
#. module: stock_demand_estimate_matrix
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet__write_uid
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet_line__write_uid
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_wizard__write_uid
msgid "Last Updated by"
msgstr "Ultimo aggiornamento di"
#. module: stock_demand_estimate_matrix
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet__write_date
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet_line__write_date
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_wizard__write_date
msgid "Last Updated on"
msgstr "Ultimo aggiornamento il"
#. module: stock_demand_estimate_matrix
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet__location_id
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_wizard__location_id
msgid "Location"
msgstr "Ubicazione"
#. module: stock_demand_estimate_matrix
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet_line__date_range_id
#: model_terms:ir.ui.view,arch_db:stock_demand_estimate_matrix.demand_estimate_wizard_view_form
#: model_terms:ir.ui.view,arch_db:stock_demand_estimate_matrix.stock_demand_estimate_sheet_view_form
msgid "Period"
msgstr "Periodo"
#. module: stock_demand_estimate_matrix
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet_line__value_x
msgid "Period Name"
msgstr "Nome periodo"
#. module: stock_demand_estimate_matrix
#: model_terms:ir.ui.view,arch_db:stock_demand_estimate_matrix.demand_estimate_wizard_view_form
msgid "Prepare"
msgstr "Prepara"
#. module: stock_demand_estimate_matrix
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet_line__product_id
msgid "Product"
msgstr "Prodotto"
#. module: stock_demand_estimate_matrix
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet_line__value_y
msgid "Product Name"
msgstr "Nome prodotto"
#. module: stock_demand_estimate_matrix
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet__product_ids
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_wizard__product_ids
#: model_terms:ir.ui.view,arch_db:stock_demand_estimate_matrix.demand_estimate_wizard_view_form
msgid "Products"
msgstr "Prodotti"
#. module: stock_demand_estimate_matrix
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet_line__product_uom_qty
msgid "Quantity"
msgstr "Quantità"
#. module: stock_demand_estimate_matrix
#: model:ir.model,name:stock_demand_estimate_matrix.model_stock_demand_estimate
msgid "Stock Demand Estimate Line"
msgstr "Riga stima richiesta giacenza"
#. module: stock_demand_estimate_matrix
#: model:ir.model,name:stock_demand_estimate_matrix.model_stock_demand_estimate_sheet
#: model_terms:ir.ui.view,arch_db:stock_demand_estimate_matrix.stock_demand_estimate_sheet_view_form
msgid "Stock Demand Estimate Sheet"
msgstr "Foglio stima richiesta giacenza"
#. module: stock_demand_estimate_matrix
#: model:ir.model,name:stock_demand_estimate_matrix.model_stock_demand_estimate_sheet_line
msgid "Stock Demand Estimate Sheet Line"
msgstr "Riga foglio stima richiesta giacenza"
#. module: stock_demand_estimate_matrix
#: model:ir.model,name:stock_demand_estimate_matrix.model_stock_demand_estimate_wizard
#: model_terms:ir.ui.view,arch_db:stock_demand_estimate_matrix.demand_estimate_wizard_view_form
msgid "Stock Demand Estimate Wizard"
msgstr "Procedura guidata stima richiesta giacenza"
#. module: stock_demand_estimate_matrix
#. odoo-python
#: code:addons/stock_demand_estimate_matrix/wizards/stock_demand_estimate_sheet.py:0
#, python-format
msgid "Stock Demand Estimates"
msgstr "Stime richiesta giacenza"
#. module: stock_demand_estimate_matrix
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet_line__location_id
msgid "Stock Location"
msgstr "Ubicazione giacenza"
#. module: stock_demand_estimate_matrix
#. odoo-python
#: code:addons/stock_demand_estimate_matrix/wizards/stock_demand_estimate_wizard.py:0
#, python-format
msgid "The start date cannot be later than the end date."
msgstr "La data di inizio non può essere successiva alla data di fine."
#. module: stock_demand_estimate_matrix
#. odoo-python
#: code:addons/stock_demand_estimate_matrix/wizards/stock_demand_estimate_sheet.py:0
#, python-format
msgid "There is no ranges created."
msgstr "Non ci sono intervalli definiti."
#. module: stock_demand_estimate_matrix
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet_line__product_uom
msgid "Unit of measure"
msgstr "Unità di misura"
#. module: stock_demand_estimate_matrix
#: model_terms:ir.ui.view,arch_db:stock_demand_estimate_matrix.stock_demand_estimate_sheet_view_form
msgid "Validate"
msgstr "Valida"
#. module: stock_demand_estimate_matrix
#. odoo-python
#: code:addons/stock_demand_estimate_matrix/wizards/stock_demand_estimate_wizard.py:0
#, python-format
msgid "You must select at least one product."
msgstr "Bisogna selezionare almeno un prodotto."
#. module: stock_demand_estimate_matrix
#: model_terms:ir.ui.view,arch_db:stock_demand_estimate_matrix.demand_estimate_wizard_view_form
#: model_terms:ir.ui.view,arch_db:stock_demand_estimate_matrix.stock_demand_estimate_sheet_view_form
msgid "to"
msgstr "a"

View File

@@ -0,0 +1,255 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * stock_demand_estimate_matrix
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: stock_demand_estimate_matrix
#: model_terms:ir.ui.view,arch_db:stock_demand_estimate_matrix.demand_estimate_wizard_view_form
#: model_terms:ir.ui.view,arch_db:stock_demand_estimate_matrix.stock_demand_estimate_sheet_view_form
msgid "Cancel"
msgstr ""
#. module: stock_demand_estimate_matrix
#: model:ir.actions.act_window,name:stock_demand_estimate_matrix.stock_demand_estimate_wizard_action
#: model:ir.ui.menu,name:stock_demand_estimate_matrix.stock_demand_estimate_wizard_menu
msgid "Create Stock Demand Estimates"
msgstr ""
#. module: stock_demand_estimate_matrix
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet__create_uid
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet_line__create_uid
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_wizard__create_uid
msgid "Created by"
msgstr ""
#. module: stock_demand_estimate_matrix
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet__create_date
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet_line__create_date
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_wizard__create_date
msgid "Created on"
msgstr ""
#. module: stock_demand_estimate_matrix
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet__date_start
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_wizard__date_start
msgid "Date From"
msgstr ""
#. module: stock_demand_estimate_matrix
#: model:ir.model,name:stock_demand_estimate_matrix.model_date_range
msgid "Date Range"
msgstr ""
#. module: stock_demand_estimate_matrix
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet__date_range_type_id
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_wizard__date_range_type_id
msgid "Date Range Type"
msgstr ""
#. module: stock_demand_estimate_matrix
#: model:ir.ui.menu,name:stock_demand_estimate_matrix.date_range_menu
msgid "Date Ranges"
msgstr ""
#. module: stock_demand_estimate_matrix
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_wizard__date_end
msgid "Date To"
msgstr ""
#. module: stock_demand_estimate_matrix
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet__date_end
msgid "Date to"
msgstr ""
#. module: stock_demand_estimate_matrix
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_date_range__days
msgid "Days between dates"
msgstr ""
#. module: stock_demand_estimate_matrix
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet__display_name
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet_line__display_name
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_wizard__display_name
msgid "Display Name"
msgstr ""
#. module: stock_demand_estimate_matrix
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet_line__estimate_id
msgid "Estimate"
msgstr ""
#. module: stock_demand_estimate_matrix
#. odoo-python
#: code:addons/stock_demand_estimate_matrix/wizards/stock_demand_estimate_wizard.py:0
#, python-format
msgid "Estimate Sheet"
msgstr ""
#. module: stock_demand_estimate_matrix
#: model_terms:ir.ui.view,arch_db:stock_demand_estimate_matrix.stock_demand_estimate_sheet_view_form
msgid "Estimated quantity"
msgstr ""
#. module: stock_demand_estimate_matrix
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet__line_ids
msgid "Estimates"
msgstr ""
#. module: stock_demand_estimate_matrix
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate__date_range_id
msgid "Estimating Period"
msgstr ""
#. module: stock_demand_estimate_matrix
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet__id
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet_line__id
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_wizard__id
msgid "ID"
msgstr ""
#. module: stock_demand_estimate_matrix
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet____last_update
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet_line____last_update
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_wizard____last_update
msgid "Last Modified on"
msgstr ""
#. module: stock_demand_estimate_matrix
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet__write_uid
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet_line__write_uid
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_wizard__write_uid
msgid "Last Updated by"
msgstr ""
#. module: stock_demand_estimate_matrix
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet__write_date
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet_line__write_date
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_wizard__write_date
msgid "Last Updated on"
msgstr ""
#. module: stock_demand_estimate_matrix
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet__location_id
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_wizard__location_id
msgid "Location"
msgstr ""
#. module: stock_demand_estimate_matrix
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet_line__date_range_id
#: model_terms:ir.ui.view,arch_db:stock_demand_estimate_matrix.demand_estimate_wizard_view_form
#: model_terms:ir.ui.view,arch_db:stock_demand_estimate_matrix.stock_demand_estimate_sheet_view_form
msgid "Period"
msgstr ""
#. module: stock_demand_estimate_matrix
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet_line__value_x
msgid "Period Name"
msgstr ""
#. module: stock_demand_estimate_matrix
#: model_terms:ir.ui.view,arch_db:stock_demand_estimate_matrix.demand_estimate_wizard_view_form
msgid "Prepare"
msgstr ""
#. module: stock_demand_estimate_matrix
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet_line__product_id
msgid "Product"
msgstr ""
#. module: stock_demand_estimate_matrix
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet_line__value_y
msgid "Product Name"
msgstr ""
#. module: stock_demand_estimate_matrix
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet__product_ids
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_wizard__product_ids
#: model_terms:ir.ui.view,arch_db:stock_demand_estimate_matrix.demand_estimate_wizard_view_form
msgid "Products"
msgstr ""
#. module: stock_demand_estimate_matrix
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet_line__product_uom_qty
msgid "Quantity"
msgstr ""
#. module: stock_demand_estimate_matrix
#: model:ir.model,name:stock_demand_estimate_matrix.model_stock_demand_estimate
msgid "Stock Demand Estimate Line"
msgstr ""
#. module: stock_demand_estimate_matrix
#: model:ir.model,name:stock_demand_estimate_matrix.model_stock_demand_estimate_sheet
#: model_terms:ir.ui.view,arch_db:stock_demand_estimate_matrix.stock_demand_estimate_sheet_view_form
msgid "Stock Demand Estimate Sheet"
msgstr ""
#. module: stock_demand_estimate_matrix
#: model:ir.model,name:stock_demand_estimate_matrix.model_stock_demand_estimate_sheet_line
msgid "Stock Demand Estimate Sheet Line"
msgstr ""
#. module: stock_demand_estimate_matrix
#: model:ir.model,name:stock_demand_estimate_matrix.model_stock_demand_estimate_wizard
#: model_terms:ir.ui.view,arch_db:stock_demand_estimate_matrix.demand_estimate_wizard_view_form
msgid "Stock Demand Estimate Wizard"
msgstr ""
#. module: stock_demand_estimate_matrix
#. odoo-python
#: code:addons/stock_demand_estimate_matrix/wizards/stock_demand_estimate_sheet.py:0
#, python-format
msgid "Stock Demand Estimates"
msgstr ""
#. module: stock_demand_estimate_matrix
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet_line__location_id
msgid "Stock Location"
msgstr ""
#. module: stock_demand_estimate_matrix
#. odoo-python
#: code:addons/stock_demand_estimate_matrix/wizards/stock_demand_estimate_wizard.py:0
#, python-format
msgid "The start date cannot be later than the end date."
msgstr ""
#. module: stock_demand_estimate_matrix
#. odoo-python
#: code:addons/stock_demand_estimate_matrix/wizards/stock_demand_estimate_sheet.py:0
#, python-format
msgid "There is no ranges created."
msgstr ""
#. module: stock_demand_estimate_matrix
#: model:ir.model.fields,field_description:stock_demand_estimate_matrix.field_stock_demand_estimate_sheet_line__product_uom
msgid "Unit of measure"
msgstr ""
#. module: stock_demand_estimate_matrix
#: model_terms:ir.ui.view,arch_db:stock_demand_estimate_matrix.stock_demand_estimate_sheet_view_form
msgid "Validate"
msgstr ""
#. module: stock_demand_estimate_matrix
#. odoo-python
#: code:addons/stock_demand_estimate_matrix/wizards/stock_demand_estimate_wizard.py:0
#, python-format
msgid "You must select at least one product."
msgstr ""
#. module: stock_demand_estimate_matrix
#: model_terms:ir.ui.view,arch_db:stock_demand_estimate_matrix.demand_estimate_wizard_view_form
#: model_terms:ir.ui.view,arch_db:stock_demand_estimate_matrix.stock_demand_estimate_sheet_view_form
msgid "to"
msgstr ""

View File

@@ -0,0 +1,2 @@
from . import stock_demand_estimate
from . import date_range

View File

@@ -0,0 +1,19 @@
# Copyright 2019 ForgeFlow S.L. (https://www.forgeflow.com)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from odoo import api, fields, models
class DateRange(models.Model):
_inherit = "date.range"
days = fields.Integer(
string="Days between dates",
compute="_compute_days",
readonly=True,
)
@api.depends("date_start", "date_end")
def _compute_days(self):
for rec in self.filtered(lambda x: x.date_start and x.date_end):
rec.days = abs((rec.date_end - rec.date_start).days) + 1

View File

@@ -0,0 +1,39 @@
# Copyright 2019 ForgeFlow S.L. (https://www.forgeflow.com)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from odoo import api, fields, models
class StockDemandEstimate(models.Model):
_inherit = "stock.demand.estimate"
date_range_id = fields.Many2one(
comodel_name="date.range", string="Estimating Period", ondelete="restrict"
)
@api.depends(
"date_range_id",
"manual_duration",
"manual_date_from",
"manual_date_to",
)
def _compute_dates(self):
date_range_records = self.filtered(lambda r: r.date_range_id)
res = super(StockDemandEstimate, self - date_range_records)._compute_dates()
for rec in date_range_records:
rec.date_from = rec.date_range_id.date_start
rec.date_to = rec.date_range_id.date_end
rec.duration = rec.date_range_id.days
return res
def name_get(self):
date_range_records = self.filtered(lambda r: r.date_range_id)
res = super(StockDemandEstimate, self - date_range_records).name_get()
for rec in date_range_records:
name = "{} - {} - {}".format(
rec.date_range_id.name,
rec.product_id.name,
rec.location_id.name,
)
res.append((rec.id, name))
return res

View File

@@ -0,0 +1,3 @@
[build-system]
requires = ["whool"]
build-backend = "whool.buildapi"

View File

@@ -0,0 +1,3 @@
- Jordi Ballester Alomar \<<jordi.ballester@forgeflow.com>\>
- Lois Rilo \<<lois.rilo@forgeflow.com>\>
- Pimolnat Suntian \<<pimolnats@ecosoft.co.th>\>

View File

@@ -0,0 +1,5 @@
This module allows to create demand estimates for a given product and
location, on configurable time periods.
The module does not provide in itself any specific usage of the
estimates.

View File

@@ -0,0 +1,7 @@
This module relies on:
- The OCA module '2D matrix for x2many fields', and can be downloaded
from Github:
<https://github.com/OCA/web/tree/13.0/web_widget_x2many_2d_matrix>
- The OCA module 'Date Range', and can be downloaded from Github:
<https://github.com/OCA/server-ux/tree/13.0/date_range>

View File

@@ -0,0 +1,8 @@
Go to *Inventory \> Configuration \> Date Ranges* and define your
estimating periods.
Go to *Inventory \> Demand Planning \> Create Demand Estimates* to
create or update your demand estimates.
Go to *Inventory \> Demand Planning \> Demand Estimates* to review the
estimates created.

View File

@@ -0,0 +1,4 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_stock_demand_estimate_sheet,access stock.demand.estimate.sheet,model_stock_demand_estimate_sheet,base.group_user,1,1,1,1
access_stock_demand_estimate_sheet_line,access stock.demand.estimate.sheet.line,model_stock_demand_estimate_sheet_line,base.group_user,1,1,1,1
access_stock_demand_estimate_wizard,access stock.demand.estimate.wizard,model_stock_demand_estimate_wizard,base.group_user,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_stock_demand_estimate_sheet access stock.demand.estimate.sheet model_stock_demand_estimate_sheet base.group_user 1 1 1 1
3 access_stock_demand_estimate_sheet_line access stock.demand.estimate.sheet.line model_stock_demand_estimate_sheet_line base.group_user 1 1 1 1
4 access_stock_demand_estimate_wizard access stock.demand.estimate.wizard model_stock_demand_estimate_wizard base.group_user 1 1 1 1

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

View File

@@ -0,0 +1,450 @@
<!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>Stock Demand Estimate Matrix</title>
<style type="text/css">
/*
:Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $
:Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils.
Despite the name, some widely supported CSS2 features are used.
See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to
customize this style sheet.
*/
/* used to remove borders from tables and images */
.borderless, table.borderless td, table.borderless th {
border: 0 }
table.borderless td, table.borderless th {
/* Override padding for "table.docutils td" with "! important".
The right padding separates the table cells. */
padding: 0 0.5em 0 0 ! important }
.first {
/* Override more specific margin styles with "! important". */
margin-top: 0 ! important }
.last, .with-subtitle {
margin-bottom: 0 ! important }
.hidden {
display: none }
.subscript {
vertical-align: sub;
font-size: smaller }
.superscript {
vertical-align: super;
font-size: smaller }
a.toc-backref {
text-decoration: none ;
color: black }
blockquote.epigraph {
margin: 2em 5em ; }
dl.docutils dd {
margin-bottom: 0.5em }
object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
overflow: hidden;
}
/* Uncomment (and remove this text!) to get bold-faced definition list terms
dl.docutils dt {
font-weight: bold }
*/
div.abstract {
margin: 2em 5em }
div.abstract p.topic-title {
font-weight: bold ;
text-align: center }
div.admonition, div.attention, div.caution, div.danger, div.error,
div.hint, div.important, div.note, div.tip, div.warning {
margin: 2em ;
border: medium outset ;
padding: 1em }
div.admonition p.admonition-title, div.hint p.admonition-title,
div.important p.admonition-title, div.note p.admonition-title,
div.tip p.admonition-title {
font-weight: bold ;
font-family: sans-serif }
div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title, .code .error {
color: red ;
font-weight: bold ;
font-family: sans-serif }
/* Uncomment (and remove this text!) to get reduced vertical space in
compound paragraphs.
div.compound .compound-first, div.compound .compound-middle {
margin-bottom: 0.5em }
div.compound .compound-last, div.compound .compound-middle {
margin-top: 0.5em }
*/
div.dedication {
margin: 2em 5em ;
text-align: center ;
font-style: italic }
div.dedication p.topic-title {
font-weight: bold ;
font-style: normal }
div.figure {
margin-left: 2em ;
margin-right: 2em }
div.footer, div.header {
clear: both;
font-size: smaller }
div.line-block {
display: block ;
margin-top: 1em ;
margin-bottom: 1em }
div.line-block div.line-block {
margin-top: 0 ;
margin-bottom: 0 ;
margin-left: 1.5em }
div.sidebar {
margin: 0 0 0.5em 1em ;
border: medium outset ;
padding: 1em ;
background-color: #ffffee ;
width: 40% ;
float: right ;
clear: right }
div.sidebar p.rubric {
font-family: sans-serif ;
font-size: medium }
div.system-messages {
margin: 5em }
div.system-messages h1 {
color: red }
div.system-message {
border: medium outset ;
padding: 1em }
div.system-message p.system-message-title {
color: red ;
font-weight: bold }
div.topic {
margin: 2em }
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
margin-top: 0.4em }
h1.title {
text-align: center }
h2.subtitle {
text-align: center }
hr.docutils {
width: 75% }
img.align-left, .figure.align-left, object.align-left, table.align-left {
clear: left ;
float: left ;
margin-right: 1em }
img.align-right, .figure.align-right, object.align-right, table.align-right {
clear: right ;
float: right ;
margin-left: 1em }
img.align-center, .figure.align-center, object.align-center {
display: block;
margin-left: auto;
margin-right: auto;
}
table.align-center {
margin-left: auto;
margin-right: auto;
}
.align-left {
text-align: left }
.align-center {
clear: both ;
text-align: center }
.align-right {
text-align: right }
/* reset inner alignment in figures */
div.align-right {
text-align: inherit }
/* div.align-center * { */
/* text-align: left } */
.align-top {
vertical-align: top }
.align-middle {
vertical-align: middle }
.align-bottom {
vertical-align: bottom }
ol.simple, ul.simple {
margin-bottom: 1em }
ol.arabic {
list-style: decimal }
ol.loweralpha {
list-style: lower-alpha }
ol.upperalpha {
list-style: upper-alpha }
ol.lowerroman {
list-style: lower-roman }
ol.upperroman {
list-style: upper-roman }
p.attribution {
text-align: right ;
margin-left: 50% }
p.caption {
font-style: italic }
p.credits {
font-style: italic ;
font-size: smaller }
p.label {
white-space: nowrap }
p.rubric {
font-weight: bold ;
font-size: larger ;
color: maroon ;
text-align: center }
p.sidebar-title {
font-family: sans-serif ;
font-weight: bold ;
font-size: larger }
p.sidebar-subtitle {
font-family: sans-serif ;
font-weight: bold }
p.topic-title {
font-weight: bold }
pre.address {
margin-bottom: 0 ;
margin-top: 0 ;
font: inherit }
pre.literal-block, pre.doctest-block, pre.math, pre.code {
margin-left: 2em ;
margin-right: 2em }
pre.code .ln { color: gray; } /* line numbers */
pre.code, code { background-color: #eeeeee }
pre.code .comment, code .comment { color: #5C6576 }
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
pre.code .literal.string, code .literal.string { color: #0C5404 }
pre.code .name.builtin, code .name.builtin { color: #352B84 }
pre.code .deleted, code .deleted { background-color: #DEB0A1}
pre.code .inserted, code .inserted { background-color: #A3D289}
span.classifier {
font-family: sans-serif ;
font-style: oblique }
span.classifier-delimiter {
font-family: sans-serif ;
font-weight: bold }
span.interpreted {
font-family: sans-serif }
span.option {
white-space: nowrap }
span.pre {
white-space: pre }
span.problematic, pre.problematic {
color: red }
span.section-subtitle {
/* font-size relative to parent (h1..h6 element) */
font-size: 80% }
table.citation {
border-left: solid 1px gray;
margin-left: 1px }
table.docinfo {
margin: 2em 4em }
table.docutils {
margin-top: 0.5em ;
margin-bottom: 0.5em }
table.footnote {
border-left: solid 1px black;
margin-left: 1px }
table.docutils td, table.docutils th,
table.docinfo td, table.docinfo th {
padding-left: 0.5em ;
padding-right: 0.5em ;
vertical-align: top }
table.docutils th.field-name, table.docinfo th.docinfo-name {
font-weight: bold ;
text-align: left ;
white-space: nowrap ;
padding-left: 0 }
/* "booktabs" style (no vertical lines) */
table.docutils.booktabs {
border: 0px;
border-top: 2px solid;
border-bottom: 2px solid;
border-collapse: collapse;
}
table.docutils.booktabs * {
border: 0px;
}
table.docutils.booktabs th {
border-bottom: thin solid;
text-align: left;
}
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
font-size: 100% }
ul.auto-toc {
list-style-type: none }
</style>
</head>
<body>
<div class="document" id="stock-demand-estimate-matrix">
<h1 class="title">Stock Demand Estimate Matrix</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:dd6235ad9f824ac586e403e2c2a17b00c6cb981efee47edf1409ed6693a44f61
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Production/Stable" src="https://img.shields.io/badge/maturity-Production%2FStable-green.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/stock-logistics-warehouse/tree/17.0/stock_demand_estimate_matrix"><img alt="OCA/stock-logistics-warehouse" src="https://img.shields.io/badge/github-OCA%2Fstock--logistics--warehouse-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/stock-logistics-warehouse-17-0/stock-logistics-warehouse-17-0-stock_demand_estimate_matrix"><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/stock-logistics-warehouse&amp;target_branch=17.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
<p>This module allows to create demand estimates for a given product and
location, on configurable time periods.</p>
<p>The module does not provide in itself any specific usage of the
estimates.</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="#usage" id="toc-entry-2">Usage</a></li>
<li><a class="reference internal" href="#bug-tracker" id="toc-entry-3">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="toc-entry-4">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="toc-entry-5">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="toc-entry-6">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="toc-entry-7">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="installation">
<h1><a class="toc-backref" href="#toc-entry-1">Installation</a></h1>
<p>This module relies on:</p>
<ul class="simple">
<li>The OCA module 2D matrix for x2many fields, and can be downloaded
from Github:
<a class="reference external" href="https://github.com/OCA/web/tree/13.0/web_widget_x2many_2d_matrix">https://github.com/OCA/web/tree/13.0/web_widget_x2many_2d_matrix</a></li>
<li>The OCA module Date Range, and can be downloaded from Github:
<a class="reference external" href="https://github.com/OCA/server-ux/tree/13.0/date_range">https://github.com/OCA/server-ux/tree/13.0/date_range</a></li>
</ul>
</div>
<div class="section" id="usage">
<h1><a class="toc-backref" href="#toc-entry-2">Usage</a></h1>
<p>Go to <em>Inventory &gt; Configuration &gt; Date Ranges</em> and define your
estimating periods.</p>
<p>Go to <em>Inventory &gt; Demand Planning &gt; Create Demand Estimates</em> to create
or update your demand estimates.</p>
<p>Go to <em>Inventory &gt; Demand Planning &gt; Demand Estimates</em> to review the
estimates created.</p>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#toc-entry-3">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/stock-logistics-warehouse/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/stock-logistics-warehouse/issues/new?body=module:%20stock_demand_estimate_matrix%0Aversion:%2017.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p>
</div>
<div class="section" id="credits">
<h1><a class="toc-backref" href="#toc-entry-4">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#toc-entry-5">Authors</a></h2>
<ul class="simple">
<li>ForgeFlow</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#toc-entry-6">Contributors</a></h2>
<ul class="simple">
<li>Jordi Ballester Alomar &lt;<a class="reference external" href="mailto:jordi.ballester&#64;forgeflow.com">jordi.ballester&#64;forgeflow.com</a>&gt;</li>
<li>Lois Rilo &lt;<a class="reference external" href="mailto:lois.rilo&#64;forgeflow.com">lois.rilo&#64;forgeflow.com</a>&gt;</li>
<li>Pimolnat Suntian &lt;<a class="reference external" href="mailto:pimolnats&#64;ecosoft.co.th">pimolnats&#64;ecosoft.co.th</a>&gt;</li>
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#toc-entry-7">Maintainers</a></h2>
<p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org">
<img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" />
</a>
<p>OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.</p>
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/stock-logistics-warehouse/tree/17.0/stock_demand_estimate_matrix">OCA/stock-logistics-warehouse</a> project on GitHub.</p>
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
</div>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,3 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from . import test_stock_demand_estimate

View File

@@ -0,0 +1,343 @@
# Copyright 2019 ForgeFlow S.L. (https://www.forgeflow.com)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from datetime import datetime
from dateutil.rrule import MONTHLY
from odoo import fields
from odoo.exceptions import UserError, ValidationError
from odoo.tests.common import TransactionCase
class TestStockDemandEstimate(TransactionCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.res_users_model = cls.env["res.users"]
cls.product_model = cls.env["product.product"]
cls.stock_location_model = cls.env["stock.location"]
cls.estimate_model = cls.env["stock.demand.estimate"]
cls.g_stock_manager = cls.env.ref("stock.group_stock_manager")
cls.g_stock_user = cls.env.ref("stock.group_stock_user")
cls.company = cls.env.ref("base.main_company")
# Create users:
cls.manager = cls._create_user(
"user_1",
[cls.g_stock_manager],
cls.company,
).id
cls.user = cls._create_user(
"user_2",
[cls.g_stock_user],
cls.company,
).id
cls.drt_monthly = cls.env["date.range.type"].create(
{"name": "Month", "allow_overlap": False}
)
generator = cls.env["date.range.generator"].create(
{
"date_start": "1943-01-01",
"name_prefix": "1943-",
"type_id": cls.drt_monthly.id,
"duration_count": 1,
"unit_of_time": str(MONTHLY),
"count": 12,
}
)
generator.action_apply()
# Create a product:
cls.product_1 = cls.product_model.create(
{"name": "Test Product 1", "type": "product", "default_code": "PROD1"}
)
# Create a location:
cls.location = cls.stock_location_model.create(
{"name": "Place", "usage": "production"}
)
@classmethod
def _create_user(cls, login, groups, company):
group_ids = [group.id for group in groups]
user = cls.res_users_model.create(
{
"name": login,
"login": login,
"password": "demo",
"email": "example@yourcompany.com",
"company_id": company.id,
"company_ids": [(4, company.id)],
"groups_id": [(6, 0, group_ids)],
}
)
return user
def test_01_demand_estimate_wizard(self):
"""Tests creation of demand estimates using wizard."""
sheets = self.env["stock.demand.estimate.sheet"].search([])
list(map(lambda sheet: sheet.unlink(), sheets))
wiz = self.env["stock.demand.estimate.wizard"]
wiz = wiz.create(
{
"date_start": "1943-01-01",
"date_end": "1943-12-31",
"location_id": self.location.id,
"date_range_type_id": self.drt_monthly.id,
"product_ids": [(6, 0, [self.product_1.id])],
}
)
wiz.create_sheet()
sheets = self.env["stock.demand.estimate.sheet"].search([])
for sheet in sheets:
self.assertEqual(
len(sheet.line_ids),
12,
"There should be 12 lines.",
)
self.assertEqual(
fields.Date.to_string(sheet.date_start),
"1943-01-01",
"The date start should be 1943-01-01",
)
self.assertEqual(
fields.Date.to_string(sheet.date_end),
"1943-12-31",
"The date end should be 1943-12-31",
)
self.assertEqual(
sheet.location_id.id,
self.location.id,
"Wrong location",
)
for line in sheet.line_ids:
line.product_uom_qty = 1
self.assertEqual(
line.product_id.id,
self.product_1.id,
"The product does not match in the line",
)
self.assertEqual(
line.location_id.id,
self.location.id,
"The product does not match in the line",
)
sheet.button_validate()
ranges = self.env["date.range"].search(
[("type_id", "=", self.drt_monthly.id)],
)
estimates = self.env["stock.demand.estimate"].search(
[("date_range_id", "in", ranges.ids)]
)
self.assertEqual(
len(estimates),
12,
"There should be 12 estimate records.",
)
for estimate in estimates:
self.assertEqual(
estimate.product_id.id,
self.product_1.id,
"The product does not match in the estimate",
)
self.assertEqual(
estimate.location_id.id,
self.location.id,
"The product does not match in the estimate",
)
sheets = self.env["stock.demand.estimate.sheet"].search([])
for sheet in sheets:
sheet.unlink()
wiz = self.env["stock.demand.estimate.wizard"]
wiz = wiz.create(
{
"date_start": "1943-01-01",
"date_end": "1943-12-31",
"location_id": self.location.id,
"date_range_type_id": self.drt_monthly.id,
"product_ids": [(6, 0, [self.product_1.id])],
}
)
wiz.create_sheet()
sheets = self.env["stock.demand.estimate.sheet"].search([])
for sheet in sheets:
for line in sheet.line_ids:
self.assertEqual(
line.product_uom_qty,
1,
"The quantity should be 1",
)
def test_02_invalid_dates(self):
wiz = self.env["stock.demand.estimate.wizard"]
with self.assertRaises(ValidationError):
wiz.create(
{
"date_start": "1943-12-31",
"date_end": "1943-01-01",
"location_id": self.location.id,
"date_range_type_id": self.drt_monthly.id,
"product_ids": [(6, 0, [self.product_1.id])],
}
)
def test_03_computed_fields(self):
date_range = self.env["date.range"].search(
[("type_id", "=", self.drt_monthly.id)], limit=1
)
estimate = self.estimate_model.create(
{
"product_id": self.product_1.id,
"location_id": self.location.id,
"date_range_id": date_range.id,
"product_uom_qty": 100.0,
}
)
expected_date_from = date_range.date_start
expected_date_to = date_range.date_end
self.assertEqual(estimate.date_from, expected_date_from)
self.assertEqual(estimate.date_to, expected_date_to)
def test_04_name_get(self):
date_range = self.env["date.range"].create(
{
"name": "Test Date Range",
"type_id": self.drt_monthly.id,
"date_start": "2023-01-01",
"date_end": "2023-01-31",
}
)
estimate = self.estimate_model.create(
{
"product_id": self.product_1.id,
"location_id": self.location.id,
"date_range_id": date_range.id,
"product_uom_qty": 100.0,
}
)
estimate_name = "{} - {} - {}".format(
date_range.name,
self.product_1.name,
self.location.name,
)
estimate_name_get = estimate.name_get()
self.assertEqual(estimate_name_get, [(estimate.id, estimate_name)])
def test_05_onchange_date_range_type_id(self):
company = self.env["res.company"].create({"name": "Test Company"})
date_range_type = self.env["date.range.type"].create(
{
"name": "Test Date Range Type",
"allow_overlap": False,
"company_id": company.id,
}
)
wizard = self.env["stock.demand.estimate.wizard"].create(
{
"date_start": "1943-01-01",
"date_end": "1943-12-31",
"location_id": self.location.id,
"date_range_type_id": date_range_type.id,
"product_ids": [(6, 0, [self.product_1.id])],
}
)
result = wizard._onchange_date_range_type_id()
location_domain = result.get("domain", {}).get("location_id", [])
expected_domain = [
("company_id", "=", company.id),
]
self.assertEqual(location_domain, expected_domain)
def test_06_prepare_demand_estimate_sheet(self):
wizard = self.env["stock.demand.estimate.wizard"].create(
{
"date_start": "2023-01-01",
"date_end": "2023-12-31",
"location_id": self.location.id,
"date_range_type_id": self.drt_monthly.id,
"product_ids": [(6, 0, [self.product_1.id])],
}
)
sheet_values = wizard._prepare_demand_estimate_sheet()
expected_values = {
"date_start": datetime.strptime("2023-01-01", "%Y-%m-%d").date(),
"date_end": datetime.strptime("2023-12-31", "%Y-%m-%d").date(),
"date_range_type_id": self.drt_monthly.id,
"location_id": self.location.id,
}
self.assertEqual(sheet_values, expected_values)
def test_07_create_sheet(self):
wizard = self.env["stock.demand.estimate.wizard"].create(
{
"date_start": "2023-01-01",
"date_end": "2023-12-31",
"location_id": self.location.id,
"date_range_type_id": self.drt_monthly.id,
"product_ids": [],
}
)
with self.assertRaises(UserError):
wizard.create_sheet()
def test_08_button_validate(self):
sheet = self.env["stock.demand.estimate.sheet"].create(
{
"date_start": "2023-01-01",
"date_end": "2023-12-31",
"date_range_type_id": self.drt_monthly.id,
"location_id": self.location.id,
}
)
product = self.env["product.product"].create({"name": "Test Product"})
line1 = self.env["stock.demand.estimate.sheet.line"].create(
{
"product_id": product.id,
"product_uom_qty": 10,
"estimate_id": self.env["stock.demand.estimate"]
.create(
{
"product_id": product.id,
"product_uom_qty": 10,
"location_id": self.location.id,
}
)
.id,
}
)
line2 = self.env["stock.demand.estimate.sheet.line"].create(
{
"product_id": product.id,
"product_uom_qty": 20,
"estimate_id": self.env["stock.demand.estimate"]
.create(
{
"product_id": product.id,
"product_uom_qty": 100,
"location_id": self.location.id,
}
)
.id,
}
)
sheet.line_ids = [line1.id, line2.id]
res = sheet.button_validate()
self.assertEqual(line2.estimate_id.product_uom_qty, line2.product_uom_qty)
self.assertEqual(
res,
{
"domain": [("id", "in", [line1.estimate_id.id, line2.estimate_id.id])],
"name": "Stock Demand Estimates",
"src_model": "stock.demand.estimate.wizard",
"view_type": "form",
"view_mode": "tree",
"res_model": "stock.demand.estimate",
"type": "ir.actions.act_window",
},
)

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" ?>
<odoo>
<menuitem
id="date_range_menu"
name="Date Ranges"
parent="stock.menu_stock_config_settings"
action="date_range.date_range_action"
sequence="99"
/>
</odoo>

View File

@@ -0,0 +1,47 @@
<?xml version="1.0" ?>
<odoo>
<record id="stock_demand_estimate_view_tree" model="ir.ui.view">
<field name="name">stock.demand.estimate.tree</field>
<field name="model">stock.demand.estimate</field>
<field
name="inherit_id"
ref="stock_demand_estimate.stock_demand_estimate_view_tree"
/>
<field name="arch" type="xml">
<field name="date_from" position="before">
<field name="date_range_id" />
</field>
<tree position="attributes">
<attribute name="edit">1</attribute>
<attribute name="editable">bottom</attribute>
</tree>
</field>
</record>
<record id="stock_demand_estimate_view_pivot" model="ir.ui.view">
<field name="name">stock.demand.estimate.pivot</field>
<field name="model">stock.demand.estimate</field>
<field
name="inherit_id"
ref="stock_demand_estimate.stock_demand_estimate_view_pivot"
/>
<field name="arch" type="xml">
<field name="product_id" position="after">
<field name="date_range_id" type="col" />
</field>
</field>
</record>
<record id="stock_demand_estimate_view_search" model="ir.ui.view">
<field name="name">stock.demand.estimate.search</field>
<field name="model">stock.demand.estimate</field>
<field
name="inherit_id"
ref="stock_demand_estimate.stock_demand_estimate_view_search"
/>
<field name="arch" type="xml">
<field name="location_id" position="after">
<field name="date_range_id" />
</field>
</field>
</record>
</odoo>

View File

@@ -0,0 +1,5 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from . import stock_demand_estimate_wizard
from . import stock_demand_estimate_sheet
from . import stock_demand_estimate_sheet_line

View File

@@ -0,0 +1,161 @@
# Copyright 2019 ForgeFlow S.L. (https://www.forgeflow.com)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from odoo import _, api, fields, models
from odoo.exceptions import UserError
from odoo.osv import expression
class StockDemandEstimateSheet(models.TransientModel):
_name = "stock.demand.estimate.sheet"
_description = "Stock Demand Estimate Sheet"
date_start = fields.Date(
string="Date From",
readonly=True,
)
date_end = fields.Date(
string="Date to",
readonly=True,
)
date_range_type_id = fields.Many2one(
string="Date Range Type",
comodel_name="date.range.type",
readonly=True,
)
location_id = fields.Many2one(
comodel_name="stock.location",
string="Location",
readonly=True,
)
line_ids = fields.Many2many(
string="Estimates",
comodel_name="stock.demand.estimate.sheet.line",
relation="stock_demand_estimate_line_rel",
)
product_ids = fields.Many2many(
string="Products",
comodel_name="product.product",
)
@api.onchange(
"date_start",
"date_end",
"date_range_type_id",
)
def _onchange_dates(self):
for sheet in self:
if not all([sheet.date_start, sheet.date_end, sheet.date_range_type_id]):
return
ranges = sheet._get_ranges()
if not ranges:
raise UserError(_("There is no ranges created."))
estimates = self.env["stock.demand.estimate"].search(
[
("product_id", "in", sheet.product_ids.ids),
("date_range_id", "in", ranges.ids),
("location_id", "=", sheet.location_id.id),
]
)
lines = []
for product in sheet.product_ids:
for _range in ranges:
estimate = estimates.filtered(
lambda x, _range=_range, product=product: (
x.date_range_id == _range and x.product_id == product
)
)
if estimate:
uom_id = fields.first(estimate).product_uom.id
uom_qty = estimate[0].product_uom_qty
estimate_id = estimate[0].id
else:
uom_id = product.uom_id.id
uom_qty = 0.0
estimate_id = None
lines.append(
(
0,
0,
sheet._get_default_estimate_line(
_range,
product,
uom_id,
uom_qty,
estimate_id=estimate_id,
),
)
)
sheet.line_ids = lines
def _get_ranges(self):
domain_1 = [
"&",
("type_id", "=", self.date_range_type_id.id),
"|",
"&",
("date_start", ">=", self.date_start),
("date_start", "<=", self.date_end),
"&",
("date_end", ">=", self.date_start),
("date_end", "<=", self.date_end),
]
domain_2 = [
"&",
("type_id", "=", self.date_range_type_id.id),
"&",
("date_start", "<=", self.date_start),
("date_end", ">=", self.date_start),
]
domain = expression.OR([domain_1, domain_2])
ranges = self.env["date.range"].search(domain)
return ranges
def _get_default_estimate_line(
self, _range, product, uom_id, uom_qty, estimate_id=None
):
name_y = f"{product.name} - {product.uom_id.name}"
if product.default_code:
name_y += f"[{product.default_code}] {name_y}"
values = {
"value_x": _range.name,
"value_y": name_y,
"date_range_id": _range.id,
"product_id": product.id,
"product_uom": uom_id,
"product_uom_qty": uom_qty,
"location_id": self.location_id.id,
"estimate_id": estimate_id,
}
return values
@api.model
def _prepare_estimate_data(self, line):
return {
"date_range_id": line.date_range_id.id,
"product_id": line.product_id.id,
"location_id": line.location_id.id,
"product_uom_qty": line.product_uom_qty,
"product_uom": line.product_id.uom_id.id,
}
def button_validate(self):
res = []
for line in self.line_ids:
if line.estimate_id:
line.estimate_id.product_uom_qty = line.product_uom_qty
res.append(line.estimate_id.id)
else:
data = self._prepare_estimate_data(line)
estimate = self.env["stock.demand.estimate"].create(data)
res.append(estimate.id)
res = {
"domain": [("id", "in", res)],
"name": _("Stock Demand Estimates"),
"src_model": "stock.demand.estimate.wizard",
"view_type": "form",
"view_mode": "tree",
"res_model": "stock.demand.estimate",
"type": "ir.actions.act_window",
}
return res

View File

@@ -0,0 +1,20 @@
# Copyright 2019 ForgeFlow S.L. (https://www.forgeflow.com)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from odoo import fields, models
class StockDemandEstimateSheetLine(models.TransientModel):
_name = "stock.demand.estimate.sheet.line"
_description = "Stock Demand Estimate Sheet Line"
estimate_id = fields.Many2one(comodel_name="stock.demand.estimate")
date_range_id = fields.Many2one(comodel_name="date.range", string="Period")
location_id = fields.Many2one(
comodel_name="stock.location", string="Stock Location"
)
product_id = fields.Many2one(comodel_name="product.product", string="Product")
value_x = fields.Char(string="Period Name")
value_y = fields.Char(string="Product Name")
product_uom = fields.Many2one(comodel_name="uom.uom", string="Unit of measure")
product_uom_qty = fields.Float(string="Quantity", digits="Product UoM")

View File

@@ -0,0 +1,91 @@
# Copyright 2019 ForgeFlow S.L. (https://www.forgeflow.com)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from odoo import _, api, fields, models
from odoo.exceptions import UserError, ValidationError
class DemandEstimateWizard(models.TransientModel):
_name = "stock.demand.estimate.wizard"
_description = "Stock Demand Estimate Wizard"
date_start = fields.Date(
string="Date From",
required=True,
)
date_end = fields.Date(
string="Date To",
required=True,
)
date_range_type_id = fields.Many2one(
string="Date Range Type",
comodel_name="date.range.type",
required=True,
)
location_id = fields.Many2one(
comodel_name="stock.location",
string="Location",
required=True,
)
product_ids = fields.Many2many(
comodel_name="product.product",
string="Products",
)
@api.onchange("date_range_type_id")
def _onchange_date_range_type_id(self):
if self.date_range_type_id.company_id:
return {
"domain": {
"location_id": [
("company_id", "=", self.date_range_type_id.company_id.id)
]
}
}
return {}
@api.constrains("date_start", "date_end")
def _check_start_end_dates(self):
self.ensure_one()
if self.date_start > self.date_end:
raise ValidationError(
_("The start date cannot be later than the end date.")
)
def _prepare_demand_estimate_sheet(self):
self.ensure_one()
return {
"date_start": self.date_start,
"date_end": self.date_end,
"date_range_type_id": self.date_range_type_id.id,
"location_id": self.location_id.id,
}
def create_sheet(self):
self.ensure_one()
if not self.product_ids:
raise UserError(_("You must select at least one product."))
# 2d matrix widget need real records to work
sheet = self.env["stock.demand.estimate.sheet"].create(
{
"date_start": self.date_start,
"date_end": self.date_end,
"date_range_type_id": self.date_range_type_id.id,
"location_id": self.location_id.id,
"product_ids": [(6, 0, self.product_ids.ids)],
}
)
sheet._onchange_dates()
res = {
"name": _("Estimate Sheet"),
"src_model": "stock.demand.estimate.wizard",
"view_type": "form",
"view_mode": "form",
"target": "new",
"res_model": "stock.demand.estimate.sheet",
"res_id": sheet.id,
"type": "ir.actions.act_window",
}
return res

View File

@@ -0,0 +1,103 @@
<?xml version="1.0" ?>
<odoo>
<record id="stock_demand_estimate_sheet_view_form" model="ir.ui.view">
<field name="name">stock.demand.estimate.sheet.form</field>
<field name="model">stock.demand.estimate.sheet</field>
<field name="arch" type="xml">
<form string="Stock Demand Estimate Sheet">
<group name="dates">
<label for="date_start" string="Period" />
<div><field name="date_start" class="oe_inline" /> to <field
name="date_end"
class="oe_inline"
/></div>
</group>
<group>
<group name="attributes" colspan="2">
<field name="date_range_type_id" />
<field name="location_id" />
</group>
</group>
<notebook>
<page name="estimated_quantity" string="Estimated quantity">
<field
name="line_ids"
nolabel="1"
widget="x2many_2d_matrix"
field_x_axis="value_x"
field_y_axis="value_y"
field_value="product_uom_qty"
x_axis_clickable="0"
y_axis_clickable="0"
>
<tree>
<field name="value_x" />
<field name="value_y" />
<field name="product_uom_qty" />
</tree>
</field>
</page>
</notebook>
<footer>
<button
name="button_validate"
type="object"
string="Validate"
class="oe_highlight"
/>
<button class="oe_link" special="cancel" string="Cancel" />
</footer>
</form>
</field>
</record>
<record id="demand_estimate_wizard_view_form" model="ir.ui.view">
<field name="name">stock.demand.estimate.wizard.form</field>
<field name="model">stock.demand.estimate.wizard</field>
<field name="arch" type="xml">
<form string="Stock Demand Estimate Wizard">
<sheet>
<group name="dates">
<label for="date_start" string="Period" />
<div>
<field name="date_start" class="oe_inline" />
to
<field name="date_end" class="oe_inline" />
</div>
</group>
<group>
<group name="attributes">
<field name="date_range_type_id" />
<field name="location_id" />
</group>
</group>
<notebook>
<page name="products" string="Products">
<field name="product_ids" nolabel="1" />
</page>
</notebook>
</sheet>
<footer>
<button
name="create_sheet"
string="Prepare"
type="object"
class="oe_highlight"
/>
<button string="Cancel" class="oe_link" special="cancel" />
</footer>
</form>
</field>
</record>
<record id="stock_demand_estimate_wizard_action" model="ir.actions.act_window">
<field name="name">Create Stock Demand Estimates</field>
<field name="res_model">stock.demand.estimate.wizard</field>
<field name="view_mode">form</field>
<field name="target">new</field>
<field name="binding_model_id" ref="model_stock_demand_estimate_sheet" />
</record>
<menuitem
id="stock_demand_estimate_wizard_menu"
parent="stock_demand_estimate.stock_demand_planning_menu"
action="stock_demand_estimate_wizard_action"
/>
</odoo>