feat(india): generate qrcode button for e-invoice (#30939)
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
index f2a696d..a0c0ecc 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -2648,6 +2648,7 @@
# reset
einvoice_settings = frappe.get_doc("E Invoice Settings")
einvoice_settings.enable = 0
+ einvoice_settings.save()
frappe.flags.country = country
def test_einvoice_json(self):
diff --git a/erpnext/regional/india/e_invoice/einvoice.js b/erpnext/regional/india/e_invoice/einvoice.js
index c4b27a5..ea56d07 100644
--- a/erpnext/regional/india/e_invoice/einvoice.js
+++ b/erpnext/regional/india/e_invoice/einvoice.js
@@ -204,6 +204,29 @@
};
add_custom_button(__("Cancel E-Way Bill"), action);
}
+
+ if (irn && !irn_cancelled) {
+ const action = () => {
+ const dialog = frappe.msgprint({
+ title: __("Generate QRCode"),
+ message: __("Generate and attach QR Code using IRN?"),
+ primary_action: {
+ action: function() {
+ frappe.call({
+ method: 'erpnext.regional.india.e_invoice.utils.generate_qrcode',
+ args: { doctype, docname: name },
+ freeze: true,
+ callback: () => frm.reload_doc() || dialog.hide(),
+ error: () => dialog.hide()
+ });
+ }
+ },
+ primary_action_label: __('Yes')
+ });
+ dialog.show();
+ };
+ add_custom_button(__("Generate QRCode"), action);
+ }
}
});
};
diff --git a/erpnext/regional/india/e_invoice/utils.py b/erpnext/regional/india/e_invoice/utils.py
index 53d3211..417f883 100644
--- a/erpnext/regional/india/e_invoice/utils.py
+++ b/erpnext/regional/india/e_invoice/utils.py
@@ -794,6 +794,7 @@
self.gstin_details_url = self.base_url + "/enriched/ei/api/master/gstin"
self.cancel_ewaybill_url = self.base_url + "/enriched/ei/api/ewayapi"
self.generate_ewaybill_url = self.base_url + "/enriched/ei/api/ewaybill"
+ self.get_qrcode_url = self.base_url + "/enriched/ei/others/qr/image"
def set_invoice(self):
self.invoice = None
@@ -857,8 +858,8 @@
return res
def auto_refresh_token(self):
- self.fetch_auth_token()
self.token_auto_refreshed = True
+ self.fetch_auth_token()
def log_request(self, url, headers, data, res):
headers.update({"password": self.credentials.password})
@@ -998,6 +999,37 @@
return failed
+ def fetch_and_attach_qrcode_from_irn(self):
+ qrcode = self.get_qrcode_from_irn(self.invoice.irn)
+ if qrcode:
+ qrcode_file = self.create_qr_code_file(qrcode)
+ frappe.db.set_value("Sales Invoice", self.invoice.name, "qrcode_image", qrcode_file.file_url)
+ frappe.msgprint(_("QR Code attached to the invoice"), alert=True)
+ else:
+ frappe.msgprint(_("QR Code not found for the IRN"), alert=True)
+
+ def get_qrcode_from_irn(self, irn):
+ import requests
+
+ headers = self.get_headers()
+ headers.update({"width": "215", "height": "215", "imgtype": "jpg", "irn": irn})
+
+ try:
+ # using requests.get instead of make_request to avoid parsing the response
+ res = requests.get(self.get_qrcode_url, headers=headers)
+ self.log_request(self.get_qrcode_url, headers, None, None)
+ if res.status_code == 200:
+ return res.content
+ else:
+ raise RequestFailed(str(res.content, "utf-8"))
+
+ except RequestFailed as e:
+ self.raise_error(errors=str(e))
+
+ except Exception:
+ log_error()
+ self.raise_error()
+
def get_irn_details(self, irn):
headers = self.get_headers()
@@ -1198,8 +1230,6 @@
return errors
def raise_error(self, raise_exception=False, errors=None):
- if errors is None:
- errors = []
title = _("E Invoice Request Failed")
if errors:
frappe.throw(errors, title=title, as_list=1)
@@ -1240,13 +1270,18 @@
def attach_qrcode_image(self):
qrcode = self.invoice.signed_qr_code
- doctype = self.invoice.doctype
- docname = self.invoice.name
- filename = "QRCode_{}.png".format(docname).replace(os.path.sep, "__")
qr_image = io.BytesIO()
url = qrcreate(qrcode, error="L")
url.png(qr_image, scale=2, quiet_zone=1)
+ qrcode_file = self.create_qr_code_file(qr_image.getvalue())
+ self.invoice.qrcode_image = qrcode_file.file_url
+
+ def create_qr_code_file(self, qr_image):
+ doctype = self.invoice.doctype
+ docname = self.invoice.name
+ filename = "QRCode_{}.png".format(docname).replace(os.path.sep, "__")
+
_file = frappe.get_doc(
{
"doctype": "File",
@@ -1255,12 +1290,12 @@
"attached_to_name": docname,
"attached_to_field": "qrcode_image",
"is_private": 0,
- "content": qr_image.getvalue(),
+ "content": qr_image,
}
)
_file.save()
frappe.db.commit()
- self.invoice.qrcode_image = _file.file_url
+ return _file
def update_invoice(self):
self.invoice.flags.ignore_validate_update_after_submit = True
@@ -1306,6 +1341,12 @@
@frappe.whitelist()
+def generate_qrcode(doctype, docname):
+ gsp_connector = GSPConnector(doctype, docname)
+ gsp_connector.fetch_and_attach_qrcode_from_irn()
+
+
+@frappe.whitelist()
def generate_eway_bill(doctype, docname, **kwargs):
gsp_connector = GSPConnector(doctype, docname)
gsp_connector.generate_eway_bill(**kwargs)