| import io |
| import os |
| from base64 import b64encode |
| |
| import frappe |
| from frappe import _ |
| from frappe.custom.doctype.custom_field.custom_field import create_custom_fields |
| from frappe.utils.data import add_to_date, get_time, getdate |
| from pyqrcode import create as qr_create |
| |
| from erpnext import get_region |
| |
| |
| def create_qr_code(doc, method=None): |
| region = get_region(doc.company) |
| if region not in ['Saudi Arabia']: |
| return |
| |
| # if QR Code field not present, create it. Invoices without QR are invalid as per law. |
| if not hasattr(doc, 'ksa_einv_qr'): |
| create_custom_fields({ |
| doc.doctype: [ |
| dict( |
| fieldname='ksa_einv_qr', |
| label='KSA E-Invoicing QR', |
| fieldtype='Attach Image', |
| read_only=1, no_copy=1, hidden=1 |
| ) |
| ] |
| }) |
| |
| # Don't create QR Code if it already exists |
| qr_code = doc.get("ksa_einv_qr") |
| if qr_code and frappe.db.exists({"doctype": "File", "file_url": qr_code}): |
| return |
| |
| meta = frappe.get_meta(doc.doctype) |
| |
| if "ksa_einv_qr" in [d.fieldname for d in meta.get_image_fields()]: |
| ''' 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.grand_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(get_vat_amount(doc)) |
| |
| 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() |
| |
| qr_image = io.BytesIO() |
| url = qr_create(base64_string, error='L') |
| url.png(qr_image, scale=2, quiet_zone=1) |
| |
| name = frappe.generate_hash(doc.name, 5) |
| |
| # making file |
| filename = f"QRCode-{name}.png".replace(os.path.sep, "__") |
| _file = frappe.get_doc({ |
| "doctype": "File", |
| "file_name": filename, |
| "is_private": 0, |
| "content": qr_image.getvalue(), |
| "attached_to_doctype": doc.get("doctype"), |
| "attached_to_name": doc.get("name"), |
| "attached_to_field": "ksa_einv_qr" |
| }) |
| |
| _file.save() |
| |
| # assigning to document |
| doc.db_set('ksa_einv_qr', _file.file_url) |
| doc.notify_update() |
| |
| def get_vat_amount(doc): |
| vat_settings = frappe.db.get_value('KSA VAT Setting', {'company': doc.company}) |
| vat_accounts = [] |
| vat_amount = 0 |
| |
| if vat_settings: |
| vat_settings_doc = frappe.get_cached_doc('KSA VAT Setting', vat_settings) |
| |
| for row in vat_settings_doc.get('ksa_vat_sales_accounts'): |
| vat_accounts.append(row.account) |
| |
| for tax in doc.get('taxes'): |
| if tax.account_head in vat_accounts: |
| vat_amount += tax.tax_amount |
| |
| return vat_amount |
| |
| def delete_qr_code_file(doc, method=None): |
| region = get_region(doc.company) |
| if region not in ['Saudi Arabia']: |
| return |
| |
| if hasattr(doc, 'ksa_einv_qr'): |
| if doc.get('ksa_einv_qr'): |
| file_doc = frappe.get_list('File', { |
| 'file_url': doc.get('ksa_einv_qr') |
| }) |
| if len(file_doc): |
| frappe.delete_doc('File', file_doc[0].name) |
| |
| def delete_vat_settings_for_company(doc, method=None): |
| if doc.country != 'Saudi Arabia': |
| return |
| |
| if frappe.db.exists('KSA VAT Setting', doc.name): |
| frappe.delete_doc('KSA VAT Setting', doc.name) |