From 3c627df47eea9eeb7579e815300e249f1583c407 Mon Sep 17 00:00:00 2001 From: robinkeunen Date: Fri, 16 Mar 2018 17:32:40 +0100 Subject: [PATCH] compute, test and display total and average consumption --- product_average_consumption/__init__.py | 1 + product_average_consumption/__openerp__.py | 53 +++++++++++++ .../models/__init__.py | 1 + .../models/product_template.py | 73 ++++++++++++++++++ product_average_consumption/tests/__init__.py | 1 + .../tests/test_product_computations.py | 77 +++++++++++++++++++ .../views/product_template_view.xml | 20 +++++ 7 files changed, 226 insertions(+) create mode 100644 product_average_consumption/__init__.py create mode 100644 product_average_consumption/__openerp__.py create mode 100644 product_average_consumption/models/__init__.py create mode 100644 product_average_consumption/models/product_template.py create mode 100644 product_average_consumption/tests/__init__.py create mode 100644 product_average_consumption/tests/test_product_computations.py create mode 100644 product_average_consumption/views/product_template_view.xml diff --git a/product_average_consumption/__init__.py b/product_average_consumption/__init__.py new file mode 100644 index 0000000..0650744 --- /dev/null +++ b/product_average_consumption/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/product_average_consumption/__openerp__.py b/product_average_consumption/__openerp__.py new file mode 100644 index 0000000..e7ebd80 --- /dev/null +++ b/product_average_consumption/__openerp__.py @@ -0,0 +1,53 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Product - Average Consumption Module for Odoo +# Copyright (C) 2013-Today GRAP (http://www.grap.coop) +# @author Julien WESTE +# @author Sylvain LE GAL (https://twitter.com/legalsylvain) +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## +{ + 'name': 'Product - Average Consumption', + 'version': '9.0.1', + 'category': 'Product', + 'description': """ +Shows figures in the product form about the average consumption of products +There are settings in Inventory/settings to define the calculation range and +the display range. +=========================================================================== + +Copyright, Author and Licence : +------------------------------- + * Copyright : 2013-Today, Groupement Régional Alimentaire de Proximité; + * Author : + * Julien WESTE; + * Sylvain LE GAL; + * Robin Keunen + * Licence : AGPL-3 (http://www.gnu.org/licenses/) + """, + 'author': 'GRAP', + 'website': 'http://www.grap.coop', + 'license': 'AGPL-3', + 'depends': [ + 'product', + 'point_of_sale' + ], + 'data': [ + 'views/product_template_view.xml', + # 'views/res_config_view.xml', + ], +} diff --git a/product_average_consumption/models/__init__.py b/product_average_consumption/models/__init__.py new file mode 100644 index 0000000..e8fa8f6 --- /dev/null +++ b/product_average_consumption/models/__init__.py @@ -0,0 +1 @@ +from . import product_template diff --git a/product_average_consumption/models/product_template.py b/product_average_consumption/models/product_template.py new file mode 100644 index 0000000..0c9620b --- /dev/null +++ b/product_average_consumption/models/product_template.py @@ -0,0 +1,73 @@ +# -*- 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, + ) + + average_consumption = fields.Float( + string='Average consumption', + compute='_compute_average_daily_consumption', + digits=(100, 2), + ) + total_consumption = fields.Float( + string='Total consumption', + compute='_compute_total_consumption', + # store=True, + ) + + @api.multi + @api.depends('total_consumption') + 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.depends('calculation_range') + @api.multi + def _compute_total_consumption(self): + for template in self: + products = ( + self.env['product.product'] + .search([('product_tmpl_id', '=', template.id)])) + products_id = products.mapped('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_id), + ('create_date', '>', fields.Datetime.to_string(pol_date_limit)) + ]) + ) + + if len(order_lines) > 0: + res = sum(order_lines.mapped('qty')) + else: + res = 0 + template.total_consumption = res + return True + + @api.multi + def _compute_stock_coverage(self): + for template in self: + template.stock_coverage = 7.1 + return True diff --git a/product_average_consumption/tests/__init__.py b/product_average_consumption/tests/__init__.py new file mode 100644 index 0000000..ed2dc58 --- /dev/null +++ b/product_average_consumption/tests/__init__.py @@ -0,0 +1 @@ +from . import test_product_computations diff --git a/product_average_consumption/tests/test_product_computations.py b/product_average_consumption/tests/test_product_computations.py new file mode 100644 index 0000000..bed73d3 --- /dev/null +++ b/product_average_consumption/tests/test_product_computations.py @@ -0,0 +1,77 @@ +# -*- coding: utf-8 -*- +from openerp.tests.common import TransactionCase +import datetime as dt + +_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) + + # enrico_groups = [1, 2, 3, 4, 8, 9, 10, 11, 14, 18, 23, # fixme + # 24, 25, 27, 28, 32, 33, 34, 35, 36, 41, + # 42, 43, 47, 48, 51, 52, 53, 54, 57, 59, + # 60, 62, 63, 64, 65, 73, 75, 76, 77] + # # suspected_groups = [10, 35], + # + # user = self.env['res.users'].create({ + # 'name': 'Test user product average consumption', + # 'login': 'testuserproductaverageconsumption', + # 'groups_id': [(6, 0, [enrico_groups])] + # }) + # self.env = self.env(user=user) + + test_product_template = ( + self.env['product.template'] + .create({'name': 'test product template', + 'calculation_range': 14, + 'consumption_calculation_method': 'sales_history', + }) + ) + + test_product = ( + self.env['product.product'] + .create({'name': 'test product', + 'product_tmpl_id': test_product_template.id + }) + ) + + for date, qty in zip(_datetimes, _quantities): + (self.env['pos.order.line'] + .create({'create_date': date, + 'qty': qty, + 'product_id': test_product.id + }) + ) + + self.test_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 product'}) + self.assertEqual(product.name, 'Test product') + + def test_compute_average_daily_consumption(self): + product_template = self.env['product.template'].browse( + self.test_product_template_id) + product_template.calculation_range = 14 # trigger compute + computed_value = product_template.average_consumption + expected_value = 4.08 + self.assertEqual(computed_value, expected_value, 7) + + def test_compute_total_consumption(self): + product_template = self.env['product.template'].browse( + self.test_product_template_id) + product_template.calculation_range = 14 # trigger compute + computed_value = product_template.total_consumption + expected_value = 57.11 + self.assertEqual(computed_value, expected_value) diff --git a/product_average_consumption/views/product_template_view.xml b/product_average_consumption/views/product_template_view.xml new file mode 100644 index 0000000..a2954f0 --- /dev/null +++ b/product_average_consumption/views/product_template_view.xml @@ -0,0 +1,20 @@ + + + + + template.consumption.form + product.template + + + + + + + + + + + + + +