diff --git a/data_migration/README.rst b/data_migration/README.rst new file mode 100644 index 00000000..c00b1b8b --- /dev/null +++ b/data_migration/README.rst @@ -0,0 +1,55 @@ +============== +Data Migration +============== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:6c1038d7a9cbeb2c3c5c88f83aa1b8fde46f13df62710fdcca509f7481c735fd + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| 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 +.. |badge3| image:: https://img.shields.io/badge/github-qrtl%2Fsst--custom-lightgray.png?logo=github + :target: https://github.com/qrtl/sst-custom/tree/15.0/data_migration + :alt: qrtl/sst-custom + +|badge1| |badge2| |badge3| + +This module reads the data from another odoo instance and create in current odoo instance. + +**Table of contents** + +.. contents:: + :local: + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* Quartile Limited + +Maintainers +~~~~~~~~~~~ + +This module is part of the `qrtl/sst-custom `_ project on GitHub. + +You are welcome to contribute. diff --git a/data_migration/__init__.py b/data_migration/__init__.py new file mode 100644 index 00000000..0650744f --- /dev/null +++ b/data_migration/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/data_migration/__manifest__.py b/data_migration/__manifest__.py new file mode 100644 index 00000000..0b7c75bb --- /dev/null +++ b/data_migration/__manifest__.py @@ -0,0 +1,17 @@ +# Copyright 2023 Quartile Limited +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +{ + "name": "Data Migration", + "version": "15.0.1.0.0", + "category": "Tools", + "author": "Quartile Limited", + "website": "https://www.quartile.co", + "license": "AGPL-3", + "depends": ["base", "queue_job"], + "data": [ + "security/ir.model.access.csv", + "data/data_migration_scheduler.xml", + "views/odoo_instance_views.xml", + ], + "installable": True, +} diff --git a/data_migration/data/data_migration_scheduler.xml b/data_migration/data/data_migration_scheduler.xml new file mode 100644 index 00000000..4e324969 --- /dev/null +++ b/data_migration/data/data_migration_scheduler.xml @@ -0,0 +1,14 @@ + + + + Partner Data Migration from another odoo instance + 1 + days + -1 + code + model._run_partner_data_migration() + + + + + diff --git a/data_migration/models/__init__.py b/data_migration/models/__init__.py new file mode 100644 index 00000000..9f9119a3 --- /dev/null +++ b/data_migration/models/__init__.py @@ -0,0 +1,5 @@ +from . import data_migration +from . import data_migration_mapping +from . import odoo_instance +from . import partner_data_migration +from . import res_partner diff --git a/data_migration/models/data_migration.py b/data_migration/models/data_migration.py new file mode 100644 index 00000000..ad9415c1 --- /dev/null +++ b/data_migration/models/data_migration.py @@ -0,0 +1,25 @@ +# Copyright 2023 Quartile Limited +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +import xmlrpc.client + +from odoo import models + + +class DataMigration(models.AbstractModel): + _name = "data.migration" + _description = "Data Migration" + + def _data_migration_authentication(self): + instance = self.env["odoo.instance"].search([]) + # Authenticate for v11 + common_v11 = xmlrpc.client.ServerProxy( + "{}/xmlrpc/2/common".format(instance.instance_url) + ) + uid_v11 = common_v11.authenticate( + instance.instance_db, instance.login, instance.password, {} + ) + models_v11 = xmlrpc.client.ServerProxy( + "{}/xmlrpc/2/object".format(instance.instance_url) + ) + return instance, uid_v11, models_v11 diff --git a/data_migration/models/data_migration_mapping.py b/data_migration/models/data_migration_mapping.py new file mode 100644 index 00000000..c5335830 --- /dev/null +++ b/data_migration/models/data_migration_mapping.py @@ -0,0 +1,29 @@ +# Copyright 2023 Quartile Limited +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import models + + +class DataMigrationMapping(models.AbstractModel): + _name = "data.migration.mapping" + + def map_many2one_field_by_name(self, env, model_name, field_value): + """ + Return the ID of a record in the specified model based on its name. + + :param env: Odoo environment. + :param model_name: The name of the model (e.g., 'res.partner'). + :param field_value: Tuple containing the ID and name of the record in the old system. + :return: ID of the record in the new system with the same name. + """ + + if not isinstance(field_value, (tuple, list)): + return field_value + + old_id, name = field_value + if model_name == "res.partner": + record = env[model_name].search([("old_id", "=", old_id),('active', 'in', [True, False])], limit=1) + else: + record = env[model_name].search([("name", "=", name)], limit=1) + + return record.id if record else False diff --git a/data_migration/models/odoo_instance.py b/data_migration/models/odoo_instance.py new file mode 100644 index 00000000..3ba4b5cd --- /dev/null +++ b/data_migration/models/odoo_instance.py @@ -0,0 +1,15 @@ +# Copyright 2023 Quartile Limited +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class OdooInstance(models.Model): + _name = "odoo.instance" + _description = "Odoo Instances" + + name = fields.Char(required=True) + instance_url = fields.Char(required=True) + instance_db = fields.Char(required=True) + login = fields.Char(required=True) + password = fields.Char(required=True) diff --git a/data_migration/models/partner_data_migration.py b/data_migration/models/partner_data_migration.py new file mode 100644 index 00000000..d452bff9 --- /dev/null +++ b/data_migration/models/partner_data_migration.py @@ -0,0 +1,132 @@ +# Copyright 2023 Quartile Limited +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import SUPERUSER_ID, api, models + + +class PartnerDataMigration(models.Model): + _name = "partner.data.migration" + _inherit = ["data.migration", "data.migration.mapping"] + _description = "Partner Data Migration" + + def _run_partner_data_migration(self): + required_fields = [ + "is_invoice_issuer", + "team_id", + "identification_type_id", + "occupation_id", + "website_published", + "date_of_birth", + "company_id", + "date", + "title", + "parent_id", + # "user_id", # user migration will handle it. + "active", + "customer", + "supplier", + "employee", + "state_id", + "country_id", + "is_company", + # "commercial_partner_id", # compute function will handle it. + "name", + "display_name", + "lang", + "tz", + "vat", + "website", + "comment", + "return_policy", + "invoice_warn", + "invoice_warn_msg", + "picking_warn", + "function", + "type", + "street", + "street2", + "zip", + "city", + "picking_warn_msg", + "sale_warn", + "email", + "phone", + "mobile", + "sale_warn_msg", + "shipping_policy", + "purchase_warn", + "purchase_warn_msg", + "profile_msg", + "identification_number", + "company_name", + "fax", + "gender", + ] + instance, uid_v11, models_v11 = self._data_migration_authentication() + offset = 0 + limit = 1000 + while True: + partners_v11 = models_v11.execute_kw( + instance.instance_db, + uid_v11, + instance.password, + "res.partner", + "search_read", + [[('active', 'in', [True, False])]], + {"fields": required_fields, "offset": offset, "limit": limit}, + ) + if not partners_v11: + break + top_level_partners = [ + partner for partner in partners_v11 if not partner.get("parent_id") + ] + child_partners = [ + partner for partner in partners_v11 if partner.get("parent_id") + ] + offset += limit + + for partner in top_level_partners: + self.with_delay()._process_partner_migration(partner, is_child=False) + + for partner in child_partners: + self.with_delay()._process_partner_migration(partner, is_child=True) + + def _process_partner_migration(self, partner, is_child=False): + env = api.Environment(self.env.cr, SUPERUSER_ID, {}) + many2one_field_mapping = { + "team_id": "crm.team", + "identification_type_id": "identification.type", + "occupation_id": "res.occupation", + "company_id": "res.company", + "state_id": "res.country.state", + "country_id": "res.country", + "title": "res.partner.title", + } + + if partner.pop("customer", False): + partner["customer_rank"] = 1 + if partner.pop("supplier", False): + partner["supplier_rank"] = 1 + date_of_birth = partner.pop("date_of_birth", False) + if date_of_birth: + partner["date_birth"] = date_of_birth + + for field, model in many2one_field_mapping.items(): + if field in partner: + partner[field] = self.map_many2one_field_by_name( + env, model, partner[field] + ) + for field, value in list(partner.items()): + if (not is_child or field != "parent_id") and ( + isinstance(value, tuple) or isinstance(value, list) + ): + partner.pop(field, None) + + if is_child and partner.get("parent_id"): + parent_id = env["res.partner"].search( + [("old_id", "=", partner["parent_id"][0])] + ) + partner["parent_id"] = parent_id.id + + partner["old_id"] = partner["id"] + env["res.partner"].create(partner) diff --git a/data_migration/models/res_partner.py b/data_migration/models/res_partner.py new file mode 100644 index 00000000..696dc451 --- /dev/null +++ b/data_migration/models/res_partner.py @@ -0,0 +1,10 @@ +# Copyright 2023 Quartile Limited +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class ResPartner(models.Model): + _inherit = "res.partner" + + old_id = fields.Integer() diff --git a/data_migration/readme/DESCRIPTION.rst b/data_migration/readme/DESCRIPTION.rst new file mode 100644 index 00000000..ccbbf117 --- /dev/null +++ b/data_migration/readme/DESCRIPTION.rst @@ -0,0 +1 @@ +This module reads the data from another odoo instance and create in current odoo instance. diff --git a/data_migration/security/ir.model.access.csv b/data_migration/security/ir.model.access.csv new file mode 100644 index 00000000..bd03c71f --- /dev/null +++ b/data_migration/security/ir.model.access.csv @@ -0,0 +1,5 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_odoo_instance,odoo.instance,model_odoo_instance,base.group_system,1,1,1,1 +access_data_migration,data.migration,model_data_migration,base.group_system,1,1,1,1 +access_data_migration_mapping,data.migration.mapping,model_data_migration_mapping,base.group_system,1,1,1,1 +access_partner_data_migration,partner.data.migration,model_partner_data_migration,base.group_system,1,1,1,1 diff --git a/data_migration/static/description/index.html b/data_migration/static/description/index.html new file mode 100644 index 00000000..720aa902 --- /dev/null +++ b/data_migration/static/description/index.html @@ -0,0 +1,409 @@ + + + + + + +Data Migration + + + +
+

