From 77b8ced4a4b128f70d11c6fc11ab3477034b2071 Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Wed, 4 Nov 2020 22:17:26 +0530 Subject: [PATCH] feat: generate eway bill from IRN --- .../patches/v12_0/setup_einvoice_fields.py | 3 +- erpnext/regional/india/e_invoice/einvoice.js | 120 +++++++++++++++++- erpnext/regional/india/e_invoice/utils.py | 56 +++++++- 3 files changed, 171 insertions(+), 8 deletions(-) diff --git a/erpnext/patches/v12_0/setup_einvoice_fields.py b/erpnext/patches/v12_0/setup_einvoice_fields.py index 9d7cfc52eb4..b72248c838d 100644 --- a/erpnext/patches/v12_0/setup_einvoice_fields.py +++ b/erpnext/patches/v12_0/setup_einvoice_fields.py @@ -37,4 +37,5 @@ def execute(): frappe.db.set_value('Custom Field', { 'fieldname': 'vehicle_no' }, 'depends_on', 'depends_on': 'eval:doc.mode_of_transport == "Road"') frappe.db.set_value('Custom Field', { 'fieldname': 'gst_vehicle_type' }, 'mandatory_depends_on', 'eval:doc.mode_of_transport == "Road"') frappe.db.set_value('Custom Field', { 'fieldname': 'lr_date' }, 'mandatory_depends_on', 'eval:in_list(["Air", "Ship", "Rail"], doc.mode_of_transport)') - frappe.db.set_value('Custom Field', { 'fieldname': 'lr_no' }, 'mandatory_depends_on', 'eval:in_list(["Air", "Ship", "Rail"], doc.mode_of_transport)') \ No newline at end of file + frappe.db.set_value('Custom Field', { 'fieldname': 'lr_no' }, 'mandatory_depends_on', 'eval:in_list(["Air", "Ship", "Rail"], doc.mode_of_transport)') + frappe.db.set_value('Custom Field', { 'fieldname': 'ewaybill' }, 'read_only_depends_on', 'eval:doc.irn && doc.ewaybill') \ No newline at end of file diff --git a/erpnext/regional/india/e_invoice/einvoice.js b/erpnext/regional/india/e_invoice/einvoice.js index 464b3b2e880..d70a8ef089e 100644 --- a/erpnext/regional/india/e_invoice/einvoice.js +++ b/erpnext/regional/india/e_invoice/einvoice.js @@ -7,7 +7,7 @@ erpnext.setup_einvoice_actions = (doctype) => { if (!einvoicing_enabled || !valid_supply_type) return; - const { docstatus, irn, irn_cancelled, ewaybill, eway_bill_cancelled, doctype, name, __unsaved } = frm.doc; + const { docstatus, irn, irn_cancelled, ewaybill, eway_bill_cancelled, name, __unsaved } = frm.doc; if (docstatus == 0 && !irn && !__unsaved) { const action = () => { @@ -22,7 +22,7 @@ erpnext.setup_einvoice_actions = (doctype) => { frm.add_custom_button(__("Generate IRN"), action, __('E Invoicing')); } - if (docstatus == 1 && irn && !irn_cancelled) { + if (docstatus == 1 && irn && !irn_cancelled && !ewaybill) { const fields = [ { "label" : "Reason", @@ -65,7 +65,118 @@ erpnext.setup_einvoice_actions = (doctype) => { frm.add_custom_button(__("Cancel IRN"), action, __("E Invoicing")); } - if (docstatus == 1 && irn && !irn_cancelled && !eway_bill_cancelled) { + if (irn && !irn_cancelled && !ewaybill) { + const fields = [ + { + 'fieldname': 'transporter', + 'label': 'Transporter', + 'fieldtype': 'Link', + 'options': 'Supplier', + 'default': frm.doc.transporter + }, + { + 'fieldname': 'gst_transporter_id', + 'label': 'GST Transporter ID', + 'fieldtype': 'Data', + 'fetch_from': 'transporter.gst_transporter_id', + 'default': frm.doc.gst_transporter_id + }, + { + 'fieldname': 'driver', + 'label': 'Driver', + 'fieldtype': 'Link', + 'options': 'Driver', + 'default': frm.doc.driver + }, + { + 'fieldname': 'lr_no', + 'label': 'Transport Receipt No', + 'fieldtype': 'Data', + 'default': frm.doc.lr_no + }, + { + 'fieldname': 'vehicle_no', + 'label': 'Vehicle No', + 'fieldtype': 'Data', + 'depends_on': 'eval:(doc.mode_of_transport === "Road")', + 'default': frm.doc.vehicle_no + }, + { + 'fieldname': 'distance', + 'label': 'Distance (in km)', + 'fieldtype': 'Float', + 'default': frm.doc.distance + }, + { + 'fieldname': 'transporter_col_break', + 'fieldtype': 'Column Break', + }, + { + 'fieldname': 'transporter_name', + 'label': 'Transporter Name', + 'fieldtype': 'Data', + 'fetch_from': 'transporter.name', + 'read_only': 1, + 'default': frm.doc.transporter_name + }, + { + 'fieldname': 'mode_of_transport', + 'label': 'Mode of Transport', + 'fieldtype': 'Select', + 'options': `\nRoad\nAir\nRail\nShip`, + 'default': frm.doc.mode_of_transport + }, + { + 'fieldname': 'driver_name', + 'label': 'Driver Name', + 'fieldtype': 'Data', + 'fetch_from': 'driver.full_name', + 'read_only': 1, + 'default': frm.doc.driver_name + }, + { + 'fieldname': 'lr_date', + 'label': 'Transport Receipt Date', + 'fieldtype': 'Date', + 'default': frm.doc.lr_date + }, + { + 'fieldname': 'gst_vehicle_type', + 'label': 'GST Vehicle Type', + 'fieldtype': 'Select', + 'options': `Regular\nOver Dimensional Cargo (ODC)`, + 'depends_on': 'eval:(doc.mode_of_transport === "Road")', + 'default': frm.doc.gst_vehicle_type + } + ] + + const action = () => { + const d = new frappe.ui.Dialog({ + title: __('Generate E-Way Bill'), + wide: 1, + fields: fields, + primary_action: function() { + const data = d.get_values(); + frappe.call({ + method: 'erpnext.regional.india.e_invoice.utils.generate_eway_bill', + args: { + docname: name, irn, + ...data + }, + freeze: true, + callback: () => frm.reload_doc() || d.hide(), + error: () => d.hide() + }) + }, + primary_action_label: __('Submit') + }); + d.show(); + }; + + frm.add_custom_button(__("Generate E-Way Bill"), action, __("E Invoicing")); + } + + if (docstatus == 1 && irn && ewaybill && !irn_cancelled && !eway_bill_cancelled) { const fields = [ { "label" : "Reason", @@ -91,8 +202,7 @@ erpnext.setup_einvoice_actions = (doctype) => { frappe.call({ method: 'erpnext.regional.india.e_invoice.utils.cancel_eway_bill', args: { - doctype: doctype, - name: name, + docname: name, eway_bill: ewaybill, reason: data.reason.split('-')[0], remark: data.remark diff --git a/erpnext/regional/india/e_invoice/utils.py b/erpnext/regional/india/e_invoice/utils.py index 11284852484..c4da7b2585f 100644 --- a/erpnext/regional/india/e_invoice/utils.py +++ b/erpnext/regional/india/e_invoice/utils.py @@ -218,7 +218,7 @@ def get_eway_bill_details(invoice): if invoice.is_return: frappe.throw(_('E-Way Bill cannot be generated for Credit Notes & Debit Notes'), title=_('E Invoice Validation Failed')) - mode_of_transport = { 'Road': '1', 'Air': '2', 'Rail': '3', 'Ship': '4' } + mode_of_transport = { '': '', 'Road': '1', 'Air': '2', 'Rail': '3', 'Ship': '4' } vehicle_type = { 'Regular': 'R', 'Over Dimensional Cargo (ODC)': 'O' } return frappe._dict(dict( @@ -381,6 +381,7 @@ class GSPConnector(): self.generate_irn_url = self.base_url + 'test/enriched/ei/api/invoice' self.cancel_irn_url = self.base_url + 'test/enriched/ei/api/invoice/cancel' self.cancel_ewaybill_url = self.base_url + '/test/enriched/ei/api/ewayapi' + self.generate_ewaybill_url = self.base_url + 'test/enriched/ei/api/ewaybill' def get_auth_token(self): if time_diff_in_seconds(self.credentials.token_expiry, now_datetime()) < 150.0: @@ -422,6 +423,8 @@ class GSPConnector(): res = make_get_request(self.gstin_details_url + params, headers=headers) if res.get('success'): return res.get('result') + else: + self.log_error(res) except Exception as e: self.log_error(e) @@ -483,6 +486,42 @@ class GSPConnector(): if res.get('success'): frappe.db.set_value(doctype, docname, 'irn_cancelled', 1) # frappe.db.set_value(doctype, docname, 'cancelled_on', res.get('CancelDate')) + else: + self.log_error(res) + + except Exception as e: + self.log_error(e) + + def generate_eway_bill(self, **kwargs): + args = frappe._dict(kwargs) + + headers = self.get_headers() + doctype = 'Sales Invoice' + docname = args.docname + eway_bill_details = get_eway_bill_details(args) + data = json.dumps({ + "Irn": args.irn, + "Distance": cint(eway_bill_details.distance), + "TransMode": eway_bill_details.mode_of_transport, + "TransId": eway_bill_details.gstin, + "TransName": eway_bill_details.transporter, + "TrnDocDt": eway_bill_details.document_date, + "TrnDocNo": eway_bill_details.document_name, + "VehNo": eway_bill_details.vehicle_no, + "VehType": eway_bill_details.vehicle_type + }) + + try: + res = make_post_request(self.generate_ewaybill_url, headers=headers, data=data) + if res.get('success'): + frappe.db.set_value(doctype, docname, 'ewaybill', res.get('result').get('EwbNo')) + frappe.db.set_value(doctype, docname, 'eway_bill_cancelled', 0) + for d in args: + if d in ['docname', 'cmd']: continue + # update eway bill details in sales invoice + frappe.db.set_value(doctype, docname, d, args[d]) + else: + self.log_error(res) except Exception as e: self.log_error(e) @@ -502,6 +541,9 @@ class GSPConnector(): frappe.db.set_value(doctype, docname, 'ewaybill', '') frappe.db.set_value(doctype, docname, 'eway_bill_cancelled', 1) + else: + self.log_error(res) + except Exception as e: self.log_error(e) @@ -516,4 +558,14 @@ def generate_irn(docname): @frappe.whitelist() def cancel_irn(docname, irn, reason, remark): gsp_connector = GSPConnector() - gsp_connector.cancel_irn(docname, irn, reason, remark) \ No newline at end of file + gsp_connector.cancel_irn(docname, irn, reason, remark) + +@frappe.whitelist() +def generate_eway_bill(**kwargs): + gsp_connector = GSPConnector() + gsp_connector.generate_eway_bill(**kwargs) + +@frappe.whitelist() +def cancel_eway_bill(docname, eway_bill, reason, remark): + gsp_connector = GSPConnector() + gsp_connector.cancel_eway_bill(docname, eway_bill, reason, remark) \ No newline at end of file