From 89976063c2f4a49d657c97ead96e19c51ff73c3b Mon Sep 17 00:00:00 2001 From: ps-tubtim Date: Mon, 23 Mar 2020 14:51:53 +0700 Subject: [PATCH] [IMP] stock_demand_estimate_matrix: black, isort --- stock_demand_estimate_matrix/__manifest__.py | 8 +- .../models/date_range.py | 9 +- .../models/stock_demand_estimate.py | 14 +- .../tests/test_stock_demand_estimate.py | 160 +++++----- .../views/date_range.xml | 16 +- .../views/stock_demand_estimate_view.xml | 34 ++- .../wizards/stock_demand_estimate_wizard.py | 278 ++++++++---------- .../stock_demand_estimate_wizard_view.xml | 103 ++++--- 8 files changed, 298 insertions(+), 324 deletions(-) diff --git a/stock_demand_estimate_matrix/__manifest__.py b/stock_demand_estimate_matrix/__manifest__.py index eac91795b..a688c18d2 100644 --- a/stock_demand_estimate_matrix/__manifest__.py +++ b/stock_demand_estimate_matrix/__manifest__.py @@ -3,15 +3,11 @@ { "name": "Stock Demand Estimate Matrix", "summary": "Allows to create demand estimates.", - "version": "12.0.2.0.0", + "version": "13.0.1.0.0", "author": "ForgeFlow, Odoo Community Association (OCA)", "website": "https://github.com/OCA/stock-logistics-warehouse", "category": "Warehouse Management", - "depends": [ - "stock_demand_estimate", - "web_widget_x2many_2d_matrix", - "date_range", - ], + "depends": ["stock_demand_estimate", "web_widget_x2many_2d_matrix", "date_range"], "data": [ "views/stock_demand_estimate_view.xml", "views/date_range.xml", diff --git a/stock_demand_estimate_matrix/models/date_range.py b/stock_demand_estimate_matrix/models/date_range.py index 802d8e46e..fa4911925 100644 --- a/stock_demand_estimate_matrix/models/date_range.py +++ b/stock_demand_estimate_matrix/models/date_range.py @@ -8,16 +8,11 @@ class DateRange(models.Model): _inherit = "date.range" days = fields.Integer( - string="Days between dates", - compute="_compute_days", - readonly=True, + 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.filtered(lambda x: x.date_start and x.date_end): - rec.days = abs(( - rec.date_end - - rec.date_start - ).days) + 1 + rec.days = abs((rec.date_end - rec.date_start).days) + 1 diff --git a/stock_demand_estimate_matrix/models/stock_demand_estimate.py b/stock_demand_estimate_matrix/models/stock_demand_estimate.py index 9bab74bdb..a0d86f369 100644 --- a/stock_demand_estimate_matrix/models/stock_demand_estimate.py +++ b/stock_demand_estimate_matrix/models/stock_demand_estimate.py @@ -5,12 +5,10 @@ from odoo import api, fields, models class StockDemandEstimate(models.Model): - _inherit = 'stock.demand.estimate' + _inherit = "stock.demand.estimate" date_range_id = fields.Many2one( - comodel_name="date.range", - string="Estimating Period", - ondelete='restrict' + comodel_name="date.range", string="Estimating Period", ondelete="restrict" ) @api.multi @@ -19,8 +17,7 @@ class StockDemandEstimate(models.Model): ) def _compute_dates(self): date_range_records = self.filtered(lambda r: r.date_range_id) - res = super( - StockDemandEstimate, self - date_range_records)._compute_dates() + res = super(StockDemandEstimate, self - date_range_records)._compute_dates() for rec in date_range_records: rec.date_from = rec.date_range_id.date_start rec.date_to = rec.date_range_id.date_end @@ -32,9 +29,8 @@ class StockDemandEstimate(models.Model): date_range_records = self.filtered(lambda r: r.date_range_id) res = super(StockDemandEstimate, self - date_range_records).name_get() for rec in date_range_records: - name = "%s - %s - %s" % ( - rec.date_range_id.name, rec.product_id.name, - rec.location_id.name, + name = "{} - {} - {}".format( + rec.date_range_id.name, rec.product_id.name, rec.location_id.name, ) res.append((rec.id, name)) return res diff --git a/stock_demand_estimate_matrix/tests/test_stock_demand_estimate.py b/stock_demand_estimate_matrix/tests/test_stock_demand_estimate.py index 6489355d7..93324a6d3 100644 --- a/stock_demand_estimate_matrix/tests/test_stock_demand_estimate.py +++ b/stock_demand_estimate_matrix/tests/test_stock_demand_estimate.py @@ -2,6 +2,7 @@ # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). from dateutil.rrule import MONTHLY + from odoo import fields from odoo.exceptions import ValidationError from odoo.tests.common import SavepointCase @@ -21,56 +22,48 @@ class TestStockDemandEstimate(SavepointCase): cls.company = cls.env.ref("base.main_company") # Create users: - 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, - }) + 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 = cls.env["date.range.generator"] - generator = generator.create({ - "date_start": "1943-01-01", - "name_prefix": "1943-", - "type_id": cls.drt_monthly.id, - "duration_count": 1, - "unit_of_time": MONTHLY, - "count": 12, - }) + generator = generator.create( + { + "date_start": "1943-01-01", + "name_prefix": "1943-", + "type_id": cls.drt_monthly.id, + "duration_count": 1, + "unit_of_time": MONTHLY, + "count": 12, + } + ) generator.action_apply() # Create a product: - cls.product_1 = cls.product_model.create({ - "name": "Test Product 1", - "type": "product", - "default_code": "PROD1", - }) + cls.product_1 = cls.product_model.create( + {"name": "Test Product 1", "type": "product", "default_code": "PROD1"} + ) # Create a location: - cls.location = cls.stock_location_model.create({ - "name": "Place", - "usage": "production", - }) + cls.location = cls.stock_location_model.create( + {"name": "Place", "usage": "production"} + ) @classmethod def _create_user(cls, login, groups, company): group_ids = [group.id for group in groups] - 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)], - }) + 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)], + } + ) return user def test_01_demand_estimate_wizard(self): @@ -79,20 +72,20 @@ class TestStockDemandEstimate(SavepointCase): 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.product_1.id])], - }) + 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.product_1.id])], + } + ) wiz.create_sheet() sheets = self.env["stock.demand.estimate.sheet"].search([]) for sheet in sheets: self.assertEqual( - len(sheet.line_ids), - 12, - "There should be 12 lines.", + len(sheet.line_ids), 12, "There should be 12 lines.", ) self.assertEqual( fields.Date.to_string(sheet.date_start), @@ -105,9 +98,7 @@ class TestStockDemandEstimate(SavepointCase): "The date end should be 1943-12-31", ) self.assertEqual( - sheet.location_id.id, - self.location.id, - "Wrong location", + sheet.location_id.id, self.location.id, "Wrong location", ) for line in sheet.line_ids: line.product_uom_qty = 1 @@ -129,9 +120,7 @@ class TestStockDemandEstimate(SavepointCase): [("date_range_id", "in", ranges.ids)] ) self.assertEqual( - len(estimates), - 12, - "There should be 12 estimate records.", + len(estimates), 12, "There should be 12 estimate records.", ) for estimate in estimates: self.assertEqual( @@ -149,44 +138,49 @@ class TestStockDemandEstimate(SavepointCase): 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.product_1.id])], - }) + 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.product_1.id])], + } + ) wiz.create_sheet() sheets = self.env["stock.demand.estimate.sheet"].search([]) for sheet in sheets: for line in sheet.line_ids: self.assertEqual( - line.product_uom_qty, - 1, - "The quantity should be 1", + line.product_uom_qty, 1, "The quantity should be 1", ) def test_02_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.product_1.id])], - }) + 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.product_1.id])], + } + ) def test_03_computed_fields(self): - range = self.env["date.range"].search( - [("type_id", "=", self.drt_monthly.id)], limit=1) - estimate = self.estimate_model.create({ - "product_id": self.product_1.id, - "location_id": self.location.id, - "date_range_id": range.id, - "product_uom_qty": 100.0, - }) - expected_date_from = range.date_start - expected_date_to = range.date_end + date_range = self.env["date.range"].search( + [("type_id", "=", self.drt_monthly.id)], limit=1 + ) + estimate = self.estimate_model.create( + { + "product_id": self.product_1.id, + "location_id": self.location.id, + "date_range_id": range.id, + "product_uom_qty": 100.0, + } + ) + expected_date_from = date_range.date_start + expected_date_to = date_range.date_end self.assertEqual(estimate.date_from, expected_date_from) self.assertEqual(estimate.date_to, expected_date_to) diff --git a/stock_demand_estimate_matrix/views/date_range.xml b/stock_demand_estimate_matrix/views/date_range.xml index dbd9544dc..559c6f85c 100644 --- a/stock_demand_estimate_matrix/views/date_range.xml +++ b/stock_demand_estimate_matrix/views/date_range.xml @@ -1,10 +1,10 @@ - + - - - + diff --git a/stock_demand_estimate_matrix/views/stock_demand_estimate_view.xml b/stock_demand_estimate_matrix/views/stock_demand_estimate_view.xml index 03998ec43..f0835e591 100644 --- a/stock_demand_estimate_matrix/views/stock_demand_estimate_view.xml +++ b/stock_demand_estimate_matrix/views/stock_demand_estimate_view.xml @@ -1,13 +1,15 @@ - + - stock.demand.estimate.tree stock.demand.estimate - + - + top @@ -15,32 +17,36 @@ - stock.demand.estimate.pivot stock.demand.estimate - + - + - stock.demand.estimate.search stock.demand.estimate - + - + - - + tree,pivot - diff --git a/stock_demand_estimate_matrix/wizards/stock_demand_estimate_wizard.py b/stock_demand_estimate_matrix/wizards/stock_demand_estimate_wizard.py index 81f32263d..ec72f83aa 100644 --- a/stock_demand_estimate_matrix/wizards/stock_demand_estimate_wizard.py +++ b/stock_demand_estimate_matrix/wizards/stock_demand_estimate_wizard.py @@ -1,64 +1,56 @@ # Copyright 2019 ForgeFlow S.L. (https://www.forgeflow.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 -from odoo.addons import decimal_precision as dp +from odoo import _, api, fields, models from odoo.exceptions import UserError, ValidationError +from odoo.osv import expression + +from odoo.addons import decimal_precision as dp class StockDemandEstimateSheet(models.TransientModel): - _name = 'stock.demand.estimate.sheet' - _description = 'Stock Demand Estimate Sheet' + _name = "stock.demand.estimate.sheet" + _description = "Stock Demand Estimate Sheet" - date_start = fields.Date( - string="Date From", - readonly=True, - ) - date_end = fields.Date( - string="Date to", - 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, + string="Date Range Type", comodel_name="date.range.type", readonly=True, ) location_id = fields.Many2one( - comodel_name="stock.location", - string="Location", - readonly=True, + 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', - ) - product_ids = fields.Many2many( - string="Products", - comodel_name="product.product", + comodel_name="stock.demand.estimate.sheet.line", + relation="stock_demand_estimate_line_rel", ) + product_ids = fields.Many2many(string="Products", comodel_name="product.product",) - @api.onchange('date_start', 'date_end', 'date_range_type_id',) + @api.onchange( + "date_start", "date_end", "date_range_type_id", + ) def _onchange_dates(self): for sheet in self: - if not all([sheet.date_start, sheet.date_end, - sheet.date_range_type_id]): + if not all([sheet.date_start, sheet.date_end, sheet.date_range_type_id]): return ranges = sheet._get_ranges() if not ranges: - raise UserError(_('There is no ranges created.')) - estimates = self.env['stock.demand.estimate'].search([ - ('product_id', 'in', sheet.product_ids.ids), - ('date_range_id', 'in', ranges.ids), - ('location_id', '=', sheet.location_id.id), - ]) + raise UserError(_("There is no ranges created.")) + estimates = self.env["stock.demand.estimate"].search( + [ + ("product_id", "in", sheet.product_ids.ids), + ("date_range_id", "in", ranges.ids), + ("location_id", "=", sheet.location_id.id), + ] + ) lines = [] for product in sheet.product_ids: for _range in ranges: estimate = estimates.filtered( - lambda x: (x.date_range_id == _range and - x.product_id == product) + lambda x: ( + x.date_range_id == _range and x.product_id == product + ) ) if estimate: uom_id = fields.first(estimate).product_uom.id @@ -68,61 +60,70 @@ class StockDemandEstimateSheet(models.TransientModel): uom_id = product.uom_id.id uom_qty = 0.0 estimate_id = None - lines.append((0, 0, sheet._get_default_estimate_line( - _range, - product, - uom_id, - uom_qty, - estimate_id=estimate_id, - ))) + lines.append( + ( + 0, + 0, + sheet._get_default_estimate_line( + _range, + product, + uom_id, + uom_qty, + estimate_id=estimate_id, + ), + ) + ) sheet.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), + "&", + ("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), + "&", + ("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) + 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) + 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) + 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, + "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): return { - 'date_range_id': line.date_range_id.id, - 'product_id': line.product_id.id, - 'location_id': line.location_id.id, - 'product_uom_qty': line.product_uom_qty, - 'product_uom': line.product_id.uom_id.id, + "date_range_id": line.date_range_id.id, + "product_id": line.product_id.id, + "location_id": line.location_id.id, + "product_uom_qty": line.product_uom_qty, + "product_uom": line.product_id.uom_id.id, } @api.multi @@ -134,130 +135,107 @@ 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)], - 'name': _('Stock Demand Estimates'), - 'src_model': 'stock.demand.estimate.wizard', - 'view_type': 'form', - 'view_mode': 'tree', - 'res_model': 'stock.demand.estimate', - 'type': 'ir.actions.act_window' + "domain": [("id", "in", res)], + "name": _("Stock Demand Estimates"), + "src_model": "stock.demand.estimate.wizard", + "view_type": "form", + "view_mode": "tree", + "res_model": "stock.demand.estimate", + "type": "ir.actions.act_window", } return res class StockDemandEstimateSheetLine(models.TransientModel): - _name = 'stock.demand.estimate.sheet.line' - _description = 'Stock Demand Estimate Sheet Line' + _name = "stock.demand.estimate.sheet.line" + _description = "Stock Demand Estimate Sheet Line" - estimate_id = fields.Many2one( - comodel_name='stock.demand.estimate' - ) - date_range_id = fields.Many2one( - comodel_name='date.range', - string='Period', - ) + 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 Name', - ) - value_y = fields.Char( - string='Product Name', + comodel_name="stock.location", string="Stock Location", ) + product_id = fields.Many2one(comodel_name="product.product", string="Product",) + value_x = fields.Char(string="Period Name",) + value_y = fields.Char(string="Product Name",) 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' + _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_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, + 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", + comodel_name="stock.location", string="Location", required=True, ) + product_ids = fields.Many2many(comodel_name="product.product", string="Products",) - @api.onchange('date_range_type_id') + @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.constrains('date_start', 'date_end') + @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.') + _("The start date cannot be later than the end date.") ) @api.multi def _prepare_demand_estimate_sheet(self): self.ensure_one() return { - '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, + "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, } @api.multi def create_sheet(self): self.ensure_one() if not self.product_ids: - raise UserError(_('You must select at least one product.')) + raise UserError(_("You must select at least one product.")) # 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 = 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 = { - 'name': _('Estimate Sheet'), - 'src_model': 'stock.demand.estimate.wizard', - 'view_type': 'form', - 'view_mode': 'form', - 'target': 'new', - 'res_model': 'stock.demand.estimate.sheet', - 'res_id': sheet.id, - 'type': 'ir.actions.act_window', + "name": _("Estimate Sheet"), + "src_model": "stock.demand.estimate.wizard", + "view_type": "form", + "view_mode": "form", + "target": "new", + "res_model": "stock.demand.estimate.sheet", + "res_id": sheet.id, + "type": "ir.actions.act_window", } return res diff --git a/stock_demand_estimate_matrix/wizards/stock_demand_estimate_wizard_view.xml b/stock_demand_estimate_matrix/wizards/stock_demand_estimate_wizard_view.xml index 014f73516..79ea09a13 100644 --- a/stock_demand_estimate_matrix/wizards/stock_demand_estimate_wizard_view.xml +++ b/stock_demand_estimate_matrix/wizards/stock_demand_estimate_wizard_view.xml @@ -1,93 +1,102 @@ - + - - + stock.demand.estimate.sheet.form stock.demand.estimate.sheet
- - - + + -
- - +
+ + - - - + + +
-
- + - - + stock.demand.estimate.wizard.form stock.demand.estimate.wizard
- - - + + -
+
- +
-
- + - - - - - + id="stock_demand_estimate_wizard_action" + /> +