Data Migration

+ + +

Beta License: AGPL-3 qrtl/sst-custom

+

This module reads the data from another odoo instance and create in current odoo instance.

+

Table of contents

+ +
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Quartile Limited
  • +
+
+
+

Maintainers

+

This module is part of the qrtl/sst-custom project on GitHub.

+

You are welcome to contribute.

+
+
+
+ + diff --git a/data_migration/views/odoo_instance_views.xml b/data_migration/views/odoo_instance_views.xml new file mode 100644 index 00000000..6fa73d29 --- /dev/null +++ b/data_migration/views/odoo_instance_views.xml @@ -0,0 +1,45 @@ + + + + odoo.instance.tree + odoo.instance + + + + + + + + odoo.instance.form + odoo.instance + +
+ + + + + + + + + +
+
+
+ + Odoo Instance + odoo.instance + + + +
diff --git a/product_category_data_migration/README.rst b/product_category_data_migration/README.rst new file mode 100644 index 00000000..49cb6aa3 --- /dev/null +++ b/product_category_data_migration/README.rst @@ -0,0 +1,55 @@ +=============================== +Product Category Data Migration +=============================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:37897a8f49ed10be45a95cd7bd2883bd6dd2962e2da3299d59c0b71cdb6af45b + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| 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 +.. |badge3| image:: https://img.shields.io/badge/github-qrtl%2Fsst--custom-lightgray.png?logo=github + :target: https://github.com/qrtl/sst-custom/tree/15.0/product_category_data_migration + :alt: qrtl/sst-custom + +|badge1| |badge2| |badge3| + +This module reads the product category data from another odoo instance and create in current odoo instance. + +**Table of contents** + +.. contents:: + :local: + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* Quartile Limited + +Maintainers +~~~~~~~~~~~ + +This module is part of the `qrtl/sst-custom `_ project on GitHub. + +You are welcome to contribute. diff --git a/product_category_data_migration/__init__.py b/product_category_data_migration/__init__.py new file mode 100644 index 00000000..0650744f --- /dev/null +++ b/product_category_data_migration/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/product_category_data_migration/__manifest__.py b/product_category_data_migration/__manifest__.py new file mode 100644 index 00000000..c242511f --- /dev/null +++ b/product_category_data_migration/__manifest__.py @@ -0,0 +1,16 @@ +# Copyright 2023 Quartile Limited +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +{ + "name": "Product Category Data Migration", + "version": "15.0.1.0.0", + "category": "Tools", + "author": "Quartile Limited", + "website": "https://www.quartile.co", + "license": "AGPL-3", + "depends": ["product"], + "data": [ + "security/ir.model.access.csv", + "data/product_category_migration_scheduler.xml", + ], + "installable": True, +} diff --git a/product_category_data_migration/data/product_category_migration_scheduler.xml b/product_category_data_migration/data/product_category_migration_scheduler.xml new file mode 100644 index 00000000..af0b5895 --- /dev/null +++ b/product_category_data_migration/data/product_category_migration_scheduler.xml @@ -0,0 +1,16 @@ + + + + Product Category Data Migration from another odoo instance + 1 + days + -1 + code + model._run_product_category_data_migration() + + + + + diff --git a/product_category_data_migration/models/__init__.py b/product_category_data_migration/models/__init__.py new file mode 100644 index 00000000..4b9f236b --- /dev/null +++ b/product_category_data_migration/models/__init__.py @@ -0,0 +1,2 @@ +from . import product_category_data_migration +from . import product_category diff --git a/product_category_data_migration/models/product_category.py b/product_category_data_migration/models/product_category.py new file mode 100644 index 00000000..4be55826 --- /dev/null +++ b/product_category_data_migration/models/product_category.py @@ -0,0 +1,10 @@ +# Copyright 2023 Quartile Limited +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class ProductCategory(models.Model): + _inherit = "product.category" + + old_id = fields.Integer() diff --git a/product_category_data_migration/models/product_category_data_migration.py b/product_category_data_migration/models/product_category_data_migration.py new file mode 100644 index 00000000..9ebd22b3 --- /dev/null +++ b/product_category_data_migration/models/product_category_data_migration.py @@ -0,0 +1,59 @@ +# Copyright 2023 Quartile Limited +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + + +from odoo import SUPERUSER_ID, api, models + + +class ProductCategoryDataMigration(models.Model): + _name = "product.category.data.migration" + _inherit = "data.migration" + + def _run_product_category_data_migration(self): + instance, uid_v11, models_v11 = self._data_migration_authentication() + category_v11 = models_v11.execute_kw( + instance.instance_db, + uid_v11, + instance.password, + "product.category", + "search_read", + [], + ) + top_level_category = [ + category for category in category_v11 if not category.get("parent_id") + ] + child_category = [ + category for category in category_v11 if category.get("parent_id") + ] + env = api.Environment(self.env.cr, SUPERUSER_ID, {}) + for category in top_level_category: + category_id = self.env["product.category"].search( + [("name", "=", category["name"])] + ) + if category_id: + continue + category_data = { + "old_id": category["id"], + "name": category["name"], + # selection field doesn't store value in db + # "property_cost_method":category["property_cost_method"], + # "inventory_valuation": category["inventory_valuation"], + } + env["product.category"].create(category_data) + for category in child_category: + category_id = self.env["product.category"].search( + [("name", "=", category["name"])] + ) + if category_id: + continue + parent_id = self.env["product.category"].search( + [("old_id", "=", category["parent_id"][0])] + ) + category_data = { + "old_id": category["id"], + "name": category["name"], + # "property_cost_method":category["property_cost_method"], + # "inventory_valuation": category["inventory_valuation"], + "parent_id": parent_id.id, + } + env["product.category"].create(category_data) diff --git a/product_category_data_migration/readme/DESCRIPTION.rst b/product_category_data_migration/readme/DESCRIPTION.rst new file mode 100644 index 00000000..9e6eb76b --- /dev/null +++ b/product_category_data_migration/readme/DESCRIPTION.rst @@ -0,0 +1 @@ +This module reads the product category data from another odoo instance and create in current odoo instance. diff --git a/product_category_data_migration/security/ir.model.access.csv b/product_category_data_migration/security/ir.model.access.csv new file mode 100644 index 00000000..dc1b2b88 --- /dev/null +++ b/product_category_data_migration/security/ir.model.access.csv @@ -0,0 +1,2 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_product_category_data_migration,product_category.data.migration,model_product_category_data_migration,base.group_system,1,1,1,1 diff --git a/product_category_data_migration/static/description/index.html b/product_category_data_migration/static/description/index.html new file mode 100644 index 00000000..315efa19 --- /dev/null +++ b/product_category_data_migration/static/description/index.html @@ -0,0 +1,409 @@ + + + + + + +Product Category Data Migration + + + +
+

