diff --git a/stock_demand_estimate/README.rst b/stock_demand_estimate/README.rst index 436eacf48..4076d5886 100644 --- a/stock_demand_estimate/README.rst +++ b/stock_demand_estimate/README.rst @@ -1,4 +1,4 @@ -.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg +.. 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 @@ -17,26 +17,25 @@ Installation This module relies on: * The OCA module '2D matrix for x2many fields', and can be downloaded from - Github: https://github.com/OCA/web/tree/10.0/web_widget_x2many_2d_matrix + Github: https://github.com/OCA/web/tree/11.0/web_widget_x2many_2d_matrix * The OCA module 'Date Range', and can be downloaded from - Github: https://github.com/OCA/server-tools/tree/10.0/date_range + Github: https://github.com/OCA/server-ux/tree/11.0/date_range Usage ===== -Go to 'Warehouse / Configuration / Demand Estimate Periods' and define your -estimating periods (monthly or weekly). +Go to 'Inventory / Configuration / Date Ranges' and define your estimating periods. -Go to 'Warehouse / Demand Planning / Create Demand Estimates' to create or +Go to 'Inventory / Demand Planning / Create Demand Estimates' to create or update your demand estimates. -Go to 'Warehouse / Demand Planning / Demand Estimates' to review the +Go to 'Inventory / 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/10.0 + :target: https://runbot.odoo-community.org/runbot/153/11.0 Bug Tracker =========== diff --git a/stock_demand_estimate/__init__.py b/stock_demand_estimate/__init__.py index 851fa8da7..db2f7970e 100644 --- a/stock_demand_estimate/__init__.py +++ b/stock_demand_estimate/__init__.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright 2016 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). diff --git a/stock_demand_estimate/__manifest__.py b/stock_demand_estimate/__manifest__.py index 8a17a7823..ad326cd4b 100644 --- a/stock_demand_estimate/__manifest__.py +++ b/stock_demand_estimate/__manifest__.py @@ -1,25 +1,25 @@ -# -*- coding: utf-8 -*- # Copyright 2016 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). { "name": "Stock Demand Estimate", "summary": "Allows to create demand estimates.", - "version": "10.0.1.0.0", + "version": "11.0.1.0.0", "author": "Eficent, " "Odoo Community Association (OCA)", - "website": "https://www.odoo-community.org", + "website": "https://github.com/OCA/stock-logistics-warehouse", "category": "Warehouse Management", - "depends": ["stock", - "web_widget_x2many_2d_matrix", - "date_range" - ], - "data": ["security/ir.model.access.csv", - "security/stock_security.xml", - "views/stock_demand_estimate_view.xml", - "wizards/stock_demand_estimate_wizard_view.xml", - ], + "depends": [ + "stock", + "web_widget_x2many_2d_matrix", + "date_range", + ], + "data": [ + "security/ir.model.access.csv", + "security/stock_security.xml", + "views/stock_demand_estimate_view.xml", + "views/date_range.xml", + "wizards/stock_demand_estimate_wizard_view.xml", + ], "license": "AGPL-3", - 'installable': True, - 'application': False, } diff --git a/stock_demand_estimate/models/__init__.py b/stock_demand_estimate/models/__init__.py index 55c1477c2..595f15d26 100644 --- a/stock_demand_estimate/models/__init__.py +++ b/stock_demand_estimate/models/__init__.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright 2016 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). diff --git a/stock_demand_estimate/models/date_range.py b/stock_demand_estimate/models/date_range.py index 2d6a49bdb..a33594d4a 100644 --- a/stock_demand_estimate/models/date_range.py +++ b/stock_demand_estimate/models/date_range.py @@ -1,6 +1,5 @@ -# -*- coding: utf-8 -*- -# © 2016 ACSONE SA/NV () -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +# Copyright 2016 Eficent Business and IT Consulting Services S.L. +# (http://www.eficent.com) from odoo import api, fields, models @@ -8,14 +7,17 @@ from odoo import api, fields, models class DateRange(models.Model): _inherit = "date.range" + days = fields.Integer( + string="Days between dates", + compute='_compute_days', + readonly=True, + ) + @api.multi @api.depends('date_start', 'date_end') def _compute_days(self): - for rec in self: - if rec.date_start and rec.date_end: - 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', readonly=True) + for rec in self.filtered(lambda x: x.date_start and x.date_end): + rec.days = abs(( + fields.Date.from_string(rec.date_end) - + fields.Date.from_string(rec.date_start) + ).days) + 1 diff --git a/stock_demand_estimate/models/stock_demand_estimate.py b/stock_demand_estimate/models/stock_demand_estimate.py index d2ff19fee..1259e1a72 100644 --- a/stock_demand_estimate/models/stock_demand_estimate.py +++ b/stock_demand_estimate/models/stock_demand_estimate.py @@ -1,70 +1,94 @@ -# -*- coding: utf-8 -*- -# © 2016 Eficent Business and IT Consulting Services S.L. +# Copyright 2016 Eficent Business and IT Consulting Services S.L. # (http://www.eficent.com) -# © 2016 Aleph Objects, Inc. (https://www.alephobjects.com/) +# Copyright 2016 Aleph Objects, Inc. (https://www.alephobjects.com/) # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). from odoo import api, fields, models, _ -import odoo.addons.decimal_precision as dp -from odoo.exceptions import Warning as UserError +from odoo.addons import decimal_precision as dp +from odoo.exceptions import UserError class StockDemandEstimate(models.Model): _name = 'stock.demand.estimate' _description = 'Stock Demand Estimate Line' + date_range_id = fields.Many2one( + comodel_name="date.range", + string="Estimating Period", + required=True, + ondelete='restrict' + ) + product_id = fields.Many2one( + comodel_name="product.product", + string="Product", + required=True, + ) + product_uom = fields.Many2one( + comodel_name="product.uom", + string="Unit of measure", + ) + location_id = fields.Many2one( + comodel_name="stock.location", + string="Location", + required=True, + ) + product_uom_qty = fields.Float( + string="Quantity", + digits=dp.get_precision('Product Unit of Measure'), + ) + product_qty = fields.Float( + 'Real Quantity', + compute='_compute_product_quantity', + inverse='_inverse_product_quantity', + digits=0, + store=True, + help='Quantity in the default UoM of the product', + readonly=True, + ) + daily_qty = fields.Float( + string='Quantity / Day', + compute='_compute_daily_qty', + ) + company_id = fields.Many2one( + comodel_name='res.company', + string='Company', + required=True, + default=lambda self: self.env['res.company']._company_default_get( + 'stock.demand.estimate' + ) + ) + + @api.multi + @api.depends('product_qty', 'date_range_id.days') + def _compute_daily_qty(self): + for rec in self: + rec.daily_qty = rec.product_qty / rec.date_range_id.days + @api.multi @api.depends('product_id', 'product_uom', 'product_uom_qty') def _compute_product_quantity(self): for rec in self: if rec.product_uom: rec.product_qty = rec.product_uom._compute_quantity( - rec.product_uom_qty, - rec.product_id.uom_id) + rec.product_uom_qty, rec.product_id.uom_id + ) def _inverse_product_quantity(self): - raise UserError(_('The requested operation cannot be ' - 'processed because of a programming error ' - 'setting the `product_qty` field instead ' - 'of the `product_uom_qty`.')) - - @api.multi - def _compute_daily_qty(self): - for rec in self: - rec.daily_qty = rec.product_qty / rec.date_range_id.days - - date_range_id = fields.Many2one( - comodel_name="date.range", - string="Estimating Period", - required=True, ondelete='restrict') - product_id = fields.Many2one(comodel_name="product.product", - string="Product", required=True) - product_uom = fields.Many2one(comodel_name="product.uom", - string="Unit of measure") - location_id = fields.Many2one(comodel_name="stock.location", - string="Location", required=True) - product_uom_qty = fields.Float( - string="Quantity", - digits=dp.get_precision('Product Unit of Measure')) - product_qty = fields.Float('Real Quantity', - compute='_compute_product_quantity', - inverse='_inverse_product_quantity', digits=0, - store=True, - help='Quantity in the default UoM of the ' - 'product', readonly=True) - daily_qty = fields.Float(string='Quantity / Day', - compute='_compute_daily_qty') - company_id = fields.Many2one( - comodel_name='res.company', string='Company', required=True, - default=lambda self: self.env['res.company']._company_default_get( - 'stock.demand.estimate')) + raise UserError(_( + 'The requested operation cannot be ' + 'processed because of a programming error ' + 'setting the `product_qty` field instead ' + 'of the `product_uom_qty`.' + )) @api.multi 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 @@ -72,16 +96,15 @@ class StockDemandEstimate(models.Model): def get_quantity_by_date_range(self, date_start, date_end): # Check if the dates overlap with the period period_date_start = fields.Date.from_string( - self.date_range_id.date_start) - period_date_end = fields.Date.from_string( - self.date_range_id.date_end) + self.date_range_id.date_start + ) + period_date_end = fields.Date.from_string(self.date_range_id.date_end) # 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 period_date_start <= date_end and period_date_end >= date_start: 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 + 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 index 311ebdf8c..216a1ed7a 100644 --- a/stock_demand_estimate/tests/__init__.py +++ b/stock_demand_estimate/tests/__init__.py @@ -1,4 +1,3 @@ -# -*- 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). diff --git a/stock_demand_estimate/tests/test_stock_demand_estimate.py b/stock_demand_estimate/tests/test_stock_demand_estimate.py index 52f694bb4..97d2d362b 100644 --- a/stock_demand_estimate/tests/test_stock_demand_estimate.py +++ b/stock_demand_estimate/tests/test_stock_demand_estimate.py @@ -1,65 +1,73 @@ -# -*- 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 odoo.tests import common from dateutil.rrule import MONTHLY from odoo.exceptions import ValidationError +from odoo.tests.common import SavepointCase -class TestStockDemandEstimate(common.TransactionCase): +class TestStockDemandEstimate(SavepointCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.res_users_model = cls.env['res.users'] + cls.product_model = cls.env['product.product'] + cls.stock_location_model = cls.env['stock.location'] - 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') + cls.g_stock_manager = cls.env.ref('stock.group_stock_manager') + cls.g_stock_user = cls.env.ref('stock.group_stock_user') + cls.company = cls.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}) + cls.manager = cls._create_user( + 'user_1', + [cls.g_stock_manager], + cls.company, + ).id + cls.user = cls._create_user( + 'user_2', + [cls.g_stock_user], + cls.company, + ).id + cls.drt_monthly = cls.env['date.range.type'].create({ + 'name': 'Month', + 'allow_overlap': False, + }) - generator = self.env['date.range.generator'] + generator = cls.env['date.range.generator'] generator = generator.create({ 'date_start': '1943-01-01', 'name_prefix': '1943-', - 'type_id': self.drt_monthly.id, + 'type_id': cls.drt_monthly.id, 'duration_count': 1, 'unit_of_time': MONTHLY, - 'count': 12}) + 'count': 12, + }) generator.action_apply() # Create a product: - self.product1 = self.product_model.create({ + cls.product1 = cls.product_model.create({ 'name': 'Test Product 1', 'type': 'product', 'default_code': 'PROD1', }) # Create a location: - self.location = self.stock_location_model.create({ + cls.location = cls.stock_location_model.create({ 'name': 'Place', - 'usage': 'production' + 'usage': 'production', }) - def _create_user(self, login, groups, company): + @classmethod + def _create_user(cls, login, groups, company): group_ids = [group.id for group in groups] - user = self.res_users_model.create({ + user = cls.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)] + 'groups_id': [(6, 0, group_ids)], }) return user @@ -74,37 +82,66 @@ class TestStockDemandEstimate(common.TransactionCase): '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])]}) + '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') + self.assertEqual( + len(sheet.line_ids), + 12, + 'There should be 12 lines.', + ) + self.assertEqual( + sheet.date_start, + '1943-01-01', + 'The date start should be 1943-01-01', + ) + self.assertEqual( + sheet.date_end, + '1943-12-31', + 'The date end should be 1943-12-31', + ) + self.assertEqual( + sheet.location_id.id, + self.location.id, + 'Wrong location', + ) 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') + self.assertEqual( + line.product_id.id, + self.product1.id, + 'The product does not match in the line', + ) + self.assertEqual( + 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.') + ranges = self.env['date.range'].search( + [('type_id', '=', self.drt_monthly.id)], + ) + estimates = self.env['stock.demand.estimate'].search( + [('date_range_id', 'in', ranges.ids)] + ) + self.assertEqual( + 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') + self.assertEqual( + estimate.product_id.id, + self.product1.id, + 'The product does not match in the estimate', + ) + self.assertEqual( + 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: @@ -115,13 +152,17 @@ class TestStockDemandEstimate(common.TransactionCase): '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])]}) + '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') + self.assertEqual( + line.product_uom_qty, + 1, + 'The quantity should be 1', + ) def test_invalid_dates(self): @@ -132,4 +173,5 @@ class TestStockDemandEstimate(common.TransactionCase): '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])]}) + 'product_ids': [(6, 0, [self.product1.id])] + }) diff --git a/stock_demand_estimate/views/date_range.xml b/stock_demand_estimate/views/date_range.xml new file mode 100644 index 000000000..c33e48198 --- /dev/null +++ b/stock_demand_estimate/views/date_range.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/stock_demand_estimate/wizards/__init__.py b/stock_demand_estimate/wizards/__init__.py index 05c5fae45..4dbc3b980 100644 --- a/stock_demand_estimate/wizards/__init__.py +++ b/stock_demand_estimate/wizards/__init__.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright 2016 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). diff --git a/stock_demand_estimate/wizards/stock_demand_estimate_wizard.py b/stock_demand_estimate/wizards/stock_demand_estimate_wizard.py index d4abacc22..76980af0c 100644 --- a/stock_demand_estimate/wizards/stock_demand_estimate_wizard.py +++ b/stock_demand_estimate/wizards/stock_demand_estimate_wizard.py @@ -1,10 +1,10 @@ -# -*- coding: utf-8 -*- -# © 2016 Eficent Business and IT Consulting Services S.L. +# Copyright 2016 Eficent Business and IT Consulting Services S.L. # (http://www.eficent.com) -# © 2016 Aleph Objects, Inc. (https://www.alephobjects.com/) +# Copyright 2016 Aleph Objects, Inc. (https://www.alephobjects.com/) # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). from odoo import api, fields, models, _ +from odoo.osv import expression import odoo.addons.decimal_precision as dp from odoo.exceptions import UserError, ValidationError @@ -13,75 +13,107 @@ class StockDemandEstimateSheet(models.TransientModel): _name = 'stock.demand.estimate.sheet' _description = 'Stock Demand Estimate Sheet' - 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('product_ids', False) - domain = [('type_id', '=', date_range_type_id), '|', '&', - ('date_start', '>=', date_start), - ('date_start', '<=', date_end), - '&', - ('date_end', '>=', date_start), - ('date_end', '<=', date_end)] - periods = self.env['date.range'].search( - domain) - domain = [('type_id', '=', date_range_type_id), - ('date_start', '<=', date_start), - ('date_end', '>=', date_start)] - periods |= self.env['date.range'].search( - domain) - products = self.env['product.product'].browse(product_ids) - - lines = [] - for product in products: - name_y = '' - if product.default_code: - name_y += '[%s] ' % product.default_code - name_y += product.name - name_y += ' - %s' % product.uom_id.name - for period in periods: - estimates = self.env['stock.demand.estimate'].search( - [('product_id', '=', product.id), - ('date_range_id', '=', period.id), - ('location_id', '=', location_id)]) - if estimates: - lines.append((0, 0, { - 'value_x': period.name, - 'value_y': name_y, - 'date_range_id': period.id, - 'product_id': product.id, - 'product_uom': estimates[0].product_uom.id, - 'location_id': location_id, - 'estimate_id': estimates[0].id, - 'product_uom_qty': estimates[0].product_uom_qty - })) - else: - lines.append((0, 0, { - 'value_x': period.name, - 'value_y': name_y, - 'date_range_id': period.id, - 'product_id': product.id, - 'product_uom': product.uom_id.id, - 'location_id': location_id, - 'product_uom_qty': 0.0 - })) - return lines - - date_start = fields.Date(string="Date From", readonly=True) - date_end = fields.Date(string="Date From", readonly=True) - date_range_type_id = fields.Many2one(string='Date Range Type', - comodel_name='date.range.type', - readonly=True) - location_id = fields.Many2one(comodel_name="stock.location", - string="Location", readonly=True) + date_start = fields.Date( + string="Date From", + readonly=True, + ) + date_end = fields.Date( + string="Date to", + readonly=True, + ) + date_range_type_id = fields.Many2one( + string='Date Range Type', + comodel_name='date.range.type', + readonly=True, + ) + location_id = fields.Many2one( + comodel_name="stock.location", + string="Location", + readonly=True, + ) line_ids = fields.Many2many( string="Estimates", comodel_name='stock.demand.estimate.sheet.line', relation='stock_demand_estimate_line_rel', - default=_default_estimate_ids) + ) + product_ids = fields.Many2many( + string="Products", + comodel_name="product.product", + ) + + @api.onchange('date_start', 'date_end', 'date_range_type_id',) + def _onchange_dates(self): + if not all([self.date_start, self.date_end, self.date_range_type_id]): + return + ranges = self._get_ranges() + if not ranges: + raise UserError(_('There is no ranges created.')) + estimates = self.env['stock.demand.estimate'].search([ + ('product_id', 'in', self.product_ids.ids), + ('date_range_id', 'in', ranges.ids), + ('location_id', '=', self.location_id.id), + ]) + lines = [] + for product in self.product_ids: + for _range in ranges: + estimate = estimates.filtered( + lambda x: (x.date_range_id == _range and + x.product_id == product) + ) + if estimate: + uom_id = estimate[0].product_uom.id + uom_qty = estimate[0].product_uom_qty + estimate_id = estimate[0].id + else: + uom_id = product.uom_id.id + uom_qty = 0.0 + estimate_id = None + lines.append((0, 0, self._get_default_estimate_line( + _range, + product, + uom_id, + uom_qty, + estimate_id=estimate_id, + ))) + self.line_ids = lines + + def _get_ranges(self): + domain_1 = [ + '&', + ('type_id', '=', self.date_range_type_id.id), '|', '&', + ('date_start', '>=', self.date_start), + ('date_start', '<=', self.date_end), + '&', + ('date_end', '>=', self.date_start), + ('date_end', '<=', self.date_end), + ] + domain_2 = [ + '&', + ('type_id', '=', self.date_range_type_id.id), + '&', + ('date_start', '<=', self.date_start), + ('date_end', '>=', self.date_start), + ] + domain = expression.OR([domain_1, domain_2]) + ranges = self.env['date.range'].search(domain) + return ranges + + def _get_default_estimate_line(self, _range, product, + uom_id, uom_qty, estimate_id=None): + name_y = '{} - {}'.format(product.name, product.uom_id.name) + if product.default_code: + name_y += '[{}] {}'.format(product.default_code, name_y) + values = { + 'value_x': _range.name, + 'value_y': name_y, + 'date_range_id': _range.id, + 'product_id': product.id, + 'product_uom': uom_id, + 'product_uom_qty': uom_qty, + 'location_id': self.location_id.id, + 'estimate_id': estimate_id, + } + return values @api.model def _prepare_estimate_data(self, line): @@ -102,8 +134,7 @@ class StockDemandEstimateSheet(models.TransientModel): res.append(line.estimate_id.id) else: data = self._prepare_estimate_data(line) - estimate = self.env['stock.demand.estimate'].create( - data) + estimate = self.env['stock.demand.estimate'].create(data) res.append(estimate.id) res = { 'domain': [('id', 'in', res)], @@ -121,50 +152,77 @@ class StockDemandEstimateSheetLine(models.TransientModel): _name = 'stock.demand.estimate.sheet.line' _description = 'Stock Demand Estimate Sheet Line' - estimate_id = fields.Many2one(comodel_name='stock.demand.estimate') + estimate_id = fields.Many2one( + comodel_name='stock.demand.estimate' + ) date_range_id = fields.Many2one( comodel_name='date.range', - string='Period') - location_id = fields.Many2one(comodel_name='stock.location', - string="Stock Location") - product_id = fields.Many2one(comodel_name='product.product', - string='Product') - value_x = fields.Char(string='Period') - value_y = fields.Char(string='Product') + string='Period', + ) + location_id = fields.Many2one( + comodel_name='stock.location', + string="Stock Location", + ) + product_id = fields.Many2one( + comodel_name='product.product', + string='Product', + ) + value_x = fields.Char( + string='Period', + ) + value_y = fields.Char( + string='Product', + ) product_uom_qty = fields.Float( - string="Quantity", digits=dp.get_precision('Product UoM')) + string="Quantity", + digits=dp.get_precision('Product UoM'), + ) class DemandEstimateWizard(models.TransientModel): _name = 'stock.demand.estimate.wizard' _description = 'Stock Demand Estimate Wizard' - date_start = fields.Date(string="Date From", required=True) - date_end = fields.Date(string="Date To", required=True) - date_range_type_id = fields.Many2one(string='Date Range Type', - comodel_name='date.range.type', - required=True) - location_id = fields.Many2one(comodel_name="stock.location", - string="Location", required=True) + date_start = fields.Date( + string="Date From", + required=True, + ) + date_end = fields.Date( + string="Date To", + required=True, + ) + date_range_type_id = fields.Many2one( + string='Date Range Type', + comodel_name='date.range.type', + required=True, + ) + location_id = fields.Many2one( + comodel_name="stock.location", + string="Location", + required=True, + ) product_ids = fields.Many2many( comodel_name="product.product", - string="Products") + string="Products", + ) @api.onchange('date_range_type_id') def _onchange_date_range_type_id(self): if self.date_range_type_id.company_id: return { - 'domain': { - 'location_id': [('company_id', '=', - self.date_range_type_id.company_id.id)]}} + 'domain': {'location_id': [ + ('company_id', '=', self.date_range_type_id.company_id.id) + ]} + } return {} - @api.one @api.constrains('date_start', 'date_end') def _check_start_end_dates(self): + self.ensure_one() if self.date_start > self.date_end: - raise ValidationError(_( - 'The start date cannot be later than the end date.')) + raise ValidationError( + _('The start date cannot be later than the end date.') + ) @api.multi def _prepare_demand_estimate_sheet(self): @@ -182,22 +240,24 @@ class DemandEstimateWizard(models.TransientModel): if not self.product_ids: 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, - 'product_ids': self.product_ids.ids - } + # 2d matrix widget need real records to work + sheet = self.env['stock.demand.estimate.sheet'].create({ + 'date_start': self.date_start, + 'date_end': self.date_end, + 'date_range_type_id': self.date_range_type_id.id, + 'location_id': self.location_id.id, + 'product_ids': [(6, 0, self.product_ids.ids)], + }) + sheet._onchange_dates() + res = { - 'context': context, 'name': _('Estimate Sheet'), 'src_model': 'stock.demand.estimate.wizard', 'view_type': 'form', 'view_mode': 'form', 'target': 'new', 'res_model': 'stock.demand.estimate.sheet', - 'type': 'ir.actions.act_window' + 'res_id': sheet.id, + 'type': 'ir.actions.act_window', } - return res 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 1b072a7fd..6a0878045 100644 --- a/stock_demand_estimate/wizards/stock_demand_estimate_wizard_view.xml +++ b/stock_demand_estimate/wizards/stock_demand_estimate_wizard_view.xml @@ -7,13 +7,12 @@ stock.demand.estimate.sheet
+ + - - - - + @@ -54,26 +53,27 @@ stock.demand.estimate.wizard - + - - - + + + + + - -
- - - -
-
+
+ + + + +