From 9bef5531525de9d2232006bf9dbb398f4c859ec0 Mon Sep 17 00:00:00 2001 From: david Date: Fri, 5 Mar 2021 18:35:03 +0100 Subject: [PATCH] [ADD] stock_forecast_report: Backport from 14.0 --- stock_forecast_report/README.rst | 89 ++++ stock_forecast_report/__init__.py | 1 + stock_forecast_report/__manifest__.py | 19 + stock_forecast_report/readme/CONTRIBUTORS.rst | 3 + stock_forecast_report/readme/DESCRIPTION.rst | 3 + stock_forecast_report/readme/ROADMAP.rst | 1 + stock_forecast_report/readme/USAGE.rst | 3 + stock_forecast_report/reports/__init__.py | 1 + .../reports/report_stock_quantity.py | 175 +++++++ .../reports/report_stock_quantity.xml | 104 +++++ .../security/ir.model.access.csv | 2 + .../static/description/icon.png | Bin 0 -> 3942 bytes .../static/description/index.html | 438 ++++++++++++++++++ .../description/screenshot_stock_forecast.png | Bin 0 -> 66125 bytes stock_forecast_report/tests/__init__.py | 1 + .../tests/test_report_stock_quantity.py | 102 ++++ 16 files changed, 942 insertions(+) create mode 100644 stock_forecast_report/README.rst create mode 100644 stock_forecast_report/__init__.py create mode 100644 stock_forecast_report/__manifest__.py create mode 100644 stock_forecast_report/readme/CONTRIBUTORS.rst create mode 100644 stock_forecast_report/readme/DESCRIPTION.rst create mode 100644 stock_forecast_report/readme/ROADMAP.rst create mode 100644 stock_forecast_report/readme/USAGE.rst create mode 100644 stock_forecast_report/reports/__init__.py create mode 100644 stock_forecast_report/reports/report_stock_quantity.py create mode 100644 stock_forecast_report/reports/report_stock_quantity.xml create mode 100644 stock_forecast_report/security/ir.model.access.csv create mode 100644 stock_forecast_report/static/description/icon.png create mode 100644 stock_forecast_report/static/description/index.html create mode 100644 stock_forecast_report/static/description/screenshot_stock_forecast.png create mode 100644 stock_forecast_report/tests/__init__.py create mode 100644 stock_forecast_report/tests/test_report_stock_quantity.py diff --git a/stock_forecast_report/README.rst b/stock_forecast_report/README.rst new file mode 100644 index 0000000..7b670bc --- /dev/null +++ b/stock_forecast_report/README.rst @@ -0,0 +1,89 @@ +===================== +Stock Forecast Report +===================== + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fstock--logistics--reporting-lightgray.png?logo=github + :target: https://github.com/OCA/stock-logistics-reporting/tree/12.0/stock_forecast_report + :alt: OCA/stock-logistics-reporting +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/stock-logistics-reporting-12-0/stock-logistics-reporting-12-0-stock_forecast_report + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png + :target: https://runbot.odoo-community.org/runbot/151/12.0 + :alt: Try me on Runbot + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module backports the stock forecast report from v14. + +.. image:: https://raw.githubusercontent.com/OCA/stock-logistics-reporting/12.0/stock_forecast_report/static/description/screenshot_stock_forecast.png + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +To use this module, you need to: + +#. Go to *Inventory > Reports > Forecasted Inventory* + +Known issues / Roadmap +====================== + +* This is a backport from the 14.0 Odoo core forecast report. + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* Tecnativa + +Contributors +~~~~~~~~~~~~ + +* `Tecnativa `_: + + * David Vidal + +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-reporting `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/stock_forecast_report/__init__.py b/stock_forecast_report/__init__.py new file mode 100644 index 0000000..6532353 --- /dev/null +++ b/stock_forecast_report/__init__.py @@ -0,0 +1 @@ +from . import reports diff --git a/stock_forecast_report/__manifest__.py b/stock_forecast_report/__manifest__.py new file mode 100644 index 0000000..38c5691 --- /dev/null +++ b/stock_forecast_report/__manifest__.py @@ -0,0 +1,19 @@ +# Copyright 2021 Odoo S.A. +# Copyright 2021 Tecnativa - David Vidal +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +{ + "name": "Stock Forecast Report", + "summary": "Backport of core 14.0 Forecast Report", + "version": "12.0.1.0.0", + "category": "Inventory", + "website": "https://github.com/OCA/stock-logistics-reporting", + "author": "Tecnativa, Odoo Community Association (OCA)", + "license": "AGPL-3", + "application": False, + "installable": True, + "depends": ["stock"], + "data": [ + "reports/report_stock_quantity.xml", + "security/ir.model.access.csv", + ], +} diff --git a/stock_forecast_report/readme/CONTRIBUTORS.rst b/stock_forecast_report/readme/CONTRIBUTORS.rst new file mode 100644 index 0000000..94b6ba9 --- /dev/null +++ b/stock_forecast_report/readme/CONTRIBUTORS.rst @@ -0,0 +1,3 @@ +* `Tecnativa `_: + + * David Vidal diff --git a/stock_forecast_report/readme/DESCRIPTION.rst b/stock_forecast_report/readme/DESCRIPTION.rst new file mode 100644 index 0000000..62afaea --- /dev/null +++ b/stock_forecast_report/readme/DESCRIPTION.rst @@ -0,0 +1,3 @@ +This module backports the stock forecast report from v14. + +.. image:: static/description/screenshot_stock_forecast.png diff --git a/stock_forecast_report/readme/ROADMAP.rst b/stock_forecast_report/readme/ROADMAP.rst new file mode 100644 index 0000000..4ba7a44 --- /dev/null +++ b/stock_forecast_report/readme/ROADMAP.rst @@ -0,0 +1 @@ +This won't be needed on 14.0+. diff --git a/stock_forecast_report/readme/USAGE.rst b/stock_forecast_report/readme/USAGE.rst new file mode 100644 index 0000000..908ae85 --- /dev/null +++ b/stock_forecast_report/readme/USAGE.rst @@ -0,0 +1,3 @@ +To use this module, you need to: + +#. Go to *Inventory > Reports > Forecasted Inventory* diff --git a/stock_forecast_report/reports/__init__.py b/stock_forecast_report/reports/__init__.py new file mode 100644 index 0000000..bd8c611 --- /dev/null +++ b/stock_forecast_report/reports/__init__.py @@ -0,0 +1 @@ +from . import report_stock_quantity diff --git a/stock_forecast_report/reports/report_stock_quantity.py b/stock_forecast_report/reports/report_stock_quantity.py new file mode 100644 index 0000000..3d4ae28 --- /dev/null +++ b/stock_forecast_report/reports/report_stock_quantity.py @@ -0,0 +1,175 @@ +# Copyright 2021 Odoo S.A. +# Copyright 2021 Tecnativa - David Vidal +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from odoo import fields, models, tools + + +class ReportStockQuantity(models.Model): + _name = "report.stock.quantity" + _auto = False + _description = "Stock Quantity Report" + + date = fields.Date(string="Date", readonly=True) + product_tmpl_id = fields.Many2one( + comodel_name="product.template", + related="product_id.product_tmpl_id", + readonly=True, + ) + product_id = fields.Many2one( + comodel_name="product.product", + string="Product", + readonly=True, + ) + state = fields.Selection( + selection=[ + ("forecast", "Forecasted Stock"), + ("in", "Forecasted Receipts"), + ("out", "Forecasted Deliveries"), + ], + string="State", + readonly=True, + ) + product_qty = fields.Float(string="Quantity", readonly=True) + move_ids = fields.One2many(comodel_name="stock.move", readonly=True) + company_id = fields.Many2one("res.company", readonly=True) + warehouse_id = fields.Many2one("stock.warehouse", readonly=True) + + def init(self): + tools.drop_view_if_exists(self._cr, "report_stock_quantity") + query = """ +CREATE or REPLACE VIEW report_stock_quantity AS ( +WITH forecast_qty AS ( + SELECT + m.id, + m.product_id, + CASE + WHEN (whs.id IS NOT NULL AND whd.id IS NULL) + OR ls.usage = 'transit' THEN 'out' + WHEN (whs.id IS NULL AND whd.id IS NOT NULL) + OR ld.usage = 'transit' THEN 'in' + END AS state, + m.date_expected::date AS date, + CASE + WHEN (whs.id IS NOT NULL AND whd.id IS NULL) + OR ls.usage = 'transit' THEN -product_qty + WHEN (whs.id IS NULL AND whd.id IS NOT NULL) + OR ld.usage = 'transit' THEN product_qty + END AS product_qty, + m.company_id, + CASE + WHEN (whs.id IS NOT NULL AND whd.id IS NULL) + OR ls.usage = 'transit' THEN whs.id + WHEN (whs.id IS NULL AND whd.id IS NOT NULL) + OR ld.usage = 'transit' THEN whd.id + END AS warehouse_id + FROM + stock_move m + LEFT JOIN stock_location ls ON (ls.id=m.location_id) + LEFT JOIN stock_location ld ON (ld.id=m.location_dest_id) + LEFT JOIN stock_warehouse whs + ON ls.parent_path like concat('%/', whs.view_location_id, '/%') + LEFT JOIN stock_warehouse whd + ON ld.parent_path like concat('%/', whd.view_location_id, '/%') + LEFT JOIN product_product pp ON pp.id=m.product_id + LEFT JOIN product_template pt ON pt.id=pp.product_tmpl_id + WHERE + pt.type = 'product' AND + product_qty != 0 AND + (whs.id IS NOT NULL OR whd.id IS NOT NULL) AND + (whs.id IS NULL OR whd.id IS NULL OR whs.id != whd.id) AND + m.state NOT IN ('cancel', 'draft', 'done') + UNION ALL + SELECT + -q.id as id, + q.product_id, + 'forecast' as state, + date.*::date, + q.quantity as product_qty, + q.company_id, + wh.id as warehouse_id + FROM + GENERATE_SERIES( + (now() at time zone 'utc')::date - interval '3month', + (now() at time zone 'utc')::date + interval '3 month', + '1 day'::interval + ) date, + stock_quant q + LEFT JOIN stock_location l ON (l.id=q.location_id) + LEFT JOIN stock_warehouse wh ON l.parent_path like concat( + '%/', wh.view_location_id, '/%') + WHERE + (l.usage = 'internal' AND wh.id IS NOT NULL) OR + l.usage = 'transit' + UNION ALL + SELECT + m.id, + m.product_id, + 'forecast' as state, + GENERATE_SERIES( + CASE + WHEN m.state = 'done' THEN ( + now() at time zone 'utc' + )::date - interval '3month' + ELSE m.date_expected::date + END, + CASE + WHEN m.state != 'done' THEN ( + now() at time zone 'utc' + )::date + interval '3 month' + ELSE m.date_expected::date - interval '1 day' + END, '1 day'::interval)::date date, + CASE + WHEN ( + (whs.id IS NOT NULL AND whd.id IS NULL) OR ls.usage = 'transit' + ) AND m.state = 'done' THEN product_qty + WHEN ( + (whs.id IS NULL AND whd.id IS NOT NULL) OR ld.usage = 'transit' + ) AND m.state = 'done' THEN -product_qty + WHEN ( + whs.id IS NOT NULL AND whd.id IS NULL + ) OR ls.usage = 'transit' THEN -product_qty + WHEN ( + whs.id IS NULL AND whd.id IS NOT NULL + ) OR ld.usage = 'transit' THEN product_qty + END AS product_qty, + m.company_id, + CASE + WHEN ( + whs.id IS NOT NULL AND whd.id IS NULL + ) OR ls.usage = 'transit' THEN whs.id + WHEN ( + whs.id IS NULL AND whd.id IS NOT NULL + ) OR ld.usage = 'transit' THEN whd.id + END AS warehouse_id + FROM + stock_move m + LEFT JOIN stock_location ls on (ls.id=m.location_id) + LEFT JOIN stock_location ld on (ld.id=m.location_dest_id) + LEFT JOIN stock_warehouse whs ON ls.parent_path like concat( + '%/', whs.view_location_id, '/%' + ) + LEFT JOIN stock_warehouse whd ON ld.parent_path like concat( + '%/', whd.view_location_id, '/%' + ) + LEFT JOIN product_product pp on pp.id=m.product_id + LEFT JOIN product_template pt on pt.id=pp.product_tmpl_id + WHERE + pt.type = 'product' AND + product_qty != 0 AND + (whs.id IS NOT NULL OR whd.id IS NOT NULL) AND + (whs.id IS NULL or whd.id IS NULL OR whs.id != whd.id) AND + m.state NOT IN ('cancel', 'draft') +) -- /forecast_qty +SELECT + MIN(id) as id, + product_id, + state, + date, + sum(product_qty) as product_qty, + company_id, + warehouse_id +FROM forecast_qty +GROUP BY product_id, state, date, company_id, warehouse_id +); +""" + self.env.cr.execute(query) diff --git a/stock_forecast_report/reports/report_stock_quantity.xml b/stock_forecast_report/reports/report_stock_quantity.xml new file mode 100644 index 0000000..18060d3 --- /dev/null +++ b/stock_forecast_report/reports/report_stock_quantity.xml @@ -0,0 +1,104 @@ + + + + stock_report_view_graph + report.stock.quantity + + + + + + + + + + + stock_report_view_pivot + report.stock.quantity + + + + + + + + + + + report.stock.quantity.search + report.stock.quantity + + + + + + + + + + + + + + + + + + + + + + + report.stock.quantity + + { + 'search_default_product_tmpl_id': active_id, + 'search_default_filter_forecast': 1, + 'graph_groupbys': ['date:day', 'product_id'], + 'graph_intervalMapping': {}, + 'graph_mode': 'line', + 'group_by': ['date:day', 'product_id'], + 'graph_measure': 'product_qty', + 'pivot_row_groupby': ['product_id'], + 'pivot_column_groupby': ['date:day'], + 'pivot_measures': ['product_qty'] + } + + + + + report.stock.quantity + + { + 'search_default_product_id': active_id, + 'search_default_filter_forecast': 1, + 'graph_groupbys': ['date:day', 'product_id'], + 'graph_intervalMapping': {}, + 'graph_mode': 'line', + 'group_by': ['date:day', 'product_id'], + 'graph_measure': 'product_qty', + 'pivot_row_groupby': ['product_id'], + 'pivot_column_groupby': ['date:day'], + 'pivot_measures': ['product_qty'] + } + + + + + Forecasted Inventory + report.stock.quantity + graph,pivot + { + 'search_default_filter_forecasted_next_days': 1, + 'graph_groupbys': ['date:day', 'product_id'], + 'graph_mode': 'line', + 'group_by': ['date:day', 'product_id'], + 'graph_measure': 'product_qty', + 'pivot_row_groupby': ['product_id'], + 'pivot_column_groupby': ['date:day'], + 'pivot_measures': ['product_qty'] + } + + + + diff --git a/stock_forecast_report/security/ir.model.access.csv b/stock_forecast_report/security/ir.model.access.csv new file mode 100644 index 0000000..71bec4e --- /dev/null +++ b/stock_forecast_report/security/ir.model.access.csv @@ -0,0 +1,2 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_report_stock_quantity,access_report_stock_quantity,model_report_stock_quantity,base.group_user,1,0,0,0 diff --git a/stock_forecast_report/static/description/icon.png b/stock_forecast_report/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..2b57236778eed3dea862170a23f92a8f1ae86b32 GIT binary patch literal 3942 zcmV-s51H_ZP) zTW}oJna6*pdnC(3k}X-bgiWw58yo}WbqJ&&A=v~HVnAR+)oxxk2{srO$<#WelH!rd zk`z_zV26P3j)j5Rmra$at=b9&$)-pVk^qUFRB*W1u?cHTz>=*QSu>hT@54+>J$;+* znbR{Z>HJ?lJeSj_`}=>tKIilqA+TuWw(Vapzy=L*oq@4f2!R0z2o{9^!vMb+L>1Z* zLSUFNV80Ce_bRkgOaB6&=VWu?`xp8=C$gtSCi54O8vVsvKX~-}lg9>FzHQr5UFdra zgPQ|ijJRF|pNkQN8SU*!F=K`EttAgep^(=;`unf*6gIy5=%dFq08Qx6O(x$kiU+eq zN(V2C=Id_JJb3X1_h^$>J7v-Kepx^57t8HDDzxWzp1$W{zt{oV^Sf>i6L_3w#rAy8 zQwX6O-3vdT7@znlfZq2XKiViT9`tme#fi8@)A`ou=0JP&ki8w(Xzf=eGFU%Xp*^?r zvvkZE{Yc=^p5JxzC4mQ-UEA|HPlNzX!^r37cCT6cp(aG(Ym*ME;6P9$m@y=1ojXqm z@ih%0)>gbXQSLz8q9VbxB7xC72Z6Cx!!UXr4pStU`6SRZ5TZwOI7^YB{J6IBvvkZE zry&V6&k9l`D37-DoGB#Gtd3D6m}MjYG&jd663h}3U?qSV6$xe!39u5tjEV%ahXlA0 zz>JCnGoJ)lX91-TC=$#r5@e*C=$#n5@_D^QzV!@Bmk2D z;5euv!OSNCK*Gy`uFkf`(gE!bT-nvh4NI5O-ZIB>(F6tt6S+J`&z#{me|z8E6xNIE zMieN!*p)7pRe?xgi=q4HXL^rzLXjXu9)ggdXaG|l7c zy#9M0d-+$vN#IgpwU8iClERR{URl+WppvO=BnaCtHv&v$DhLViz87i9B;UT_vlWvM zu<4qs>27URV**PIMS=kB1t9@g4PdH@F@c^;qMtv6o7CFSx3-a31h z$6tAs6C)$RNZ{7b$?NQMo`QSl-uq1G)uv$nE#Ef6KWHGz%x|1ed zuj%~#v~>PF{-L*rb%&m1ESsxrY8weE63RLTusgybn*(JeA4&uO_ls@5Zs}JX#stk{ zDZY2pjgcnbRL?~haqZ&8k&g)+JAynV1bV9ad%mMNrq_z0o=WoRc^xe2>XLE#fz;JH z*V-{>lrSdn+!17#tjaf4MgTL$lmuETi8ef3*W^$3XR2e~u?7-2_XN6Bh|J12RYm~f zO9DNWL?0do;Qg~_Yd!7Iih6e7y(iGT=SPryC=$RtPFzW#C5x4B>WveB<>;wXHJ*7m z+0Rop3B30NO1|gYWv$#el0Zu)(MN_IuWvp0G^a;Ksz33NvY+478*)hCxhF8nEV&OnIP&F!*T-DDf!@E zxs4)0kmQ@HmkBD}!)ql$qTZEn%Iavt8vQEYhXj{(b#c>*K9D}W@ z6bcT)xmAXiN(D~7DboapwhXekvs2o&nUvu|veH|wB=D+y9}*4v%%=$<(8p4B zO+Ex$sj4(4XiFqGwBZi!y2_b+fZnz?4&1eY{#BQIjtOc>zNyycW?F(g6bdV2s-K}q zV2?f|(CS_JroyaQyH)N*LhzG2Ze#7GpYT17E(F_dUB|l1Ryx|%Qo--}Uh3;v#KFM< zy4u=mYR6S#YRuv}rYU{2+A)FFh~z`%dz&8#E&>j$znxDlTNdb8x)5x?bsaaaTrqh( zJ(WVQaR9e$;X;N623Qb9@-cJeoTY&z65zKXBw_`1w4DU4g#!E5_w(t#<)Mz3&@^`R z-^!Q!`lM9;((Z1C1_$WwXs@XqKTXbZEVDGJB%px?2{;K>wJTOsb<8GB z zd1BMue17#OtNQ+ut}ceQ4A3)gUQPW7BFB1%Y!c8w0}#T|E!ix)*5A(cmtQXB&`r9| zk2h`PbE{T``rhKsPM+Q}z{T_DOX)`?dCh{Pk$^@TAfTh?WHRi$qn{f-87^6s)SO80 z775Hp}~P@7JNM9nEfE11Pv#E9|>AA8GgLJpD$doI+8BTX-e?az4!2$ zl`DNew`g7mLxTfcvY@&RA;YN@1N#qzUN&~DkRqQ1jU|8?T^!wd>FaZSe_=-lPY(`oY4?Jv+8<7(*tl~Szx?x?p`RU;Et5w?g2ocSj5ZQ9 zr^ngRe=9d#byZ!uGPk*z-S^$g)yvDLmfh{`3=KZO(uE7FYS&EuJ0F|@!aqRDo5?0R z62yZ5W)y-%dYm8Lb_-uwv!<$M3x-koLoRBaGl#wRZ)R<2ajC1Vje~;^uzb;?s@k(B z-&7bAd^9!|`7e+fX8=_`z4c%q?rzR@GE0o#tPjc#{A5{U56OzG;Ggyy6Om z1|MKWPfu0tcqQLd5EG1ykMqXq5B&G{Q#%P7Z-9~$_3;Z_)zZS9pSiZGW>V=i_wL%m zk&`F+?z7MFvm-~VYNxHGgZ2NZ7u-+AU)bWK!!E2&07lW*$u@Cg6( z!|iNY_tnXTsn?DlXaA8uaxya!{I`gPQ8ft~ZU8g+07p-r;0|>fr!mS->@GZcad{Yk| zILNX0|1Z$@y^?P#S19n%&>?>L=QnHatDmY(zFkIV7x_~1t(6;?1cV6-Nzdz{u=6gQ6=B1x{`otWB}Q^ zFfqaXd-rkV==qUFc{%_v#`K#q&o*jU?1xzbl($T^9Zu(O3ACkrd$^g?$YkEt+SClj+PzIQ0 zYBv9WMUrL*$^g?lQNrBvMDt&A#cSH$p#osrMQ3ZK4pRk^}nSbv&edOpf9}c`bT7T z@Z-@W&%gFMnx@g+-a%{2oKXK;c_nwH(rI3L^B9l3{3|lKoRnt=+WB*c)mtBOw~A7{ zr0e8*FQ%Yr?i)PqW^glyO-=8eQtJTILZ##znkM}zqB20-WvP6Szn?%EAkMN@e(5FI z`w5f*;wrQ9ONonWXOS{M9AzEwMZB{}86a-5RDM177%BtAN!H}oX^){YKwPBjr z6~20sKpCJBvQ~cSC2Qr@jRYtI)L)i+KKNH|$p`nRaWNo)GJs5ZCEu!;kw6(h zmP*OD&+{FM83~jDWXMwa_6qh?Oh}*%P^&yD-yR)`2?>+|YLR8C=UKTiCIJ);;9*fE zU+Fs8g^P-nAEa{QMuJ=p4C6yZfNEsF=i4iG8jwKC z?TZ?~M51M_0XZ~H{h2Q>xg{Tu3XdTP$mP(-#z=f{I!iX2F66V{fvH;u0IRod{knnJ zfFZ6Eg2iF4ky3nR7@S5JzY!RRkL}p;jQRTi18m(IDh~a4 + + + + + +Stock Forecast Report + + + +
+

