mirror of
https://github.com/frappe/erpnext.git
synced 2026-06-05 13:24:47 +00:00
fix(india): critical e-invoicing fixes (#25164)
* fix: place of supply & same object reference issue * fix(regional): remove shipping address GSTIN validation for e-invoice * fix: stopiteration error Co-authored-by: bhavesh95863 <34086262+bhavesh95863@users.noreply.github.com>
This commit is contained in:
@@ -86,10 +86,10 @@ def get_doc_details(invoice):
|
|||||||
invoice_date=invoice_date
|
invoice_date=invoice_date
|
||||||
))
|
))
|
||||||
|
|
||||||
def get_party_details(address_name):
|
def get_party_details(address_name, company_address=None, billing_address=None, shipping_address=None):
|
||||||
d = frappe.get_all('Address', filters={'name': address_name}, fields=['*'])[0]
|
d = frappe.get_all('Address', filters={'name': address_name}, fields=['*'])[0]
|
||||||
|
|
||||||
if (not d.gstin
|
if ((not d.gstin and not shipping_address)
|
||||||
or not d.city
|
or not d.city
|
||||||
or not d.pincode
|
or not d.pincode
|
||||||
or not d.address_title
|
or not d.address_title
|
||||||
@@ -107,13 +107,17 @@ def get_party_details(address_name):
|
|||||||
# according to einvoice standard
|
# according to einvoice standard
|
||||||
pincode = 999999
|
pincode = 999999
|
||||||
|
|
||||||
return frappe._dict(dict(
|
party_address_details = frappe._dict(dict(
|
||||||
gstin=d.gstin, legal_name=d.address_title,
|
legal_name=d.address_title,
|
||||||
location=d.city, pincode=d.pincode,
|
location=d.city,
|
||||||
state_code=d.gst_state_number,
|
state_code=d.gst_state_number,
|
||||||
address_line1=d.address_line1,
|
address_line1=d.address_line1,
|
||||||
address_line2=d.address_line2
|
address_line2=d.address_line2
|
||||||
))
|
))
|
||||||
|
if d.gstin:
|
||||||
|
party_address_details.gstin = d.gstin
|
||||||
|
|
||||||
|
return party_address_details
|
||||||
|
|
||||||
def get_gstin_details(gstin):
|
def get_gstin_details(gstin):
|
||||||
if not hasattr(frappe.local, 'gstin_cache'):
|
if not hasattr(frappe.local, 'gstin_cache'):
|
||||||
@@ -320,14 +324,18 @@ def make_einvoice(invoice):
|
|||||||
item_list = get_item_list(invoice)
|
item_list = get_item_list(invoice)
|
||||||
doc_details = get_doc_details(invoice)
|
doc_details = get_doc_details(invoice)
|
||||||
invoice_value_details = get_invoice_value_details(invoice)
|
invoice_value_details = get_invoice_value_details(invoice)
|
||||||
seller_details = get_party_details(invoice.company_address)
|
seller_details = get_party_details(invoice.company_address, company_address=1)
|
||||||
|
|
||||||
if invoice.gst_category == 'Overseas':
|
if invoice.gst_category == 'Overseas':
|
||||||
buyer_details = get_overseas_address_details(invoice.customer_address)
|
buyer_details = get_overseas_address_details(invoice.customer_address)
|
||||||
else:
|
else:
|
||||||
buyer_details = get_party_details(invoice.customer_address)
|
buyer_details = get_party_details(invoice.customer_address, billing_address=1)
|
||||||
place_of_supply = get_place_of_supply(invoice, invoice.doctype) or invoice.billing_address_gstin
|
place_of_supply = get_place_of_supply(invoice, invoice.doctype)
|
||||||
place_of_supply = place_of_supply[:2]
|
if place_of_supply:
|
||||||
|
place_of_supply = place_of_supply.split('-')[0]
|
||||||
|
else:
|
||||||
|
place_of_supply = invoice.billing_address_gstin[:2]
|
||||||
|
|
||||||
buyer_details.update(dict(place_of_supply=place_of_supply))
|
buyer_details.update(dict(place_of_supply=place_of_supply))
|
||||||
|
|
||||||
shipping_details = payment_details = prev_doc_details = eway_bill_details = frappe._dict({})
|
shipping_details = payment_details = prev_doc_details = eway_bill_details = frappe._dict({})
|
||||||
@@ -335,7 +343,7 @@ def make_einvoice(invoice):
|
|||||||
if invoice.gst_category == 'Overseas':
|
if invoice.gst_category == 'Overseas':
|
||||||
shipping_details = get_overseas_address_details(invoice.shipping_address_name)
|
shipping_details = get_overseas_address_details(invoice.shipping_address_name)
|
||||||
else:
|
else:
|
||||||
shipping_details = get_party_details(invoice.shipping_address_name)
|
shipping_details = get_party_details(invoice.shipping_address_name, shipping_address=1)
|
||||||
|
|
||||||
if invoice.is_pos and invoice.base_paid_amount:
|
if invoice.is_pos and invoice.base_paid_amount:
|
||||||
payment_details = get_payment_details(invoice)
|
payment_details = get_payment_details(invoice)
|
||||||
@@ -343,7 +351,7 @@ def make_einvoice(invoice):
|
|||||||
if invoice.is_return and invoice.return_against:
|
if invoice.is_return and invoice.return_against:
|
||||||
prev_doc_details = get_return_doc_reference(invoice)
|
prev_doc_details = get_return_doc_reference(invoice)
|
||||||
|
|
||||||
if invoice.transporter:
|
if invoice.transporter and cint(invoice.distance):
|
||||||
eway_bill_details = get_eway_bill_details(invoice)
|
eway_bill_details = get_eway_bill_details(invoice)
|
||||||
|
|
||||||
# not yet implemented
|
# not yet implemented
|
||||||
@@ -371,7 +379,10 @@ def make_einvoice(invoice):
|
|||||||
|
|
||||||
return einvoice
|
return einvoice
|
||||||
|
|
||||||
def validate_einvoice(validations, einvoice, errors=[]):
|
def validate_einvoice(validations, einvoice, errors=None):
|
||||||
|
if errors is None:
|
||||||
|
errors = []
|
||||||
|
|
||||||
for fieldname, field_validation in validations.items():
|
for fieldname, field_validation in validations.items():
|
||||||
value = einvoice.get(fieldname, None)
|
value = einvoice.get(fieldname, None)
|
||||||
if not value or value == "None":
|
if not value or value == "None":
|
||||||
@@ -417,7 +428,7 @@ def validate_einvoice(validations, einvoice, errors=[]):
|
|||||||
errors.append(_('{} should not exceed {} characters').format(label, max_length))
|
errors.append(_('{} should not exceed {} characters').format(label, max_length))
|
||||||
if value_type == 'number' and (value > maximum or value < minimum):
|
if value_type == 'number' and (value > maximum or value < minimum):
|
||||||
errors.append(_('{} {} should be between {} and {}').format(label, value, minimum, maximum))
|
errors.append(_('{} {} should be between {} and {}').format(label, value, minimum, maximum))
|
||||||
if pattern_str and not pattern.match(value):
|
if pattern_str and not pattern.match(value) and field_validation.get('validationMsg'):
|
||||||
errors.append(field_validation.get('validationMsg'))
|
errors.append(field_validation.get('validationMsg'))
|
||||||
|
|
||||||
return errors
|
return errors
|
||||||
@@ -448,13 +459,18 @@ class GSPConnector():
|
|||||||
gstin = self.get_seller_gstin()
|
gstin = self.get_seller_gstin()
|
||||||
if not self.e_invoice_settings.enable:
|
if not self.e_invoice_settings.enable:
|
||||||
frappe.throw(_("E-Invoicing is disabled. Please enable it from {} to generate e-invoices.").format(get_link_to_form("E Invoice Settings", "E Invoice Settings")))
|
frappe.throw(_("E-Invoicing is disabled. Please enable it from {} to generate e-invoices.").format(get_link_to_form("E Invoice Settings", "E Invoice Settings")))
|
||||||
credentials = next(d for d in self.e_invoice_settings.credentials if d.gstin == gstin)
|
|
||||||
|
credentials_for_gstin = [d for d in self.e_invoice_settings.credentials if d.gstin == gstin]
|
||||||
|
if credentials_for_gstin:
|
||||||
|
credentials = credentials_for_gstin[0]
|
||||||
|
else:
|
||||||
|
frappe.throw(_('Cannot find e-invoicing credentials for GSTIN {}. Please check E-Invoice Settings').format(gstin))
|
||||||
else:
|
else:
|
||||||
credentials = self.e_invoice_settings.credentials[0] if self.e_invoice_settings.credentials else None
|
credentials = self.e_invoice_settings.credentials[0] if self.e_invoice_settings.credentials else None
|
||||||
return credentials
|
return credentials
|
||||||
|
|
||||||
def get_seller_gstin(self):
|
def get_seller_gstin(self):
|
||||||
gstin = self.invoice.company_gstin or frappe.db.get_value('Address', self.invoice.company_address, 'gstin')
|
gstin = frappe.db.get_value('Address', self.invoice.company_address, 'gstin')
|
||||||
if not gstin:
|
if not gstin:
|
||||||
frappe.throw(_('Cannot retrieve Company GSTIN. Please select company address with valid GSTIN.'))
|
frappe.throw(_('Cannot retrieve Company GSTIN. Please select company address with valid GSTIN.'))
|
||||||
return gstin
|
return gstin
|
||||||
|
|||||||
Reference in New Issue
Block a user