Product Category Data Migration

+ + +

Beta License: AGPL-3 qrtl/sst-custom

+

This module reads the product category data from another odoo instance and create in current odoo instance.

+

Table of contents

+ +
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Quartile Limited
  • +
+
+
+

Maintainers

+

This module is part of the qrtl/sst-custom project on GitHub.

+

You are welcome to contribute.

+
+
+
+ + diff --git a/purchase_order_migration/__init__.py b/purchase_order_migration/__init__.py new file mode 100644 index 00000000..0650744f --- /dev/null +++ b/purchase_order_migration/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/purchase_order_migration/__manifest__.py b/purchase_order_migration/__manifest__.py new file mode 100644 index 00000000..3a71d05f --- /dev/null +++ b/purchase_order_migration/__manifest__.py @@ -0,0 +1,16 @@ +# Copyright 2024 Quartile Limited +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +{ + "name": "Purchase Order Data Migration", + "version": "15.0.1.0.0", + "category": "Tools", + "author": "Quartile Limited", + "website": "https://www.quartile.co", + "license": "AGPL-3", + "depends": ["purchase", "data_migration"], + "data": [ + "security/ir.model.access.csv", + "data/purchase_migration_scheduler.xml", + ], + "installable": True, +} diff --git a/purchase_order_migration/data/purchase_migration_scheduler.xml b/purchase_order_migration/data/purchase_migration_scheduler.xml new file mode 100644 index 00000000..068c9873 --- /dev/null +++ b/purchase_order_migration/data/purchase_migration_scheduler.xml @@ -0,0 +1,16 @@ + + + + Purchase Order Data Migration from another odoo instance + 1 + days + -1 + code + model._run_purchase_order_data_migration() + + + + + diff --git a/purchase_order_migration/models/__init__.py b/purchase_order_migration/models/__init__.py new file mode 100644 index 00000000..6d130de0 --- /dev/null +++ b/purchase_order_migration/models/__init__.py @@ -0,0 +1,2 @@ +from . import purchase_order +from . import purchase_order_migration diff --git a/purchase_order_migration/models/purchase_order.py b/purchase_order_migration/models/purchase_order.py new file mode 100644 index 00000000..c923ce85 --- /dev/null +++ b/purchase_order_migration/models/purchase_order.py @@ -0,0 +1,10 @@ +# Copyright 2024 Quartile Limited +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class PurchaseOrder(models.Model): + _inherit = "purchase.order" + + old_id = fields.Integer() diff --git a/purchase_order_migration/models/purchase_order_migration.py b/purchase_order_migration/models/purchase_order_migration.py new file mode 100644 index 00000000..007df863 --- /dev/null +++ b/purchase_order_migration/models/purchase_order_migration.py @@ -0,0 +1,187 @@ +# Copyright 2023 Quartile Limited +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import SUPERUSER_ID, api, models + + +class PurchaseOrderMigration(models.Model): + _name = "purchase.order.migration" + _inherit = ["data.migration", "data.migration.mapping"] + _description = "Purchase Order Data Migration" + + def get_or_create_dummy_product(self): + env = api.Environment(self.env.cr, SUPERUSER_ID, {}) + # Check if the dummy product already exists + dummy_product = env["product.product"].search( + [("default_code", "=", "DUMMY_PRODUCT")], limit=1 + ) + if dummy_product: + return dummy_product.id + else: + # If the dummy product does not exist, create it + dummy_product = env["product.product"].create( + { + "name": "Dummy Product", + "type": "product", + "default_code": "DUMMY_PRODUCT", + "taxes_id": False, # Assuming no taxes, adjust if necessary + } + ) + return dummy_product.id + + def _run_purchase_order_data_migration(self): + required_fields = [ + "id", + "name", + "origin", + "partner_ref", + "date_order", + "date_approve", + "partner_id", + "dest_address_id", + "currency_id", + "state", + "notes", + "date_planned", + "amount_untaxed", + "amount_tax", + "amount_total", + "fiscal_position_id", + "payment_term_id", + "incoterm_id", + "company_id", + "address", + "remark", + "picking_type_id", + "sale_prediction_amount", + "request_channel_id", + "request_medium_id", + "call_back", + "state_id", + "city", + "street", + "street2", + "zip", + "phone_update", + "phone_search", + "supplier_phone", + "supplier_mobile", + "purchase_category_id", + "employee_id", + "shop_id", + "purchase_by_id", + "allow_convert", + # 'sale_order_id', # To check need to migrate or not + ] + instance, uid_v11, models_v11 = self._data_migration_authentication() + offset = 0 + limit = 1000 + while True: + purchase_order_v11 = models_v11.execute_kw( + instance.instance_db, + uid_v11, + instance.password, + "purchase.order", + "search_read", + [], + {"fields": required_fields, "offset": offset, "limit": limit}, + ) + if not purchase_order_v11: + break + offset += limit + + for purchase in purchase_order_v11: + self.with_delay()._process_purchase_order_migration(purchase) + + def _process_purchase_order_migration(self, purchase): + env = api.Environment(self.env.cr, SUPERUSER_ID, {}) + many2one_field_mapping = { + "incoterm_id": "account.incoterms", + "fiscal_position_id": "account.fiscal.position", + "company_id": "res.company", + "payment_term_id": "account.payment.term", + "currency_id": "res.currency", + "dest_address_id": "res.partner", + "partner_id": "res.partner", + "request_channel_id": "request.channel", + "request_medium_id": "request.medium", + "purchase_category_id": "purchase.category", + "employee_id": "hr.employee", + "shop_id": "stock.warehouse", + "purchase_by_id": "hr.employee", + "state_id": "res.country.state", + "sale_order_id": "sale.order", + "picking_type_id": "stock.picking.type", + } + description = purchase["picking_type_id"][1].split(": ") + purchase["picking_type_id"][1] = description[1] + for field, model in many2one_field_mapping.items(): + if field in purchase: + purchase[field] = self.map_many2one_field_by_name( + env, model, purchase[field] + ) + state = purchase["state"] + purchase["state"] = False + purchase["old_id"] = purchase["id"] + order = env["purchase.order"].create(purchase) + self.create_purchase_order_line(order) + order.write( + { + "amount_tax": purchase["amount_tax"], + "amount_untaxed": purchase["amount_untaxed"], + "amount_total": purchase["amount_total"], + "state": state, + } + ) + + def create_purchase_order_line(self, order): + required_fields = [ + "account_analytic_id", + "analytic_tag_ids", + "company_id", + "date_planned", + "name", + "price_subtotal", + "price_tax", + "price_total", + "price_unit", + "product_qty", + "product_uom", + "qty_invoiced", + "qty_received", + "taxes_id", + ] + + instance, uid_v11, models_v11 = self._data_migration_authentication() + purchase_order_line_v11 = models_v11.execute_kw( + instance.instance_db, + uid_v11, + instance.password, + "purchase.order.line", + "search_read", + [], + {"fields": required_fields, "domain": [("order_id", "=", order.old_id)]}, + ) + for line in purchase_order_line_v11: + env = api.Environment(self.env.cr, SUPERUSER_ID, {}) + many2one_field_mapping = { + "account_analytic_id": "account.analytic.account", + "analytic_tag_ids": "account.analytic.tag", + "company_id": "res.company", + "product_uom": "uom.uom", + } + dummy_product_id = self.get_or_create_dummy_product() + line["product_id"] = dummy_product_id + for field, model in many2one_field_mapping.items(): + if field in line and line[field]: + line[field] = self.map_many2one_field_by_name( + env, model, line[field] + ) + for field, value in list(line.items()): + if isinstance(value, tuple) or isinstance(value, list): + line.pop(field, None) + + line["order_id"] = order.id + order_line = env["purchase.order.line"].create(line) + order_line.taxes_id = False + order_line.write({"price_tax": line["price_tax"]}) diff --git a/purchase_order_migration/security/ir.model.access.csv b/purchase_order_migration/security/ir.model.access.csv new file mode 100644 index 00000000..80810bfb --- /dev/null +++ b/purchase_order_migration/security/ir.model.access.csv @@ -0,0 +1,2 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_purchase_order_migration,purchase.order.migration,model_purchase_order_migration,base.group_system,1,1,1,1 diff --git a/res_users_data_migration/README.rst b/res_users_data_migration/README.rst new file mode 100644 index 00000000..c9eeaa07 --- /dev/null +++ b/res_users_data_migration/README.rst @@ -0,0 +1,55 @@ +=================== +User Data Migration +=================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:b806a3379a38836cafb2a005dbd7b5443de499aba661047bab8522fcbc7cf614 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| 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 +.. |badge3| image:: https://img.shields.io/badge/github-qrtl%2Fsst--custom-lightgray.png?logo=github + :target: https://github.com/qrtl/sst-custom/tree/15.0/res_users_data_migration + :alt: qrtl/sst-custom + +|badge1| |badge2| |badge3| + +This module reads the user data from another odoo instance and create in current odoo instance. + +**Table of contents** + +.. contents:: + :local: + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* Quartile Limited + +Maintainers +~~~~~~~~~~~ + +This module is part of the `qrtl/sst-custom `_ project on GitHub. + +You are welcome to contribute. diff --git a/res_users_data_migration/__init__.py b/res_users_data_migration/__init__.py new file mode 100644 index 00000000..0650744f --- /dev/null +++ b/res_users_data_migration/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/res_users_data_migration/__manifest__.py b/res_users_data_migration/__manifest__.py new file mode 100644 index 00000000..bc80eabf --- /dev/null +++ b/res_users_data_migration/__manifest__.py @@ -0,0 +1,13 @@ +# Copyright 2023 Quartile Limited +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +{ + "name": "User Data Migration", + "version": "15.0.1.0.0", + "category": "Tools", + "author": "Quartile Limited", + "website": "https://www.quartile.co", + "license": "AGPL-3", + "depends": ["data_migration"], + "data": ["security/ir.model.access.csv", "data/user_migration_scheduler.xml"], + "installable": True, +} diff --git a/res_users_data_migration/data/user_migration_scheduler.xml b/res_users_data_migration/data/user_migration_scheduler.xml new file mode 100644 index 00000000..3d8e73d1 --- /dev/null +++ b/res_users_data_migration/data/user_migration_scheduler.xml @@ -0,0 +1,14 @@ + + + + User Data Migration from another odoo instance + 1 + days + -1 + code + model._run_user_data_migration() + + + + + diff --git a/res_users_data_migration/models/__init__.py b/res_users_data_migration/models/__init__.py new file mode 100644 index 00000000..b30b3081 --- /dev/null +++ b/res_users_data_migration/models/__init__.py @@ -0,0 +1,2 @@ +from . import user_data_migration +from . import res_users diff --git a/res_users_data_migration/models/res_users.py b/res_users_data_migration/models/res_users.py new file mode 100644 index 00000000..bfd353d0 --- /dev/null +++ b/res_users_data_migration/models/res_users.py @@ -0,0 +1,10 @@ +# Copyright 2023 Quartile Limited +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class ResUsers(models.Model): + _inherit = "res.users" + + old_id = fields.Integer() diff --git a/res_users_data_migration/models/user_data_migration.py b/res_users_data_migration/models/user_data_migration.py new file mode 100644 index 00000000..772bbfc4 --- /dev/null +++ b/res_users_data_migration/models/user_data_migration.py @@ -0,0 +1,43 @@ +# Copyright 2023 Quartile Limited +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + + +from odoo import models + + +class UserDataMigration(models.Model): + _name = "user.data.migration" + _inherit = "data.migration" + + def _run_user_data_migration(self): + instance, uid_v11, models_v11 = self._data_migration_authentication() + users_v11 = models_v11.execute_kw( + instance.instance_db, + uid_v11, + instance.password, + "res.users", + "search_read", + [], + ) + for user in users_v11: + # Use with_delay() to add each user creation to the job queue + self.with_delay()._create_user_job(user) + + def _create_user_job(self, user): + user_id = self.env["res.users"].search([("login", "=", user["login"])]) + if not user_id: + partner_id = self.env["res.partner"].search( + [("old_id", "=", user["partner_id"][0])] + ) + user_data = { + "name": user["name"], + "login": user["login"], + # "password": hashlib.sha256(user["password"].encode()).hexdigest(), + "partner_id": partner_id.id, + } + existing_user = self.env["res.users"].search( + [("login", "=", user["login"])], limit=1 + ) + if existing_user: + return True + self.env["res.users"].create(user_data) diff --git a/res_users_data_migration/readme/DESCRIPTION.rst b/res_users_data_migration/readme/DESCRIPTION.rst new file mode 100644 index 00000000..9d1e7e51 --- /dev/null +++ b/res_users_data_migration/readme/DESCRIPTION.rst @@ -0,0 +1 @@ +This module reads the user data from another odoo instance and create in current odoo instance. diff --git a/res_users_data_migration/security/ir.model.access.csv b/res_users_data_migration/security/ir.model.access.csv new file mode 100644 index 00000000..86c4fc26 --- /dev/null +++ b/res_users_data_migration/security/ir.model.access.csv @@ -0,0 +1,2 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_user_data_migration,user.data.migration,model_user_data_migration,base.group_system,1,1,1,1 diff --git a/res_users_data_migration/static/description/index.html b/res_users_data_migration/static/description/index.html new file mode 100644 index 00000000..ea727c9d --- /dev/null +++ b/res_users_data_migration/static/description/index.html @@ -0,0 +1,409 @@ + + + + + + +User Data Migration + + + +
+

