feat: GST E Invoicing (#23455)

* feat: init e-invoice settings

* feat: read public key file

* feat: rsa encryption with public key

* feat: save token and sek from auth request

* chore: handle error response

* feat: AES decryption of SEK with appkey

* feat: decrypt json data with SEK

* feat: make e invoice from erpnext sales invoice

* feat: generate IRN

* feat: decode signed json and QR code

* chore: validations

* feat: cancel IRN

* feat: complete e-invoice schema

* chore: move e-invoice settings to regional

* chore: split einvoice settings and operations

* chore: rename schema to template & js cleanup

* feat: make IRN field on regional setup

* feat: Generate & Cancel IRN from Sales Invoice

* chore: minor fixes

* fix: item discount

* chore: show irn cancelled check after cancellation

* fix: hide cancel irn dialog on error

* fix: public key is required on validate

* fix: cannot find attached key file

* fix: validation if e invoicing is disabled

* fix: do not show generate irn for invalid supply type

* fix: update irn_cancelled after cancelling irn

* chore: show irn field for proper gst_category

* feat: e-way bill details in e-invoice

* fix: save e-way bill no on irn generation

* chore: no copy on e invoice custom fields

* feat: cancel e-way bill before cancelling IRN

* feat: manual download / upload json

* chore: group e-invoicing actions

* fix: fn name

* chore: save signed invoice and qrcode after uplaoding irn

* fix: fetch token if not valid

* chore: move einvoicing stuff to seperate folder

* feat: QRCode Image and E-Invoice Print Format

* fix: bug

* fix: invalid syntax

* chore: code cleanup

* chore: clean up e invoice actions

* fix: download & upload e-invoice

* fix: print format

* fix: validations

* fix: add permissions on regional setup

* feat: add patch

* fix: validate document name

* fix: return date

* fix: credit note einvoice

* fix: validations

* fix: error logging

* fix: e_invoice module not found

* fix: add missing package

* fix: rename e_invoice_utils.py

* fix: einvoice field validation

* fix: patch

* fix: invoice totals calculation

* fix: other charges calculation

* chore: improve document name validation message

* fix: qr code image string

* feat: initialize GSP connector

* chore: remove unwanted fields

* fix: qr code generation

* feat: fetch and cache GSTIN details

* feat: generate & cancel IRN

* feat: cancel eway bill

* chore: remove unwanted fuctions

* chore: clean up einvoice actions

* fix: attach qrcode on irn generation

* fix: generate & cancel IRN

* fix: show/hide eway bill fields

* fix: valiations

* feat: generate eway bill from IRN

* chore: remove unwanted imports

* chore: error logging

* feat: header & footer in GST E Invoice

* chore: remove test pincode

* fix: invalid syntax

* feat: cess non advolem on einvoice item

* chore: remove fetch token from e invocie settings

* fix: imports

* fix: error handling

* feat: update timeline on einvoice actions

* fix: qrcode image size

* fix: exclude intra company transactions

* fix: eway bill test

* fix: ewaybill mandatory conditions

* chore: add tests

* fix: returning condition

* feat: log e-invocing requests

* chore: add ack date and ack no field for print formats

* fix: sider issues

* feat: show e-invoice preview before IRN generation

* fix: use as_list for error message

* fix: minor ux issues

* fix: dialog is undefined

* fix: error handling

* feat: add docs link to e invoice settings

* feat: multiple gstins for e invoicing

* fix: uncomment test condition

* fix: remove test pincode

* fix: cannot cancel irn without submitting sales invoice

* chore: code cleanup

* fix: sider issues

* fix: e invoice request log permissions

Co-authored-by: Nabin Hait <nabinhait@gmail.com>
diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py
index cbcd6e3..5321a9a 100644
--- a/erpnext/regional/india/setup.py
+++ b/erpnext/regional/india/setup.py
@@ -87,7 +87,7 @@
 			)).insert()
 
 def add_permissions():
-	for doctype in ('GST HSN Code', 'GST Settings', 'GSTR 3B Report', 'Lower Deduction Certificate'):
+	for doctype in ('GST HSN Code', 'GST Settings', 'GSTR 3B Report', 'Lower Deduction Certificate', 'E Invoice Settings'):
 		add_permission(doctype, 'All', 0)
 		for role in ('Accounts Manager', 'Accounts User', 'System Manager'):
 			add_permission(doctype, role, 0)
