qr on equipment
This commit is contained in:
parent
c3883f6a18
commit
7122e23e60
|
|
@ -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
|
||||
})
|
||||
|
|
@ -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,
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import maintenance_equipment
|
||||
from . import res_company
|
||||
|
|
@ -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
|
||||
})
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import custom_qrcode_generator
|
||||
|
|
@ -0,0 +1,188 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<template id="report_equipment_simple_label2x7">
|
||||
<t t-set="qrcode_size" t-value="'height:14mm'"/>
|
||||
<t t-set="table_style" t-value="'width:97mm;height:37.1mm;margin:inherit;' + table_style"/>
|
||||
<td t-att-style="make_invisible and 'visibility:hidden;'" >
|
||||
<div class="o_label_full" t-att-style="table_style">
|
||||
<div class="o_label_name">
|
||||
<strong t-field="equipment.name"/>
|
||||
</div>
|
||||
<div class="o_label_data">
|
||||
<div class="text-center o_label_right_column">
|
||||
<t t-if="equipment.qr_code">
|
||||
<div t-field="equipment.qr_code" t-options="{'widget': 'image'}" style="width: 130px;margin-top: -40px;"/>
|
||||
</t>
|
||||
</div>
|
||||
<div class="text-left" style="line-height:normal;word-wrap: break-word;">
|
||||
<span class="text-nowrap" t-field="equipment.serial_no"/>
|
||||
<div class="o_label_extra_data">
|
||||
<span t-field="equipment.comp_serial_no"/>
|
||||
</div>
|
||||
<t t-if="equipment.warranty_date">
|
||||
<strong t-field="equipment.warranty_date"/>
|
||||
</t>
|
||||
</div>
|
||||
<div class="o_label_clear"></div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</template>
|
||||
|
||||
<template id="report_equipment_simple_label4x7">
|
||||
<t t-set="barcode_size" t-value="'width:80px;'"/>
|
||||
<t t-set="table_style" t-value="'width:47mm;height:37.1mm;margin:inherit;' + table_style"/>
|
||||
<td t-att-style="make_invisible and 'visibility:hidden;'" >
|
||||
<div class="o_label_full" t-att-style="table_style">
|
||||
<div class="o_label_name">
|
||||
<strong t-field="equipment.name"/>
|
||||
</div>
|
||||
<div class= "text-center o_label_right_column">
|
||||
<t t-if="equipment.qr_code">
|
||||
<div t-field="equipment.qr_code" t-options="{'widget': 'image'}" style="width:95px;padding:0px;margin-top:-10px"/>
|
||||
</t>
|
||||
</div>
|
||||
<div class="text-left o_label_left_column" style="line-height:normal;word-wrap: break-word;">
|
||||
<div class="o_label_data">
|
||||
<strong t-field="equipment.serial_no"/>
|
||||
<span t-field="equipment.comp_serial_no"/>
|
||||
<t t-if="equipment.warranty_date">
|
||||
<strong t-field="equipment.warranty_date"/>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</template>
|
||||
|
||||
<template id="report_equipment_simple_label2x5">
|
||||
<div class="d-flex flex-column" style="
|
||||
width: 87mm;
|
||||
height:40mm;
|
||||
border: 1.5px solid black;
|
||||
border-radius: 6px;
|
||||
padding: 6px;
|
||||
font-family: Arial, Roboto, sans-serif;
|
||||
font-size: 11px;
|
||||
margin-bottom: 15px;
|
||||
">
|
||||
|
||||
<!-- Header -->
|
||||
<div class="text-center fw-bold" style="
|
||||
font-size: 15px;
|
||||
border-bottom: 1px solid #ccc;
|
||||
padding-bottom: 4px;
|
||||
white-space: nowrap;
|
||||
">
|
||||
FTPROTECH - Asset Management Team
|
||||
</div>
|
||||
|
||||
<!-- Main Content -->
|
||||
<div class="d-flex" style="flex: 1; padding-top: 6px;">
|
||||
|
||||
<!-- Left Column -->
|
||||
<div class="flex-grow-1 pe-2" style="white-space: nowrap;">
|
||||
<div class="d-flex">
|
||||
<div class="fw-bold" style="width: 40%;">Asset Tag:</div>
|
||||
<div style="width: 60%; overflow: visible;"><t style="padding-left:5px;" t-esc="equipment.name"/></div>
|
||||
</div>
|
||||
<div class="d-flex">
|
||||
<div class="fw-bold" style="width: 40%;">Serial Number:</div>
|
||||
<div style="width: 60%; overflow: visible;"><t style="padding-left:5px;" t-esc="equipment.serial_no"/></div>
|
||||
</div>
|
||||
<div class="d-flex">
|
||||
<div class="fw-bold" style="width: 40%;">Model Number:</div>
|
||||
<div style="width: 60%; overflow: visible;"><t style="padding-left:5px;" t-esc="equipment.model"/></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Right Column - QR Code -->
|
||||
<div class="d-flex justify-content-end align-items-center" style="width: 30%;">
|
||||
<t t-if="equipment.name">
|
||||
<div t-field="equipment.qr_code"
|
||||
t-options="{'widget': 'image'}"
|
||||
style="width: 90px; height: 90px; display: inline-block;">
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template id="report_quipmentlabel">
|
||||
<t t-call="web.html_container">
|
||||
<t t-if="columns and rows">
|
||||
<t t-if="columns == 2 and rows == 7">
|
||||
<t t-set="padding_page" t-value="'padding: 14mm 3mm'"/>
|
||||
<t t-set="report_to_call" t-value="'aspl_equipment_qrcode_generator.report_equipment_simple_label2x7'"/>
|
||||
</t>
|
||||
<t t-if="columns == 4 and rows == 7">
|
||||
<t t-set="padding_page" t-value="'padding: 14mm 3mm'"/>
|
||||
<t t-set="report_to_call" t-value="'aspl_equipment_qrcode_generator.report_equipment_simple_label4x7'"/>
|
||||
</t>
|
||||
<t t-if="columns == 2 and rows == 5">
|
||||
<t t-set="padding_page" t-value="'padding: 14mm 3mm'"/>
|
||||
<t t-set="report_to_call" t-value="'aspl_equipment_qrcode_generator.report_equipment_simple_label2x5'"/>
|
||||
</t>
|
||||
<t t-foreach="range(page_numbers)" t-as="page">
|
||||
<div class="o_label_sheet" t-att-style="padding_page">
|
||||
<table class="my-0 table table-sm table-borderless" style="border-spacing: 5mm 3mm;">
|
||||
<t t-foreach="range(rows)" t-as="row">
|
||||
<tr>
|
||||
<t t-foreach="range(columns)" t-as="column">
|
||||
<t t-if="equipment_data">
|
||||
<t t-set="current_data" t-value="equipment_data.popitem()"/>
|
||||
<t t-set="equipment" t-value="current_data[0]"/>
|
||||
<t t-set="table_style" t-value="'border: 1px solid black;'"/>
|
||||
<t t-call="{{report_to_call}}"/>
|
||||
</t>
|
||||
</t>
|
||||
</tr>
|
||||
</t>
|
||||
</table>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<template id="maintenance_quip">
|
||||
<t t-call="web.basic_layout">
|
||||
<div class="page">
|
||||
<t t-call="aspl_equipment_qrcode_generator.report_quipmentlabel">
|
||||
<t t-set="products" t-value="products"/>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<record id="paperformat_label_sheet_qrcode" model="report.paperformat">
|
||||
<field name="name">A4 Label Sheet</field>
|
||||
<field name="default" eval="True"/>
|
||||
<field name="format">A4</field>
|
||||
<field name="page_height">0</field>
|
||||
<field name="page_width">0</field>
|
||||
<field name="orientation">Portrait</field>
|
||||
<field name="margin_top">0</field>
|
||||
<field name="margin_bottom">0</field>
|
||||
<field name="margin_left">0</field>
|
||||
<field name="margin_right">0</field>
|
||||
<field name="disable_shrinking" eval="True"/>
|
||||
<field name="dpi">96</field>
|
||||
</record>
|
||||
|
||||
<record id="report_equipment_label" model="ir.actions.report">
|
||||
<field name="name">Equipment QR-code (PDF)</field>
|
||||
<field name="model">maintenance.equipment</field>
|
||||
<field name="report_type">qweb-pdf</field>
|
||||
<field name="report_name">aspl_equipment_qrcode_generator.maintenance_quip</field>
|
||||
<field name="report_file">aspl_equipment_qrcode_generator.maintenance_quip</field>
|
||||
<field name="paperformat_id" ref="aspl_equipment_qrcode_generator.paperformat_label_sheet_qrcode"/>
|
||||
<field name="print_report_name">'Products Labels - %s' % (object.name)</field>
|
||||
<field name="binding_model_id" eval="False"/>
|
||||
<field name="binding_type">report</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
|
|
@ -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)
|
||||
|
|
@ -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
|
||||
|
Binary file not shown.
|
After Width: | Height: | Size: 9.2 KiB |
|
|
@ -0,0 +1,56 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<record id="view_extend_equipment_tree" model="ir.ui.view">
|
||||
<field name="name">maintenance.equipment.tree.inherit</field>
|
||||
<field name="model">maintenance.equipment</field>
|
||||
<field name="priority" eval="16"/>
|
||||
<field name="inherit_id" ref="maintenance.hr_equipment_view_tree"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//list" position="inside">
|
||||
<header>
|
||||
<button string="Print QR-code" type="object" name="action_print_qrcode_layout"/>
|
||||
</header>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_extend_equipment_form" model="ir.ui.view">
|
||||
<field name="name">maintenance.equipment.form.inherit</field>
|
||||
<field name="model">maintenance.equipment</field>
|
||||
<field name="priority" eval="16"/>
|
||||
<field name="inherit_id" ref="maintenance.hr_equipment_view_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//page[@name='product_information']" position="inside">
|
||||
<group>
|
||||
<field name="comp_serial_no"/>
|
||||
</group>
|
||||
</xpath>
|
||||
<xpath expr="//sheet" position="before">
|
||||
<header>
|
||||
<button string="Generate Serial Number" type="object" name="generate_serial_no" class="oe_highlight"/>
|
||||
</header>
|
||||
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="generate_serial_no_action" model="ir.actions.server">
|
||||
<field name="name">Generate Serial Number</field>
|
||||
<field name="model_id" ref="model_maintenance_equipment"/>
|
||||
<field name="binding_model_id" ref="model_maintenance_equipment"/>
|
||||
<field name="binding_view_types">list</field>
|
||||
<field name="state">code</field>
|
||||
<field name="code">action = records.generate_serial_no()</field>
|
||||
</record>
|
||||
|
||||
<record id="generate_qrcode_no_action" model="ir.actions.server">
|
||||
<field name="name">Print QR-Code</field>
|
||||
<field name="model_id" ref="model_maintenance_equipment"/>
|
||||
<field name="binding_model_id" ref="model_maintenance_equipment"/>
|
||||
<field name="binding_view_types">form</field>
|
||||
<field name="state">code</field>
|
||||
<field name="code">action = records.action_print_qrcode_layout()</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import equipment_label_layout
|
||||
|
|
@ -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)
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="equipment_label_layout_form" model="ir.ui.view">
|
||||
<field name="name">equipment.label.layout.form</field>
|
||||
<field name="model">equipment.label.layout</field>
|
||||
<field name="mode">primary</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<group>
|
||||
<group>
|
||||
<field name="print_format" widget="radio"/>
|
||||
</group>
|
||||
</group>
|
||||
<footer>
|
||||
<button name="process_label" string="Confirm" type="object" class="btn-primary"/>
|
||||
<button string="Discard" class="btn-secondary" special="cancel"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_open_label_layout_equipment" model="ir.actions.act_window">
|
||||
<field name="name">Choose Labels Layout</field>
|
||||
<field name="res_model">equipment.label.layout</field>
|
||||
<field name="view_ids"
|
||||
eval="[(5, 0, 0),
|
||||
(0, 0, {'view_mode': 'form', 'view_id': ref('equipment_label_layout_form')})]" />
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
</odoo>
|
||||
Loading…
Reference in New Issue