blob: b47adc95f723fa81beff4638ef66acf8a6a8dbdd [file] [log] [blame]
Ahmad8a425702021-09-14 14:45:23 +05001import io
2import os
Ahmadd1746ca2021-11-24 02:54:43 +01003from base64 import b64encode
Ahmad8a425702021-09-14 14:45:23 +05004
Ahmad940db712021-09-17 01:14:41 +05005import frappe
Ahmadd1746ca2021-11-24 02:54:43 +01006from frappe import _
Dany Robert276bf732021-12-07 12:11:43 +05307from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
Ahmadd1746ca2021-11-24 02:54:43 +01008from frappe.utils.data import add_to_date, get_time, getdate
Dany Robert45fce5a2021-12-07 18:29:16 +05309from pyqrcode import create as qr_create
Ahmad940db712021-09-17 01:14:41 +050010
11from erpnext import get_region
12
Ahmad8a425702021-09-14 14:45:23 +050013
Dany Robertebd41792021-12-07 12:15:58 +053014def create_qr_code(doc, method=None):
Ahmad8a425702021-09-14 14:45:23 +050015 region = get_region(doc.company)
Ankush Menat494bd9e2022-03-28 18:52:46 +053016 if region not in ["Saudi Arabia"]:
Ahmad8a425702021-09-14 14:45:23 +050017 return
18
Dany Robert276bf732021-12-07 12:11:43 +053019 # if QR Code field not present, create it. Invoices without QR are invalid as per law.
Ankush Menat494bd9e2022-03-28 18:52:46 +053020 if not hasattr(doc, "ksa_einv_qr"):
21 create_custom_fields(
22 {
23 doc.doctype: [
24 dict(
25 fieldname="ksa_einv_qr",
26 label="KSA E-Invoicing QR",
27 fieldtype="Attach Image",
28 read_only=1,
29 no_copy=1,
30 hidden=1,
31 )
32 ]
33 }
34 )
Ahmad8a425702021-09-14 14:45:23 +050035
36 # Don't create QR Code if it already exists
Dany Robert276bf732021-12-07 12:11:43 +053037 qr_code = doc.get("ksa_einv_qr")
Ahmad8a425702021-09-14 14:45:23 +050038 if qr_code and frappe.db.exists({"doctype": "File", "file_url": qr_code}):
39 return
40
Dany Robert276bf732021-12-07 12:11:43 +053041 meta = frappe.get_meta(doc.doctype)
Ahmad940db712021-09-17 01:14:41 +050042
Dany Robert276bf732021-12-07 12:11:43 +053043 if "ksa_einv_qr" in [d.fieldname for d in meta.get_image_fields()]:
Ankush Menat494bd9e2022-03-28 18:52:46 +053044 """TLV conversion for
Dany Robert276bf732021-12-07 12:11:43 +053045 1. Seller's Name
46 2. VAT Number
47 3. Time Stamp
48 4. Invoice Amount
49 5. VAT Amount
Ankush Menat494bd9e2022-03-28 18:52:46 +053050 """
Dany Robert276bf732021-12-07 12:11:43 +053051 tlv_array = []
52 # Sellers Name
Saqib Ansariac273912021-11-20 11:22:19 +053053
Ankush Menat494bd9e2022-03-28 18:52:46 +053054 seller_name = frappe.db.get_value("Company", doc.company, "company_name_in_arabic")
Ahmad940db712021-09-17 01:14:41 +050055
Dany Robert276bf732021-12-07 12:11:43 +053056 if not seller_name:
Ankush Menat494bd9e2022-03-28 18:52:46 +053057 frappe.throw(_("Arabic name missing for {} in the company document").format(doc.company))
Ahmad940db712021-09-17 01:14:41 +050058
Dany Robert276bf732021-12-07 12:11:43 +053059 tag = bytes([1]).hex()
Ankush Menat494bd9e2022-03-28 18:52:46 +053060 length = bytes([len(seller_name.encode("utf-8"))]).hex()
61 value = seller_name.encode("utf-8").hex()
62 tlv_array.append("".join([tag, length, value]))
Saqib Ansariac273912021-11-20 11:22:19 +053063
Dany Robert276bf732021-12-07 12:11:43 +053064 # VAT Number
Ankush Menat494bd9e2022-03-28 18:52:46 +053065 tax_id = frappe.db.get_value("Company", doc.company, "tax_id")
Dany Robert276bf732021-12-07 12:11:43 +053066 if not tax_id:
Ankush Menat494bd9e2022-03-28 18:52:46 +053067 frappe.throw(_("Tax ID missing for {} in the company document").format(doc.company))
Ahmadd1746ca2021-11-24 02:54:43 +010068
Dany Robert276bf732021-12-07 12:11:43 +053069 tag = bytes([2]).hex()
70 length = bytes([len(tax_id)]).hex()
Ankush Menat494bd9e2022-03-28 18:52:46 +053071 value = tax_id.encode("utf-8").hex()
72 tlv_array.append("".join([tag, length, value]))
Ahmadd1746ca2021-11-24 02:54:43 +010073
Dany Robert276bf732021-12-07 12:11:43 +053074 # Time Stamp
75 posting_date = getdate(doc.posting_date)
76 time = get_time(doc.posting_time)
77 seconds = time.hour * 60 * 60 + time.minute * 60 + time.second
78 time_stamp = add_to_date(posting_date, seconds=seconds)
Ankush Menat494bd9e2022-03-28 18:52:46 +053079 time_stamp = time_stamp.strftime("%Y-%m-%dT%H:%M:%SZ")
Ahmadd1746ca2021-11-24 02:54:43 +010080
Dany Robert276bf732021-12-07 12:11:43 +053081 tag = bytes([3]).hex()
82 length = bytes([len(time_stamp)]).hex()
Ankush Menat494bd9e2022-03-28 18:52:46 +053083 value = time_stamp.encode("utf-8").hex()
84 tlv_array.append("".join([tag, length, value]))
Ahmadd1746ca2021-11-24 02:54:43 +010085
Dany Robert276bf732021-12-07 12:11:43 +053086 # Invoice Amount
87 invoice_amount = str(doc.grand_total)
88 tag = bytes([4]).hex()
89 length = bytes([len(invoice_amount)]).hex()
Ankush Menat494bd9e2022-03-28 18:52:46 +053090 value = invoice_amount.encode("utf-8").hex()
91 tlv_array.append("".join([tag, length, value]))
Ahmadd1746ca2021-11-24 02:54:43 +010092
Dany Robert276bf732021-12-07 12:11:43 +053093 # VAT Amount
Deepesh Gargb37559c2022-03-14 16:13:35 +053094 vat_amount = str(get_vat_amount(doc))
Ahmadd1746ca2021-11-24 02:54:43 +010095
Dany Robert276bf732021-12-07 12:11:43 +053096 tag = bytes([5]).hex()
97 length = bytes([len(vat_amount)]).hex()
Ankush Menat494bd9e2022-03-28 18:52:46 +053098 value = vat_amount.encode("utf-8").hex()
99 tlv_array.append("".join([tag, length, value]))
Ahmadd1746ca2021-11-24 02:54:43 +0100100
Dany Robert276bf732021-12-07 12:11:43 +0530101 # Joining bytes into one
Ankush Menat494bd9e2022-03-28 18:52:46 +0530102 tlv_buff = "".join(tlv_array)
Ahmadd1746ca2021-11-24 02:54:43 +0100103
Dany Robert276bf732021-12-07 12:11:43 +0530104 # base64 conversion for QR Code
105 base64_string = b64encode(bytes.fromhex(tlv_buff)).decode()
Ahmadd1746ca2021-11-24 02:54:43 +0100106
Dany Robert276bf732021-12-07 12:11:43 +0530107 qr_image = io.BytesIO()
Ankush Menat494bd9e2022-03-28 18:52:46 +0530108 url = qr_create(base64_string, error="L")
Dany Robert276bf732021-12-07 12:11:43 +0530109 url.png(qr_image, scale=2, quiet_zone=1)
Ahmad940db712021-09-17 01:14:41 +0500110
Dany Robert276bf732021-12-07 12:11:43 +0530111 name = frappe.generate_hash(doc.name, 5)
Saqib7511a9e2021-12-03 16:13:44 +0530112
Dany Robert276bf732021-12-07 12:11:43 +0530113 # making file
114 filename = f"QRCode-{name}.png".replace(os.path.sep, "__")
Ankush Menat494bd9e2022-03-28 18:52:46 +0530115 _file = frappe.get_doc(
116 {
117 "doctype": "File",
118 "file_name": filename,
119 "is_private": 0,
120 "content": qr_image.getvalue(),
121 "attached_to_doctype": doc.get("doctype"),
122 "attached_to_name": doc.get("name"),
123 "attached_to_field": "ksa_einv_qr",
124 }
125 )
Ahmad8a425702021-09-14 14:45:23 +0500126
Dany Robert276bf732021-12-07 12:11:43 +0530127 _file.save()
Ahmad8a425702021-09-14 14:45:23 +0500128
Dany Robert276bf732021-12-07 12:11:43 +0530129 # assigning to document
Ankush Menat494bd9e2022-03-28 18:52:46 +0530130 doc.db_set("ksa_einv_qr", _file.file_url)
Dany Robert276bf732021-12-07 12:11:43 +0530131 doc.notify_update()
Ahmad8a425702021-09-14 14:45:23 +0500132
Ankush Menat494bd9e2022-03-28 18:52:46 +0530133
Deepesh Gargb37559c2022-03-14 16:13:35 +0530134def get_vat_amount(doc):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530135 vat_settings = frappe.db.get_value("KSA VAT Setting", {"company": doc.company})
Deepesh Gargb37559c2022-03-14 16:13:35 +0530136 vat_accounts = []
Deepesh Garg3cc2e532022-03-14 16:27:04 +0530137 vat_amount = 0
Deepesh Gargb37559c2022-03-14 16:13:35 +0530138
139 if vat_settings:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530140 vat_settings_doc = frappe.get_cached_doc("KSA VAT Setting", vat_settings)
Deepesh Gargb37559c2022-03-14 16:13:35 +0530141
Ankush Menat494bd9e2022-03-28 18:52:46 +0530142 for row in vat_settings_doc.get("ksa_vat_sales_accounts"):
Deepesh Gargb37559c2022-03-14 16:13:35 +0530143 vat_accounts.append(row.account)
144
Ankush Menat494bd9e2022-03-28 18:52:46 +0530145 for tax in doc.get("taxes"):
Deepesh Gargb37559c2022-03-14 16:13:35 +0530146 if tax.account_head in vat_accounts:
147 vat_amount += tax.tax_amount
148
149 return vat_amount
Ahmad8a425702021-09-14 14:45:23 +0500150
Ankush Menat494bd9e2022-03-28 18:52:46 +0530151
Dany Robert276bf732021-12-07 12:11:43 +0530152def delete_qr_code_file(doc, method=None):
Ahmad8a425702021-09-14 14:45:23 +0500153 region = get_region(doc.company)
Ankush Menat494bd9e2022-03-28 18:52:46 +0530154 if region not in ["Saudi Arabia"]:
Ahmad8a425702021-09-14 14:45:23 +0500155 return
156
Ankush Menat494bd9e2022-03-28 18:52:46 +0530157 if hasattr(doc, "ksa_einv_qr"):
158 if doc.get("ksa_einv_qr"):
159 file_doc = frappe.get_list("File", {"file_url": doc.get("ksa_einv_qr")})
Ahmad8a425702021-09-14 14:45:23 +0500160 if len(file_doc):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530161 frappe.delete_doc("File", file_doc[0].name)
162
Deepesh Garg73c56512021-11-22 14:21:53 +0530163
Dany Robert3e974922021-12-08 08:03:30 +0530164def delete_vat_settings_for_company(doc, method=None):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530165 if doc.country != "Saudi Arabia":
Deepesh Garg73c56512021-11-22 14:21:53 +0530166 return
167
Ankush Menat494bd9e2022-03-28 18:52:46 +0530168 if frappe.db.exists("KSA VAT Setting", doc.name):
169 frappe.delete_doc("KSA VAT Setting", doc.name)