You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							174 lines
						
					
					
						
							7.4 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							174 lines
						
					
					
						
							7.4 KiB
						
					
					
				| # -*- coding: utf-8 -*- | |
| ############################################################################### | |
| # | |
| #    Cybrosys Technologies Pvt. Ltd. | |
| # | |
| #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). | |
| #    Author: Jumana Haseen (odoo@cybrosys.com) | |
| # | |
| #    You can modify it under the terms of the GNU AFFERO | |
| #    GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. | |
| # | |
| #    You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE | |
| #    (AGPL v3) along with this program. | |
| #    If not, see <https://www.gnu.org/licenses/>. | |
| 
 | |
| ############################################################################### | |
| from io import BytesIO | |
| import binascii | |
| import pytz | |
| 
 | |
| from odoo import api, fields, models, _ | |
| from odoo.exceptions import UserError | |
| from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT | |
| 
 | |
| try: | |
|     import qrcode | |
| except ImportError: | |
|     qrcode = None | |
| try: | |
|     import base64 | |
| except ImportError: | |
|     base64 = None | |
| 
 | |
| 
 | |
| class AccountMove(models.Model): | |
|     """Class for adding new button and a page in account move""" | |
|     _inherit = 'account.move' | |
| 
 | |
|     qr = fields.Binary(string="QR Code", compute='generate_qrcode', store=True, | |
|                        help="QR code") | |
|     qr_button = fields.Boolean(string="Qr Button", compute="_compute_qr", | |
|                                help="Is QR button is enable or not") | |
|     qr_page = fields.Boolean(string="Qr Page", compute="_compute_qr", | |
|                              help="Is QR page is enable or not") | |
| 
 | |
|     @api.depends('qr_button') | |
|     def _compute_qr(self): | |
|         """Compute function for checking the value of a field in settings""" | |
|         for record in self: | |
|             qr_code = self.env['ir.config_parameter'].sudo().get_param( | |
|                 'advanced_vat_invoice.is_qr') | |
|             qr_code_generate_method = self.env[ | |
|                 'ir.config_parameter'].sudo().get_param( | |
|                 'advanced_vat_invoice.generate_qr') | |
|             record.qr_button = True if qr_code and qr_code_generate_method == 'manually' else False | |
|             record.qr_page = True if (qr_code and record.state in ['posted', | |
|                                                                    'cancelled'] | |
|                                       and qr_code_generate_method == 'manually' | |
|                                       or qr_code_generate_method == 'automatically') \ | |
|                 else False | |
| 
 | |
|     def timezone(self, userdate): | |
|         """Function to convert a user's date to their timezone.""" | |
|         tz_name = self.env.context.get('tz') or self.env.user.tz | |
|         contex_tz = pytz.timezone(tz_name) | |
|         date_time = pytz.utc.localize(userdate).astimezone(contex_tz) | |
|         return date_time.strftime(DEFAULT_SERVER_DATETIME_FORMAT) | |
| 
 | |
|     def string_hexa(self, value): | |
|         """Convert a string to a hexadecimal representation.""" | |
|         if value: | |
|             string = str(value) | |
|             string_bytes = string.encode("UTF-8") | |
|             encoded_hex_value = binascii.hexlify(string_bytes) | |
|             hex_value = encoded_hex_value.decode("UTF-8") | |
|             return hex_value | |
| 
 | |
|     def hexa(self, tag, length, value): | |
|         """Generate a hex value with tag, length, and value.""" | |
|         if tag and length and value: | |
|             hex_string = self.string_hexa(value) | |
|             length = int(len(hex_string) / 2) | |
|             conversion_table = ['0', '1', '2', '3', '4', '5', '6', '7', '8', | |
|                                 '9', 'a', 'b', 'c', 'd', 'e', 'f'] | |
|             hexadecimal = '' | |
|             while (length > 0): | |
|                 remainder = length % 16 | |
|                 hexadecimal = conversion_table[remainder] + hexadecimal | |
|                 length = length // 16 | |
|             if len(hexadecimal) == 1: | |
|                 hexadecimal = "0" + hexadecimal | |
|             return tag + hexadecimal + hex_string | |
| 
 | |
