From cd20343a80c91255edd41ab3dbe813e6c1e75f46 Mon Sep 17 00:00:00 2001 From: geomer198 Date: Wed, 5 Oct 2022 18:42:11 +0300 Subject: [PATCH] [IMP] mrp_subcontracting_partner_management : Changed 'is_subcontractor_partner' field position. When subcontractor name changed then changes subcontractor related records name. --- .../__manifest__.py | 4 +- .../models/res_partner.py | 442 +++++++++--------- .../readme/CONFIGURE.rst | 5 +- .../readme/USAGE.rst | 3 + .../static/description/icon.png | Bin 28872 -> 9455 bytes .../tests/__init__.py | 2 +- ..._create_subcontractor_partner_location.py} | 76 ++- .../views/res_partner.xml | 19 - .../views/res_partner_views.xml | 36 ++ ..._type.xml => stock_picking_type_views.xml} | 0 10 files changed, 319 insertions(+), 268 deletions(-) rename mrp_subcontracting_partner_management/tests/{test_create_sybcontractor_partner_location.py => test_create_subcontractor_partner_location.py} (77%) delete mode 100644 mrp_subcontracting_partner_management/views/res_partner.xml create mode 100644 mrp_subcontracting_partner_management/views/res_partner_views.xml rename mrp_subcontracting_partner_management/views/{stock_picking_type.xml => stock_picking_type_views.xml} (100%) diff --git a/mrp_subcontracting_partner_management/__manifest__.py b/mrp_subcontracting_partner_management/__manifest__.py index f6f9df02f..d93c6adcc 100644 --- a/mrp_subcontracting_partner_management/__manifest__.py +++ b/mrp_subcontracting_partner_management/__manifest__.py @@ -10,8 +10,8 @@ "external_dependencies": {}, "demo": [], "data": [ - "views/res_partner.xml", - "views/stock_picking_type.xml", + "views/res_partner_views.xml", + "views/stock_picking_type_views.xml", ], "qweb": [], "installable": True, diff --git a/mrp_subcontracting_partner_management/models/res_partner.py b/mrp_subcontracting_partner_management/models/res_partner.py index 585ba2aa5..a4decbfea 100644 --- a/mrp_subcontracting_partner_management/models/res_partner.py +++ b/mrp_subcontracting_partner_management/models/res_partner.py @@ -1,3 +1,5 @@ +import re + from odoo import api, fields, models @@ -6,258 +8,234 @@ class ResPartner(models.Model): is_subcontractor_partner = fields.Boolean(string="Subcontractor") subcontracted_created_location_id = fields.Many2one( - copy=False, comodel_name="stock.location" + comodel_name="stock.location", copy=False ) partner_picking_type_id = fields.Many2one( - copy=False, comodel_name="stock.picking.type" - ) - partner_buy_rule_id = fields.Many2one( - copy=False, - comodel_name="stock.rule", - ) - partner_resupply_rule_id = fields.Many2one( - copy=False, - comodel_name="stock.rule", + comodel_name="stock.picking.type", copy=False ) + partner_buy_rule_id = fields.Many2one(comodel_name="stock.rule", copy=False) + partner_resupply_rule_id = fields.Many2one(comodel_name="stock.rule", copy=False) - def _set_subcontracting_values_active(self, active): + def action_subcontractor_location_stock(self): + """Open subcontractor location stock list""" self.ensure_one() - if self.subcontracted_created_location_id: - self.subcontracted_created_location_id.active = active - if self.partner_picking_type_id: - self.partner_picking_type_id.active = active - if self.partner_buy_rule_id: - self.partner_buy_rule_id.active = active - if self.partner_resupply_rule_id: - self.partner_resupply_rule_id.active = active - - def unlink(self): - """ - This Method is override to archive all subcontracting field - """ - for record in self: - record._set_subcontracting_values_active(False) - result = super(ResPartner, self).unlink() - return result - - def write(self, values): - for record in self: - is_subcontractor_partner = values.get("is_subcontractor_partner") - active = values.get("active") - if is_subcontractor_partner is not None: - values.update(record._update_subcontractor_entities_for_record(values)) - if active is not None: - record._set_subcontracting_values_active(active) - super(ResPartner, self).write(values) + action = self.env["ir.actions.actions"]._for_xml_id( + "stock.location_open_quants" + ) + active_ids = self.property_stock_subcontractor.ids + action.update(domain=[("location_id", "child_of", active_ids)]) + return action @api.model - def create(self, values): - partner = super(ResPartner, self).create(values) - if values.get("is_subcontractor_partner", False): - partner._create_subcontractor_entities() - return partner + def get_data_struct(self): + return { + # Updating Subcontracting Location + "subcontracted_created_location_id": "_create_subcontracting_location_data", + # Updating Subcontracting operation type + "partner_picking_type_id": "_create_operation_type_for_subcontracting", + # Updating Route Rule for Subcontracting buy + "partner_buy_rule_id": "_create_route_rule_for_subcontracting", + # Updating Route Rule for Subcontracting resupply + "partner_resupply_rule_id": "_create_route_rule_for_subcontracting_resupply", + } + + def _set_subcontracting_values_active(self, active): + """Set subcontracting values active/inactive by argument key""" + for key in self.get_data_struct(): + self.mapped(key).write({"active": active}) + + @api.model + def _update_name_translation(self, records, name): + """Update name field translation for records""" + self.env["ir.translation"].search( + [ + ("name", "=", "{},name".format(records._name)), + ("res_id", "in", records.ids), + ("value", "!=", name), + ] + ).write({"value": name}) + + def _update_subcontractor_values_name(self, name): + """ + Update subcontractor related records: + - Location; + - Operation type; + - Route Rule for Subcontracting buy; + - Route Rule for Subcontracting resupply. + """ + partners = self.filtered(lambda p: p.is_subcontractor_partner) + field_names = [*self.get_data_struct(), "property_stock_subcontractor"] + field_names.remove("partner_picking_type_id") + for field in field_names: + records = partners.mapped(field) + records.write({"name": name}) + self._update_name_translation(records, name) + type_name = "%s: IN" % name + code = "".join(re.findall(r"\b\w", type_name)) + picks = partners.mapped("partner_picking_type_id") + picks.write({"name": type_name, "sequence_code": code}) + self._update_name_translation(picks, type_name) + + def unlink(self): + """This Method is override to archive all subcontracting field""" + self._set_subcontracting_values_active(False) + return super(ResPartner, self).unlink() + + def write(self, vals): + if "is_subcontractor_partner" in vals: + self._update_subcontractor_entities_for_record( + vals.get("is_subcontractor_partner") + ) + if "active" in vals: + self._set_subcontracting_values_active(vals.get("active")) + result = super(ResPartner, self).write(vals) + if vals.get("name"): + self._update_subcontractor_values_name(vals.get("name")) + return result + + @api.model_create_multi + def create(self, vals_list): + records = super(ResPartner, self).create(vals_list) + check_data = self.get_data_struct().items() + for record in records.filtered( + lambda r: r.is_subcontractor_partner and r.is_company + ): + values = {} + for key, func in check_data: + if not getattr(record, key) or not values.get(key): + values.update(**getattr(record, func)(values) or {}) + if values: + record.write(values) + return records + + def _update_subcontractor_entities_for_record(self, is_subcontractor_partner): + if not is_subcontractor_partner: + return self._set_subcontracting_values_active(False) + data_items = self.get_data_struct().items() + for rec in self: + vals = {} + for key, record, func in map( + lambda f: (f[0], getattr(rec, f[0]), f[1]), data_items + ): + if record: + record.active = True + else: + if not getattr(rec, key) or not vals.get(key): + vals.update(**getattr(rec, func)(vals) or {}) + if vals: + rec.write(vals) def _compose_entity_name(self): - """Compose entity name. - Override this function to implement onw logic - Returns: - name (char) composed name + """ + Compose entity name. Override this function to implement onw logic + :return: name (char) composed name """ return self.display_name - def _create_location(self, parent_location, company): - """Creating Subcontracting Location starts here""" - - location_vals = { - "name": self._compose_entity_name(), - "usage": "internal", - "location_id": parent_location or False, - "company_id": company.id, - "active": True, - } - location_rec = self.subcontracted_created_location_id - if not location_rec: - location_rec = self.env["stock.location"].create(location_vals) - return location_rec - - def _create_subcontracted_operation_type(self, warehouse, location): + def _create_subcontracted_operation_type(self, vals): """Creating Operation Type for Subcontracting""" - name = self._compose_entity_name() - operation_type_name = "{}: {}".format(name, " IN") - sequence_code = "" - for code in list(filter(None, operation_type_name.split(" "))): - sequence_code += code[0] - operation_type_rec = self.partner_picking_type_id - if not operation_type_rec: - operation_type_vals = { - "name": operation_type_name, - "code": "incoming", - "sequence_code": sequence_code, - "is_subcontractor": True, - } - if warehouse: - operation_type_vals.update({"warehouse_id": warehouse.id}) - if location: - operation_type_vals.update({"default_location_dest_id": location.id}) - operation_type_rec = self.env["stock.picking.type"].create( - operation_type_vals - ) - return operation_type_rec + location_id = self._get_location_id_for_record(vals) + if "partner_picking_type_id" in vals: + return vals.get("partner_picking_type_id"), location_id + if self.partner_picking_type_id: + return self.partner_picking_type_id.id, location_id + operation_type_name = "%s: IN" % self._compose_entity_name() + operation_type_vals = { + "name": operation_type_name, + "code": "incoming", + "sequence_code": "".join(re.findall(r"\b\w", operation_type_name)), + "is_subcontractor": True, + } + company = self.company_id or self.env.company + warehouse = self.env["stock.warehouse"].search( + [("company_id", "=", company.id)], limit=1 + ) + if warehouse: + operation_type_vals.update({"warehouse_id": warehouse.id}) + if location_id: + operation_type_vals.update({"default_location_dest_id": location_id}) + return ( + self.env["stock.picking.type"].create(operation_type_vals).id, + location_id, + ) - def _create_subcontracted_buy_rule(self, operation_type_rec, location): - """Creating Route Rule for Subcontracting starts here""" - rule = self.partner_buy_rule_id - if not rule: - buy_route = self.env.ref( - "purchase_stock.route_warehouse0_buy", raise_if_not_found=False - ) - rule = self.env["stock.rule"].create( + def _get_location_id_for_record(self, vals): + self.ensure_one() + if "subcontracted_created_location_id" in vals: + return vals.get("subcontracted_created_location_id") + if self.subcontracted_created_location_id: + return self.subcontracted_created_location_id.id + company = self.company_id or self.env.company + parent_location = ( + company.subcontracting_location_id and company.subcontracting_location_id.id + ) + return ( + self.env["stock.location"] + .create( { "name": self._compose_entity_name(), - "action": "buy", - "picking_type_id": operation_type_rec.id, - "location_id": location.id, - "route_id": buy_route.id, + "usage": "internal", + "location_id": parent_location or False, + "company_id": company.id, + "active": True, } ) - self.partner_buy_rule_id = rule - return rule + .id + ) - def _create_subcontracted_resupply_rule(self, location): - """# Creating Route Rule for Subcontracting resupply on order starts here""" - resupply_on_order_route = self.env.ref( + def _create_subcontracting_location_data(self, vals): + self.ensure_one() + location_id = self._get_location_id_for_record(vals) + return { + "property_stock_subcontractor": location_id, + "subcontracted_created_location_id": location_id, + } + + def _create_operation_type_for_subcontracting(self, vals): + self.ensure_one() + # Creating Operation Type for Subcontracting starts here + operation_type_rec_id, _ = self._create_subcontracted_operation_type(vals) + return {"partner_picking_type_id": operation_type_rec_id} + + def _create_route_rule_for_subcontracting(self, vals): + self.ensure_one() + operation_type_rec_id, location_id = self._create_subcontracted_operation_type( + vals + ) + route = self.env.ref( + "purchase_stock.route_warehouse0_buy", raise_if_not_found=False + ) + buy_rule = self.env["stock.rule"].create( + { + "name": self._compose_entity_name(), + "action": "buy", + "picking_type_id": operation_type_rec_id, + "location_id": location_id, + "route_id": route.id, + } + ) + return {"partner_buy_rule_id": buy_rule.id} + + def _create_route_rule_for_subcontracting_resupply(self, vals): + self.ensure_one() + prop = self.env["ir.property"]._get( + "property_stock_production", "product.template" + ) + picking_type = self.env.ref("stock.picking_type_out", raise_if_not_found=False) + route = self.env.ref( "mrp_subcontracting.route_resupply_subcontractor_mto", raise_if_not_found=False, ) - delivery_type = self.env.ref("stock.picking_type_out", raise_if_not_found=False) - production = self.env["ir.property"]._get( - "property_stock_production", "product.template" + rule = self.env["stock.rule"].create( + { + "name": self._compose_entity_name(), + "action": "pull", + "partner_address_id": self._origin.id, + "picking_type_id": picking_type.id, + "location_id": prop.id, + "location_src_id": self._get_location_id_for_record(vals), + "route_id": route.id, + "procure_method": "mts_else_mto", + } ) - pull_rule = self.partner_resupply_rule_id - if not pull_rule: - pull_rule = self.env["stock.rule"].create( - { - "name": self._compose_entity_name(), - "action": "pull", - "partner_address_id": self._origin.id, - "picking_type_id": delivery_type.id, - "location_id": production.id, - "location_src_id": location.id, - "route_id": resupply_on_order_route.id, - "procure_method": "mts_else_mto", - } - ) - self.partner_resupply_rule_id = pull_rule - return pull_rule - - def _create_subcontractor_entities(self): - """Create entities for the subcontractor - - Stock location - - Stock operation type - - "Buy" stock rule - """ - for rec in self.filtered(lambda p: p.company_type == "company"): - partner_update_vals = rec._create_subcontractor_entities_for_record() - rec.write(partner_update_vals) - - def _update_subcontractor_entities_for_record(self, values): - self.ensure_one() - is_subcontractor_partner = values.get("is_subcontractor_partner") - - check_data = { - # Updating Subcontracting Location - "subcontracted_created_location_id": self._create_subcontracting_location_data, - # Updating Subcontracting operation type - "partner_picking_type_id": self._create_operation_type_for_subcontracting, - # Updating Route Rule for Subcontracting buy - "partner_buy_rule_id": self._create_route_rule_for_subcontracting, - # Updating Route Rule for Subcontracting resupply - "partner_resupply_rule_id": self._create_route_rule_for_subcontracting_resupply, - } - for field_name in check_data: - if is_subcontractor_partner is True and getattr(self, field_name): - getattr(self, field_name).active = True - elif is_subcontractor_partner is True and not getattr(self, field_name): - values.update(check_data[field_name]()) - elif is_subcontractor_partner is False and getattr(self, field_name): - getattr(self, field_name).active = False - - return values - - def _create_subcontractor_entities_for_record(self): - self.ensure_one() - partner_update_vals = {"is_subcontractor_partner": True} - # Creating Subcontracting Location ends here - partner_update_vals.update(self._create_subcontracting_location_data()) - partner_update_vals.update(self._create_operation_type_for_subcontracting()) - # Creating Route Rule for Subcontracting starts here - partner_update_vals.update(self._create_route_rule_for_subcontracting()) - # Creating Route Rule for Subcontracting resupply on order starts here - partner_update_vals.update( - self._create_route_rule_for_subcontracting_resupply() - ) - return partner_update_vals - - def _get_location_for_record(self): - self.ensure_one() - location = self.subcontracted_created_location_id - if not location: - default_company = self.env.company - company = self.company_id or default_company - parent_location = ( - company.subcontracting_location_id - and company.subcontracting_location_id.id - ) - location = self._create_location(parent_location, company) - self.subcontracted_created_location_id = location - return location - - def _get_warehouse_for_record(self): - self.ensure_one() - default_company = self.env.company - default_warehouse = self.env["stock.warehouse"].search( - [("company_id", "=", default_company.id)] - )[0] - company = self.company_id or default_company - warehouse = ( - self.env["stock.warehouse"].search([("company_id", "=", company.id)])[0] - if self.company_id - else default_warehouse - ) # noqa - return warehouse - - def _create_subcontracting_location_data(self): - self.ensure_one() - location = self._get_location_for_record() - return { - "property_stock_subcontractor": location.id, - "subcontracted_created_location_id": location.id, - } - - def _create_operation_type_for_subcontracting(self): - self.ensure_one() - operation_type_rec = self.partner_picking_type_id - if not operation_type_rec: - # Creating Operation Type for Subcontracting starts here - location = self._get_location_for_record() - warehouse = self._get_warehouse_for_record() - operation_type_rec = self._create_subcontracted_operation_type( - warehouse, location - ) - self.partner_picking_type_id = operation_type_rec - return {"partner_picking_type_id": operation_type_rec.id} - - def _create_route_rule_for_subcontracting(self): - location = self._get_location_for_record() - warehouse = self._get_warehouse_for_record() - operation_type_rec = self._create_subcontracted_operation_type( - warehouse, location - ) - buy_rule = self._create_subcontracted_buy_rule(operation_type_rec, location) - - return {"partner_buy_rule_id": buy_rule.id} - - def _create_route_rule_for_subcontracting_resupply(self): - location = self._get_location_for_record() - resupply_rule = self._create_subcontracted_resupply_rule(location) - return {"partner_resupply_rule_id": resupply_rule.id} + return {"partner_resupply_rule_id": rule.id} diff --git a/mrp_subcontracting_partner_management/readme/CONFIGURE.rst b/mrp_subcontracting_partner_management/readme/CONFIGURE.rst index 0862077f4..01d08757f 100644 --- a/mrp_subcontracting_partner_management/readme/CONFIGURE.rst +++ b/mrp_subcontracting_partner_management/readme/CONFIGURE.rst @@ -1 +1,4 @@ -* No configuration is required +To see newly created rules, go to **Settings** > **Inventory** and activate "Multi step routes". + +It is also possible to allow a user to check inventory locations in **Sales & Purchases** tab of **Vendor** without activating dev mode. +To do so, enable technical extra right **Display Inventory section on Vendor** in user. diff --git a/mrp_subcontracting_partner_management/readme/USAGE.rst b/mrp_subcontracting_partner_management/readme/USAGE.rst index b5502316a..9f7e8bc18 100644 --- a/mrp_subcontracting_partner_management/readme/USAGE.rst +++ b/mrp_subcontracting_partner_management/readme/USAGE.rst @@ -2,3 +2,6 @@ * Enable the "Subcontractor" checkbox * New entities are created or existing are used if were created previously * When disabled all associated enties will be archived +* When name of subcontractor is updated, names of entities are updated automatically. +* It is also possible to check inventory locations using **Subcontractor Location Stock** smart button on partner. +* When name of subcontractor is updated, names of entities (subcontracting location, operation type, rules) are updated automatically. diff --git a/mrp_subcontracting_partner_management/static/description/icon.png b/mrp_subcontracting_partner_management/static/description/icon.png index ea708b0a29ee106a8799f18ff661aa6641f6478c..3a0328b516c4980e8e44cdb63fd945757ddd132d 100644 GIT binary patch literal 9455 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 z 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 Xviia!U7SGha1wx#SCgwmn*{w2TRX*I literal 28872 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 diff --git a/mrp_subcontracting_partner_management/tests/__init__.py b/mrp_subcontracting_partner_management/tests/__init__.py index c7819b815..6e67837d7 100644 --- a/mrp_subcontracting_partner_management/tests/__init__.py +++ b/mrp_subcontracting_partner_management/tests/__init__.py @@ -1,3 +1,3 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. -from . import test_create_sybcontractor_partner_location +from . import test_create_subcontractor_partner_location diff --git a/mrp_subcontracting_partner_management/tests/test_create_sybcontractor_partner_location.py b/mrp_subcontracting_partner_management/tests/test_create_subcontractor_partner_location.py similarity index 77% rename from mrp_subcontracting_partner_management/tests/test_create_sybcontractor_partner_location.py rename to mrp_subcontracting_partner_management/tests/test_create_subcontractor_partner_location.py index 2624fb4dd..6eee789b2 100644 --- a/mrp_subcontracting_partner_management/tests/test_create_sybcontractor_partner_location.py +++ b/mrp_subcontracting_partner_management/tests/test_create_subcontractor_partner_location.py @@ -5,23 +5,10 @@ from odoo.tests import common, tagged class TestSubcontractedPartner(common.SavepointCase): @classmethod def setUpClass(cls): - """ - - Create a Partner record “Wood Corner” - - Type will be Company and new boolean is_subcontractor_partner is Set True - """ super().setUpClass() cls.partner_id = cls.env.ref("base.res_partner_12") cls.partner_obj = cls.env["res.partner"] - def _get_partner(self): - return self.partner_obj.create( - { - "name": "Test partner", - "is_company": True, - "is_subcontractor_partner": True, - } - ) - def test_is_subcontractor_partner_first_time(self): self.partner_id.update( { @@ -181,3 +168,66 @@ class TestSubcontractedPartner(common.SavepointCase): [("name", "=", partner_id.partner_buy_rule_id.name)] ) self.assertTrue(len(rules) == 2, "There are must be 2 subcontractor rules") + + def test_change_subcontractor_location(self): + expected_text = "Test partner" + partner = self.partner_obj.create( + { + "name": "Test partner", + "is_company": True, + "is_subcontractor_partner": True, + } + ) + location = partner.property_stock_subcontractor + self.assertEqual( + location.name, + expected_text, + msg="Location name must be equal to {}".format(expected_text), + ) + + fields = [ + "subcontracted_created_location_id", + "partner_buy_rule_id", + "partner_resupply_rule_id", + "property_stock_subcontractor", + ] + expected_text = "Test partner 1" + partner.name = expected_text + for field in fields: + location = getattr(partner, field) + self.assertEqual( + location.name, + expected_text, + msg="Record name must be equal to {}".format(expected_text), + ) + + picking = partner.partner_picking_type_id + expected_text = "%s: IN" % expected_text + self.assertEqual( + picking.name, + expected_text, + msg="Record name must be equal to '{}'".format(expected_text), + ) + self.assertEqual( + picking.sequence_code, "Tp1I", msg="Sequence code must be equal to 'Tp1I'" + ) + + def test_action_subcontractor_location_stock(self): + self.partner_id.update({"is_subcontractor_partner": True}) + action = self.partner_id.action_subcontractor_location_stock() + self.assertEqual( + action.get("domain"), + [ + ( + "location_id", + "child_of", + self.partner_id.property_stock_subcontractor.ids, + ) + ], + msg="Domains must be the same", + ) + self.assertEqual( + action.get("res_model"), + "stock.quant", + msg="Model must be equal to 'stock.quant'", + ) diff --git a/mrp_subcontracting_partner_management/views/res_partner.xml b/mrp_subcontracting_partner_management/views/res_partner.xml deleted file mode 100644 index 1802199a0..000000000 --- a/mrp_subcontracting_partner_management/views/res_partner.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - res.partner.form.inherit.subcontractor - res.partner - - - - - - - - - - diff --git a/mrp_subcontracting_partner_management/views/res_partner_views.xml b/mrp_subcontracting_partner_management/views/res_partner_views.xml new file mode 100644 index 000000000..29c77d7c0 --- /dev/null +++ b/mrp_subcontracting_partner_management/views/res_partner_views.xml @@ -0,0 +1,36 @@ + + + + + res.partner.form.inherit.subcontractor + res.partner + + + + + + + + + + res.partner.stock.property.form.inherit + res.partner + + + + +