diff --git a/addons_extensions/aspl_equipment_qrcode_generator/__init__.py b/addons_extensions/aspl_equipment_qrcode_generator/__init__.py new file mode 100644 index 000000000..e7843e8bf --- /dev/null +++ b/addons_extensions/aspl_equipment_qrcode_generator/__init__.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- + +from odoo import api, SUPERUSER_ID + +from . import models +from . import report +from . import wizard + + +# TODO: Generate Sequence For each company for Equipment +def pre_init_hook(env): + company_ids = env['res.company'].search([]) + for company_id in company_ids: + sequence_id = env['ir.sequence'].search( + [('name', '=', 'Equipment Company Sequence'), ('company_id', '=', company_id.id)]) + if not sequence_id: + env['ir.sequence'].create({ + 'name': 'Equipment Company Sequence', + 'prefix': company_id.id, + 'padding': 5, + 'number_increment': 1, + 'company_id': company_id.id + }) diff --git a/addons_extensions/aspl_equipment_qrcode_generator/__manifest__.py b/addons_extensions/aspl_equipment_qrcode_generator/__manifest__.py new file mode 100644 index 000000000..f2d08eb66 --- /dev/null +++ b/addons_extensions/aspl_equipment_qrcode_generator/__manifest__.py @@ -0,0 +1,25 @@ + +{ + "name": "QR Code on Equipment", + 'category': '', + "summary": "Add QR Code on equipment .", + 'license': 'LGPL-3', + "price": 00.00, + 'description': """ + The Equipment Management Module generates unique QR codes for each asset, offering instant details and direct Odoo profile access for seamless management. + """, + "author": "Raman Marikanti", + "depends": ['account','maintenance'], + "external_dependencies": { + 'python': ['qrcode'] + }, + "data": [ + 'views/maintenance_equipment.xml', + 'security/ir.model.access.csv', + 'report/custom_qrcode.xml', + 'wizard/equipment_label_layout_views.xml', + ], + 'pre_init_hook': 'pre_init_hook', + "application": True, + "installable": True, +} diff --git a/addons_extensions/aspl_equipment_qrcode_generator/models/__init__.py b/addons_extensions/aspl_equipment_qrcode_generator/models/__init__.py new file mode 100644 index 000000000..e176a441b --- /dev/null +++ b/addons_extensions/aspl_equipment_qrcode_generator/models/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- + +from . import maintenance_equipment +from . import res_company diff --git a/addons_extensions/aspl_equipment_qrcode_generator/models/maintenance_equipment.py b/addons_extensions/aspl_equipment_qrcode_generator/models/maintenance_equipment.py new file mode 100644 index 000000000..4e7b2172c --- /dev/null +++ b/addons_extensions/aspl_equipment_qrcode_generator/models/maintenance_equipment.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- + +from odoo import models, fields + + +class MaintenanceEquipment(models.Model): + _inherit = 'maintenance.equipment' + + qr_code = fields.Binary("QR Code") + comp_serial_no = fields.Char("Inventory Serial No", tracking=True) + serial_no = fields.Char('Mfg. Serial Number', copy=False) + + def action_print_qrcode_layout(self): + action = self.env['ir.actions.act_window']._for_xml_id('aspl_equipment_qrcode_generator.action_open_label_layout_equipment') + action['context'] = {'default_equipment_ids': self.ids} + return action + + def generate_serial_no(self): + for equipment_id in self: + if not equipment_id.comp_serial_no: + company_id = equipment_id.company_id.id + sequence_id = self.env['ir.sequence'].search( + [('name', '=', 'Equipment Company Sequence'), ('company_id', '=', company_id)]) + if sequence_id: + data = sequence_id._next() + equipment_id.write({ + 'comp_serial_no': data + }) diff --git a/addons_extensions/aspl_equipment_qrcode_generator/models/res_company.py b/addons_extensions/aspl_equipment_qrcode_generator/models/res_company.py new file mode 100644 index 000000000..5d23f92da --- /dev/null +++ b/addons_extensions/aspl_equipment_qrcode_generator/models/res_company.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- + +from odoo import models, api + + +class ResCompany(models.Model): + _inherit = 'res.company' + + @api.model_create_multi + def create(self, vals): + result = super(ResCompany, self).create(vals) + sequence_id = self.env['ir.sequence'].search( + [('name', '=', 'Equipment Company Sequence'), ('company_id', '=', result.id)]) + if not sequence_id: + self.env['ir.sequence'].create({ + 'name': 'Equipment Company Sequence', + 'prefix': result.id, + 'padding': 5, + 'number_increment': 1, + 'company_id': result.id + }) + return result diff --git a/addons_extensions/aspl_equipment_qrcode_generator/report/__init__.py b/addons_extensions/aspl_equipment_qrcode_generator/report/__init__.py new file mode 100644 index 000000000..d46550c1b --- /dev/null +++ b/addons_extensions/aspl_equipment_qrcode_generator/report/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import custom_qrcode_generator diff --git a/addons_extensions/aspl_equipment_qrcode_generator/report/custom_qrcode.xml b/addons_extensions/aspl_equipment_qrcode_generator/report/custom_qrcode.xml new file mode 100644 index 000000000..bdb3f1ebd --- /dev/null +++ b/addons_extensions/aspl_equipment_qrcode_generator/report/custom_qrcode.xml @@ -0,0 +1,188 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + FTPROTECH - Asset Management Team + + + + + + + + + Asset Tag: + + + + Serial Number: + + + + Model Number: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A4 Label Sheet + + A4 + 0 + 0 + Portrait + 0 + 0 + 0 + 0 + + 96 + + + + Equipment QR-code (PDF) + maintenance.equipment + qweb-pdf + aspl_equipment_qrcode_generator.maintenance_quip + aspl_equipment_qrcode_generator.maintenance_quip + + 'Products Labels - %s' % (object.name) + + report + + + \ No newline at end of file diff --git a/addons_extensions/aspl_equipment_qrcode_generator/report/custom_qrcode_generator.py b/addons_extensions/aspl_equipment_qrcode_generator/report/custom_qrcode_generator.py new file mode 100644 index 000000000..3e83581fb --- /dev/null +++ b/addons_extensions/aspl_equipment_qrcode_generator/report/custom_qrcode_generator.py @@ -0,0 +1,86 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +import base64 +import math +from io import BytesIO + +import qrcode +from odoo import models + + +def generate_qr_code(value): + qr = qrcode.QRCode( + version=1, + error_correction=qrcode.constants.ERROR_CORRECT_L, + box_size=20, + border=4, + ) + qr.add_data(value) + qr.make(fit=True) + img = qr.make_image() + temp = BytesIO() + img.save(temp, format="PNG") + qr_img = base64.b64encode(temp.getvalue()) + return qr_img + + +def _prepare_data(env, data): + equipment_label_layout_id = env['equipment.label.layout'].browse(data['equipment_label_layout_id']) + equipment_dict = {} + equipment_ids = equipment_label_layout_id.equipment_ids + for equipment in equipment_ids: + if not equipment.name: + continue + equipment_dict[equipment] = 1 + combine_equipment_detail = "" + + # Generate Equipment Redirect LInk + url = env['ir.config_parameter'].sudo().get_param('web.base.url') + menuId = env.ref('maintenance.menu_equipment_form').sudo().id + actionId = env.ref('maintenance.hr_equipment_action').sudo().id + + equipment_link = url + '/web#id=' + str(equipment.id) + '&menu_id=' + str(menuId) + '&action=' + str( + actionId) + '&model=maintenance.equipment&view_type=form' + + # Prepare main Equipment Detail + main_equipment_detail = "" + main_equipment_detail = main_equipment_detail.join( + "Name: " + str(equipment.name) + "\n" + + "Model: " + str(equipment.model) + "\n" + + "Mfg serial no: " + str(equipment.serial_no) + "\n" + "Warranty Exp. Date: " +str(equipment.warranty_date) + "\n" + "Category: " +str(equipment.category_id.name)+ "\n" + "Contact No: "+str(equipment.technician_user_id.phone) +"\n" + "Contact Email: "+str(equipment.technician_user_id.login) + ) + # main_equipment_detail = equipment_link + '\n' + '\n' + main_equipment_detail + + # Prepare Child Equipment Detail + combine_equipment_detail = main_equipment_detail + + combine_equipment_detail += '\n' + '\n' + equipment_link + + # Generate Qr Code depends on Details + qr_image = generate_qr_code(combine_equipment_detail) + equipment.write({ + 'qr_code': qr_image + }) + env.cr.commit() + page_numbers = (len(equipment_ids) - 1) // (equipment_label_layout_id.rows * equipment_label_layout_id.columns) + 1 + + dict_equipment = { + 'rows': equipment_label_layout_id.rows, + 'columns': equipment_label_layout_id.columns, + 'page_numbers': page_numbers, + 'equipment_data': equipment_dict + } + return dict_equipment + + +class ReportProductTemplateLabel(models.AbstractModel): + _name = 'report.aspl_equipment_qrcode_generator.maintenance_quip' + _description = 'Equipment QR-code Report' + + def _get_report_values(self, docids, data): + return _prepare_data(self.env, data) diff --git a/addons_extensions/aspl_equipment_qrcode_generator/security/ir.model.access.csv b/addons_extensions/aspl_equipment_qrcode_generator/security/ir.model.access.csv new file mode 100644 index 000000000..c950bd953 --- /dev/null +++ b/addons_extensions/aspl_equipment_qrcode_generator/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_equipment_label_layout,access.equipment_label_layout,model_equipment_label_layout,,1,1,1,1 \ No newline at end of file diff --git a/addons_extensions/aspl_equipment_qrcode_generator/static/description/icon.png b/addons_extensions/aspl_equipment_qrcode_generator/static/description/icon.png new file mode 100644 index 000000000..8c9fe1923 Binary files /dev/null and b/addons_extensions/aspl_equipment_qrcode_generator/static/description/icon.png differ diff --git a/addons_extensions/aspl_equipment_qrcode_generator/views/maintenance_equipment.xml b/addons_extensions/aspl_equipment_qrcode_generator/views/maintenance_equipment.xml new file mode 100644 index 000000000..339680397 --- /dev/null +++ b/addons_extensions/aspl_equipment_qrcode_generator/views/maintenance_equipment.xml @@ -0,0 +1,56 @@ + + + + + maintenance.equipment.tree.inherit + maintenance.equipment + + + + + + + + + + + + + maintenance.equipment.form.inherit + maintenance.equipment + + + + + + + + + + + + + + + + + + + Generate Serial Number + + + list + code + action = records.generate_serial_no() + + + + Print QR-Code + + + form + code + action = records.action_print_qrcode_layout() + + + diff --git a/addons_extensions/aspl_equipment_qrcode_generator/wizard/__init__.py b/addons_extensions/aspl_equipment_qrcode_generator/wizard/__init__.py new file mode 100644 index 000000000..0ccb5a51f --- /dev/null +++ b/addons_extensions/aspl_equipment_qrcode_generator/wizard/__init__.py @@ -0,0 +1,3 @@ +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from . import equipment_label_layout diff --git a/addons_extensions/aspl_equipment_qrcode_generator/wizard/equipment_label_layout.py b/addons_extensions/aspl_equipment_qrcode_generator/wizard/equipment_label_layout.py new file mode 100644 index 000000000..71598c803 --- /dev/null +++ b/addons_extensions/aspl_equipment_qrcode_generator/wizard/equipment_label_layout.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import _, api, fields, models + + +class EquipmentLabelLayout(models.TransientModel): + _name = 'equipment.label.layout' + _description = 'Choose the sheet layout to print the labels' + + print_format = fields.Selection([ + ('2x5', '2 x 5'), + ('2x7', '2 x 7'), + ('4x7', '4 x 7')], string="Format", default='2x5', required=True) + equipment_ids = fields.Many2many('maintenance.equipment') + rows = fields.Integer(compute='_compute_dimensions') + columns = fields.Integer(compute='_compute_dimensions') + + @api.depends('print_format') + def _compute_dimensions(self): + for wizard in self: + if 'x' in wizard.print_format: + columns, rows = wizard.print_format.split('x')[:2] + wizard.columns = int(columns) + wizard.rows = int(rows) + else: + wizard.columns, wizard.rows = 1, 1 + + + def process_label(self): + xml_id = 'aspl_equipment_qrcode_generator.report_equipment_label' + data = { + 'equipment_label_layout_id':self.id + } + + return self.env.ref(xml_id).report_action(None, data=data) \ No newline at end of file diff --git a/addons_extensions/aspl_equipment_qrcode_generator/wizard/equipment_label_layout_views.xml b/addons_extensions/aspl_equipment_qrcode_generator/wizard/equipment_label_layout_views.xml new file mode 100644 index 000000000..9e7dc5ca2 --- /dev/null +++ b/addons_extensions/aspl_equipment_qrcode_generator/wizard/equipment_label_layout_views.xml @@ -0,0 +1,30 @@ + + + + equipment.label.layout.form + equipment.label.layout + primary + + + + + + + + + + + + + + Choose Labels Layout + equipment.label.layout + + new + +