|     def qr_code_data(self): | |
|         """Generate QR code data for the current record.""" | |
|         seller_name = str(self.company_id.name) | |
|         seller_vat_no = self.company_id.vat or '' | |
|         seller_hex = self.hexa("01", "0c", seller_name) | |
|         vat_hex = self.hexa("02", "0f", seller_vat_no) or "" | |
|         time_stamp = self.timezone(self.create_date) | |
|         date_hex = self.hexa("03", "14", time_stamp) | |
|         amount_total = self.currency_id._convert( | |
|             self.amount_total, | |
|             self.env.ref('base.SAR'), | |
|             self.env.company, self.invoice_date or fields.Date.today()) | |
|         total_with_vat_hex = self.hexa("04", "0a", | |
|                                        str(round(amount_total, 2))) | |
|         amount_tax = self.currency_id._convert( | |
|             self.amount_tax, | |
|             self.env.ref('base.SAR'), | |
|             self.env.company, self.invoice_date or fields.Date.today()) | |
|         total_vat_hex = self.hexa("05", "09", | |
|                                   str(round(amount_tax, 2))) | |
|         qr_hex = (seller_hex + vat_hex + date_hex + total_with_vat_hex + | |
|                   total_vat_hex) | |
|         encoded_base64_bytes = base64.b64encode(bytes.fromhex(qr_hex)).decode() | |
|         return encoded_base64_bytes | |
| 
 | |
|     @api.depends('state') | |
|     def generate_qrcode(self): | |
|         """Generate and save QR code after the invoice is posted.""" | |
|         param = self.env['ir.config_parameter'].sudo() | |
|         qr_code = param.get_param('advanced_vat_invoice.generate_qr') | |
|         for rec in self: | |
|             if rec.state == 'posted': | |
|                 if qrcode and base64: | |
|                     if qr_code == 'automatically': | |
|                         qr = qrcode.QRCode( | |
|                             version=4, | |
|                             error_correction=qrcode.constants.ERROR_CORRECT_L, | |
|                             box_size=4, | |
|                             border=1, | |
|                         ) | |
|                         qr.add_data(self._origin.qr_code_data()) | |
|                         qr.make(fit=True) | |
|                         img = qr.make_image() | |
|                         temp = BytesIO() | |
|                         img.save(temp, format="PNG") | |
|                         qr_image = base64.b64encode(temp.getvalue()) | |
|                         rec.qr = qr_image | |
|                 else: | |
|                     raise UserError( | |
|                         _('Necessary Requirements To Run This Operation Is ' | |
|                           'Not Satisfied')) | |
| 
 | |
|     def generate_qr_button(self): | |
|         """Manually generate and save QR code.""" | |
|         param = self.env['ir.config_parameter'].sudo() | |
|         qr_code = param.get_param('advanced_vat_invoice.generate_qr') | |
|         for rec in self: | |
|             if qrcode and base64: | |
|                 if qr_code == 'manually': | |
|                     qr = qrcode.QRCode( | |
|                         version=4, | |
|                         error_correction=qrcode.constants.ERROR_CORRECT_L, | |
|                         box_size=4, | |
|                         border=1, | |
|                     ) | |
|                     qr.add_data(self.qr_code_data()) | |
|                     qr.make(fit=True) | |
|                     img = qr.make_image() | |
|                     temp = BytesIO() | |
|                     img.save(temp, format="PNG") | |
|                     qr_image = base64.b64encode(temp.getvalue()) | |
|                     rec.qr = qr_image | |
|             else: | |
|                 raise UserError( | |
|                     _('Necessary Requirements To Run This Operation Is ' | |
|                       'Not Satisfied'))
 | |
| 
 |