Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add stock_reorder_forecast module with tests
- Loading branch information
Showing
30 changed files
with
2,013 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg | ||
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html | ||
:alt: License: AGPL-3 | ||
|
||
====================== | ||
Stock Reorder Forecast | ||
====================== | ||
|
||
|
||
Allows to predict date when stock levels will reach minimum by | ||
analizying sales volume in a period and therefore to trigger RFQ's ahead | ||
of time | ||
|
||
Extends stock to calculate period turnover and ultimate date of order | ||
(the date where we reach minimum stock) | ||
This module allows to create RFQ's by checking the product form and | ||
examining the ultimate purchase value. | ||
|
||
The ultimate purchase value is the date we forecast this product will not be | ||
available. It is obtained by calculating the average sales rate of this | ||
product and predicting at this rate how long will it take for the | ||
stock to reach 0 at this speed. | ||
|
||
The period upon wich we calculate this average rate be personalized, default is: | ||
|
||
TURNOVER_PERIOD = Amount of time to calculate average (default 365) | ||
TURNOVER_AVERAGE = Average sale rate in that period. | ||
Ultimate Purchase = Day in the future where stock should finish at current | ||
rate. | ||
|
||
All values are (period, average) are kept on (in order of importance): | ||
* Supplier Info | ||
* Partner | ||
* Category | ||
|
||
if the values are not set on supplier info it will default to values on | ||
partner, if not set on supplier will default to category, if not set anywhere | ||
will default to Hardcoded values (ir.config.parameters period=365 days). | ||
|
||
THe user can also trigger orders from the supplier form. There is a wizard | ||
that would allow to order: | ||
|
||
* All the products provided by this partner (in required amounts | ||
considering turnover_average, current stock and maximum_stock) | ||
* All the products provided by this partner as primary supplier | ||
|
||
This wizard also provides an overview of existing RFQ lines | ||
|
||
The turnover average and the ultimate purchase derived by it are calculated in | ||
bulk by a daily cron job. | ||
|
||
|
||
Configuration | ||
============= | ||
|
||
To configure this module, you need to: | ||
set turnover_period stock_period_max , stock_period_min on: | ||
|
||
* Product | ||
* Supplier Infos | ||
* Partners | ||
* Categories | ||
* Default value | ||
|
||
These values will be taken in this order of priority (highest to lowest) | ||
if the values in product, Supplier Info, Partners, Categories are all not | ||
set it will revert to Default Value, defined in installation data is a | ||
company parameter. | ||
|
||
Also set the frequency of turnover and purchase date calculation by setting | ||
in Automatic Actions the execution of cron job "Purchase Proposal Refresh" | ||
(by default set at once a day). | ||
|
||
|
||
Usage | ||
===== | ||
|
||
Set on product and/or partner(supplier) and/or product category the values | ||
of turnover period. | ||
|
||
Make sure the cron job "Purchase Proposal Refresh" is activated, launch it | ||
manually the first time in order to have all "ultimate dates" for products | ||
calculated. Set the cron job time/date at a convenient time and frequency, this | ||
job will refresh all stats used for forcasting ultimate purchase date. If you | ||
have a high volume of sales and do frequent resupplies it is advisable to | ||
launch it multiple times a day. | ||
|
||
|
||
View products to see all products with an ultimate order date, for that | ||
interface you can generate a RFQ to desired date. | ||
|
||
You can also view from the partner/supplier form all products ordered by this | ||
partner. | ||
|
||
#. Go to ... | ||
|
||
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas | ||
:alt: Try me on Runbot | ||
:target: https://runbot.odoo-community.org/runbot/{repo_id}/{branch} | ||
|
||
.. repo_id is available in https://github.com/OCA/maintainer-tools/blob/master/tools/repos_with_ids.txt | ||
.. branch is "9.0" for example | ||
Known issues / Roadmap | ||
====================== | ||
* Does not support Multicompany, calculation of stats will allways work on | ||
cross-company products purchases and pickings. It will only calculate outgoing | ||
moves , not internal moves. So the stats will be representative of all | ||
companies global stats (all sales from all companies/turnover period of | ||
product). | ||
|
||
Implementing a full multicompany support will require additional support | ||
datastrutures. | ||
|
||
from a functional stand point, the global stats may be still usefull in some | ||
multicompany configurations, not all. | ||
|
||
|
||
* Another useful feature would be to trigger RFQ's automatically. Currently | ||
the users receive stats and can press a button to make a RFQ based on their | ||
decisions. we could make options to make an automatic RFQ when ultimate | ||
purchase gets up to X days from now. | ||
|
||
|
||
Bug Tracker | ||
=========== | ||
|
||
Bugs are tracked on `GitHub Issues | ||
<https://github.com/OCA/{project_repo}/issues>`_. In case of trouble, please | ||
check there if your issue has already been reported. If you spotted it first, | ||
help us smashing it by providing a detailed and welcomed feedback. | ||
|
||
Images | ||
------ | ||
|
||
* Odoo Community Association: `Icon <https://github.com/OCA/maintainer-tools/blob/master/template/module/static/description/icon.svg>`_. | ||
|
||
Contributors | ||
------------ | ||
|
||
* Giovanni Francesco Capalbo <giovanni@therp.nl> | ||
* Holger Brunn <hbrunn@therp.nl> | ||
* Hans Van Dijk <hvd400@gmail.com> | ||
* Ronald Portier <rportier@therp.nl> | ||
|
||
Funders | ||
------- | ||
|
||
The development of this module has been financially supported by: | ||
|
||
* Therp B.V. | ||
|
||
Maintainer | ||
---------- | ||
|
||
.. image:: https://odoo-community.org/logo.png | ||
:alt: Odoo Community Association | ||
:target: https://odoo-community.org | ||
|
||
This module is maintained by the OCA. | ||
|
||
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. | ||
|
||
To contribute to this module, please visit https://odoo-community.org. | ||
|
||
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg | ||
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html | ||
:alt: License: AGPL-3 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# -*- coding: utf-8 -*- | ||
# © 2016 Therp BV <http://therp.nl> | ||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). | ||
from . import models | ||
from . import wizards |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
# -*- coding: utf-8 -*- | ||
# © 2016 Therp BV <http://therp.nl> | ||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). | ||
{ | ||
"name": "Stock reorder forecast", | ||
"version": "9.0.1.0.0", | ||
"author": "Therp BV,Odoo Community Association (OCA)", | ||
"license": "AGPL-3", | ||
"category": "Stock", | ||
"summary": "Predict date stock levels will reach minimum and trigger RFQ", | ||
"depends": [ | ||
'product', | ||
'stock', | ||
'sale', | ||
'purchase' | ||
], | ||
"demo": [ | ||
'demo/data.xml', | ||
], | ||
"data": [ | ||
'data/ir_config_parameter.xml', | ||
'wizards/purchase_wizard.xml', | ||
'wizards/purchase_supplier_wizard.xml', | ||
'views/product_product.xml', | ||
"views/product_template.xml", | ||
'views/product_supplierinfo.xml', | ||
'views/product_category.xml', | ||
'views/partner_view.xml', | ||
'data/cron.xml', | ||
], | ||
"installable": True, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<openerp> | ||
<data noupdate="1"> | ||
<record forcecreate="True" id="ir_cron_mail_scheduler_action" model="ir.cron"> | ||
<field name="name">Purchase Proposal Refresh</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 eval="False" name="doall"/> | ||
<field eval="'product.product'" name="model"/> | ||
<field eval="'calc_purchase_date'" name="function"/> | ||
<field eval="'()'" name="args"/> | ||
</record> | ||
</data> | ||
</openerp> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
<?xml version="1.0"?> | ||
<openerp> | ||
<data noupdate="1"> | ||
<record id="config_turnover_period" model="ir.config_parameter"> | ||
<field name="key">default_turnover_period</field> | ||
<field name="value">365</field> | ||
</record> | ||
|
||
<record id="config_default_period_min" model="ir.config_parameter"> | ||
<field name="key">default_period_min</field> | ||
<field name="value">91</field> | ||
</record> | ||
|
||
<record id="config_default_period_max" model="ir.config_parameter"> | ||
<field name="key">default_period_max</field> | ||
<field name="value">185</field> | ||
</record> | ||
|
||
<record id="config_default_purchase_multiple" model="ir.config_parameter"> | ||
<field name="key">default_purchase_multiple</field> | ||
<field name="value">1.0</field> | ||
</record> | ||
</data> | ||
</openerp> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<openerp> | ||
<data noupdate="1"> | ||
<record id="product_template1" model="product.template"> | ||
<field name="name">TMPL1</field> | ||
<field | ||
name="route_ids" | ||
eval="[(6,0,[ref('purchase.route_warehouse0_buy'), ref('stock.route_warehouse0_mto')])]"></field> | ||
<field name="categ_id" ref="product.product_category_5"></field> | ||
</record> | ||
|
||
<record id="product_template2" model="product.template"> | ||
<field name="name">TMPL2</field> | ||
<field | ||
name="route_ids" | ||
eval="[(6,0,[ref('purchase.route_warehouse0_buy'), ref('stock.route_warehouse0_mto')])]"></field> | ||
<field name="categ_id" ref="product.product_category_2"></field> | ||
</record> | ||
|
||
<record id="product_template3" model="product.template"> | ||
<field name="name">TMPL3</field> | ||
<field | ||
name="route_ids" | ||
eval="[(6,0,[ref('purchase.route_warehouse0_buy'), ref('stock.route_warehouse0_mto')])]"></field> | ||
|
||
<field name="categ_id" ref="product.product_category_3"></field> | ||
</record> | ||
|
||
<!-- product --> | ||
<record id="product_noper" model="product.product"> | ||
<field name="name">product_noperiod</field> | ||
<field name="product_tmpl_id" ref="product_template1"/> | ||
<field name="type">product</field> | ||
</record> | ||
|
||
<record id="product_period90" model="product.product"> | ||
<field name="name">PERIOD90</field> | ||
<field name="product_tmpl_id" ref="product_template2"/> | ||
<field name="type">product</field> | ||
<field name="turnover_period">90</field> | ||
|
||
</record> | ||
|
||
<record id="product_period180" model="product.product"> | ||
<field name="name">PERIOD180</field> | ||
<field name="product_tmpl_id" ref="product_template3"/> | ||
<field name="type">product</field> | ||
<field name="turnover_period">180</field> | ||
</record> | ||
|
||
|
||
<!-- Suppliers --> | ||
|
||
<record id="product_supplierinfo_1" model="product.supplierinfo"> | ||
<field name="product_tmpl_id" ref="product_template1"/> | ||
<field name="product_id" ref="product_noper"/> | ||
<field name="name" ref="base.res_partner_1"/> | ||
<field name="delay">2</field> | ||
<field name="min_qty">1</field> | ||
</record> | ||
|
||
<record id="product_supplierinfo_2" model="product.supplierinfo"> | ||
<field name="product_tmpl_id" ref="product_template2"/> | ||
<field name="product_id" ref="product_period90"/> | ||
<field name="name" ref="base.res_partner_4"/> | ||
<field name="delay">1</field> | ||
<field name="min_qty">1</field> | ||
</record> | ||
|
||
<record id="product_supplierinfo_3" model="product.supplierinfo"> | ||
<field name="product_tmpl_id" ref="product_template3"/> | ||
<field name="product_id" ref="product_period180"/> | ||
<field name="name" ref="base.res_partner_3"/> | ||
<field name="delay">1</field> | ||
<field name="min_qty">1</field> | ||
</record> | ||
|
||
<!-- new partner to be sure it isnt supplying anthing --> | ||
|
||
<record id="partner_new_forsupply" model="res.partner"> | ||
<field name="name">New partner</field> | ||
<field name="company_id" ref="base.main_company"/> | ||
<field name="customer" eval="False"/> | ||
<field name="email">demo@demo.com</field> | ||
<field name="street">center street</field> | ||
<field name="city">belleville</field> | ||
<field name="zip">5431</field> | ||
</record> | ||
|
||
<record id="product_supplierinfo_new" model="product.supplierinfo"> | ||
<field name="product_tmpl_id" ref="product_template3"/> | ||
<field name="product_id" ref="product_period180"/> | ||
<field name="name" ref="partner_new_forsupply"/> | ||
<field name="delay">1</field> | ||
<field name="min_qty">1</field> | ||
</record> | ||
|
||
<record id="cat_no_period" model="product.category"> | ||
<field name="name">NOPERIOD</field> | ||
</record> | ||
<record id="cat_period_30" model="product.category"> | ||
<field name="name">PERIOD30</field> | ||
<field name="turnover_period">30</field> | ||
</record> | ||
<record id="cat_period_180" model="product.category"> | ||
<field name="name">PERIOD180</field> | ||
<field name="turnover_period">180</field> | ||
</record> | ||
<record id="cat_period_360" model="product.category"> | ||
<field name="name">PERIOD360</field> | ||
<field name="turnover_period">360</field> | ||
</record> | ||
|
||
</data> | ||
</openerp> | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
# -*- coding: utf-8 -*- | ||
# © 2016 Therp BV <http://therp.nl> | ||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). | ||
|
||
from . import product_product | ||
from . import product_category | ||
from . import product_supplierinfo | ||
from . import purchase_order | ||
from . import purchase_order_line | ||
from . import res_partner | ||
from . import procurement_order | ||
from . import product_template |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# -*- coding: utf-8 -*- | ||
# © 2016 Therp BV <http://therp.nl> | ||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). | ||
from openerp import api, models | ||
|
||
|
||
class ProcurementOrder(models.Model): | ||
_inherit = 'procurement.order' | ||
|
||
@api.model | ||
def _run(self, procurement): | ||
if (procurement.rule_id and procurement.rule_id.action == 'buy'): | ||
# disable making PO's from procurement orders | ||
return True | ||
return super(ProcurementOrder, self)._run(procurement) |
Oops, something went wrong.