diff --git a/stock_demand_estimate/README.rst b/stock_demand_estimate/README.rst index 2fba92c0f..b640d0e95 100644 --- a/stock_demand_estimate/README.rst +++ b/stock_demand_estimate/README.rst @@ -28,18 +28,15 @@ Usage Go to 'Warehouse / Configuration / Demand Estimate Periods' and define your estimating periods (monthly or weekly). - Go to 'Warehouse / Demand Planning / Create Demand Estimates' to create or update your demand estimates. Go to 'Warehouse / Demand Planning / Demand Estimates' to review the estimates created. - .. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas :alt: Try me on Runbot - :target: https://runbot.odoo-community.org/runbot/153/8.0 - + :target: https://runbot.odoo-community.org/runbot/153/9.0 Bug Tracker =========== @@ -62,7 +59,6 @@ Contributors * Jordi Ballester Alomar - Maintainer ---------- diff --git a/stock_demand_estimate/__openerp__.py b/stock_demand_estimate/__openerp__.py index d2b165a19..04f151bda 100644 --- a/stock_demand_estimate/__openerp__.py +++ b/stock_demand_estimate/__openerp__.py @@ -5,8 +5,8 @@ { "name": "Stock Demand Estimate", "summary": "Allows to create demand estimates.", - "version": "8.0.1.0.0", - "author": "Eficent Business and IT Consulting Services S.L," + "version": "9.0.1.0.0", + "author": "Eficent, " "Odoo Community Association (OCA)", "website": "https://www.odoo-community.org", "category": "Warehouse Management", @@ -21,5 +21,5 @@ ], "license": "AGPL-3", 'installable': True, - 'application': True, + 'application': False, } diff --git a/stock_demand_estimate/models/date_range.py b/stock_demand_estimate/models/date_range.py index 34321dc34..7f8ab153e 100644 --- a/stock_demand_estimate/models/date_range.py +++ b/stock_demand_estimate/models/date_range.py @@ -3,8 +3,6 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). from openerp import api, fields, models -from openerp.tools.translate import _ -from openerp.exceptions import ValidationError class DateRange(models.Model): @@ -15,8 +13,9 @@ class DateRange(models.Model): def _compute_days(self): for rec in self: if rec.date_start and rec.date_end: - rec.days = (fields.Date.from_string(rec.date_start) - - fields.Date.from_string(rec.date_end)).days + 1 + rec.days = abs((fields.Date.from_string( + rec.date_end) - fields.Date.from_string( + rec.date_start)).days) + 1 days = fields.Float(string="Days between dates", - compute='_compute_days', store=True, readonly=True) + compute='_compute_days', readonly=True) diff --git a/stock_demand_estimate/models/stock_demand_estimate.py b/stock_demand_estimate/models/stock_demand_estimate.py index 8afcd8770..1ef7eaf70 100644 --- a/stock_demand_estimate/models/stock_demand_estimate.py +++ b/stock_demand_estimate/models/stock_demand_estimate.py @@ -22,7 +22,7 @@ class StockDemandEstimate(models.Model): rec.product_id.uom_id.id, rec.product_uom_qty, rec.product_uom.id) - def _set_product_qty(self): + def _inverse_product_qty(self): raise UserError(_('The requested operation cannot be ' 'processed because of a programming error ' 'setting the `product_qty` field instead ' @@ -36,7 +36,7 @@ class StockDemandEstimate(models.Model): date_range_id = fields.Many2one( comodel_name="date.range", string="Estimating Period", - required=True) + required=True, ondelete='restrict') product_id = fields.Many2one(comodel_name="product.product", string="Product", required=True) product_uom = fields.Many2one(comodel_name="product.uom", @@ -47,7 +47,7 @@ class StockDemandEstimate(models.Model): string="Quantity", digits_compute=dp.get_precision('Product Unit of Measure')) product_qty = fields.Float('Real Quantity', compute='_compute_product_qty', - inverse='_set_product_qty', digits=0, + inverse='_inverse_product_qty', digits=0, store=True, help='Quantity in the default UoM of the ' 'product', readonly=True) @@ -62,8 +62,8 @@ class StockDemandEstimate(models.Model): def name_get(self): res = [] for rec in self: - name = "%s - %s - %s" % (rec.date_range_id.name, rec.product_id.name, - rec.location_id.name) + name = "%s - %s - %s" % (rec.date_range_id.name, + rec.product_id.name, rec.location_id.name) res.append((rec.id, name)) return res @@ -77,11 +77,10 @@ class StockDemandEstimate(models.Model): # We need only the periods that overlap # the dates introduced by the user. - if (date_start <= period_date_start <= date_end - or date_start <= period_date_end <= date_end): + if (date_start <= period_date_start <= date_end or date_start <= + period_date_end <= date_end): overlap_date_start = max(period_date_start, date_start) overlap_date_end = min(period_date_end, date_end) days = (abs(overlap_date_end-overlap_date_start)).days + 1 return days * self.daily_qty return 0.0 - diff --git a/stock_demand_estimate/tests/__init__.py b/stock_demand_estimate/tests/__init__.py new file mode 100644 index 000000000..311ebdf8c --- /dev/null +++ b/stock_demand_estimate/tests/__init__.py @@ -0,0 +1,6 @@ +# -*- coding: utf-8 -*- +# Copyright 2017 Eficent Business and IT Consulting Services S.L. +# (http://www.eficent.com) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +from . import test_stock_demand_estimate diff --git a/stock_demand_estimate/tests/test_stock_demand_estimate.py b/stock_demand_estimate/tests/test_stock_demand_estimate.py new file mode 100644 index 000000000..1f3336a92 --- /dev/null +++ b/stock_demand_estimate/tests/test_stock_demand_estimate.py @@ -0,0 +1,135 @@ +# -*- coding: utf-8 -*- +# Copyright 2017 Eficent Business and IT Consulting Services S.L. +# (http://www.eficent.com) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +from openerp.tests import common +from dateutil.rrule import MONTHLY +from openerp.exceptions import ValidationError + + +class TestStockDemandEstimate(common.TransactionCase): + + def setUp(self): + super(TestStockDemandEstimate, self).setUp() + self.res_users_model = self.env['res.users'] + self.product_model = self.env['product.product'] + self.stock_location_model = self.env['stock.location'] + + self.g_stock_manager = self.env.ref('stock.group_stock_manager') + self.g_stock_user = self.env.ref('stock.group_stock_user') + self.company = self.env.ref('base.main_company') + + # Create users: + self.manager = self._create_user( + 'user_1', [self.g_stock_manager], self.company).id + self.user = self._create_user( + 'user_2', [self.g_stock_user], self.company).id + self.drt_monthly = self.env['date.range.type'].create( + {'name': 'Month', + 'allow_overlap': False}) + + generator = self.env['date.range.generator'] + generator = generator.create({ + 'date_start': '1943-01-01', + 'name_prefix': '1943-', + 'type_id': self.drt_monthly.id, + 'duration_count': 1, + 'unit_of_time': MONTHLY, + 'count': 12}) + generator.action_apply() + + # Create a product: + self.product1 = self.product_model.create({ + 'name': 'Test Product 1', + 'type': 'product', + 'default_code': 'PROD1', + }) + # Create a location: + self.location = self.stock_location_model.create({ + 'name': 'Place', + 'usage': 'production' + }) + + def _create_user(self, login, groups, company): + group_ids = [group.id for group in groups] + user = self.res_users_model.create({ + 'name': login, + 'login': login, + 'password': 'demo', + 'email': 'example@yourcompany.com', + 'company_id': company.id, + 'company_ids': [(4, company.id)], + 'groups_id': [(6, 0, group_ids)] + }) + return user + + def test_demand_estimate(self): + """Tests creation of demand estimates.""" + sheets = self.env['stock.demand.estimate.sheet'].search([]) + for sheet in sheets: + sheet.unlink() + wiz = self.env['stock.demand.estimate.wizard'] + wiz = wiz.create({ + 'date_start': '1943-01-01', + 'date_end': '1943-12-31', + 'location_id': self.location.id, + 'date_range_type_id': self.drt_monthly.id, + 'product_ids': [(6, 0, [self.product1.id])]}) + wiz.create_sheet() + sheets = self.env['stock.demand.estimate.sheet'].search([]) + for sheet in sheets: + + self.assertEquals(len(sheet.line_ids), 12, + 'There should be 12 lines.') + self.assertEquals(sheet.date_start, '1943-01-01', + 'The date start should be 1943-01-01') + self.assertEquals(sheet.date_end, '1943-12-31', + 'The date end should be 1943-12-31') + self.assertEquals(sheet.location_id.id, self.location.id, + 'Wrong location') + self.assertEquals(sheet.product_ids.ids, [self.product1.id], + 'Wrong products') + for line in sheet.line_ids: + line.product_uom_qty = 1 + self.assertEquals(line.product_id.id, self.product1.id, + 'The product does not match in the line') + self.assertEquals(line.location_id.id, self.location.id, + 'The product does not match in the line') + sheet.button_validate() + estimates = self.env['stock.demand.estimate'].search([( + 'date_range_type_id', '=', self.drt_monthly)]) + self.assertEquals(len(estimates), 12, 'There should be 12 ' + 'estimate records.') + for estimate in estimates: + self.assertEquals(estimate.product_id.id, self.product1.id, + 'The product does not match in the estimate') + self.assertEquals(estimate.location_id.id, self.location.id, + 'The product does not match in the estimate') + + sheets = self.env['stock.demand.estimate.sheet'].search([]) + for sheet in sheets: + sheet.unlink() + wiz = self.env['stock.demand.estimate.wizard'] + wiz = wiz.create({ + 'date_start': '1943-01-01', + 'date_end': '1943-12-31', + 'location_id': self.location.id, + 'date_range_type_id': self.drt_monthly.id, + 'product_ids': [(6, 0, [self.product1.id])]}) + wiz.create_sheet() + sheets = self.env['stock.demand.estimate.sheet'].search([]) + for sheet in sheets: + for line in sheet.line_ids: + self.assertEquals(line.product_uom_qty, 1, + 'The quantity should be 1') + + def test_invalid_dates(self): + + wiz = self.env['stock.demand.estimate.wizard'] + with self.assertRaises(ValidationError): + wiz.create({ + 'date_start': '1943-12-31', + 'date_end': '1943-01-01', + 'location_id': self.location.id, + 'date_range_type_id': self.drt_monthly.id, + 'product_ids': [(6, 0, [self.product1.id])]}) diff --git a/stock_demand_estimate/wizards/stock_demand_estimate_wizard.py b/stock_demand_estimate/wizards/stock_demand_estimate_wizard.py index dc4c8f405..ebab92e02 100644 --- a/stock_demand_estimate/wizards/stock_demand_estimate_wizard.py +++ b/stock_demand_estimate/wizards/stock_demand_estimate_wizard.py @@ -6,33 +6,20 @@ from openerp import api, fields, models, _ import openerp.addons.decimal_precision as dp -from openerp.exceptions import Warning as UserError +from openerp.exceptions import UserError, ValidationError class StockDemandEstimateSheet(models.TransientModel): _name = 'stock.demand.estimate.sheet' _description = 'Stock Demand Estimate Sheet' - def _default_date_start(self): - return self.env.context.get('date_start', False) - - def _default_date_end(self): - return self.env.context.get('date_end', False) - - def _default_location_id(self): - location_id = self.env.context.get('location_id', False) - if location_id: - return self.env['stock.location'].browse(location_id) - else: - return False - def _default_estimate_ids(self): date_start = self.env.context.get('default_date_start', False) date_end = self.env.context.get('default_date_end', False) date_range_type_id = self.env.context.get('default_date_range_type_id', False) location_id = self.env.context.get('default_location_id', False) - product_ids = self.env.context.get('default_product_ids', False) + product_ids = self.env.context.get('product_ids', False) domain = [('type_id', '=', date_range_type_id), '|', '&', ('date_start', '>=', date_start), ('date_start', '<=', date_end), @@ -136,7 +123,7 @@ class StockDemandEstimateSheetLine(models.TransientModel): estimate_id = fields.Many2one(comodel_name='stock.demand.estimate') date_range_id = fields.Many2one( - comodel_name='stock.demand.estimate.period', + comodel_name='date.range', string='Period') location_id = fields.Many2one(comodel_name='stock.location', string="Stock Location") @@ -163,6 +150,13 @@ class DemandEstimateWizard(models.TransientModel): comodel_name="product.product", string="Products") + @api.one + @api.constrains('date_start', 'date_end') + def _check_start_end_dates(self): + if self.date_start > self.date_end: + raise ValidationError(_( + 'The start date cannot be later than the end date.')) + @api.multi def _prepare_demand_estimate_sheet(self): self.ensure_one() @@ -177,14 +171,14 @@ class DemandEstimateWizard(models.TransientModel): def create_sheet(self): self.ensure_one() if not self.product_ids: - raise UserError(_('You must select at lease one product.')) + raise UserError(_('You must select at least one product.')) context = { 'default_date_start': self.date_start, 'default_date_end': self.date_end, 'default_date_range_type_id': self.date_range_type_id.id, 'default_location_id': self.location_id.id, - 'default_product_ids': self.product_ids.ids + 'product_ids': self.product_ids.ids } res = { 'context': context, diff --git a/stock_demand_estimate/wizards/stock_demand_estimate_wizard_view.xml b/stock_demand_estimate/wizards/stock_demand_estimate_wizard_view.xml index 5753a5a3b..64a046ba3 100644 --- a/stock_demand_estimate/wizards/stock_demand_estimate_wizard_view.xml +++ b/stock_demand_estimate/wizards/stock_demand_estimate_wizard_view.xml @@ -20,7 +20,8 @@
- +