Stock Forecast Report

+ + +

Beta License: AGPL-3 OCA/stock-logistics-reporting Translate me on Weblate Try me on Runbot

+

This module backports the stock forecast report from v14.

+https://raw.githubusercontent.com/OCA/stock-logistics-reporting/12.0/stock_forecast_report/static/description/screenshot_stock_forecast.png +

Table of contents

+ +
+

Usage

+

To use this module, you need to:

+
    +
  1. Go to Inventory > Reports > Forecasted Inventory
  2. +
+
+
+

Known issues / Roadmap

+
    +
  • This is a backport from the 14.0 Odoo core forecast report.
  • +
+
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +feedback.

+

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

+
+
+

Credits

+
+

Authors

+
    +
  • Tecnativa
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

This module is part of the OCA/stock-logistics-reporting project on GitHub.

+

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

+
+
+
+ + diff --git a/stock_forecast_report/static/description/screenshot_stock_forecast.png b/stock_forecast_report/static/description/screenshot_stock_forecast.png new file mode 100644 index 0000000000000000000000000000000000000000..30a6c52e128991a1d47cca3be28f80f2ca086039 GIT binary patch literal 66125 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 Iv~Pd>4_Smpga7~l literal 0 HcmV?d00001 diff --git a/stock_forecast_report/tests/__init__.py b/stock_forecast_report/tests/__init__.py new file mode 100644 index 0000000..dbe0c4a --- /dev/null +++ b/stock_forecast_report/tests/__init__.py @@ -0,0 +1 @@ +from . import test_report_stock_quantity diff --git a/stock_forecast_report/tests/test_report_stock_quantity.py b/stock_forecast_report/tests/test_report_stock_quantity.py new file mode 100644 index 0000000..e2be7c1 --- /dev/null +++ b/stock_forecast_report/tests/test_report_stock_quantity.py @@ -0,0 +1,102 @@ +# Copyright 2021 Odoo S.A. +# Copyright 2021 Tecnativa - David Vidal +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from odoo import fields +from odoo.tests.common import TransactionCase + + +class TestReportStockQuantity(TransactionCase): + def setUp(self): + super().setUp() + self.product1 = self.env["product.product"].create({ + "name": "Mellohi", + "default_code": "C418", + "type": "product", + "categ_id": self.env.ref("product.product_category_all").id, + "tracking": "lot", + "barcode": "scan_me" + }) + wh = self.env["stock.warehouse"].create({ + "name": "Base Warehouse", + "code": "TESTWH" + }) + self.categ_unit = self.env.ref("uom.product_uom_categ_unit") + self.uom_unit = self.env["uom.uom"].search( + [ + ("category_id", "=", self.categ_unit.id), + ("uom_type", "=", "reference") + ], + limit=1 + ) + self.customer_location = self.env.ref("stock.stock_location_customers") + self.supplier_location = self.env.ref("stock.stock_location_suppliers") + # Replenish + self.move1 = self.env["stock.move"].create({ + "name": "test_in_1", + "location_id": self.supplier_location.id, + "location_dest_id": wh.lot_stock_id.id, + "product_id": self.product1.id, + "product_uom": self.uom_unit.id, + "product_uom_qty": 100.0, + "state": "done", + "date": fields.Datetime.now(), + "date_expected": fields.Datetime.now(), + }) + self.quant1 = self.env["stock.quant"].create({ + "product_id": self.product1.id, + "location_id": wh.lot_stock_id.id, + "quantity": 100.0, + }) + self.move2 = self.env["stock.move"].create({ + "name": "test_out_1", + "location_id": wh.lot_stock_id.id, + "location_dest_id": self.customer_location.id, + "product_id": self.product1.id, + "product_uom": self.uom_unit.id, + "product_uom_qty": 120.0, + "state": "partially_available", + "date": fields.Datetime.add(fields.Datetime.now(), days=3), + "date_expected": fields.Datetime.add(fields.Datetime.now(), days=3), + }) + self.move2.date = fields.Datetime.add(fields.Datetime.now(), days=3) + + def test_report_stock_quantity(self): + from_date = fields.Date.to_string( + fields.Date.add(fields.Date.today(), days=-1)) + to_date = fields.Date.to_string( + fields.Date.add(fields.Date.today(), days=4)) + report = self.env["report.stock.quantity"].read_group( + [ + ("date", ">=", from_date), + ("date", "<=", to_date), + ("product_id", "=", self.product1.id) + ], + ["product_qty", "date", "product_id", "state"], + ["date:day", "product_id", "state"], + lazy=False + ) + forecast_report = ( + [x["product_qty"] for x in report if x["state"] == "forecast"] + ) + self.assertEqual(forecast_report, [0, 100, 100, 100, -20, -20]) + + def test_report_stock_quantity_with_product_qty_filter(self): + from_date = fields.Date.to_string( + fields.Date.add(fields.Date.today(), days=-1) + ) + to_date = fields.Date.to_string( + fields.Date.add(fields.Date.today(), days=4) + ) + report = self.env["report.stock.quantity"].read_group( + [ + ("product_qty", "<", 0), ("date", ">=", from_date), + ("date", "<=", to_date), ("product_id", "=", self.product1.id) + ], + ["product_qty", "date", "product_id", "state"], + ["date:day", "product_id", "state"], + lazy=False + ) + forecast_report = ( + [x["product_qty"] for x in report if x["state"] == "forecast"] + ) + self.assertEqual(forecast_report, [-20, -20])