Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(KSA VAT): QR Code as per ZATKA specification #28534

Closed
wants to merge 3 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 69 additions & 16 deletions erpnext/regional/saudi_arabia/utils.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import io
import os
from base64 import b64encode

import frappe
from frappe import _
from frappe.utils.data import add_to_date, get_time, getdate
from pyqrcode import create as qr_create

from erpnext import get_region
Expand All @@ -28,24 +31,74 @@ def create_qr_code(doc, method):

for field in meta.get_image_fields():
if field.fieldname == 'qr_code':
from urllib.parse import urlencode
''' TLV conversion for
1. Seller's Name
2. VAT Number
3. Time Stamp
4. Invoice Amount
5. VAT Amount
'''
tlv_array = []
# Sellers Name

seller_name = frappe.db.get_value(
'Company',
doc.company,
'company_name_in_arabic')

if not seller_name:
frappe.throw(_('Arabic name missing for {} in the company document'.format(doc.company)))

tag = bytes([1]).hex()
length = bytes([len(seller_name.encode('utf-8'))]).hex()
value = seller_name.encode('utf-8').hex()
tlv_array.append(''.join([tag, length, value]))

# VAT Number
tax_id = frappe.db.get_value('Company', doc.company, 'tax_id')
if not tax_id:
frappe.throw(_('Tax ID missing for {} in the company document'.format(doc.company)))

tag = bytes([2]).hex()
length = bytes([len(tax_id)]).hex()
value = tax_id.encode('utf-8').hex()
tlv_array.append(''.join([tag, length, value]))

# Time Stamp
posting_date = getdate(doc.posting_date)
time = get_time(doc.posting_time)
seconds = time.hour * 60 * 60 + time.minute * 60 + time.second
time_stamp = add_to_date(posting_date, seconds=seconds)
time_stamp = time_stamp.strftime('%Y-%m-%dT%H:%M:%SZ')

tag = bytes([3]).hex()
length = bytes([len(time_stamp)]).hex()
value = time_stamp.encode('utf-8').hex()
tlv_array.append(''.join([tag, length, value]))

# Invoice Amount
invoice_amount = str(doc.total)
tag = bytes([4]).hex()
length = bytes([len(invoice_amount)]).hex()
value = invoice_amount.encode('utf-8').hex()
tlv_array.append(''.join([tag, length, value]))

# VAT Amount
vat_amount = str(doc.total_taxes_and_charges)

tag = bytes([5]).hex()
length = bytes([len(vat_amount)]).hex()
value = vat_amount.encode('utf-8').hex()
tlv_array.append(''.join([tag, length, value]))

# Joining bytes into one
tlv_buff = ''.join(tlv_array)

# base64 conversion for QR Code
base64_string = b64encode(bytes.fromhex(tlv_buff)).decode()

# Creating public url to print format
default_print_format = frappe.db.get_value('Property Setter', dict(property='default_print_format', doc_type=doc.doctype), "value")

# System Language
language = frappe.get_system_settings('language')

params = urlencode({
'format': default_print_format or 'Standard',
'_lang': language,
'key': doc.get_signature()
})

# creating qr code for the url
url = f"{ frappe.utils.get_url() }/{ doc.doctype }/{ doc.name }?{ params }"
qr_image = io.BytesIO()
url = qr_create(url, error='L')
url = qr_create(base64_string, error='L')
url.png(qr_image, scale=2, quiet_zone=1)

# making file
Expand Down