User Data Migration

+ + +

Beta License: AGPL-3 qrtl/sst-custom

+

This module reads the user data from another odoo instance and create in current odoo instance.

+

Table of contents

+ +
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Quartile Limited
  • +
+
+
+

Maintainers

+

This module is part of the qrtl/sst-custom project on GitHub.

+

You are welcome to contribute.

+
+
+
+ + diff --git a/setup/data_migration/odoo/addons/data_migration b/setup/data_migration/odoo/addons/data_migration new file mode 120000 index 00000000..eceadc08 --- /dev/null +++ b/setup/data_migration/odoo/addons/data_migration @@ -0,0 +1 @@ +../../../../data_migration \ No newline at end of file diff --git a/setup/data_migration/setup.py b/setup/data_migration/setup.py new file mode 100644 index 00000000..28c57bb6 --- /dev/null +++ b/setup/data_migration/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/setup/product_category_data_migration/odoo/addons/product_category_data_migration b/setup/product_category_data_migration/odoo/addons/product_category_data_migration new file mode 120000 index 00000000..d5eb3e56 --- /dev/null +++ b/setup/product_category_data_migration/odoo/addons/product_category_data_migration @@ -0,0 +1 @@ +../../../../product_category_data_migration \ No newline at end of file diff --git a/setup/product_category_data_migration/setup.py b/setup/product_category_data_migration/setup.py new file mode 100644 index 00000000..28c57bb6 --- /dev/null +++ b/setup/product_category_data_migration/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/setup/purchase_order_migration/odoo/addons/purchase_order_migration b/setup/purchase_order_migration/odoo/addons/purchase_order_migration new file mode 120000 index 00000000..2c545ad2 --- /dev/null +++ b/setup/purchase_order_migration/odoo/addons/purchase_order_migration @@ -0,0 +1 @@ +../../../../purchase_order_migration \ No newline at end of file diff --git a/setup/purchase_order_migration/setup.py b/setup/purchase_order_migration/setup.py new file mode 100644 index 00000000..28c57bb6 --- /dev/null +++ b/setup/purchase_order_migration/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/setup/res_users_data_migration/odoo/addons/res_users_data_migration b/setup/res_users_data_migration/odoo/addons/res_users_data_migration new file mode 120000 index 00000000..dee182de --- /dev/null +++ b/setup/res_users_data_migration/odoo/addons/res_users_data_migration @@ -0,0 +1 @@ +../../../../res_users_data_migration \ No newline at end of file diff --git a/setup/res_users_data_migration/setup.py b/setup/res_users_data_migration/setup.py new file mode 100644 index 00000000..28c57bb6 --- /dev/null +++ b/setup/res_users_data_migration/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +)