diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index bd79f7997d67..7e634c6cfb0d 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -2585,6 +2585,7 @@ def test_einvoice_submission_without_irn(self): # 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 c4b27a5d63b4..ea56d07d6dad 100644 --- a/erpnext/regional/india/e_invoice/einvoice.js +++ b/erpnext/regional/india/e_invoice/einvoice.js @@ -204,6 +204,29 @@ erpnext.setup_einvoice_actions = (doctype) => { }; 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 ad3be875f9c3..c2ff751023d0 100644 --- a/erpnext/regional/india/e_invoice/utils.py +++ b/erpnext/regional/india/e_invoice/utils.py @@ -793,6 +793,7 @@ def __init__(self, doctype=None, docname=None): 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 @@ -856,8 +857,8 @@ def make_request(self, request_type, url, headers=None, data=None): 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}) @@ -997,6 +998,37 @@ def bulk_generate_irn(invoices): 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() @@ -1237,13 +1269,18 @@ def set_einvoice_data(self, res): 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", @@ -1252,12 +1289,12 @@ def attach_qrcode_image(self): "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 @@ -1302,6 +1339,12 @@ def cancel_irn(doctype, docname, irn, reason, remark): gsp_connector.cancel_irn(irn, reason, remark) +@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)