Browse Source

refactor module name

pull/139/head
robinkeunen 6 years ago
committed by robin.keunen
parent
commit
171bbf8ad4
  1. 3
      stock_coverage/README.md
  2. 1
      stock_coverage/__init__.py
  3. 23
      stock_coverage/__openerp__.py
  4. 14
      stock_coverage/data/cron.xml
  5. 1
      stock_coverage/models/__init__.py
  6. 124
      stock_coverage/models/product_template.py
  7. 1
      stock_coverage/tests/__init__.py
  8. 101
      stock_coverage/tests/test_stock_coverage.py
  9. 40
      stock_coverage/views/product_template_view.xml

3
stock_coverage/README.md

@ -0,0 +1,3 @@
- initializing the computed fields
- daily cron
- manual trigger

1
stock_coverage/__init__.py

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

23
stock_coverage/__openerp__.py

@ -0,0 +1,23 @@
# -*- encoding: utf-8 -*-
{
'name': 'Product - Stock Coverage',
'version': '9.0.1',
'category': 'Product',
'description': """
Shows figures in the product form related to stock coverage
There are settings in Inventory/settings to define the calculation range and
the display range.
""",
'author': 'coop it easy',
'website': 'coopiteasy.be',
'license': 'AGPL-3',
'depends': [
'product',
'point_of_sale',
'stock'
],
'data': [
'views/product_template_view.xml',
'data/cron.xml',
],
}

14
stock_coverage/data/cron.xml

@ -0,0 +1,14 @@
<odoo>
<data noupdate="0">
<record id="ir_cron_update_article_consumption" model="ir.cron">
<field name="name">Stock Coverage - Update Article Consumption</field>
<field name="interval_number">24</field>
<field name="interval_type">hours</field>
<field name="numbercall">-1</field>
<field name="doall" eval="False" />
<field name="model">product.template</field>
<field name="function">_batch_compute_total_consumption</field>
<field name="args">()</field>
</record>
</data>
</odoo>

1
stock_coverage/models/__init__.py

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

124
stock_coverage/models/product_template.py

@ -0,0 +1,124 @@
# -*- encoding: utf-8 -*-
from openerp import models, fields, api
import datetime as dt
class ProductTemplate(models.Model):
_inherit = "product.template"
consumption_calculation_method = fields.Selection(
selection=[('sales_history', 'Sales History')],
string='Consumption Calculation Method',
default='sales_history',
)
calculation_range = fields.Integer(
'Calculation range (days)',
default=365, # todo sensible defaults, 14, 28?
)
average_consumption = fields.Float(
string='Average Consumption',
compute='_compute_average_daily_consumption',
readonly=True,
digits=(100, 2),
)
total_consumption = fields.Float(
string='Total Consumption',
default=0,
readonly=True,
digits=(100, 2),
)
estimated_stock_coverage = fields.Float(
string='Estimated Stock Coverage (days)',
compute='_compute_estimated_stock_coverage',
default=0,
digits=(100, 2),
readonly=True,
)
@api.multi
@api.depends('calculation_range')
def _compute_average_daily_consumption(self):
for template in self:
if template.calculation_range > 0:
avg = template.total_consumption / template.calculation_range
else:
avg = 0
template.average_consumption = avg
return True
@api.multi
@api.onchange('calculation_range')
def _compute_total_consumption(self):
for template in self:
products = (
self.env['product.product']
.search([('product_tmpl_id', '=', template.id)]))
today = dt.date.today()
pol_date_limit = (
today - dt.timedelta(days=template.calculation_range))
order_lines = (
self.env['pos.order.line']
.search([
('product_id', 'in', products.ids),
('create_date', '>',
fields.Datetime.to_string(pol_date_limit))
])
)
if order_lines:
order_lines = order_lines.filtered(
lambda oi: oi.order_id.state in ['done', 'invoiced', 'paid']) # noqa
res = sum(order_lines.mapped('qty'))
else:
res = 0
template.total_consumption = res
return True
@api.multi
@api.depends('calculation_range')
def _compute_estimated_stock_coverage(self):
for product_template in self:
qty = product_template.qty_available
avg = product_template.average_consumption
if avg > 0:
product_template.estimated_stock_coverage = qty / avg
else:
# todo what would be a good default value? (not float(inf))
product_template.estimated_stock_coverage = 9999
return True
@api.model
def _batch_compute_total_consumption(self):
products = (
self.env['product.template']
.search([('active', '=', True)])
)
query = """
select
template.id as product_template_id,
sum(pol.qty) as total_consumption
from pos_order_line pol
join pos_order po ON pol.order_id = po.id
join product_product product ON pol.product_id = product.id
join product_template template ON product.product_tmpl_id = template.id
where po.state in ('done', 'invoiced', 'paid')
and template.active
and pol.create_date
BETWEEN date_trunc('day', now()) - calculation_range * interval '1 days'
and date_trunc('day', now())
group by product_template_id
"""
self.env.cr.execute(query)
results = {pid: qty for pid, qty in self.env.cr.fetchall()}
for product in products:
product.total_consumption = results.get(product.id, product.total_consumption)

