diff --git a/stock_cycle_count/models/stock_cycle_count.py b/stock_cycle_count/models/stock_cycle_count.py index ea373c2a3..89384fca8 100644 --- a/stock_cycle_count/models/stock_cycle_count.py +++ b/stock_cycle_count/models/stock_cycle_count.py @@ -84,20 +84,23 @@ class StockCycleCount(models.Model): "responsible_id": self.responsible_id.id, } - @api.model - def create(self, vals): - vals["name"] = self.env["ir.sequence"].next_by_code("stock.cycle.count") or "" - return super(StockCycleCount, self).create(vals) + @api.model_create_multi + def create(self, vals_list): + for vals in vals_list: + vals["name"] = ( + self.env["ir.sequence"].next_by_code("stock.cycle.count") or "" + ) + return super().create(vals_list) def action_create_inventory_adjustment(self): - if any([s != "draft" for s in self.mapped("state")]): + if any([state != "draft" for state in self.mapped("state")]): raise UserError(_("You can only confirm cycle counts in state 'Planned'.")) for rec in self: data = rec._prepare_inventory_adjustment() inv = self.env["stock.inventory"].create(data) - if self.company_id.auto_start_inventory_from_cycle_count: + if rec.company_id.auto_start_inventory_from_cycle_count: inv.prefill_counted_quantity = ( - self.company_id.inventory_adjustment_counted_quantities + rec.company_id.inventory_adjustment_counted_quantities ) inv.action_state_to_in_progress() if inv.prefill_counted_quantity == "zero": @@ -109,9 +112,9 @@ class StockCycleCount(models.Model): return True def action_view_inventory(self): - action = self.env.ref( + action = self.env["ir.actions.act_window"]._for_xml_id( "stock_inventory.action_view_inventory_group_form" - ).read()[0] + ) action["context"] = {} adjustment_ids = self.mapped("stock_adjustment_ids").ids if len(adjustment_ids) > 1: diff --git a/stock_cycle_count/models/stock_cycle_count_rule.py b/stock_cycle_count/models/stock_cycle_count_rule.py index 30ee41d0b..15f7a7545 100644 --- a/stock_cycle_count/models/stock_cycle_count_rule.py +++ b/stock_cycle_count/models/stock_cycle_count_rule.py @@ -12,6 +12,47 @@ class StockCycleCountRule(models.Model): _name = "stock.cycle.count.rule" _description = "Stock Cycle Counts Rules" + name = fields.Char(required=True) + rule_type = fields.Selection( + selection="_selection_rule_types", string="Type of rule", required=True + ) + rule_description = fields.Char(compute="_compute_rule_description") + active = fields.Boolean(default=True) + periodic_qty_per_period = fields.Integer(string="Counts per period", default=1) + periodic_count_period = fields.Integer(string="Period in days") + turnover_inventory_value_threshold = fields.Float() + currency_id = fields.Many2one( + comodel_name="res.currency", string="Currency", compute="_compute_currency_id" + ) + accuracy_threshold = fields.Float( + string="Minimum Accuracy Threshold", digits=(3, 2) + ) + apply_in = fields.Selection( + string="Apply this rule in:", + selection=[ + ("warehouse", "Selected warehouses"), + ("location", "Selected Location Zones."), + ], + default="warehouse", + ) + warehouse_ids = fields.Many2many( + comodel_name="stock.warehouse", + relation="warehouse_cycle_count_rule_rel", + column1="rule_id", + column2="warehouse_id", + string="Warehouses where applied", + compute="_compute_warehouse_ids", + store=True, + readonly=False, + ) + location_ids = fields.Many2many( + comodel_name="stock.location", + relation="location_cycle_count_rule_rel", + column1="rule_id", + column2="location_id", + string="Zones where applied", + ) + def _compute_currency_id(self): for rec in self: rec.currency_id = self.env.user.company_id.currency_id @@ -94,53 +135,15 @@ class StockCycleCountRule(models.Model): if rec.periodic_count_period < 0: raise ValidationError(_("You cannot define a negative period.")) - @api.onchange("location_ids") - def _onchange_locaton_ids(self): - """Get the warehouses for the selected locations.""" - wh_ids = [] - for loc in self.location_ids: - wh_ids.append(loc.warehouse_id.id) - wh_ids = list(set(wh_ids)) - wh_ids = [wh for wh in wh_ids if wh] - self.warehouse_ids = self.env["stock.warehouse"].browse(wh_ids) - - name = fields.Char(required=True) - rule_type = fields.Selection( - selection="_selection_rule_types", string="Type of rule", required=True - ) - rule_description = fields.Char(compute="_compute_rule_description") - active = fields.Boolean(default=True) - periodic_qty_per_period = fields.Integer(string="Counts per period", default=1) - periodic_count_period = fields.Integer(string="Period in days") - turnover_inventory_value_threshold = fields.Float() - currency_id = fields.Many2one( - comodel_name="res.currency", string="Currency", compute="_compute_currency_id" - ) - accuracy_threshold = fields.Float( - string="Minimum Accuracy Threshold", digits=(3, 2) - ) - apply_in = fields.Selection( - string="Apply this rule in:", - selection=[ - ("warehouse", "Selected warehouses"), - ("location", "Selected Location Zones."), - ], - default="warehouse", - ) - warehouse_ids = fields.Many2many( - comodel_name="stock.warehouse", - relation="warehouse_cycle_count_rule_rel", - column1="rule_id", - column2="warehouse_id", - string="Warehouses where applied", - ) - location_ids = fields.Many2many( - comodel_name="stock.location", - relation="location_cycle_count_rule_rel", - column1="rule_id", - column2="location_id", - string="Zones where applied", - ) + @api.depends("location_ids") + def _compute_warehouse_ids(self): + for record in self: + wh_ids = [] + for loc in record.location_ids: + if loc.warehouse_id: # Make sure warehouse_id is set + wh_ids.append(loc.warehouse_id.id) + wh_ids = list(set(wh_ids)) # Remove duplicates + record.warehouse_ids = [(6, 0, wh_ids)] def compute_rule(self, locs): if self.rule_type == "periodic": @@ -184,7 +187,7 @@ class StockCycleCountRule(models.Model): ) + timedelta(days=period) if next_date < datetime.today(): next_date = datetime.today() - except Exception as e: + except AttributeError as e: raise UserError( _( "Error found determining the frequency of periodic " @@ -220,35 +223,36 @@ class StockCycleCountRule(models.Model): @api.model def _compute_rule_turnover(self, locs): cycle_counts = [] + location_ids = locs.mapped("id") + inventories = self.env["stock.inventory"].search( + [ + ("location_ids", "in", location_ids), + ("state", "in", ["confirm", "done", "draft"]), + ] + ) + inventory_dates_by_location = {loc.id: [] for loc in locs} + for inventory in inventories: + for location in inventory.location_ids: + if location.id in inventory_dates_by_location: + inventory_dates_by_location[location.id].append(inventory.date) + for loc in locs: - last_inventories = ( - self.env["stock.inventory"] - .search( - [ - ("location_ids", "in", [loc.id]), - ("state", "in", ["confirm", "done", "draft"]), - ] - ) - .mapped("date") - ) + last_inventories = inventory_dates_by_location.get(loc.id, []) if last_inventories: latest_inventory = sorted(last_inventories, reverse=True)[0] moves = self._get_turnover_moves(loc, latest_inventory) if moves: - total_turnover = 0.0 - for m in moves: - turnover = self._compute_turnover(m) - total_turnover += turnover + total_turnover = sum(self._compute_turnover(m) for m in moves) try: if total_turnover > self.turnover_inventory_value_threshold: next_date = datetime.today() cycle_count = self._propose_cycle_count(next_date, loc) cycle_counts.append(cycle_count) - except Exception as e: + except AttributeError as e: raise UserError( _( - "Error found when comparing turnover with the " - "rule threshold. %s" + "Error found when comparing turnover " + "with the rule threshold. %s" ) % str(e) ) from e diff --git a/stock_cycle_count/models/stock_inventory.py b/stock_cycle_count/models/stock_inventory.py index 13afd4d31..0fa157098 100644 --- a/stock_cycle_count/models/stock_inventory.py +++ b/stock_cycle_count/models/stock_inventory.py @@ -11,20 +11,6 @@ PERCENT = 100.0 class StockInventory(models.Model): _inherit = "stock.inventory" - @api.depends("state", "stock_quant_ids") - def _compute_inventory_accuracy(self): - for inv in self: - theoretical = sum(inv.stock_quant_ids.mapped(lambda x: abs(x.quantity))) - abs_discrepancy = sum( - inv.stock_quant_ids.mapped(lambda x: abs(x.inventory_diff_quantity)) - ) - if theoretical: - inv.inventory_accuracy = max( - PERCENT * (theoretical - abs_discrepancy) / theoretical, 0.0 - ) - if not inv.stock_quant_ids and inv.state == "done": - inv.inventory_accuracy = PERCENT - prefill_counted_quantity = fields.Selection( string="Counted Quantities", help="Allows to start with a pre-filled counted quantity for each lines or " @@ -49,20 +35,19 @@ class StockInventory(models.Model): group_operator="avg", ) - def _get_default_counted_quantitites(self): - company_id = self.env.context.get("default_company_id", self.env.company) - return company_id.inventory_adjustment_counted_quantities or "counted" - - prefill_counted_quantity = fields.Selection( - string="Counted Quantities", - help="Allows to start with a pre-filled counted quantity for each lines or " - "with all counted quantities set to zero.", - default=_get_default_counted_quantitites, - selection=[ - ("counted", "Default to stock on hand"), - ("zero", "Default to zero"), - ], - ) + @api.depends("state", "stock_quant_ids") + def _compute_inventory_accuracy(self): + for inv in self: + theoretical = sum(inv.stock_quant_ids.mapped(lambda x: abs(x.quantity))) + abs_discrepancy = sum( + inv.stock_quant_ids.mapped(lambda x: abs(x.inventory_diff_quantity)) + ) + if theoretical: + inv.inventory_accuracy = max( + PERCENT * (theoretical - abs_discrepancy) / theoretical, 0.0 + ) + if not inv.stock_quant_ids and inv.state == "done": + inv.inventory_accuracy = PERCENT def _update_cycle_state(self): for inv in self: @@ -99,21 +84,22 @@ class StockInventory(models.Model): return True def action_state_to_done(self): - res = super(StockInventory, self).action_state_to_done() + res = super().action_state_to_done() self._update_cycle_state() return res def action_force_done(self): - res = super(StockInventory, self).action_force_done() + res = super().action_force_done() self._update_cycle_state() return res - @api.model - def create(self, vals): - res = super().create(vals) - if not res.cycle_count_id: - res._link_to_planned_cycle_count() - return res + @api.model_create_multi + def create(self, vals_list): + inventories = super().create(vals_list) + for inv in inventories: + if not inv.cycle_count_id: + inv._link_to_planned_cycle_count() + return inventories def _is_consistent_with_cycle_count(self): self.ensure_one() @@ -153,7 +139,9 @@ class StockInventory(models.Model): if not is_consistent: raise ValidationError( _( - "The Inventory Adjustment is inconsistent with the Cycle Count:\n%s" + "The Inventory Adjustment is inconsistent " + "with the Cycle Count:\n%(message)s", + message=msg, ) % msg ) diff --git a/stock_cycle_count/models/stock_location.py b/stock_cycle_count/models/stock_location.py index 9210ce52b..2a09fc760 100644 --- a/stock_cycle_count/models/stock_location.py +++ b/stock_cycle_count/models/stock_location.py @@ -21,28 +21,6 @@ except (ImportError, IOError) as err: class StockLocation(models.Model): _inherit = "stock.location" - def _compute_loc_accuracy(self): - for rec in self: - history = self.env["stock.inventory"].search( - [("location_ids", "in", rec.id), ("state", "=", "done")], - order="write_date desc", - ) - if history: - wh = rec.warehouse_id - if ( - wh.counts_for_accuracy_qty - and len(history) > wh.counts_for_accuracy_qty - ): - rec.loc_accuracy = mean( - history[: wh.counts_for_accuracy_qty].mapped( - "inventory_accuracy" - ) - ) - else: - rec.loc_accuracy = mean(history.mapped("inventory_accuracy")) - else: - rec.loc_accuracy = 0 - zero_confirmation_disabled = fields.Boolean( string="Disable Zero Confirmations", help="Define whether this location will trigger a zero-confirmation " @@ -60,19 +38,46 @@ class StockLocation(models.Model): string="Inventory Accuracy", compute="_compute_loc_accuracy", digits=(3, 2) ) + def _compute_loc_accuracy(self): + history = self.env["stock.inventory"].search( + [("location_ids", "in", self.ids), ("state", "=", "done")], + order="write_date desc", + ) + for rec in self: + loc_history = history.filtered_domain([("location_ids", "in", rec.id)]) + if loc_history: + wh = rec.warehouse_id + if ( + wh.counts_for_accuracy_qty + and len(loc_history) > wh.counts_for_accuracy_qty + ): + rec.loc_accuracy = mean( + loc_history[: wh.counts_for_accuracy_qty].mapped( + "inventory_accuracy" + ) + ) + else: + rec.loc_accuracy = mean(loc_history.mapped("inventory_accuracy")) + else: + rec.loc_accuracy = 0 + def _get_zero_confirmation_domain(self): self.ensure_one() domain = [("location_id", "=", self.id), ("quantity", ">", 0.0)] return domain def check_zero_confirmation(self): + rule_model = self.env["stock.cycle.count.rule"] + warehouse_ids = self.mapped("warehouse_id.id") + zero_rules = rule_model.search( + [("rule_type", "=", "zero"), ("warehouse_ids", "in", warehouse_ids)] + ) + warehouse_to_rules = {rule.warehouse_ids.id: rule for rule in zero_rules} + for rec in self: if not rec.zero_confirmation_disabled: wh = rec.warehouse_id - rule_model = self.env["stock.cycle.count.rule"] - zero_rule = rule_model.search( - [("rule_type", "=", "zero"), ("warehouse_ids", "=", wh.id)] - ) + zero_rule = warehouse_to_rules.get(wh.id) if zero_rule: quants = self.env["stock.quant"].search( rec._get_zero_confirmation_domain() diff --git a/stock_cycle_count/models/stock_warehouse.py b/stock_cycle_count/models/stock_warehouse.py index 75a392d7e..49eaa1028 100644 --- a/stock_cycle_count/models/stock_warehouse.py +++ b/stock_cycle_count/models/stock_warehouse.py @@ -41,7 +41,7 @@ class StockWarehouse(models.Model): @api.model def _get_cycle_count_locations_search_domain(self, parent): domain = [ - ("parent_path", "=like", parent.parent_path + "%"), + ("id", "child_of", parent.id), ("cycle_count_disabled", "=", False), ] return domain @@ -81,56 +81,62 @@ class StockWarehouse(models.Model): returns a list with required dates for the cycle count of each location""" for rec in self: - proposed_cycle_counts = [] - rules = rec._cycle_count_rules_to_compute() - for rule in rules: - locations = rec._search_cycle_count_locations(rule) - if locations: - proposed_cycle_counts.extend(rule.compute_rule(locations)) + proposed_cycle_counts = rec._get_proposed_cycle_counts() if proposed_cycle_counts: - locations = list({d["location"] for d in proposed_cycle_counts}) - for loc in locations: - proposed_for_loc = list( - filter(lambda x: x["location"] == loc, proposed_cycle_counts) - ) - earliest_date = min(d["date"] for d in proposed_for_loc) - cycle_count_proposed = list( - filter(lambda x: x["date"] == earliest_date, proposed_for_loc) - )[0] - domain = [("location_id", "=", loc.id), ("state", "in", ["draft"])] - existing_cycle_counts = self.env["stock.cycle.count"].search(domain) - if existing_cycle_counts: - existing_earliest_date = sorted( - existing_cycle_counts.mapped("date_deadline") - )[0] - existing_earliest_date = fields.Date.from_string( - existing_earliest_date - ) - cycle_count_proposed_date = fields.Date.from_string( - cycle_count_proposed["date"] - ) - if cycle_count_proposed_date < existing_earliest_date: - cc_to_update = existing_cycle_counts.search( - [("date_deadline", "=", existing_earliest_date)] - ) - cc_to_update.write( - { - "date_deadline": cycle_count_proposed_date, - "cycle_count_rule_id": cycle_count_proposed[ - "rule_type" - ].id, - } - ) - delta = ( - fields.Datetime.from_string(cycle_count_proposed["date"]) - - datetime.today() - ) - if ( - not existing_cycle_counts - and delta.days < rec.cycle_count_planning_horizon - ): - cc_vals = self._prepare_cycle_count(cycle_count_proposed) - self.env["stock.cycle.count"].create(cc_vals) + cc_vals_list = rec._process_cycle_counts(proposed_cycle_counts) + self.env["stock.cycle.count"].create(cc_vals_list) + + def _get_proposed_cycle_counts(self): + proposed_cycle_counts = [] + rules = self._cycle_count_rules_to_compute() + for rule in rules: + locations = self._search_cycle_count_locations(rule) + if locations: + proposed_cycle_counts.extend(rule.compute_rule(locations)) + return proposed_cycle_counts + + def _process_cycle_counts(self, proposed_cycle_counts): + cc_vals_list = [] + locations = list({d["location"] for d in proposed_cycle_counts}) + for loc in locations: + proposed_for_loc = list( + filter(lambda x: x["location"] == loc, proposed_cycle_counts) + ) + earliest_date = min(d["date"] for d in proposed_for_loc) + cycle_count_proposed = next( + filter(lambda x: x["date"] == earliest_date, proposed_for_loc) + ) + self._handle_existing_cycle_counts(loc, cycle_count_proposed) + delta = ( + fields.Datetime.from_string(cycle_count_proposed["date"]) + - datetime.today() + ) + if delta.days < self.cycle_count_planning_horizon: + cc_vals = self._prepare_cycle_count(cycle_count_proposed) + cc_vals_list.append(cc_vals) + return cc_vals_list + + def _handle_existing_cycle_counts(self, location, cycle_count_proposed): + domain = [("location_id", "=", location.id), ("state", "in", ["draft"])] + existing_cycle_counts = self.env["stock.cycle.count"].search(domain) + if existing_cycle_counts: + existing_earliest_date = sorted( + existing_cycle_counts.mapped("date_deadline") + )[0] + existing_earliest_date = fields.Date.from_string(existing_earliest_date) + cycle_count_proposed_date = fields.Date.from_string( + cycle_count_proposed["date"] + ) + if cycle_count_proposed_date < existing_earliest_date: + cc_to_update = existing_cycle_counts.filtered( + lambda x: x.date_deadline == existing_earliest_date + ) + cc_to_update.write( + { + "date_deadline": cycle_count_proposed_date, + "cycle_count_rule_id": cycle_count_proposed["rule_type"].id, + } + ) @api.model def cron_cycle_count(self): diff --git a/stock_cycle_count/reports/report_stock_location_accuracy.py b/stock_cycle_count/reports/report_stock_location_accuracy.py index 880efb661..00aab7800 100644 --- a/stock_cycle_count/reports/report_stock_location_accuracy.py +++ b/stock_cycle_count/reports/report_stock_location_accuracy.py @@ -22,9 +22,11 @@ class LocationAccuracyReport(models.AbstractModel): def _get_location_data(self, locations): data = dict() inventory_obj = self.env["stock.inventory"] + location_ids = locations.mapped("id") + counts = inventory_obj.search([("location_id", "in", location_ids)]) for loc in locations: - counts = inventory_obj.search(self._get_inventory_domain(loc.id)) - data[loc] = counts + loc_counts = counts.filtered(lambda c: c.location_id == loc) + data[loc] = loc_counts return data def render_html(self, data=None): diff --git a/stock_cycle_count/tests/test_stock_cycle_count.py b/stock_cycle_count/tests/test_stock_cycle_count.py index 4e55ab264..ad2066163 100644 --- a/stock_cycle_count/tests/test_stock_cycle_count.py +++ b/stock_cycle_count/tests/test_stock_cycle_count.py @@ -8,84 +8,80 @@ from odoo.tests import common class TestStockCycleCount(common.TransactionCase): - def setUp(self): - super(TestStockCycleCount, self).setUp() - self.res_users_model = self.env["res.users"] - self.cycle_count_model = self.env["stock.cycle.count"] - self.stock_cycle_count_rule_model = self.env["stock.cycle.count.rule"] - self.inventory_model = self.env["stock.inventory"] - self.stock_location_model = self.env["stock.location"] - self.stock_move_model = self.env["stock.move"] - self.stock_warehouse_model = self.env["stock.warehouse"] - self.product_model = self.env["product.product"] - self.quant_model = self.env["stock.quant"] - self.move_model = self.env["stock.move"] + @classmethod + def setUpClass(cls): + super(TestStockCycleCount, cls).setUpClass() + cls.res_users_model = cls.env["res.users"] + cls.cycle_count_model = cls.env["stock.cycle.count"] + cls.stock_cycle_count_rule_model = cls.env["stock.cycle.count.rule"] + cls.inventory_model = cls.env["stock.inventory"] + cls.stock_location_model = cls.env["stock.location"] + cls.stock_move_model = cls.env["stock.move"] + cls.stock_warehouse_model = cls.env["stock.warehouse"] + cls.product_model = cls.env["product.product"] + cls.quant_model = cls.env["stock.quant"] + cls.move_model = cls.env["stock.move"] - self.company = self.env.ref("base.main_company") - self.partner = self.env.ref("base.res_partner_1") - self.g_stock_manager = self.env.ref("stock.group_stock_manager") - self.g_stock_user = self.env.ref("stock.group_stock_user") + cls.company = cls.env.ref("base.main_company") + cls.partner = cls.env.ref("base.res_partner_1") + cls.g_stock_manager = cls.env.ref("stock.group_stock_manager") + cls.g_stock_user = cls.env.ref("stock.group_stock_user") # 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 + 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 # Create warehouses: - self.big_wh = self.stock_warehouse_model.create( + cls.big_wh = cls.stock_warehouse_model.create( {"name": "BIG", "code": "B", "cycle_count_planning_horizon": 30} ) - self.small_wh = self.stock_warehouse_model.create( - {"name": "SMALL", "code": "S"} - ) + cls.small_wh = cls.stock_warehouse_model.create({"name": "SMALL", "code": "S"}) # Create rules: - self.rule_periodic = self._create_stock_cycle_count_rule_periodic( - self.manager, "rule_1", [2, 7] + cls.rule_periodic = cls._create_stock_cycle_count_rule_periodic( + cls.manager, "rule_1", [2, 7] ) - self.rule_turnover = self._create_stock_cycle_count_rule_turnover( - self.manager, "rule_2", [100] + cls.rule_turnover = cls._create_stock_cycle_count_rule_turnover( + cls.manager, "rule_2", [100] ) - self.rule_accuracy = self._create_stock_cycle_count_rule_accuracy( - self.manager, "rule_3", [5], self.big_wh.view_location_id.ids - ) - self.zero_rule = self._create_stock_cycle_count_rule_zero( - self.manager, "rule_4" + cls.rule_accuracy = cls._create_stock_cycle_count_rule_accuracy( + cls.manager, "rule_3", [5], cls.big_wh.view_location_id.ids ) + cls.zero_rule = cls._create_stock_cycle_count_rule_zero(cls.manager, "rule_4") # Configure warehouses: - self.rule_ids = [ - self.rule_periodic.id, - self.rule_turnover.id, - self.rule_accuracy.id, - self.zero_rule.id, + cls.rule_ids = [ + cls.rule_periodic.id, + cls.rule_turnover.id, + cls.rule_accuracy.id, + cls.zero_rule.id, ] - self.big_wh.write({"cycle_count_rule_ids": [(6, 0, self.rule_ids)]}) + cls.big_wh.write({"cycle_count_rule_ids": [(6, 0, cls.rule_ids)]}) # Create a location: - self.count_loc = self.stock_location_model.create( + cls.count_loc = cls.stock_location_model.create( {"name": "Place", "usage": "production"} ) - self.stock_location_model._parent_store_compute() + cls.stock_location_model._parent_store_compute() # Create a cycle count: - self.cycle_count_1 = self.cycle_count_model.with_user(self.manager).create( + cls.cycle_count_1 = cls.cycle_count_model.with_user(cls.manager).create( { "name": "Test cycle count", - "cycle_count_rule_id": self.rule_periodic.id, - "location_id": self.count_loc.id, + "cycle_count_rule_id": cls.rule_periodic.id, + "location_id": cls.count_loc.id, } ) # Create a product: - self.product1 = self.product_model.create( + cls.product1 = cls.product_model.create( {"name": "Test Product 1", "type": "product", "default_code": "PROD1"} ) - 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, @@ -97,8 +93,9 @@ class TestStockCycleCount(common.TransactionCase): ) return user - def _create_stock_cycle_count_rule_periodic(self, uid, name, values): - rule = self.stock_cycle_count_rule_model.with_user(uid).create( + @classmethod + def _create_stock_cycle_count_rule_periodic(cls, uid, name, values): + rule = cls.stock_cycle_count_rule_model.with_user(uid).create( { "name": name, "rule_type": "periodic", @@ -108,8 +105,9 @@ class TestStockCycleCount(common.TransactionCase): ) return rule - def _create_stock_cycle_count_rule_turnover(self, uid, name, values): - rule = self.stock_cycle_count_rule_model.with_user(uid).create( + @classmethod + def _create_stock_cycle_count_rule_turnover(cls, uid, name, values): + rule = cls.stock_cycle_count_rule_model.with_user(uid).create( { "name": name, "rule_type": "turnover", @@ -118,8 +116,9 @@ class TestStockCycleCount(common.TransactionCase): ) return rule - def _create_stock_cycle_count_rule_accuracy(self, uid, name, values, zone_ids): - rule = self.stock_cycle_count_rule_model.with_user(uid).create( + @classmethod + def _create_stock_cycle_count_rule_accuracy(cls, uid, name, values, zone_ids): + rule = cls.stock_cycle_count_rule_model.with_user(uid).create( { "name": name, "rule_type": "accuracy", @@ -130,8 +129,9 @@ class TestStockCycleCount(common.TransactionCase): ) return rule - def _create_stock_cycle_count_rule_zero(self, uid, name): - rule = self.stock_cycle_count_rule_model.with_user(uid).create( + @classmethod + def _create_stock_cycle_count_rule_zero(cls, uid, name): + rule = cls.stock_cycle_count_rule_model.with_user(uid).create( {"name": name, "rule_type": "zero"} ) return rule @@ -263,7 +263,6 @@ class TestStockCycleCount(common.TransactionCase): for r in rules: r._compute_rule_description() self.assertTrue(r.rule_description, "No description provided") - self.rule_accuracy._onchange_locaton_ids() self.assertEqual( self.rule_accuracy.warehouse_ids.ids, self.big_wh.ids,