[ADD] Inventory Turnover Report

This commit is contained in:
Daniel Reis
2020-03-27 12:32:21 +00:00
parent bebf47196d
commit 8da669fa23
10 changed files with 214 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
=========================
Inventory Turnover Report
=========================
.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

View File

@@ -0,0 +1,3 @@
# Copyrigh 2020 Open Source Integrators
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from . import models

View File

@@ -0,0 +1,20 @@
# Copyrigh 2020 Open Source Integrators
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
{
"name": "Inventory Turnover Report",
"summary": "Analize inventory turnover in the last 6 and 12 months",
"version": "12.0.1.0.0",
"development_status": "beta",
"category": "Warehouse",
"website": "https://github.com/OCA/stock-logistics-reporting",
"author": "Open Source Integrators, Odoo Community Association (OCA)",
"maintainers": ["dreispt"],
"license": "AGPL-3",
"installable": True,
"depends": [
"stock",
],
"data": [
'views/product_views.xml',
],
}

View File

@@ -0,0 +1 @@
from . import product_product

View File

@@ -0,0 +1,122 @@
# Copyright 2020 Open Source Intgerators
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from dateutil.relativedelta import relativedelta
from odoo import fields, models
class Product(models.Model):
_inherit = "product.product"
def _compute_quantities_in_dict(self, from_date):
domain_base = [
('product_id', 'in', self.ids),
('date', '>=', from_date)]
domain_in = domain_base + [
('picking_id.picking_type_id.code',
'in', ['incoming', 'mrp_operation'])]
domain_return = domain_base + [
('location_dest_id.usage',
'in', ['supplier', 'inventory']) # loss
]
Move = self.env['stock.move']
moves_in = {
item['product_id'][0]: item['product_qty']
for item in Move.read_group(
domain_in,
['product_id', 'product_qty'],
['product_id'])}
moves_return = {
item['product_id'][0]: item['product_qty']
for item in Move.read_group(
domain_return,
['product_id', 'product_qty'],
['product_id'])}
return {
x.id: (
moves_in.get(x.id, 0)
- moves_return.get(x.id, 0))
for x in self}
def _compute_inventory_turn_report(self):
month = relativedelta(month=1)
today = fields.Date.today()
at_6m_ago = today - 6 * month
at_12m_ago = today - 12 * month
available6m = {
x.id: x.qty_available
for x in self.with_context(to_date=at_6m_ago)}
available12m = {
x.id: x.qty_available
for x in self.with_context(to_date=at_12m_ago)}
gotten6m = self._compute_quantities_in_dict(from_date=at_6m_ago)
gotten12m = self._compute_quantities_in_dict(from_date=at_12m_ago)
for prod in self:
prod.total_cost = prod.qty_available * prod.standard_price
# Quantity initially available
prod.qty_available_6m = available6m.get(prod.id)
prod.qty_available_12m = available12m.get(prod.id)
# Quantity gotten (produced + procured)
prod.qty_gotten_6m = gotten6m.get(prod.id)
prod.qty_gotten_12m = gotten12m.get(prod.id)
# Quantity consumed in period
prod.qty_consumed_6m = (
prod.qty_available_6m
+ prod.qty_gotten_6m
- prod.qty_available)
prod.qty_consumed_12m = (
prod.qty_available_12m
+ prod.qty_gotten_12m
- prod.qty_available)
# Months of Inventory
prod.months_of_inventory_6m = (
0.0 if not prod.qty_consumed_6m else
prod.qty_available / prod.qty_consumed_6m * 6)
prod.months_of_inventory_12m = (
0.0 if not prod.qty_consumed_12m else
prod.qty_available / prod.qty_consumed_12m * 12)
# Turns / Cycles per Month
prod.inventory_turns_6m = (
0.0 if not prod.months_of_inventory_6m else
12 / prod.months_of_inventory_6m)
prod.inventory_turns_12m = (
0.0 if not prod.months_of_inventory_12m else
12 / prod.months_of_inventory_12m)
total_cost = fields.Float(
compute="_compute_inventory_turn_report",
help="= Qty. on hand x Current Cost")
qty_available_6m = fields.Float(
name="Qty. 6m Ago",
compute="_compute_inventory_turn_report",
help="Qty. on hand 6 months ago")
qty_gotten_6m = fields.Float(
name="Qty. Gotten 6m",
compute="_compute_inventory_turn_report",
help="Qty. Procured or Produced in the the last 6 months")
qty_consumed_6m = fields.Float(
compute="_compute_inventory_turn_report",
help="Qty. consumed in the the last 6 months")
months_of_inventory_6m = fields.Float(
compute="_compute_inventory_turn_report",
help="Months of Inventory, in the last 6 months")
inventory_turns_6m = fields.Float(
compute="_compute_inventory_turn_report",
help="Inventory Turns / Cycles in the last 6 months")
qty_available_12m = fields.Float(
name="Qty. 12m ago",
compute="_compute_inventory_turn_report",
help="= Qty. on hand 12 months ago")
qty_gotten_12m = fields.Float(
name="Qty. Gotten 12m",
compute="_compute_inventory_turn_report",
help="Qty. Procured or Produced in the the last 12 months")
qty_consumed_12m = fields.Float(
compute="_compute_inventory_turn_report",
help="Qty. consumed in the the last 12 months")
months_of_inventory_12m = fields.Float(
compute="_compute_inventory_turn_report",
help="Months of Inventory, in the last 12 months")
inventory_turns_12m = fields.Float(
compute="_compute_inventory_turn_report",
help="Inventory Turns / Cycles in the last 12 months")

