2021-09-14 09:45:23 +00:00
|
|
|
import io
|
|
|
|
import os
|
2021-11-24 01:54:43 +00:00
|
|
|
from base64 import b64encode
|
2021-09-14 09:45:23 +00:00
|
|
|
|
2021-09-16 20:14:41 +00:00
|
|
|
import frappe
|
2021-11-24 01:54:43 +00:00
|
|
|
from frappe import _
|
2021-12-07 06:41:43 +00:00
|
|
|
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
|
2021-11-24 01:54:43 +00:00
|
|
|
from frappe.utils.data import add_to_date, get_time, getdate
|
2021-12-07 12:59:16 +00:00
|
|
|
from pyqrcode import create as qr_create
|
2021-09-16 20:14:41 +00:00
|
|
|
|
|
|
|
from erpnext import get_region
|
|
|
|
|
2021-09-14 09:45:23 +00:00
|
|
|
|
2021-12-07 06:45:58 +00:00
|
|
|
def create_qr_code(doc, method=None):
|
2021-09-14 09:45:23 +00:00
|
|
|
region = get_region(doc.company)
|
2022-03-28 13:22:46 +00:00
|
|
|
if region not in ["Saudi Arabia"]:
|
2021-09-14 09:45:23 +00:00
|
|
|
return
|
|
|
|
|
2021-12-07 06:41:43 +00:00
|
|
|
# if QR Code field not present, create it. Invoices without QR are invalid as per law.
|
2022-03-28 13:22:46 +00:00
|
|
|
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,
|
|
|
|
)
|
|
|
|
]
|
|
|
|
}
|
|
|
|
)
|
2021-09-14 09:45:23 +00:00
|
|
|
|
|
|
|
# Don't create QR Code if it already exists
|
2021-12-07 06:41:43 +00:00
|
|
|
qr_code = doc.get("ksa_einv_qr")
|
2021-09-14 09:45:23 +00:00
|
|
|
if qr_code and frappe.db.exists({"doctype": "File", "file_url": qr_code}):
|
|
|
|
return
|
|
|
|
|
2021-12-07 06:41:43 +00:00
|
|
|
meta = frappe.get_meta(doc.doctype)
|
|
|
|
|
|
|
|
if "ksa_einv_qr" in [d.fieldname for d in meta.get_image_fields()]:
|
2022-03-28 13:22:46 +00:00
|
|
|
"""TLV conversion for
|
2021-12-07 06:41:43 +00:00
|
|
|
1. Seller's Name
|
|
|
|
2. VAT Number
|
|
|
|
3. Time Stamp
|
|
|
|
4. Invoice Amount
|
|
|
|
5. VAT Amount
|
2022-03-28 13:22:46 +00:00
|
|
|
"""
|
2021-12-07 06:41:43 +00:00
|
|
|
tlv_array = []
|
|
|
|
# Sellers Name
|
|
|
|
|
2022-03-28 13:22:46 +00:00
|
|
|
seller_name = frappe.db.get_value("Company", doc.company, "company_name_in_arabic")
|
2021-12-07 06:41:43 +00:00
|
|
|
|
|
|
|
if not seller_name:
|
2022-03-28 13:22:46 +00:00
|
|
|
frappe.throw(_("Arabic name missing for {} in the company document").format(doc.company))
|
2021-12-07 06:41:43 +00:00
|
|
|
|
|
|
|
tag = bytes([1]).hex()
|
2022-03-28 13:22:46 +00:00
|
|
|
length = bytes([len(seller_name.encode("utf-8"))]).hex()
|
|
|
|
value = seller_name.encode("utf-8").hex()
|
|
|
|
tlv_array.append("".join([tag, length, value]))
|
2021-12-07 06:41:43 +00:00
|
|
|
|
|
|
|
# VAT Number
|
2022-03-28 13:22:46 +00:00
|
|
|
tax_id = frappe.db.get_value("Company", doc.company, "tax_id")
|
2021-12-07 06:41:43 +00:00
|
|
|
if not tax_id:
|
2022-03-28 13:22:46 +00:00
|
|
|
frappe.throw(_("Tax ID missing for {} in the company document").format(doc.company))
|
2021-12-07 06:41:43 +00:00
|
|
|
|
|
|
|
tag = bytes([2]).hex()
|
|
|
|
length = bytes([len(tax_id)]).hex()
|
2022-03-28 13:22:46 +00:00
|
|
|
value = tax_id.encode("utf-8").hex()
|
|
|
|
tlv_array.append("".join([tag, length, value]))
|
2021-12-07 06:41:43 +00:00
|
|
|
|
|
|
|
# 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)
|
2022-03-28 13:22:46 +00:00
|
|
|
time_stamp = time_stamp.strftime("%Y-%m-%dT%H:%M:%SZ")
|
2021-12-07 06:41:43 +00:00
|
|
|
|
|
|
|
tag = bytes([3]).hex()
|
|
|
|
length = bytes([len(time_stamp)]).hex()
|
2022-03-28 13:22:46 +00:00
|
|
|
value = time_stamp.encode("utf-8").hex()
|
|
|
|
tlv_array.append("".join([tag, length, value]))
|
2021-12-07 06:41:43 +00:00
|
|
|
|
|
|
|
# Invoice Amount
|
2022-09-05 06:15:43 +00:00
|
|
|
invoice_amount = str(doc.base_grand_total)
|
2021-12-07 06:41:43 +00:00
|
|
|
tag = bytes([4]).hex()
|
|
|
|
length = bytes([len(invoice_amount)]).hex()
|
2022-03-28 13:22:46 +00:00
|
|
|
value = invoice_amount.encode("utf-8").hex()
|
|
|
|
tlv_array.append("".join([tag, length, value]))
|
2021-12-07 06:41:43 +00:00
|
|
|
|
|
|
|
# VAT Amount
|
2022-03-14 10:43:35 +00:00
|
|
|
vat_amount = str(get_vat_amount(doc))
|
2021-12-07 06:41:43 +00:00
|
|
|
|
|
|
|
tag = bytes([5]).hex()
|
|
|
|
length = bytes([len(vat_amount)]).hex()
|
2022-03-28 13:22:46 +00:00
|
|
|
value = vat_amount.encode("utf-8").hex()
|
|
|
|
tlv_array.append("".join([tag, length, value]))
|
2021-12-07 06:41:43 +00:00
|
|
|
|
|
|
|
# Joining bytes into one
|
2022-03-28 13:22:46 +00:00
|
|
|
tlv_buff = "".join(tlv_array)
|
2021-12-07 06:41:43 +00:00
|
|
|
|
|
|
|
# base64 conversion for QR Code
|
|
|
|
base64_string = b64encode(bytes.fromhex(tlv_buff)).decode()
|
|
|
|
|
|
|
|
qr_image = io.BytesIO()
|
2022-03-28 13:22:46 +00:00
|
|
|
url = qr_create(base64_string, error="L")
|
2021-12-07 06:41:43 +00:00
|
|
|
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, "__")
|
2022-03-28 13:22:46 +00:00
|
|
|
_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",
|
|
|
|
}
|
|
|
|
)
|
2021-12-07 06:41:43 +00:00
|
|
|
|
|
|
|
_file.save()
|
|
|
|
|
|
|
|
# assigning to document
|
2022-03-28 13:22:46 +00:00
|
|
|
doc.db_set("ksa_einv_qr", _file.file_url)
|
2021-12-07 06:41:43 +00:00
|
|
|
doc.notify_update()
|
|
|
|
|
2022-03-28 13:22:46 +00:00
|
|
|
|
2022-03-14 10:43:35 +00:00
|
|
|
def get_vat_amount(doc):
|
2022-03-28 13:22:46 +00:00
|
|
|
vat_settings = frappe.db.get_value("KSA VAT Setting", {"company": doc.company})
|
2022-03-14 10:43:35 +00:00
|
|
|
vat_accounts = []
|
2022-03-14 10:57:04 +00:00
|
|
|
vat_amount = 0
|
2022-03-14 10:43:35 +00:00
|
|
|
|
|
|
|
if vat_settings:
|
2022-03-28 13:22:46 +00:00
|
|
|
vat_settings_doc = frappe.get_cached_doc("KSA VAT Setting", vat_settings)
|
2022-03-14 10:43:35 +00:00
|
|
|
|
2022-03-28 13:22:46 +00:00
|
|
|
for row in vat_settings_doc.get("ksa_vat_sales_accounts"):
|
2022-03-14 10:43:35 +00:00
|
|
|
vat_accounts.append(row.account)
|
|
|
|
|
2022-03-28 13:22:46 +00:00
|
|
|
for tax in doc.get("taxes"):
|
2022-03-14 10:43:35 +00:00
|
|
|
if tax.account_head in vat_accounts:
|
2022-09-05 06:15:43 +00:00
|
|
|
vat_amount += tax.base_tax_amount
|
2022-03-14 10:43:35 +00:00
|
|
|
|
|
|
|
return vat_amount
|
2021-12-07 06:41:43 +00:00
|
|
|
|
2022-03-28 13:22:46 +00:00
|
|
|
|
2021-12-07 06:41:43 +00:00
|
|
|
def delete_qr_code_file(doc, method=None):
|
2021-09-14 09:45:23 +00:00
|
|
|
region = get_region(doc.company)
|
2022-03-28 13:22:46 +00:00
|
|
|
if region not in ["Saudi Arabia"]:
|
2021-09-14 09:45:23 +00:00
|
|
|
return
|
|
|
|
|
2022-03-28 13:22:46 +00:00
|
|
|
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")})
|
2021-09-14 09:45:23 +00:00
|
|
|
if len(file_doc):
|
2022-03-28 13:22:46 +00:00
|
|
|
frappe.delete_doc("File", file_doc[0].name)
|
|
|
|
|
2021-11-22 08:51:53 +00:00
|
|
|
|
2021-12-08 02:33:30 +00:00
|
|
|
def delete_vat_settings_for_company(doc, method=None):
|
2022-03-28 13:22:46 +00:00
|
|
|
if doc.country != "Saudi Arabia":
|
2021-11-22 08:51:53 +00:00
|
|
|
return
|
|
|
|
|
2022-03-28 13:22:46 +00:00
|
|
|
if frappe.db.exists("KSA VAT Setting", doc.name):
|
|
|
|
frappe.delete_doc("KSA VAT Setting", doc.name)
|