1
stock_coverage/tests/__init__.py

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

101
stock_coverage/tests/test_stock_coverage.py

@ -0,0 +1,101 @@
# -*- coding: utf-8 -*-
from collections import namedtuple
from openerp.tests.common import TransactionCase
from openerp.addons.stock.product import product_template as ProductTemplate
from openerp.addons.stock.product import product_product as ProductProduct
import datetime as dt
# fixme setup tests based on demo data, test on a clean database
_datetimes = map(
lambda d: d.strftime('%Y-%m-%d %H:%M:%S'),
(dt.datetime.now() - dt.timedelta(days=d) for d in range(0, 24, 2)))
_quantities = [0.64, 6.45, 9.65, 1.76, 9.14, 3.99,
6.92, 2.25, 6.91, 1.44, 6.52, 1.44]
class TestProductTemplate(TransactionCase):
def setUp(self, *args, **kwargs):
result = super(TestProductTemplate, self).setUp(*args, **kwargs)
test_product_template = (
self.env['product.template']
.create({'name': 'test product template',
'calculation_range': 14,
'consumption_calculation_method': 'sales_history',
'product_template_id': 0,
})
)
pid = (
self.env['product.product']
.search([('product_tmpl_id', '=', test_product_template.id)])
.ids
).pop()
for date, qty in zip(_datetimes, _quantities):
(self.env['pos.order.line']
.create({'create_date': date,
'qty': qty,
'product_id': pid,
})
)
def _product_available(*args, **kwargs):
products = (
self.env['product.product']
.search([
('product_tmpl_id', '=', test_product_template.id)])
)
mock_data = {
'qty_available': 53.2,
'incoming_qty': 14,
'outgoing_qty': 4.1,
'virtual_available': 53.2 + 14 - 4.1,
}
return {pid: mock_data for pid in products.ids}
# mock area
# ProductTemplate._product_available = _product_available
# ProductProduct._product_available = _product_available
# Order = namedtuple('Order', ['id', 'state'])
# PosOrderLine.order_id = Order('1', 'done')
test_product_template._compute_total_consumption()
self.product_template_id = test_product_template.id
return result
def test_create(self):
"""Create a simple product template"""
Template = self.env['product.template']
product = Template.create({'name': 'Test create product'})
self.assertEqual(product.name, 'Test create product')
def test_compute_average_daily_consumption(self):
"""Test computed field average_daily_consumption"""
ProductTemplate = self.env['product.template']
product_template = ProductTemplate.browse(self.product_template_id)
computed_value = product_template.average_consumption
expected_value = 4.08
self.assertAlmostEqual(computed_value, expected_value, 7)
def test_compute_total_consumption(self):
"""Test total consumption was computed in setup"""
ProductTemplate = self.env['product.template']
product_template = ProductTemplate.browse(self.product_template_id)
computed_value = product_template.total_consumption
expected_value = 57.11
self.assertAlmostEqual(computed_value, expected_value)
# def test_compute_estimated_stock_coverage(self):
# """Test computed field estimated_stock_coverage"""
# ProductTemplate = self.env['product.template']
# product_template = ProductTemplate.browse(self.product_template_id)
# computed_value = product_template.estimated_stock_coverage
# expected_value = 13.04
# self.assertAlmostEqual(computed_value, expected_value)

40
stock_coverage/views/product_template_view.xml

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<record id="beesdoo_product_form" model="ir.ui.view">
<field name="name">template.consumption.form</field>
<field name="model">product.template</field>
<field eval="7" name="priority"/>
<field name="inherit_id" ref="product.product_template_only_form_view"/>
<field name="arch" type="xml">
<group name="stock_property" position="after">
<group name="Consumption Figures">
<field name="consumption_calculation_method"/>
<field name="calculation_range" />
<field name="average_consumption"/>
<field name="total_consumption"/>
<field name="estimated_stock_coverage"/>
</group>
</group>
</field>
</record>
<record id="beesdoo_product_tree" model="ir.ui.view">
<field name="name">template.consumption.tree</field>
<field name="model">product.template</field>
<field eval="7" name="priority"/>
<field name="inherit_id" ref="product.product_template_tree_view"/>
<field name="arch" type="xml">
<tree>
<field name="volume" invisible="1"/>
<field name="weight" invisible="1"/>
<field name="estimated_stock_coverage"/>
<field name="average_consumption"/>
<field name="total_consumption"/>
<field name="calculation_range"/>
</tree>
</field>
</record>
</odoo>
Loading…
Cancel
Save