| @ -0,0 +1,47 @@ | |||||
|  | .. image:: https://img.shields.io/badge/license-LGPL--3-green.svg | ||||
|  |     :target: https://www.gnu.org/licenses/lgpl-3.0-standalone.html | ||||
|  |     :alt: License: LGPL-3 | ||||
|  | 
 | ||||
|  | Import Bill Of Materials | ||||
|  | ======================== | ||||
|  | Import Bill Of Materials using CSV or Excel files | ||||
|  | 
 | ||||
|  | Configuration | ||||
|  | ============= | ||||
|  | * Check the Import BOM field in users | ||||
|  | 
 | ||||
|  | Company | ||||
|  | ------- | ||||
|  | * `Cybrosys Techno Solutions <https://cybrosys.com/>`__ | ||||
|  | 
 | ||||
|  | License | ||||
|  | ------- | ||||
|  | General Public License, Version 3 (LGPL v3). | ||||
|  | (https://www.gnu.org/licenses/lgpl-3.0-standalone.html) | ||||
|  | 
 | ||||
|  | Credits | ||||
|  | ------- | ||||
|  | * Developers: (V17) Developer Anurudh P, | ||||
|  |               (V18) Developer Ranjith R, | ||||
|  |      Contact: odoo@cybrosys.com | ||||
|  | Contacts | ||||
|  | -------- | ||||
|  | * Mail Contact : odoo@cybrosys.com | ||||
|  | * Website : https://cybrosys.com | ||||
|  | 
 | ||||
|  | Bug Tracker | ||||
|  | ----------- | ||||
|  | Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. | ||||
|  | 
 | ||||
|  | Maintainer | ||||
|  | ========== | ||||
|  | .. image:: https://cybrosys.com/images/logo.png | ||||
|  |    :target: https://cybrosys.com | ||||
|  | 
 | ||||
|  | This module is maintained by Cybrosys Technologies. | ||||
|  | 
 | ||||
|  | For support and more information, please visit `Our Website <https://cybrosys.com/>`__ | ||||
|  | 
 | ||||
|  | Further information | ||||
|  | =================== | ||||
|  | HTML Description: `<static/description/index.html>`__ | ||||
| @ -0,0 +1,22 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################# | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Ranjith R(<https://www.cybrosys.com>) | ||||
|  | # | ||||
|  | #    You can modify it under the terms of the GNU LESSER | ||||
|  | #    GENERAL PUBLIC LICENSE (LGPL v3), Version 3. | ||||
|  | # | ||||
|  | #    This program is distributed in the hope that it will be useful, | ||||
|  | #    but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  | #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  | #    GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. | ||||
|  | # | ||||
|  | #    You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE | ||||
|  | #    (LGPL v3) along with this program. | ||||
|  | #    If not, see <http://www.gnu.org/licenses/>. | ||||
|  | # | ||||
|  | ############################################################################# | ||||
|  | from . import wizards | ||||
| @ -0,0 +1,56 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################# | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Ranjith R (<https://www.cybrosys.com>) | ||||
|  | # | ||||
|  | #    You can modify it under the terms of the GNU LESSER | ||||
|  | #    GENERAL PUBLIC LICENSE (LGPL v3), Version 3. | ||||
|  | # | ||||
|  | #    This program is distributed in the hope that it will be useful, | ||||
|  | #    but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  | #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  | #    GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. | ||||
|  | # | ||||
|  | #    You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE | ||||
|  | #    (LGPL v3) along with this program. | ||||
|  | #    If not, see <http://www.gnu.org/licenses/>. | ||||
|  | # | ||||
|  | ############################################################################# | ||||
|  | { | ||||
|  |     'name': 'Import Bill Of Materials', | ||||
|  |     'version': '18.0.1.0.0', | ||||
|  |     'category': 'Manufacturing', | ||||
|  |     'summary': """Import Bill of materials using CSV, Excel file""", | ||||
|  |     'description': 'Using this module we can import bom by searching' | ||||
|  |                    ' the products in diffrent ways in csv or excel files', | ||||
|  |     'author': 'Cybrosys Techno Solutions', | ||||
|  |     'company': 'Cybrosys Techno Solutions', | ||||
|  |     'maintainer': 'Cybrosys Techno Solutions', | ||||
|  |     'website': 'https://www.cybrosys.com', | ||||
|  |     'depends': ['base', 'stock', 'mrp'], | ||||
|  |     'data': { | ||||
|  |         'security/ir.model.access.csv', | ||||
|  |         'security/import_bom_security.xml', | ||||
|  |         'views/bom_import_menu_view.xml', | ||||
|  |         'wizards/bom_import_view.xml', | ||||
|  |         'wizards/success_message_view.xml', | ||||
|  |     }, | ||||
|  |     'assets': { | ||||
|  |         'web.assets_backend': [ | ||||
|  |             'import_bill_of_materials_in_mrp/static/src/css/style.css' | ||||
|  |         ], | ||||
|  |     }, | ||||
|  |     'external_dependencies': { | ||||
|  |         'python': [ | ||||
|  |             'openpyxl' | ||||
|  |         ], | ||||
|  |     }, | ||||
|  |     'images': ['static/description/banner.png'], | ||||
|  |     'license': 'LGPL-3', | ||||
|  |     'installable': True, | ||||
|  |     'auto_install': False, | ||||
|  |     'application': False, | ||||
|  | } | ||||
| @ -0,0 +1,6 @@ | |||||
|  | ## Module <import_bill_of_materials_in_mrp> | ||||
|  | 
 | ||||
|  | #### 21.12.2025 | ||||
|  | #### Version 18.0.1.0.0 | ||||
|  | #### ADD | ||||
|  | - Initial commit for Import Bill Of Materials | ||||
| @ -0,0 +1,7 @@ | |||||
|  | <?xml version="1.0" encoding="utf-8"?> | ||||
|  | <odoo> | ||||
|  |     <!-- Security groups for Import BOM  --> | ||||
|  |     <record id="import_bom_group_id" model="res.groups"> | ||||
|  |         <field name="name">Import BOM</field> | ||||
|  |     </record> | ||||
|  | </odoo> | ||||
| 
 | 
| After Width: | Height: | Size: 1.1 KiB | 
| After Width: | Height: | Size: 210 KiB | 
| After Width: | Height: | Size: 209 KiB | 
| After Width: | Height: | Size: 109 KiB | 
| After Width: | Height: | Size: 495 B | 
| After Width: | Height: | Size: 1.0 KiB | 
| After Width: | Height: | Size: 624 B | 
| After Width: | Height: | Size: 136 KiB | 
| After Width: | Height: | Size: 214 KiB | 
| After Width: | Height: | Size: 36 KiB | 
| After Width: | Height: | Size: 3.6 KiB | 
| After Width: | Height: | Size: 310 B | 
| After Width: | Height: | Size: 929 B | 
| After Width: | Height: | Size: 1.3 KiB | 
| After Width: | Height: | Size: 3.3 KiB | 
| After Width: | Height: | Size: 1.4 KiB | 
| After Width: | Height: | Size: 17 KiB | 
| After Width: | Height: | Size: 542 B | 
| After Width: | Height: | Size: 576 B | 
| After Width: | Height: | Size: 733 B | 
| After Width: | Height: | Size: 4.3 KiB | 
| After Width: | Height: | Size: 1.2 KiB | 
| After Width: | Height: | Size: 4.0 KiB | 
| After Width: | Height: | Size: 1.7 KiB | 
| After Width: | Height: | Size: 738 KiB | 
| After Width: | Height: | Size: 2.2 KiB | 
| After Width: | Height: | Size: 911 B | 
| After Width: | Height: | Size: 1.1 KiB | 
| After Width: | Height: | Size: 1.2 KiB | 
| After Width: | Height: | Size: 1.2 KiB | 
| After Width: | Height: | Size: 600 B | 
| After Width: | Height: | Size: 673 B | 
| After Width: | Height: | Size: 2.0 KiB | 
| After Width: | Height: | Size: 462 B | 
| After Width: | Height: | Size: 2.1 KiB | 
| After Width: | Height: | Size: 926 B | 
| After Width: | Height: | Size: 9.0 KiB | 
| After Width: | Height: | Size: 23 KiB | 
| After Width: | Height: | Size: 7.0 KiB | 
| After Width: | Height: | Size: 878 B | 
| After Width: | Height: | Size: 1.2 KiB | 
| After Width: | Height: | Size: 653 B | 
| After Width: | Height: | Size: 800 B | 
| After Width: | Height: | Size: 905 B | 
| After Width: | Height: | Size: 189 KiB | 
| After Width: | Height: | Size: 4.3 KiB | 
| After Width: | Height: | Size: 839 B | 
| After Width: | Height: | Size: 1.7 KiB | 
| After Width: | Height: | Size: 5.9 KiB | 
| After Width: | Height: | Size: 1.6 KiB | 
| After Width: | Height: | Size: 34 KiB | 
| After Width: | Height: | Size: 26 KiB | 
| After Width: | Height: | Size: 3.8 KiB | 
| After Width: | Height: | Size: 23 KiB | 
| After Width: | Height: | Size: 1.9 KiB | 
| After Width: | Height: | Size: 2.3 KiB | 
| After Width: | Height: | Size: 427 B | 
| After Width: | Height: | Size: 627 B | 
| After Width: | Height: | Size: 1.1 KiB | 
| After Width: | Height: | Size: 1.2 KiB | 
| After Width: | Height: | Size: 988 B | 
| After Width: | Height: | Size: 3.7 KiB | 
| After Width: | Height: | Size: 5.0 KiB | 
| After Width: | Height: | Size: 875 B | 
| After Width: | Height: | Size: 1.2 KiB | 
| After Width: | Height: | Size: 767 KiB | 
| After Width: | Height: | Size: 138 KiB | 
| After Width: | Height: | Size: 760 KiB | 
| After Width: | Height: | Size: 92 KiB | 
| After Width: | Height: | Size: 697 KiB | 
| After Width: | Height: | Size: 1.1 MiB | 
| After Width: | Height: | Size: 108 KiB | 
| After Width: | Height: | Size: 97 KiB | 
| After Width: | Height: | Size: 124 KiB | 
| After Width: | Height: | Size: 88 KiB | 
| After Width: | Height: | Size: 87 KiB | 
| After Width: | Height: | Size: 145 KiB | 
| After Width: | Height: | Size: 97 KiB | 
| After Width: | Height: | Size: 130 KiB | 
| After Width: | Height: | Size: 9.8 KiB | 
| 
 | 
| @ -0,0 +1,19 @@ | |||||
|  | .div_pos{ | ||||
|  |     margin-left: 508px !important; | ||||
|  |     margin-top: 10px; | ||||
|  | } | ||||
|  | .csv{ | ||||
|  |     margin: 0 10px; | ||||
|  |     font-size: 12px; | ||||
|  |     line-height: 1.5; | ||||
|  |     border-radius: 3px; | ||||
|  |     padding: 8px 10px; | ||||
|  |     color: #ffffff; | ||||
|  | } | ||||
|  | .xlsx{ | ||||
|  |     font-size: 12px; | ||||
|  |     line-height: 1.5; | ||||
|  |     border-radius: 3px; | ||||
|  |     padding: 8px 10px; | ||||
|  |     color: #ffffff; | ||||
|  | } | ||||
| @ -0,0 +1,15 @@ | |||||
|  | <?xml version="1.0" encoding="utf-8"?> | ||||
|  | <odoo> | ||||
|  |     <!-- Menu for  Import BOM --> | ||||
|  |     <record id="action_import_bom" model="ir.actions.act_window"> | ||||
|  |             <field name="name">Import BOM</field> | ||||
|  |             <field name="res_model">bom.import</field> | ||||
|  |             <field name="view_mode">form</field> | ||||
|  |             <field name="target">new</field> | ||||
|  |     </record> | ||||
|  |     <menuitem id="menu_import_bom" | ||||
|  |         parent="mrp.menu_mrp_bom" | ||||
|  |         action="action_import_bom" | ||||
|  |         groups="import_bill_of_materials_in_mrp.import_bom_group_id" | ||||
|  |     /> | ||||
|  | </odoo> | ||||
| @ -0,0 +1,23 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################# | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Ranjith R (<https://www.cybrosys.com>) | ||||
|  | # | ||||
|  | #    You can modify it under the terms of the GNU LESSER | ||||
|  | #    GENERAL PUBLIC LICENSE (LGPL v3), Version 3. | ||||
|  | # | ||||
|  | #    This program is distributed in the hope that it will be useful, | ||||
|  | #    but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  | #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  | #    GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. | ||||
|  | # | ||||
|  | #    You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE | ||||
|  | #    (LGPL v3) along with this program. | ||||
|  | #    If not, see <http://www.gnu.org/licenses/>. | ||||
|  | # | ||||
|  | ############################################################################# | ||||
|  | from . import bom_import | ||||
|  | from . import success_message | ||||
| @ -0,0 +1,261 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################# | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Ranjith R (<https://www.cybrosys.com>) | ||||
|  | # | ||||
|  | #    You can modify it under the terms of the GNU LESSER | ||||
|  | #    GENERAL PUBLIC LICENSE (LGPL v3), Version 3. | ||||
|  | # | ||||
|  | #    This program is distributed in the hope that it will be useful, | ||||
|  | #    but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  | #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  | #    GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. | ||||
|  | # | ||||
|  | #    You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE | ||||
|  | #    (LGPL v3) along with this program. | ||||
|  | #    If not, see <http://www.gnu.org/licenses/>. | ||||
|  | # | ||||
|  | ############################################################################# | ||||
|  | import binascii | ||||
|  | import certifi | ||||
|  | import csv | ||||
|  | import tempfile | ||||
|  | import urllib3 | ||||
|  | import xlrd | ||||
|  | from odoo import fields,models, _ | ||||
|  | import base64 | ||||
|  | import openpyxl | ||||
|  | from io import BytesIO | ||||
|  | from odoo.exceptions import UserError | ||||
|  | from odoo.tools import ustr | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | class BomImport(models.TransientModel): | ||||
|  |     """This is a transient model for creating a wizard for importing bom """ | ||||
|  |     _name = 'bom.import' | ||||
|  |     _description = 'Import Bom wizard' | ||||
|  | 
 | ||||
|  |     file_type = fields.Selection([('csv', 'CSV File'), | ||||
|  |                                   ('xls', 'Excel File')], | ||||
|  |                                  String='File Type', Required=True, | ||||
|  |                                  default='csv', | ||||
|  |                                  help='File type of importing file') | ||||
|  |     name = fields.Char(string='name') | ||||
|  |     bom_type = fields.Selection( | ||||
|  |         [('mtp', 'Manufacture This Product'), ('kit', 'Kit')], | ||||
|  |         String='BOM Type', Required=True, | ||||
|  |         default='mtp', helf='Type of Bill of Materials') | ||||
|  |     product_variant_by = fields.Selection( | ||||
|  |         [('default_code', 'Internal Reference'), | ||||
|  |          ('barcode', 'Barcode')], String='Product Variant By', Required=True, | ||||
|  |         default='default_code', help='Product variant type in file') | ||||
|  |     product_by = fields.Selection([('name', 'Name'), | ||||
|  |                                    ('default_code', 'Internal Reference'), | ||||
|  |                                    ('barcode', 'Barcode')], String='Product By', | ||||
|  |                                   Required=True, default='name', | ||||
|  |                                   help='Product type in file') | ||||
|  |     file = fields.Binary(String='Upload File', Required=True, | ||||
|  |                          help='File to Import') | ||||
|  | 
 | ||||
|  |     def action_import_bom(self): | ||||
|  |         """function for importing bom through csv or Excel file""" | ||||
|  |         if self.file: | ||||
|  |             if self.file_type == 'csv': | ||||
|  |                 try: | ||||
|  |                     file = base64.b64decode(self.file) | ||||
|  |                     file_string = file.decode('utf-8') | ||||
|  |                     file_string.split('\n') | ||||
|  |                     urllib3.PoolManager(cert_reqs='CERT_REQUIRED', | ||||
|  |                                         ca_certs=certifi.where()) | ||||
|  |                 except: | ||||
|  |                     raise UserError(_("Please choose the correct file!")) | ||||
|  |                 for rec in self: | ||||
|  |                     file = str(base64.decodebytes( | ||||
|  |                         rec.file).decode('utf-8')) | ||||
|  |                     reader = csv.reader(file.splitlines()) | ||||
|  |                     next(reader) | ||||
|  |                     last_bom_id = False | ||||
|  |                     rec_count = 0 | ||||
|  |                     try: | ||||
|  |                         for col in reader: | ||||
|  |                             bom_data = {} | ||||
|  |                             bom_line_dict = {} | ||||
|  |                             if col[1]: | ||||
|  |                                 rec_count += 1 | ||||
|  |                                 if rec.product_by == 'name': | ||||
|  |                                     product_search = 'name' | ||||
|  |                                 elif rec.product_by == 'default_code': | ||||
|  |                                     product_search = 'default_code' | ||||
|  |                                 else: | ||||
|  |                                     product_search = 'barcode' | ||||
|  |                                 product = self.env['product.template'].search( | ||||
|  |                                     [(product_search, '=', col[1])], limit=1) | ||||
|  |                                 bom_data.update({'product_tmpl_id': product.id, | ||||
|  |                                                  'code': col[0]}) | ||||
|  |                                 if col[2]: | ||||
|  |                                     if rec.product_variant_by == 'default_code': | ||||
|  |                                         variant_search = 'default_code' | ||||
|  |                                     else: | ||||
|  |                                         variant_search = 'barcode' | ||||
|  |                                     variant = self.env[ | ||||
|  |                                         'product.product'].search( | ||||
|  |                                         [(variant_search, '=', col[2])], | ||||
|  |                                         limit=1) | ||||
|  |                                     bom_data.update({'product_id': variant.id}) | ||||
|  |                                     if col[4]: | ||||
|  |                                         uom = self.env['uom.uom'].search( | ||||
|  |                                             [('name', '=', col[4])], limit=1) | ||||
|  |                                         bom_data.update( | ||||
|  |                                             {'product_uom_id': uom.id}) | ||||
|  |                                     else: | ||||
|  |                                         bom_data.update( | ||||
|  |                                             {'product_uom_id': variant.uom_id}) | ||||
|  |                                 if col[3]: | ||||
|  |                                     bom_data.update({'product_qty': col[3]}) | ||||
|  |                                 else: | ||||
|  |                                     bom_data.update({'product_qty': 1}) | ||||
|  | 
 | ||||
|  |                                 if rec.bom_type == 'mtp': | ||||
|  |                                     bom_data.update({'type': 'normal'}) | ||||
|  |                                 else: | ||||
|  |                                     bom_data.update({'type': 'phantom'}) | ||||
|  |                                 bom_bom = rec.env['mrp.bom'].create(bom_data) | ||||
|  |                                 last_bom_id = bom_bom.id | ||||
|  |                             if col[5]: | ||||
|  |                                 if rec.product_variant_by == 'default_code': | ||||
|  |                                     variant_search = 'default_code' | ||||
|  |                                 else: | ||||
|  |                                     variant_search = 'barcode' | ||||
|  |                                 variant = self.env['product.product'].search( | ||||
|  |                                     [(variant_search, '=', col[5])], limit=1) | ||||
|  |                                 bom_line_dict.update({'product_id': variant.id, | ||||
|  |                                                       'bom_id': last_bom_id | ||||
|  |                                                       }) | ||||
|  |                                 if col[6]: | ||||
|  |                                     bom_line_dict.update( | ||||
|  |                                         {'product_qty': col[6]}) | ||||
|  |                                 else: | ||||
|  |                                     bom_line_dict.update({'product_qty': 1}) | ||||
|  |                                 if col[7]: | ||||
|  |                                     uom = self.env['uom.uom'].search( | ||||
|  |                                         [('name', '=', col[7])], limit=1) | ||||
|  |                                     bom_line_dict.update( | ||||
|  |                                         {'product_uom_id': uom.id}) | ||||
|  |                                 else: | ||||
|  |                                     bom_line_dict.update( | ||||
|  |                                         {'product_uom_id': product.uom_id}) | ||||
|  |                                 self.env['mrp.bom.line'].create(bom_line_dict) | ||||
|  |                         return rec.success_message(rec_count) | ||||
|  |                     except Exception as e: | ||||
|  |                         raise UserError( | ||||
|  |                             _("Sorry, The CSV file you provided " | ||||
|  |                               "does not match our required format" + ustr( | ||||
|  |                                 e))) | ||||
|  | 
 | ||||
|  |             if self.file_type == 'xls': | ||||
|  |                 try: | ||||
|  |                     file_string = tempfile.NamedTemporaryFile(suffix=".xlsx") | ||||
|  |                     file_string.write(binascii.a2b_base64(self.file)) | ||||
|  |                     book = xlrd.open_workbook(file_string.name) | ||||
|  |                     book.sheet_by_index(0) | ||||
|  |                     urllib3.PoolManager(cert_reqs='CERT_REQUIRED', | ||||
|  |                                         ca_certs=certifi.where()) | ||||
|  |                 except: | ||||
|  |                     raise UserError(_("Please choose the correct file")) | ||||
|  |                 for rec in self: | ||||
|  |                     try: | ||||
|  |                         wb = openpyxl.load_workbook( | ||||
|  |                             filename=BytesIO(base64.b64decode(rec.file)), | ||||
|  |                             read_only=True) | ||||
|  |                         ws = wb.active | ||||
|  |                         rec_count = 0 | ||||
|  |                         for col in ws.iter_rows(min_row=2, values_only=True): | ||||
|  |                             bom_data = {} | ||||
|  |                             bom_line_dict = {} | ||||
|  |                             if col[1]: | ||||
|  |                                 rec_count += 1 | ||||
|  |                                 if rec.product_by == 'name': | ||||
|  |                                     product_search = 'name' | ||||
|  |                                 elif rec.product_by == 'default_code': | ||||
|  |                                     product_search = 'default_code' | ||||
|  |                                 else: | ||||
|  |                                     product_search = 'barcode' | ||||
|  |                                 product = self.env['product.template'].search( | ||||
|  |                                     [(product_search, '=', col[1])], limit=1) | ||||
|  |                                 bom_data.update({'product_tmpl_id': product.id, | ||||
|  |                                                  'code': col[0]}) | ||||
|  |                                 if col[2]: | ||||
|  |                                     if rec.product_variant_by == 'default_code': | ||||
|  |                                         variant_search = 'default_code' | ||||
|  |                                     else: | ||||
|  |                                         variant_search = 'barcode' | ||||
|  |                                     variant = self.env[ | ||||
|  |                                         'product.product'].search( | ||||
|  |                                         [(variant_search, '=', col[2])], | ||||
|  |                                         limit=1) | ||||
|  |                                     bom_data.update({'product_id': variant.id}) | ||||
|  |                                     if col[4]: | ||||
|  |                                         uom = self.env['uom.uom'].search( | ||||
|  |                                             [('name', '=', col[4])], limit=1) | ||||
|  |                                         bom_data.update( | ||||
|  |                                             {'product_uom_id': uom.id}) | ||||
|  |                                     else: | ||||
|  |                                         bom_data.update( | ||||
|  |                                             {'product_uom_id': variant.uom_id}) | ||||
|  |                                 if col[3]: | ||||
|  |                                     bom_data.update({'product_qty': col[3]}) | ||||
|  |                                 else: | ||||
|  |                                     bom_data.update({'product_qty': 1}) | ||||
|  | 
 | ||||
|  |                                 if rec.bom_type == 'mtp': | ||||
|  |                                     bom_data.update({'type': 'normal'}) | ||||
|  |                                 else: | ||||
|  |                                     bom_data.update({'type': 'phantom'}) | ||||
|  |                                 bom_bom = rec.env['mrp.bom'].create(bom_data) | ||||
|  |                                 last_bom_id = bom_bom.id | ||||
|  |                             if col[5]: | ||||
|  |                                 if rec.product_variant_by == 'default_code': | ||||
|  |                                     variant_search = 'default_code' | ||||
|  |                                 else: | ||||
|  |                                     variant_search = 'barcode' | ||||
|  |                                 variant = self.env['product.product'].search( | ||||
|  |                                     [(variant_search, '=', col[5])], limit=1) | ||||
|  |                                 bom_line_dict.update({'product_id': variant.id, | ||||
|  |                                                       'bom_id': last_bom_id | ||||
|  |                                                       }) | ||||
|  |                                 if col[6]: | ||||
|  |                                     bom_line_dict.update( | ||||
|  |                                         {'product_qty': col[6]}) | ||||
|  |                                 else: | ||||
|  |                                     bom_line_dict.update({'product_qty': 1}) | ||||
|  |                                 if col[7]: | ||||
|  |                                     uom = self.env['uom.uom'].search( | ||||
|  |                                         [('name', '=', col[7])], limit=1) | ||||
|  |                                     bom_line_dict.update( | ||||
|  |                                         {'product_uom_id': uom.id}) | ||||
|  |                                 else: | ||||
|  |                                     bom_line_dict.update( | ||||
|  |                                         {'product_uom_id': product.uom_id}) | ||||
|  |                                 self.env['mrp.bom.line'].create(bom_line_dict) | ||||
|  |                         return rec.success_message(rec_count) | ||||
|  |                     except Exception as e: | ||||
|  |                         raise UserError( | ||||
|  |                             _("Sorry, The Excel file you provided" | ||||
|  |                               " does not match our required format" + ustr( | ||||
|  |                                 e))) | ||||
|  | 
 | ||||
|  |     def success_message(self, rec_count): | ||||
|  |         """function for displaying success message""" | ||||
|  |         message_id = self.env['success.message'].create( | ||||
|  |             {'message': str(rec_count) + " Records imported successfully"}) | ||||
|  |         return { | ||||
|  |             'name': 'Message', | ||||
|  |             'type': 'ir.actions.act_window', | ||||
|  |             'view_mode': 'form', | ||||
|  |             'res_model': 'success.message', | ||||
|  |             'res_id': message_id.id, | ||||
|  |             'target': 'new' | ||||
|  |         } | ||||
| @ -0,0 +1,43 @@ | |||||
|  | <?xml version="1.0" encoding="utf-8"?> | ||||
|  | <odoo> | ||||
|  |     <!-- wizard of importing Bill of Materials --> | ||||
|  |     <record id="bom_import_view_form" model="ir.ui.view"> | ||||
|  |         <field name="name">bom.import</field> | ||||
|  |         <field name="model">bom.import</field> | ||||
|  |         <field name="arch" type="xml"> | ||||
|  |             <form name="Import BOM"> | ||||
|  |                 <group> | ||||
|  |                     <group> | ||||
|  |                         <field name="file_type" widget="radio"/> | ||||
|  |                         <field name="bom_type" widget="radio"/> | ||||
|  |                         <field name="file" filename="name"/> | ||||
|  |                     </group> | ||||
|  |                     <group> | ||||
|  |                         <field name="product_variant_by" widget="radio"/> | ||||
|  |                         <field name="product_by" widget="radio"/> | ||||
|  |                     </group> | ||||
|  |                     <field name="name" invisible="1"/> | ||||
|  |                 </group> | ||||
|  |                 <footer> | ||||
|  |                     <button name="action_import_bom" string="Apply" | ||||
|  |                             type="object" class="btn-primary"/> | ||||
|  |                     <button string="Cancel" class="btn-default" | ||||
|  |                             special="cancel"/> | ||||
|  |                     <div class="div_pos"> | ||||
|  |                         <strong>Download Sample:</strong> | ||||
|  |                         <a href="/import_bill_of_materials_in_mrp/static/download/import_bom_csv.csv" | ||||
|  |                            class="oe_link" target="_blank"> | ||||
|  |                              <i class="fa fa-download"/> | ||||
|  |                             CSV file | ||||
|  |                         </a> | ||||
|  |                         <a href="/import_bill_of_materials_in_mrp/static/download/import_bom_excel.xlsx" | ||||
|  |                            class="oe_link" target="_blank"> | ||||
|  |                              <i class="fa fa-download"/> | ||||
|  |                             Excel file | ||||
|  |                         </a> | ||||
|  |                     </div> | ||||
|  |                 </footer> | ||||
|  |             </form> | ||||
|  |         </field> | ||||
|  |     </record> | ||||
|  | </odoo> | ||||
| @ -0,0 +1,35 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################# | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Ranjith R (<https://www.cybrosys.com>) | ||||
|  | # | ||||
|  | #    You can modify it under the terms of the GNU LESSER | ||||
|  | #    GENERAL PUBLIC LICENSE (LGPL v3), Version 3. | ||||
|  | # | ||||
|  | #    This program is distributed in the hope that it will be useful, | ||||
|  | #    but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  | #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  | #    GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. | ||||
|  | # | ||||
|  | #    You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE | ||||
|  | #    (LGPL v3) along with this program. | ||||
|  | #    If not, see <http://www.gnu.org/licenses/>. | ||||
|  | # | ||||
|  | ############################################################################# | ||||
|  | from odoo import fields, models | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | class SuccessMessage(models.TransientModel): | ||||
|  |     """model for adding warning message """ | ||||
|  | 
 | ||||
|  |     _name = 'success.message' | ||||
|  |     _description = "Show Message" | ||||
|  | 
 | ||||
|  |     message = fields.Text('Success', required=True) | ||||
|  | 
 | ||||
|  |     def action_close(self): | ||||
|  |         """function for close button""" | ||||
|  |         return {'type': 'ir.actions.act_window_close'} | ||||
| @ -0,0 +1,16 @@ | |||||
|  | <?xml version="1.0" encoding="utf-8"?> | ||||
|  | <odoo> | ||||
|  |     <!--This XML defines a view for displaying a success message in an Odoo wizard--> | ||||
|  |     <record id="success_message_wizard" model="ir.ui.view"> | ||||
|  |         <field name="name">success.message.form</field> | ||||
|  |         <field name="model">success.message</field> | ||||
|  |         <field name="arch" type="xml"> | ||||
|  |             <form> | ||||
|  |                 <field name="message" readonly="True"/> | ||||
|  |                 <footer> | ||||
|  |                     <button name="action_close" string="Ok" type="object" class="oe_highlight"/> | ||||
|  |                 </footer> | ||||
|  |             </form> | ||||
|  |         </field> | ||||
|  |     </record> | ||||
|  | </odoo> | ||||