@@ -103,9 +103,10 @@
 def add_print_formats():
 	frappe.reload_doc("regional", "print_format", "gst_tax_invoice")
 	frappe.reload_doc("accounts", "print_format", "gst_pos_invoice")
+	frappe.reload_doc("accounts", "print_format", "GST E-Invoice")
 
 	frappe.db.sql(""" update `tabPrint Format` set disabled = 0 where
-		name in('GST POS Invoice', 'GST Tax Invoice') """)
+		name in('GST POS Invoice', 'GST Tax Invoice', 'GST E-Invoice') """)
 
 def make_custom_fields(update=True):
 	hsn_sac_field = dict(fieldname='gst_hsn_code', label='HSN/SAC',
@@ -351,7 +352,6 @@
 			'label': 'Mode of Transport',
 			'fieldtype': 'Select',
 			'options': '\nRoad\nAir\nRail\nShip',
-			'default': 'Road',
 			'insert_after': 'transporter_name',
 			'print_hide': 1,
 			'translatable': 0
@@ -388,13 +388,34 @@
 			'fieldname': 'ewaybill',
 			'label': 'E-Way Bill No.',
 			'fieldtype': 'Data',
-			'depends_on': 'eval:(doc.docstatus === 1)',
+			'depends_on': 'eval:((doc.docstatus === 1 || doc.ewaybill) && doc.eway_bill_cancelled === 0)',
 			'allow_on_submit': 1,
 			'insert_after': 'tax_id',
 			'translatable': 0
 		}
 	]
 
+	si_einvoice_fields = [
+		dict(fieldname='irn', label='IRN', fieldtype='Data', read_only=1, insert_after='customer', no_copy=1, print_hide=1,
+			depends_on='eval:in_list(["Registered Regular", "SEZ", "Overseas", "Deemed Export"], doc.gst_category) && doc.irn_cancelled === 0'),
+		
+		dict(fieldname='ack_no', label='Ack. No.', fieldtype='Data', read_only=1, hidden=1, insert_after='irn', no_copy=1, print_hide=1),
+		
+		dict(fieldname='ack_date', label='Ack. Date', fieldtype='Data', read_only=1, hidden=1, insert_after='ack_no', no_copy=1, print_hide=1),
+
+		dict(fieldname='irn_cancelled', label='IRN Cancelled', fieldtype='Check', no_copy=1, print_hide=1,
+			depends_on='eval:(doc.irn_cancelled === 1)', read_only=1, allow_on_submit=1, insert_after='customer'),
+
+		dict(fieldname='eway_bill_cancelled', label='E-Way Bill Cancelled', fieldtype='Check', no_copy=1, print_hide=1,
+			depends_on='eval:(doc.eway_bill_cancelled === 1)', read_only=1, allow_on_submit=1, insert_after='customer'),
+
+		dict(fieldname='signed_einvoice', fieldtype='Code', options='JSON', hidden=1, no_copy=1, print_hide=1, read_only=1),
+
+		dict(fieldname='signed_qr_code', fieldtype='Code', options='JSON', hidden=1, no_copy=1, print_hide=1, read_only=1),
+
+		dict(fieldname='qrcode_image', label='QRCode', fieldtype='Attach Image', hidden=1, no_copy=1, print_hide=1, read_only=1)
+	]
+
 	custom_fields = {
 		'Address': [
 			dict(fieldname='gstin', label='Party GSTIN', fieldtype='Data',
@@ -407,7 +428,7 @@
 		'Purchase Invoice': purchase_invoice_gst_category + invoice_gst_fields + purchase_invoice_itc_fields + purchase_invoice_gst_fields,
 		'Purchase Order': purchase_invoice_gst_fields,
 		'Purchase Receipt': purchase_invoice_gst_fields,
-		'Sales Invoice': sales_invoice_gst_category + invoice_gst_fields + sales_invoice_shipping_fields + sales_invoice_gst_fields + si_ewaybill_fields,
+		'Sales Invoice': sales_invoice_gst_category + invoice_gst_fields + sales_invoice_shipping_fields + sales_invoice_gst_fields + si_ewaybill_fields + si_einvoice_fields,
 		'Delivery Note': sales_invoice_gst_fields + ewaybill_fields + sales_invoice_shipping_fields,
 		'Sales Order': sales_invoice_gst_fields,
 		'Tax Category': inter_state_gst_field,