View File

@@ -0,0 +1,3 @@
* Open Source Integrators
* Daniel Reis <dreis@opensourceintegrators.com>

View File

@@ -0,0 +1 @@
Report to compute the inventory turnover cycles in the last 6 and 12 months.

View File

@@ -0,0 +1 @@
The report is available at Inventory > Reporting > Inventory Turnover.

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

View File

@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="view_stock_inv_turns_tree" model="ir.ui.view">
<field name="model">product.product</field>
<field name="arch" type="xml">
<tree >
<field name="categ_id" invisible="True"/>
<field name="display_name"/>
<field name="total_cost" string="Current Cost"/>
<field name="standard_price"/>
<field name="qty_available"/>
<field name="qty_available_6m"/>
<field name="qty_available_12m"/>
<field name="qty_consumed_6m"/>
<field name="qty_consumed_12m"/>
<field name="qty_gotten_6m"/>
<field name="qty_gotten_12m"/>
<field name="months_of_inventory_6m"/>
<field name="months_of_inventory_12m"/>
<field name="inventory_turns_6m"/>
<field name="inventory_turns_12m"/>
</tree>
</field>
</record>
<record id="view_stock_inv_turns_search" model="ir.ui.view">
<field name="model">product.product</field>
<field name="inherit_id" ref="product.product_search_form_view"/>
<field name="arch" type="xml">
<field name="name" position="after">
<filter string="Category" name="group_by_categ" domain="[]" context="{'group_by': 'categ_id'}" />
<filter string="Is in stock" name="filter_is_in_stock" domain="[('qty_available', '>', 0)]" />
</field>
</field>
</record>
<record id="stock_inv_turns_report" model="ir.actions.act_window">
<field name="name">Inventory Turnover</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">product.product</field>
<field name="view_mode">tree,form,pivot,graph</field>
<field name="view_id" ref="view_stock_inv_turns_tree"/>
<field name="context">{'search_default_group_by_categ': True, 'search_default_filter_is_in_stock': True}</field>
</record>
<menuitem id="menu_stock_inv_turns_report"
name="Inventory Turnover"
parent="stock.menu_warehouse_report"
action="stock_inv_turns_report"
sequence="50"/>
</data>
</odoo>