diff --git a/erpnext/accounts/doctype/sales_invoice/regional/india.js b/erpnext/accounts/doctype/sales_invoice/regional/india.js index f54bce8aac7..1ed4b92e7a4 100644 --- a/erpnext/accounts/doctype/sales_invoice/regional/india.js +++ b/erpnext/accounts/doctype/sales_invoice/regional/india.js @@ -1,8 +1,6 @@ {% include "erpnext/regional/india/taxes.js" %} -{% include "erpnext/regional/india/e_invoice/einvoice.js" %} erpnext.setup_auto_gst_taxation('Sales Invoice'); -erpnext.setup_einvoice_actions('Sales Invoice') frappe.ui.form.on("Sales Invoice", { setup: function(frm) { @@ -48,6 +46,8 @@ frappe.ui.form.on("Sales Invoice", { }, __("Create")); } - } + }, }); + + diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 9cf3e62c695..2f8b782356d 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -225,9 +225,9 @@ class SalesInvoice(SellingController): frappe.throw(_("At least one mode of payment is required for POS invoice.")) def before_cancel(self): - super(SalesInvoice, self).before_cancel() self.update_time_sheet(None) + def on_cancel(self): super(SalesInvoice, self).on_cancel() diff --git a/erpnext/accounts/print_format/gst_e_invoice/__init__.py b/erpnext/accounts/print_format/gst_e_invoice/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/accounts/print_format/gst_e_invoice/gst_e_invoice.html b/erpnext/accounts/print_format/gst_e_invoice/gst_e_invoice.html deleted file mode 100644 index b4255038d39..00000000000 --- a/erpnext/accounts/print_format/gst_e_invoice/gst_e_invoice.html +++ /dev/null @@ -1,147 +0,0 @@ -{%- from "templates/print_formats/standard_macros.html" import add_header, render_field, print_value -%} -{%- set einvoice = json.loads(doc.signed_einvoice) -%} - -
-
- -
-
-
1. Transaction Details
-
-
-
-
{{ einvoice.Irn }}
-
-
-
-
{{ einvoice.AckNo }}
-
-
-
-
{{ frappe.utils.format_datetime(einvoice.AckDt, "dd/MM/yyyy hh:mm:ss") }}
-
-
-
-
{{ einvoice.TranDtls.SupTyp }}
-
-
-
-
{{ einvoice.DocDtls.Typ }}
-
-
-
-
{{ einvoice.DocDtls.No }}
-
-
-
- -
-
-
-
2. Party Details
- {%- set seller = einvoice.SellerDtls -%} -
-
Seller
-

{{ seller.Gstin }}

-

{{ seller.LglNm }}

-

{{ seller.Addr1 }}

- {%- if seller.Addr2 -%}

{{ seller.Addr2 }}

{% endif %} -

{{ seller.Loc }}

-

{{ frappe.db.get_value("Address", doc.company_address, "gst_state") }} - {{ seller.Pin }}

- - {%- if einvoice.ShipDtls -%} - {%- set shipping = einvoice.ShipDtls -%} -
Shipping
-

{{ shipping.Gstin }}

-

{{ shipping.LglNm }}

-

{{ shipping.Addr1 }}

- {%- if shipping.Addr2 -%}

{{ shipping.Addr2 }}

{% endif %} -

{{ shipping.Loc }}

-

{{ frappe.db.get_value("Address", doc.shipping_address_name, "gst_state") }} - {{ shipping.Pin }}

- {% endif %} -
- {%- set buyer = einvoice.BuyerDtls -%} -
-
Buyer
-

{{ buyer.Gstin }}

-

{{ buyer.LglNm }}

-

{{ buyer.Addr1 }}

- {%- if buyer.Addr2 -%}

{{ buyer.Addr2 }}

{% endif %} -

{{ buyer.Loc }}

-

{{ frappe.db.get_value("Address", doc.customer_address, "gst_state") }} - {{ buyer.Pin }}

-
-
-
-
3. Item Details
- - - - - - - - - - - - - - - - - - {% for item in einvoice.ItemList %} - - - - - - - - - - - - - - {% endfor %} - -
Sr. No.ItemHSN CodeQtyUOMRateDiscountTaxable AmountTax RateOther ChargesTotal
{{ item.SlNo }}{{ item.PrdDesc }}{{ item.HsnCd }}{{ item.Qty }}{{ item.Unit }}{{ frappe.utils.fmt_money(item.UnitPrice, None, "INR") }}{{ frappe.utils.fmt_money(item.Discount, None, "INR") }}{{ frappe.utils.fmt_money(item.AssAmt, None, "INR") }}{{ item.GstRt + item.CesRt }} %{{ frappe.utils.fmt_money(0, None, "INR") }}{{ frappe.utils.fmt_money(item.TotItemVal, None, "INR") }}
-
-
-
4. Value Details
- - - - - - - - - - - - - - - - - {%- set value_details = einvoice.ValDtls -%} - - - - - - - - - - - - - -
Taxable AmountCGSTSGSTIGSTCESSState CESSDiscountOther ChargesRound OffTotal Value
{{ frappe.utils.fmt_money(value_details.AssVal, None, "INR") }}{{ frappe.utils.fmt_money(value_details.CgstVal, None, "INR") }}{{ frappe.utils.fmt_money(value_details.SgstVal, None, "INR") }}{{ frappe.utils.fmt_money(value_details.IgstVal, None, "INR") }}{{ frappe.utils.fmt_money(value_details.CesVal, None, "INR") }}{{ frappe.utils.fmt_money(0, None, "INR") }}{{ frappe.utils.fmt_money(value_details.Discount, None, "INR") }}{{ frappe.utils.fmt_money(0, None, "INR") }}{{ frappe.utils.fmt_money(value_details.RndOffAmt, None, "INR") }}{{ frappe.utils.fmt_money(value_details.TotInvVal, None, "INR") }}
-
-
\ No newline at end of file diff --git a/erpnext/accounts/print_format/gst_e_invoice/gst_e_invoice.json b/erpnext/accounts/print_format/gst_e_invoice/gst_e_invoice.json deleted file mode 100644 index 1001199a092..00000000000 --- a/erpnext/accounts/print_format/gst_e_invoice/gst_e_invoice.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "align_labels_right": 1, - "creation": "2020-10-10 18:01:21.032914", - "custom_format": 0, - "default_print_language": "en-US", - "disabled": 1, - "doc_type": "Sales Invoice", - "docstatus": 0, - "doctype": "Print Format", - "font": "Default", - "html": "", - "idx": 0, - "line_breaks": 1, - "modified": "2020-10-23 19:54:40.634936", - "modified_by": "Administrator", - "module": "Accounts", - "name": "GST E-Invoice", - "owner": "Administrator", - "print_format_builder": 0, - "print_format_type": "Jinja", - "raw_printing": 0, - "show_section_headings": 1, - "standard": "Yes" -} \ No newline at end of file diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index 00f37943848..58c7e847910 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -106,14 +106,8 @@ class AccountsController(TransactionBase): self.validate_deferred_start_and_end_date() validate_regional(self) - - validate_einvoice_fields(self) - if self.doctype != 'Material Request': apply_pricing_rule_on_transaction(self) - - def before_cancel(self): - validate_einvoice_fields(self) def validate_deferred_start_and_end_date(self): for d in self.items: @@ -1412,7 +1406,3 @@ def update_child_qty_rate(parent_doctype, trans_items, parent_doctype_name, chil @erpnext.allow_regional def validate_regional(doc): pass - -@erpnext.allow_regional -def validate_einvoice_fields(doc): - pass \ No newline at end of file diff --git a/erpnext/hooks.py b/erpnext/hooks.py index 81fad7df4ad..5270e7beea2 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -357,8 +357,7 @@ regional_overrides = { 'erpnext.accounts.party.get_regional_address_details': 'erpnext.regional.india.utils.get_regional_address_details', 'erpnext.hr.utils.calculate_annual_eligible_hra_exemption': 'erpnext.regional.india.utils.calculate_annual_eligible_hra_exemption', 'erpnext.hr.utils.calculate_hra_exemption_for_period': 'erpnext.regional.india.utils.calculate_hra_exemption_for_period', - 'erpnext.accounts.doctype.purchase_invoice.purchase_invoice.make_regional_gl_entries': 'erpnext.regional.india.utils.make_regional_gl_entries', - 'erpnext.controllers.accounts_controller.validate_einvoice_fields': 'erpnext.regional.india.e_invoice.utils.validate_einvoice_fields' + 'erpnext.accounts.doctype.purchase_invoice.purchase_invoice.make_regional_gl_entries': 'erpnext.regional.india.utils.make_regional_gl_entries' }, 'United Arab Emirates': { 'erpnext.controllers.taxes_and_totals.update_itemised_tax_data': 'erpnext.regional.united_arab_emirates.utils.update_itemised_tax_data' diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 36574d09ae2..b5f31bafa7e 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -677,5 +677,4 @@ erpnext.patches.v12_0.set_multi_uom_in_rfq erpnext.patches.v12_0.update_state_code_for_daman_and_diu erpnext.patches.v12_0.rename_lost_reason_detail erpnext.patches.v12_0.update_leave_application_status -erpnext.patches.v12_0.update_payment_entry_status -erpnext.patches.v12_0.setup_einvoice_fields \ No newline at end of file +erpnext.patches.v12_0.update_payment_entry_status \ No newline at end of file diff --git a/erpnext/patches/v12_0/setup_einvoice_fields.py b/erpnext/patches/v12_0/setup_einvoice_fields.py deleted file mode 100644 index e230eb0bf75..00000000000 --- a/erpnext/patches/v12_0/setup_einvoice_fields.py +++ /dev/null @@ -1,31 +0,0 @@ -from __future__ import unicode_literals -import frappe -from frappe.custom.doctype.custom_field.custom_field import create_custom_fields -from erpnext.regional.india.setup import add_permissions, add_print_formats - -def execute(): - company = frappe.get_all('Company', filters = {'country': 'India'}) - if not company: - return - - custom_fields = { - 'Sales Invoice': [ - 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='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) - ] - } - create_custom_fields(custom_fields, update=True) - add_permissions() - add_print_formats() \ No newline at end of file diff --git a/erpnext/regional/doctype/e_invoice_settings/__init__.py b/erpnext/regional/doctype/e_invoice_settings/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.js b/erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.js deleted file mode 100644 index e9fb622b6b6..00000000000 --- a/erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.js +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on('E Invoice Settings', { - refresh: function(frm) { - if (!frm.doc.enable) return; - frm.trigger("show_fetch_token_btn"); - }, - - show_fetch_token_btn(frm) { - const { token_expiry } = frm.doc; - const now = frappe.datetime.now_datetime(); - const expiry_in_mins = moment(token_expiry).diff(now, "minute"); - if (expiry_in_mins <= 1 || !token_expiry) { - frm.add_custom_button(__("Fetch Token"), - () => { - frm.call({ - method: 'erpnext.regional.india.e_invoice.e_invoice_utils.fetch_token', - freeze: true, - callback: () => frm.refresh() - }); - } - ); - } - } -}); diff --git a/erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.json b/erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.json deleted file mode 100644 index d9a1c4976a9..00000000000 --- a/erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.json +++ /dev/null @@ -1,120 +0,0 @@ -{ - "actions": [], - "creation": "2020-09-24 16:23:16.235722", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "enable", - "section_break_2", - "client_id", - "client_secret", - "public_key_file", - "public_key", - "column_break_3", - "gstin", - "username", - "password", - "auto_refresh_token", - "auth_token", - "token_expiry", - "sek" - ], - "fields": [ - { - "default": "0", - "fieldname": "enable", - "fieldtype": "Check", - "label": "Enable" - }, - { - "depends_on": "enable", - "fieldname": "section_break_2", - "fieldtype": "Section Break" - }, - { - "fieldname": "client_id", - "fieldtype": "Data", - "in_list_view": 1, - "label": "Client ID", - "reqd": 1 - }, - { - "fieldname": "client_secret", - "fieldtype": "Data", - "label": "Client Secret", - "reqd": 1 - }, - { - "fieldname": "public_key_file", - "fieldtype": "Attach", - "label": "Public Key", - "reqd": 1 - }, - { - "fieldname": "public_key", - "fieldtype": "Long Text", - "hidden": 1, - "read_only": 1 - }, - { - "fieldname": "column_break_3", - "fieldtype": "Column Break" - }, - { - "fieldname": "gstin", - "fieldtype": "Data", - "label": "GSTIN", - "reqd": 1 - }, - { - "fieldname": "username", - "fieldtype": "Data", - "label": "Username", - "reqd": 1 - }, - { - "fieldname": "password", - "fieldtype": "Password", - "label": "Password", - "reqd": 1 - }, - { - "default": "0", - "description": "Token will be automatically refreshed 10 mins before expiry", - "fieldname": "auto_refresh_token", - "fieldtype": "Check", - "label": "Auto Refresh Token" - }, - { - "fieldname": "auth_token", - "fieldtype": "Data", - "hidden": 1, - "read_only": 1 - }, - { - "fieldname": "token_expiry", - "fieldtype": "Datetime", - "hidden": 1, - "read_only": 1 - }, - { - "fieldname": "sek", - "fieldtype": "Data", - "hidden": 1, - "read_only": 1 - } - ], - "index_web_pages_for_search": 1, - "issingle": 1, - "links": [], - "modified": "2020-10-23 19:55:11.417161", - "modified_by": "Administrator", - "module": "Regional", - "name": "E Invoice Settings", - "owner": "Administrator", - "permissions": [], - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.py b/erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.py deleted file mode 100644 index e90d07edbd6..00000000000 --- a/erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.py +++ /dev/null @@ -1,26 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals -import frappe -from frappe import _ -from frappe.utils.data import cstr -from frappe.model.document import Document -from frappe.custom.doctype.property_setter.property_setter import make_property_setter - -class EInvoiceSettings(Document): - def validate(self): - mandatory_fields = ['client_id', 'client_secret', 'gstin', 'username', 'password', 'public_key_file'] - for d in mandatory_fields: - if not self.get(d): - frappe.throw(_("{} is required").format(frappe.unscrub(d)), title=_("Missing Values")) - - def before_save(self): - if not self.public_key or self.has_value_changed('public_key_file'): - self.public_key = self.read_key_file() - - def read_key_file(self): - key_file = frappe.get_doc('File', dict(attached_to_name=self.doctype)) - with open(key_file.get_full_path(), 'rb') as f: - return cstr(f.read()) \ No newline at end of file diff --git a/erpnext/regional/doctype/e_invoice_settings/test_e_invoice_settings.py b/erpnext/regional/doctype/e_invoice_settings/test_e_invoice_settings.py deleted file mode 100644 index a11ce63ee6c..00000000000 --- a/erpnext/regional/doctype/e_invoice_settings/test_e_invoice_settings.py +++ /dev/null @@ -1,10 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt -from __future__ import unicode_literals - -# import frappe -import unittest - -class TestEInvoiceSettings(unittest.TestCase): - pass diff --git a/erpnext/regional/india/e_invoice/__init__.py b/erpnext/regional/india/e_invoice/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/regional/india/e_invoice/einv_item_template.json b/erpnext/regional/india/e_invoice/einv_item_template.json deleted file mode 100644 index f87b0f15f3c..00000000000 --- a/erpnext/regional/india/e_invoice/einv_item_template.json +++ /dev/null @@ -1,26 +0,0 @@ -{{ - "SlNo": "{item.sr_no}", - "PrdDesc": "{item.description}", - "IsServc": "{item.is_service_item}", - "HsnCd": "{item.gst_hsn_code}", - "Barcde": "{item.barcode}", - "Unit": "{item.uom}", - "Qty": "{item.qty}", - "FreeQty": "{item.free_qty}", - "UnitPrice": "{item.unit_rate}", - "TotAmt": "{item.total_amount}", - "Discount": "{item.discount_amount}", - "AssAmt": "{item.base_amount}", - "PrdSlNo": "{item.serial_no}", - "GstRt": "{item.tax_rate}", - "IgstAmt": "{item.igst_amount}", - "CgstAmt": "{item.cgst_amount}", - "SgstAmt": "{item.sgst_amount}", - "CesRt": "{item.cess_rate}", - "CesAmt": "{item.cess_amount}", - "TotItemVal": "{item.total_value}", - "BchDtls": {{ - "Nm": "{item.batch_no}", - "ExpDt": "{item.batch_expiry_date}" - }} -}} \ No newline at end of file diff --git a/erpnext/regional/india/e_invoice/einv_template.json b/erpnext/regional/india/e_invoice/einv_template.json deleted file mode 100644 index 46741ca0337..00000000000 --- a/erpnext/regional/india/e_invoice/einv_template.json +++ /dev/null @@ -1,109 +0,0 @@ -{{ - "Version": "1.1", - "TranDtls": {{ - "TaxSch": "{trans_details.tax_scheme}", - "SupTyp": "{trans_details.supply_type}", - "RegRev": "{trans_details.reverse_charge}", - "EcmGstin": "{trans_details.ecom_gstin}", - "IgstOnIntra": "{trans_details.igst_on_intra}" - }}, - "DocDtls": {{ - "Typ": "{doc_details.invoice_type}", - "No": "{doc_details.invoice_name}", - "Dt": "{doc_details.invoice_date}" - }}, - "SellerDtls": {{ - "Gstin": "{seller_details.gstin}", - "LglNm": "{seller_details.legal_name}", - "TrdNm": "{seller_details.trade_name}", - "Loc": "{seller_details.location}", - "Pin": "{seller_details.pincode}", - "Stcd": "{seller_details.state_code}", - "Addr1": "{seller_details.address_line1}", - "Addr2": "{seller_details.address_line2}", - "Ph": "{seller_details.phone}", - "Em": "{seller_details.email}" - }}, - "BuyerDtls": {{ - "Gstin": "{buyer_details.gstin}", - "LglNm": "{buyer_details.legal_name}", - "TrdNm": "{buyer_details.trade_name}", - "Addr1": "{buyer_details.address_line1}", - "Addr2": "{buyer_details.address_line2}", - "Loc": "{buyer_details.location}", - "Pin": "{buyer_details.pincode}", - "Stcd": "{buyer_details.state_code}", - "Ph": "{buyer_details.phone}", - "Em": "{buyer_details.email}", - "Pos": "{buyer_details.place_of_supply}" - }}, - "DispDtls": {{ - "Nm": "{dispatch_details.company_name}", - "Addr1": "{dispatch_details.address_line1}", - "Addr2": "{dispatch_details.address_line2}", - "Loc": "{dispatch_details.location}", - "Pin": "{dispatch_details.pincode}", - "Stcd": "{dispatch_details.state_code}" - }}, - "ShipDtls": {{ - "Gstin": "{shipping_details.gstin}", - "LglNm": "{shipping_details.legal_name}", - "TrdNm": "{shipping_details.trader_name}", - "Addr1": "{shipping_details.address_line1}", - "Addr2": "{shipping_details.address_line2}", - "Loc": "{shipping_details.location}", - "Pin": "{shipping_details.pincode}", - "Stcd": "{shipping_details.state_code}" - }}, - "ItemList": [ - {item_list} - ], - "ValDtls": {{ - "AssVal": "{value_details.base_net_total}", - "CgstVal": "{value_details.total_cgst_amt}", - "SgstVal": "{value_details.total_sgst_amt}", - "IgstVal": "{value_details.total_igst_amt}", - "CesVal": "{value_details.total_cess_amt}", - "Discount": "{value_details.invoice_discount_amt}", - "RndOffAmt": "{value_details.round_off}", - "TotInvVal": "{value_details.base_grand_total}", - "TotInvValFc": "{value_details.grand_total}" - }}, - "PayDtls": {{ - "Nm": "{payment_details.payee_name}", - "AccDet": "{payment_details.account_no}", - "Mode": "{payment_details.mode_of_payment}", - "FinInsBr": "{payment_details.ifsc_code}", - "PayTerm": "{payment_details.terms}", - "PaidAmt": "{payment_details.paid_amount}", - "PaymtDue": "{payment_details.outstanding_amount}" - }}, - "RefDtls": {{ - "DocPerdDtls": {{ - "InvStDt": "{period_details.start_date}", - "InvEndDt": "{period_details.end_date}" - }}, - "PrecDocDtls": [{{ - "InvNo": "{prev_doc_details.invoice_name}", - "InvDt": "{prev_doc_details.invoice_date}" - }}] - }}, - "ExpDtls": {{ - "ShipBNo": "{export_details.bill_no}", - "ShipBDt": "{export_details.bill_date}", - "Port": "{export_details.port}", - "ForCur": "{export_details.foreign_curr_code}", - "CntCode": "{export_details.country_code}", - "ExpDuty": "{export_details.export_duty}" - }}, - "EwbDtls": {{ - "TransId": "{eway_bill_details.gstin}", - "TransName": "{eway_bill_details.name}", - "TransMode": "{eway_bill_details.mode_of_transport}", - "Distance": "{eway_bill_details.distance}", - "TransDocNo": "{eway_bill_details.document_name}", - "TransDocDt": "{eway_bill_details.document_date}", - "VehNo": "{eway_bill_details.vehicle_no}", - "VehType": "{eway_bill_details.vehicle_type}" - }} -}} \ No newline at end of file diff --git a/erpnext/regional/india/e_invoice/einv_validation.json b/erpnext/regional/india/e_invoice/einv_validation.json deleted file mode 100644 index 3f0767b8be8..00000000000 --- a/erpnext/regional/india/e_invoice/einv_validation.json +++ /dev/null @@ -1,830 +0,0 @@ -{ - "Version": { - "type": "string", - "minLength": 1, - "maxLength": 6 - }, - "Irn": { - "type": "string", - "minLength": 64, - "maxLength": 64 - }, - "TranDtls": { - "type": "object", - "properties": { - "TaxSch": { - "type": "string", - "minLength": 3, - "maxLength": 10, - "enum": ["GST"] - }, - "SupTyp": { - "type": "string", - "minLength": 3, - "maxLength": 10, - "enum": ["B2B", "SEZWP", "SEZWOP", "EXPWP", "EXPWOP", "DEXP"] - }, - "RegRev": { - "type": "string", - "minLength": 1, - "maxLength": 1, - "enum": ["Y", "N"] - }, - "EcmGstin": { - "type": "string", - "minLength": 15, - "maxLength": 15, - "pattern": "([0-9]{2}[0-9A-Z]{13})" - }, - "IgstOnIntra": { - "type": "string", - "minLength": 1, - "maxLength": 1, - "enum": ["Y", "N"] - } - }, - "required": ["TaxSch", "SupTyp"] - }, - "DocDtls": { - "type": "object", - "properties": { - "Typ": { - "type": "string", - "minLength": 3, - "maxLength": 3, - "enum": ["INV", "CRN", "DBN"] - }, - "No": { - "type": "string", - "minLength": 1, - "maxLength": 16, - "pattern": "^([A-Z1-9]{1}[A-Z0-9/-]{0,15})$", - "label": "Document Name", - "validationMsg": "Document name should not be starting with 0, / and -" - }, - "Dt": { - "type": "string", - "minLength": 10, - "maxLength": 10, - "pattern": "[0-3][0-9]/[0-1][0-9]/[2][0][1-2][0-9]", - "validationMsg": "Document Date is invalid" - } - }, - "required": ["Typ", "No", "Dt"] - }, - "SellerDtls": { - "type": "object", - "properties": { - "Gstin": { - "type": "string", - "minLength": 15, - "maxLength": 15, - "pattern": "([0-9]{2}[0-9A-Z]{13})", - "validationMsg": "Seller GSTIN is invalid" - }, - "LglNm": { - "type": "string", - "minLength": 3, - "maxLength": 100 - }, - "TrdNm": { - "type": "string", - "minLength": 3, - "maxLength": 100 - }, - "Addr1": { - "type": "string", - "minLength": 3, - "maxLength": 100 - }, - "Addr2": { - "type": "string", - "minLength": 3, - "maxLength": 100 - }, - "Loc": { - "type": "string", - "minLength": 3, - "maxLength": 50 - }, - "Pin": { - "type": "number", - "minimum": 100000, - "maximum": 999999 - }, - "Stcd": { - "type": "string", - "minLength": 1, - "maxLength": 2 - }, - "Ph": { - "type": "string", - "minLength": 6, - "maxLength": 12 - }, - "Em": { - "type": "string", - "minLength": 6, - "maxLength": 100 - } - }, - "required": ["Gstin", "LglNm", "Addr1", "Loc", "Pin", "Stcd"] - }, - "BuyerDtls": { - "type": "object", - "properties": { - "Gstin": { - "type": "string", - "minLength": 3, - "maxLength": 15, - "pattern": "^(([0-9]{2}[0-9A-Z]{13})|URP)$", - "validationMsg": "Buyer GSTIN is invalid" - }, - "LglNm": { - "type": "string", - "minLength": 3, - "maxLength": 100 - }, - "TrdNm": { - "type": "string", - "minLength": 3, - "maxLength": 100 - }, - "Pos": { - "type": "string", - "minLength": 1, - "maxLength": 2 - }, - "Addr1": { - "type": "string", - "minLength": 3, - "maxLength": 100 - }, - "Addr2": { - "type": "string", - "minLength": 3, - "maxLength": 100 - }, - "Loc": { - "type": "string", - "minLength": 3, - "maxLength": 100 - }, - "Pin": { - "type": "number", - "minimum": 100000, - "maximum": 999999 - }, - "Stcd": { - "type": "string", - "minLength": 1, - "maxLength": 2 - }, - "Ph": { - "type": "string", - "minLength": 6, - "maxLength": 12 - }, - "Em": { - "type": "string", - "minLength": 6, - "maxLength": 100 - } - }, - "required": ["Gstin", "LglNm", "Pos", "Addr1", "Loc", "Stcd"] - }, - "DispDtls": { - "type": "object", - "properties": { - "Nm": { - "type": "string", - "minLength": 3, - "maxLength": 100 - }, - "Addr1": { - "type": "string", - "minLength": 3, - "maxLength": 100 - }, - "Addr2": { - "type": "string", - "minLength": 3, - "maxLength": 100 - }, - "Loc": { - "type": "string", - "minLength": 3, - "maxLength": 100 - }, - "Pin": { - "type": "number", - "minimum": 100000, - "maximum": 999999 - }, - "Stcd": { - "type": "string", - "minLength": 1, - "maxLength": 2 - } - }, - "required": ["Nm", "Addr1", "Loc", "Pin", "Stcd"] - }, - "ShipDtls": { - "type": "object", - "properties": { - "Gstin": { - "type": "string", - "maxLength": 15, - "minLength": 3, - "pattern": "^(([0-9]{2}[0-9A-Z]{13})|URP)$", - "validationMsg": "Shipping Address GSTIN is invalid" - }, - "LglNm": { - "type": "string", - "minLength": 3, - "maxLength": 100 - }, - "TrdNm": { - "type": "string", - "minLength": 3, - "maxLength": 100 - }, - "Addr1": { - "type": "string", - "minLength": 3, - "maxLength": 100 - }, - "Addr2": { - "type": "string", - "minLength": 3, - "maxLength": 100 - }, - "Loc": { - "type": "string", - "minLength": 3, - "maxLength": 100 - }, - "Pin": { - "type": "number", - "minimum": 100000, - "maximum": 999999 - }, - "Stcd": { - "type": "string", - "minLength": 1, - "maxLength": 2 - } - }, - "required": ["LglNm", "Addr1", "Loc", "Pin", "Stcd"] - }, - "ItemList": { - "type": "Array", - "properties": { - "SlNo": { - "type": "string", - "minLength": 1, - "maxLength": 6 - }, - "PrdDesc": { - "type": "string", - "minLength": 3, - "maxLength": 300 - }, - "IsServc": { - "type": "string", - "minLength": 1, - "maxLength": 1, - "enum": ["Y", "N"] - }, - "HsnCd": { - "type": "string", - "minLength": 4, - "maxLength": 8 - }, - "Barcde": { - "type": "string", - "minLength": 3, - "maxLength": 30 - }, - "Qty": { - "type": "number", - "minimum": 0, - "maximum": 9999999999.999 - }, - "FreeQty": { - "type": "number", - "minimum": 0, - "maximum": 9999999999.999 - }, - "Unit": { - "type": "string", - "minLength": 3, - "maxLength": 8 - }, - "UnitPrice": { - "type": "number", - "minimum": 0, - "maximum": 999999999999.999 - }, - "TotAmt": { - "type": "number", - "minimum": 0, - "maximum": 999999999999.99 - }, - "Discount": { - "type": "number", - "minimum": 0, - "maximum": 999999999999.99 - }, - "PreTaxVal": { - "type": "number", - "minimum": 0, - "maximum": 999999999999.99 - }, - "AssAmt": { - "type": "number", - "minimum": 0, - "maximum": 999999999999.99 - }, - "GstRt": { - "type": "number", - "minimum": 0, - "maximum": 999.999 - }, - "IgstAmt": { - "type": "number", - "minimum": 0, - "maximum": 999999999999.99 - }, - "CgstAmt": { - "type": "number", - "minimum": 0, - "maximum": 999999999999.99 - }, - "SgstAmt": { - "type": "number", - "minimum": 0, - "maximum": 999999999999.99 - }, - "CesRt": { - "type": "number", - "minimum": 0, - "maximum": 999.999 - }, - "CesAmt": { - "type": "number", - "minimum": 0, - "maximum": 999999999999.99 - }, - "CesNonAdvlAmt": { - "type": "number", - "minimum": 0, - "maximum": 999999999999.99 - }, - "StateCesRt": { - "type": "number", - "minimum": 0, - "maximum": 999.999 - }, - "StateCesAmt": { - "type": "number", - "minimum": 0, - "maximum": 999999999999.99 - }, - "StateCesNonAdvlAmt": { - "type": "number", - "minimum": 0, - "maximum": 999999999999.99 - }, - "OthChrg": { - "type": "number", - "minimum": 0, - "maximum": 999999999999.99 - }, - "TotItemVal": { - "type": "number", - "minimum": 0, - "maximum": 999999999999.99 - }, - "OrdLineRef": { - "type": "string", - "minLength": 1, - "maxLength": 50 - }, - "OrgCntry": { - "type": "string", - "minLength": 2, - "maxLength": 2 - }, - "PrdSlNo": { - "type": "string", - "minLength": 1, - "maxLength": 20 - }, - "BchDtls": { - "type": "object", - "properties": { - "Nm": { - "type": "string", - "minLength": 3, - "maxLength": 20 - }, - "ExpDt": { - "type": "string", - "maxLength": 10, - "minLength": 10, - "pattern": "[0-3][0-9]/[0-1][0-9]/[2][0][1-2][0-9]", - "validationMsg": "Expiry Date is invalid" - }, - "WrDt": { - "type": "string", - "maxLength": 10, - "minLength": 10, - "pattern": "[0-3][0-9]/[0-1][0-9]/[2][0][1-2][0-9]", - "validationMsg": "Warranty Date is invalid" - } - }, - "required": ["Nm"] - }, - "AttribDtls": { - "type": "Array", - "Attribute": { - "type": "object", - "properties": { - "Nm": { - "type": "string", - "minLength": 1, - "maxLength": 100 - }, - "Val": { - "type": "string", - "minLength": 1, - "maxLength": 100 - } - } - } - } - }, - "required": [ - "SlNo", - "IsServc", - "HsnCd", - "UnitPrice", - "TotAmt", - "AssAmt", - "GstRt", - "TotItemVal" - ] - }, - "ValDtls": { - "type": "object", - "properties": { - "AssVal": { - "type": "number", - "minimum": 0, - "maximum": 99999999999999.99 - }, - "CgstVal": { - "type": "number", - "maximum": 99999999999999.99, - "minimum": 0 - }, - "SgstVal": { - "type": "number", - "minimum": 0, - "maximum": 99999999999999.99 - }, - "IgstVal": { - "type": "number", - "minimum": 0, - "maximum": 99999999999999.99 - }, - "CesVal": { - "type": "number", - "minimum": 0, - "maximum": 99999999999999.99 - }, - "StCesVal": { - "type": "number", - "minimum": 0, - "maximum": 99999999999999.99 - }, - "Discount": { - "type": "number", - "minimum": 0, - "maximum": 99999999999999.99 - }, - "OthChrg": { - "type": "number", - "minimum": 0, - "maximum": 99999999999999.99 - }, - "RndOffAmt": { - "type": "number", - "minimum": 0, - "maximum": 99.99 - }, - "TotInvVal": { - "type": "number", - "minimum": 0, - "maximum": 99999999999999.99 - }, - "TotInvValFc": { - "type": "number", - "minimum": 0, - "maximum": 99999999999999.99 - } - }, - "required": ["AssVal", "TotInvVal"] - }, - "PayDtls": { - "type": "object", - "properties": { - "Nm": { - "type": "string", - "minLength": 1, - "maxLength": 100 - }, - "AccDet": { - "type": "string", - "minLength": 1, - "maxLength": 18 - }, - "Mode": { - "type": "string", - "minLength": 1, - "maxLength": 18 - }, - "FinInsBr": { - "type": "string", - "minLength": 1, - "maxLength": 11 - }, - "PayTerm": { - "type": "string", - "minLength": 1, - "maxLength": 100 - }, - "PayInstr": { - "type": "string", - "minLength": 1, - "maxLength": 100 - }, - "CrTrn": { - "type": "string", - "minLength": 1, - "maxLength": 100 - }, - "DirDr": { - "type": "string", - "minLength": 1, - "maxLength": 100 - }, - "CrDay": { - "type": "number", - "minimum": 0, - "maximum": 9999 - }, - "PaidAmt": { - "type": "number", - "minimum": 0, - "maximum": 99999999999999.99 - }, - "PaymtDue": { - "type": "number", - "minimum": 0, - "maximum": 99999999999999.99 - } - } - }, - "RefDtls": { - "type": "object", - "properties": { - "InvRm": { - "type": "string", - "maxLength": 100, - "minLength": 3, - "pattern": "^[0-9A-Za-z/-]{3,100}$" - }, - "DocPerdDtls": { - "type": "object", - "properties": { - "InvStDt": { - "type": "string", - "maxLength": 10, - "minLength": 10, - "pattern": "[0-3][0-9]/[0-1][0-9]/[2][0][1-2][0-9]" - }, - "InvEndDt": { - "type": "string", - "maxLength": 10, - "minLength": 10, - "pattern": "[0-3][0-9]/[0-1][0-9]/[2][0][1-2][0-9]" - } - }, - "required": ["InvStDt", "InvEndDt"] - }, - "PrecDocDtls": { - "type": "object", - "properties": { - "InvNo": { - "type": "string", - "minLength": 1, - "maxLength": 16, - "pattern": "^[1-9A-Z]{1}[0-9A-Z/-]{1,15}$" - }, - "InvDt": { - "type": "string", - "maxLength": 10, - "minLength": 10, - "pattern": "[0-3][0-9]/[0-1][0-9]/[2][0][1-2][0-9]" - }, - "OthRefNo": { - "type": "string", - "minLength": 1, - "maxLength": 20 - } - }, - "required": ["InvNo", "InvDt"] - }, - "ContrDtls": { - "type": "object", - "properties": { - "RecAdvRefr": { - "type": "string", - "minLength": 1, - "maxLength": 20, - "pattern": "^([0-9A-Za-z/-]){1,20}$" - }, - "RecAdvDt": { - "type": "string", - "minLength": 10, - "maxLength": 10, - "pattern": "[0-3][0-9]/[0-1][0-9]/[2][0][1-2][0-9]" - }, - "TendRefr": { - "type": "string", - "minLength": 1, - "maxLength": 20, - "pattern": "^([0-9A-Za-z/-]){1,20}$" - }, - "ContrRefr": { - "type": "string", - "minLength": 1, - "maxLength": 20, - "pattern": "^([0-9A-Za-z/-]){1,20}$" - }, - "ExtRefr": { - "type": "string", - "minLength": 1, - "maxLength": 20, - "pattern": "^([0-9A-Za-z/-]){1,20}$" - }, - "ProjRefr": { - "type": "string", - "minLength": 1, - "maxLength": 20, - "pattern": "^([0-9A-Za-z/-]){1,20}$" - }, - "PORefr": { - "type": "string", - "minLength": 1, - "maxLength": 16, - "pattern": "^([0-9A-Za-z/-]){1,16}$" - }, - "PORefDt": { - "type": "string", - "minLength": 10, - "maxLength": 10, - "pattern": "[0-3][0-9]/[0-1][0-9]/[2][0][1-2][0-9]" - } - } - } - }, - "required": ["InvStDt", "InvEndDt"] - }, - "AddlDocDtls": { - "type": "Array", - "AddlDocument": { - "type": "object", - "properties": { - "Url": { - "type": "string", - "minLength": 3, - "maxLength": 100 - }, - "Docs": { - "type": "string", - "minLength": 3, - "maxLength": 1000 - }, - "Info": { - "type": "string", - "minLength": 3, - "maxLength": 1000 - } - } - } - }, - "ExpDtls": { - "type": "object", - "properties": { - "ShipBNo": { - "type": "string", - "minLength": 1, - "maxLength": 20 - }, - "ShipBDt": { - "type": "string", - "minLength": 10, - "maxLength": 10, - "pattern": "[0-3][0-9]/[0-1][0-9]/[2][0][1-2][0-9]" - }, - "Port": { - "type": "string", - "minLength": 2, - "maxLength": 10, - "pattern": "^[0-9A-Za-z]{2,10}$" - }, - "RefClm": { - "type": "string", - "minLength": 1, - "maxLength": 1 - }, - "ForCur": { - "type": "string", - "minLength": 3, - "maxLength": 16 - }, - "CntCode": { - "type": "string", - "minLength": 2, - "maxLength": 2 - }, - "ExpDuty": { - "type": "number", - "minimum": 0, - "maximum": 999999999999.99 - } - } - }, - "EwbDtls": { - "type": "object", - "properties": { - "TransId": { - "type": "string", - "minLength": 15, - "maxLength": 15 - }, - "TransName": { - "type": "string", - "minLength": 3, - "maxLength": 100 - }, - "TransMode": { - "type": "string", - "maxLength": 1, - "minLength": 1, - "enum": ["1", 2, 3, 4] - }, - "Distance": { - "type": "number", - "minimum": 1, - "maximum": 9999 - }, - "TransDocNo": { - "type": "string", - "minLength": 1, - "maxLength": 15, - "pattern": "^([0-9A-Z/-]){1,15}$" - }, - "TransDocDt": { - "type": "string", - "minLength": 10, - "maxLength": 10, - "pattern": "[0-3][0-9]/[0-1][0-9]/[2][0][1-2][0-9]" - }, - "VehNo": { - "type": "string", - "minLength": 4, - "maxLength": 20 - }, - "VehType": { - "type": "string", - "minLength": 1, - "maxLength": 1, - "enum": ["O", "R"] - } - }, - "required": ["Distance"] - }, - "required": [ - "Version", - "TranDtls", - "DocDtls", - "SellerDtls", - "BuyerDtls", - "ItemList", - "ValDtls" - ] -} diff --git a/erpnext/regional/india/e_invoice/einvoice.js b/erpnext/regional/india/e_invoice/einvoice.js deleted file mode 100644 index 4627b96795f..00000000000 --- a/erpnext/regional/india/e_invoice/einvoice.js +++ /dev/null @@ -1,96 +0,0 @@ -erpnext.setup_einvoice_actions = (doctype) => { - frappe.ui.form.on(doctype, { - refresh(frm) { - const einvoicing_enabled = frappe.db.get_value("E Invoice Settings", "E Invoice Settings", "enable"); - const supply_type = frm.doc.gst_category; - const valid_supply_type = ['Registered Regular', 'SEZ', 'Overseas', 'Deemed Export'].includes(supply_type) - - if (!einvoicing_enabled || !valid_supply_type) return; - - const { docstatus, irn, irn_cancelled, doctype, name, __unsaved } = frm.doc; - - if (docstatus == 0 && !irn && !__unsaved) { - frm.add_custom_button( - "Download E-Invoice", - () => { - frappe.call({ - method: 'erpnext.regional.india.e_invoice.e_invoice_utils.make_einvoice', - args: { doctype, name }, - freeze: true, - callback: (res) => { - if (!res.exc) { - const args = { - cmd: 'erpnext.regional.india.e_invoice.e_invoice_utils.download_einvoice', - einvoice: JSON.stringify([res.message]), - name: name - }; - open_url_post(frappe.request.url, args); - } - } - }) - }, "E-Invoicing"); - frm.add_custom_button( - "Upload Signed E-Invoice", - () => { - new frappe.ui.FileUploader({ - method: 'erpnext.regional.india.e_invoice.e_invoice_utils.upload_einvoice', - allow_multiple: 0, - doctype: doctype, - docname: name, - on_success: (attachment, r) => { - if (!r.exc) { - frm.reload_doc(); - } - } - }); - }, "E-Invoicing"); - } - if (docstatus == 1 && irn && !irn_cancelled) { - frm.add_custom_button( - "Cancel IRN", - () => { - const d = new frappe.ui.Dialog({ - title: __('Cancel IRN'), - fields: [ - { - "label" : "Reason", "fieldname": "reason", - "fieldtype": "Select", "reqd": 1, "default": "1-Duplicate", - "options": ["1-Duplicate", "2-Data Entry Error", "3-Order Cancelled", "4-Other"] - }, - { - "label": "Remark", "fieldname": "remark", "fieldtype": "Data", "reqd": 1 - } - ], - primary_action: function() { - const data = d.get_values(); - const args = { - cmd: 'erpnext.regional.india.e_invoice.e_invoice_utils.download_cancel_einvoice', - irn: irn, reason: data.reason.split('-')[0], remark: data.remark, name: name - }; - open_url_post(frappe.request.url, args); - d.hide(); - }, - primary_action_label: __('Download JSON') - }); - d.show(); - }, "E-Invoicing"); - - frm.add_custom_button( - "Upload Cancel JSON", - () => { - new frappe.ui.FileUploader({ - method: 'erpnext.regional.india.e_invoice.e_invoice_utils.upload_cancel_ack', - allow_multiple: 0, - doctype: doctype, - docname: name, - on_success: (attachment, r) => { - if (!r.exc) { - frm.reload_doc(); - } - } - }); - }, "E-Invoicing"); - } - } - }) -} \ No newline at end of file diff --git a/erpnext/regional/india/e_invoice/utils.py b/erpnext/regional/india/e_invoice/utils.py deleted file mode 100644 index f6ed33ddb91..00000000000 --- a/erpnext/regional/india/e_invoice/utils.py +++ /dev/null @@ -1,626 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals -import os -import re -import jwt -import json -import base64 -import frappe -from six import string_types -from Crypto.PublicKey import RSA -from pyqrcode import create as qrcreate -from Crypto.Cipher import PKCS1_v1_5, AES -from Crypto.Util.Padding import pad, unpad -from frappe.model.document import Document -from frappe import _, get_module_path, scrub, bold -from frappe.integrations.utils import make_post_request, make_get_request -from erpnext.regional.india.utils import get_gst_accounts, get_place_of_supply -from frappe.utils.data import get_datetime, cstr, cint, formatdate as format_date, flt, time_diff_in_seconds, now_datetime - -def validate_einvoice_fields(doc): - einvoicing_enabled = frappe.db.get_value('E Invoice Settings', 'E Invoice Settings', 'enable') - invalid_doctype = doc.doctype not in ['Sales Invoice', 'Purchase Invoice'] - invalid_supply_type = doc.gst_category not in ['Registered Regular', 'SEZ', 'Overseas', 'Deemed Export'] - - if invalid_doctype or invalid_supply_type or not einvoicing_enabled: return - - if doc.docstatus == 0 and doc._action == 'save': - if doc.irn: - frappe.throw(_('You cannot edit the invoice after generating IRN'), title=_('Edit Not Allowed')) - if len(doc.name) > 16: - title = _('Document Name Too Long') - msg = (_('As you have E-Invoicing enabled, To be able to generate IRN for this invoice, document name {} exceed 16 letters. ') - .format(bold(_('should not')))) - msg += '

' - msg += (_('You {} modify your {} in order to have document name of {} length of 16. ') - .format(bold(_('must')), bold(_('naming series')), bold(_('maximum')))) - frappe.throw(msg, title=title) - - elif doc.docstatus == 1 and doc._action == 'submit' and not doc.irn: - frappe.throw(_('You must generate IRN before submitting the document.'), title=_('Missing IRN')) - - elif doc.docstatus == 2 and doc._action == 'cancel' and not doc.irn_cancelled: - frappe.throw(_('You must cancel IRN before cancelling the document.'), title=_('Cancel Not Allowed')) - -def get_credentials(): - doc = frappe.get_doc('E Invoice Settings') - if not doc.enable: - frappe.throw(_("To setup E Invoicing you need to enable E Invoice Settings first."), title=_("E Invoicing Disabled")) - - if not doc.token_expiry or time_diff_in_seconds(now_datetime(), doc.token_expiry) > 5.0: - fetch_token(doc) - doc.load_from_db() - - return doc - -def rsa_encrypt(msg, key): - if not (isinstance(msg, bytes) or isinstance(msg, bytearray)): - msg = str.encode(msg) - - rsa_pub_key = RSA.import_key(key) - cipher = PKCS1_v1_5.new(rsa_pub_key) - enc_msg = cipher.encrypt(msg) - b64_enc_msg = base64.b64encode(enc_msg) - return b64_enc_msg.decode() - -def aes_decrypt(enc_msg, key): - encode_as_b64 = True - if not (isinstance(key, bytes) or isinstance(key, bytearray)): - key = base64.b64decode(key) - encode_as_b64 = False - - cipher = AES.new(key, AES.MODE_ECB) - b64_enc_msg = base64.b64decode(enc_msg) - msg_bytes = cipher.decrypt(b64_enc_msg) - msg_bytes = unpad(msg_bytes, AES.block_size) # due to ECB/PKCS5Padding - if encode_as_b64: - msg_bytes = base64.b64encode(msg_bytes) - return msg_bytes.decode() - -def aes_encrypt(msg, key): - if not (isinstance(key, bytes) or isinstance(key, bytearray)): - key = base64.b64decode(key) - - cipher = AES.new(key, AES.MODE_ECB) - bytes_msg = str.encode(msg) - padded_bytes_msg = pad(bytes_msg, AES.block_size) - enc_msg = cipher.encrypt(padded_bytes_msg) - b64_enc_msg = base64.b64encode(enc_msg) - return b64_enc_msg.decode() - -def jwt_decrypt(token): - return jwt.decode(token, verify=False) - -def get_header(creds): - headers = { 'content-type': 'application/json' } - headers.update(dict(client_id=creds.client_id, client_secret=creds.client_secret, user_name=creds.username)) - headers.update(dict(Gstin=creds.gstin, AuthToken=creds.auth_token)) - return headers - -@frappe.whitelist() -def fetch_token(credentials=None): - if not credentials: - credentials = frappe.get_doc('E Invoice Settings') - - endpoint = 'https://einv-apisandbox.nic.in/eivital/v1.03/auth' - headers = { 'content-type': 'application/json' } - headers.update(dict(client_id=credentials.client_id, client_secret=credentials.client_secret)) - payload = dict(UserName=credentials.username, ForceRefreshAccessToken=bool(credentials.auto_refresh_token)) - - appkey = bytearray(os.urandom(32)) - enc_appkey = rsa_encrypt(appkey, credentials.public_key) - - password = credentials.get_password(fieldname='password') - enc_password = rsa_encrypt(password, credentials.public_key) - - payload.update(dict(Password=enc_password, AppKey=enc_appkey)) - - res = make_post_request(endpoint, headers=headers, data=json.dumps({ 'data': payload })) - handle_err_response(res) - - auth_token, token_expiry, sek = extract_token_and_sek(res, appkey) - - credentials.auth_token = auth_token - credentials.token_expiry = get_datetime(token_expiry) - credentials.sek = sek - credentials.save() - -def extract_token_and_sek(response, appkey): - data = response.get('Data') - auth_token = data.get('AuthToken') - token_expiry = data.get('TokenExpiry') - enc_sek = data.get('Sek') - sek = aes_decrypt(enc_sek, appkey) - return auth_token, token_expiry, sek - -def attach_signed_invoice(doctype, name, data): - f = frappe.get_doc({ - 'doctype': 'File', - 'file_name': 'E-INV--{}.json'.format(name), - 'attached_to_doctype': doctype, - 'attached_to_name': name, - 'content': json.dumps(data), - 'is_private': True - }).insert() - -def get_gstin_details(gstin): - credentials = get_credentials() - - endpoint = 'https://einv-apisandbox.nic.in/eivital/v1.03/Master/gstin/{gstin}'.format(gstin=gstin) - headers = get_header(credentials) - - res = make_get_request(endpoint, headers=headers) - handle_err_response(res) - - enc_details = res.get('Data') - json_str = aes_decrypt(enc_details, credentials.sek) - details = json.loads(json_str) - - return details - -@frappe.whitelist() -def generate_irn(doctype, name): - endpoint = 'https://einv-apisandbox.nic.in/eicore/v1.03/Invoice' - credentials = get_credentials() - headers = get_header(credentials) - - einvoice = make_einvoice(doctype, name) - einvoice = json.dumps(einvoice) - - enc_einvoice_json = aes_encrypt(einvoice, credentials.sek) - payload = dict(Data=enc_einvoice_json) - - res = make_post_request(endpoint, headers=headers, data=json.dumps(payload)) - res = handle_err_response(res) - - enc_json = res.get('Data') - json_str = aes_decrypt(enc_json, credentials.sek) - - signed_einvoice = json.loads(json_str) - decrypt_irn_response(signed_einvoice) - - update_einvoice_fields(doctype, name, signed_einvoice) - - attach_qrcode_image(doctype, name) - attach_signed_invoice(doctype, name, signed_einvoice['DecryptedSignedInvoice']) - - return signed_einvoice - -def get_irn_details(irn): - credentials = get_credentials() - - endpoint = 'https://einv-apisandbox.nic.in/eicore/v1.03/Invoice/irn/{irn}'.format(irn=irn) - headers = get_header(credentials) - - res = make_get_request(endpoint, headers=headers) - handle_err_response(res) - - return res - -@frappe.whitelist() -def cancel_irn(doctype, name, irn, reason, remark=''): - credentials = get_credentials() - - endpoint = 'https://einv-apisandbox.nic.in/eicore/v1.03/Invoice/Cancel' - headers = get_header(credentials) - - cancel_einv = json.dumps(dict(Irn=irn, CnlRsn=reason, CnlRem=remark)) - enc_json = aes_encrypt(cancel_einv, credentials.sek) - payload = dict(Data=enc_json) - - res = make_post_request(endpoint, headers=headers, data=json.dumps(payload)) - handle_err_response(res) - - frappe.db.set_value(doctype, name, 'irn_cancelled', 1) - - return res - -@frappe.whitelist() -def cancel_eway_bill(doctype, name, eway_bill, reason, remark=''): - credentials = get_credentials() - endpoint = 'https://einv-apisandbox.nic.in/ewaybillapi/v1.03/ewayapi' - headers = get_header(credentials) - - cancel_eway_bill_json = json.dumps(dict(ewbNo=eway_bill, cancelRsnCode=reason, cancelRmrk=remark)) - enc_json = aes_encrypt(cancel_eway_bill_json, credentials.sek) - payload = dict(action='CANEWB', Data=enc_json) - - res = make_post_request(endpoint, headers=headers, data=json.dumps(payload)) - handle_err_response(res) - - frappe.db.set_value(doctype, name, 'ewaybill', '') - frappe.db.set_value(doctype, name, 'eway_bill_cancelled', 1) - - return res - -def decrypt_irn_response(data): - enc_signed_invoice = data['SignedInvoice'] - enc_signed_qr_code = data['SignedQRCode'] - signed_invoice = jwt_decrypt(enc_signed_invoice)['data'] - signed_qr_code = jwt_decrypt(enc_signed_qr_code)['data'] - data['DecryptedSignedInvoice'] = json.loads(signed_invoice) - data['DecryptedSignedQRCode'] = json.loads(signed_qr_code) - -def handle_err_response(response): - if response.get('Status') == 0: - err_details = response.get('ErrorDetails') - errors = [] - for d in err_details: - err_code = d.get('ErrorCode') - - if err_code == '2150': - irn = [d['Desc']['Irn'] for d in response.get('InfoDtls') if d['InfCd'] == 'DUPIRN'] - response = get_irn_details(irn[0]) - return response - - errors.append(d.get('ErrorMessage')) - - if errors: - frappe.log_error(title="E Invoice API Request Failed", message=json.dumps(errors, default=str, indent=4)) - if len(errors) > 1: - li = ['
  • '+ d +'
  • ' for d in errors] - frappe.throw(_("""""").format(''.join(li)), title=_('API Request Failed')) - else: - frappe.throw(errors[0], title=_('API Request Failed')) - - return response - -def read_json(name): - file_path = os.path.join(os.path.dirname(__file__), '{name}.json'.format(name=name)) - with open(file_path, 'r') as f: - return cstr(f.read()) - -def get_trans_details(invoice): - supply_type = '' - if invoice.gst_category == 'Registered Regular': supply_type = 'B2B' - elif invoice.gst_category == 'SEZ': supply_type = 'SEZWOP' - elif invoice.gst_category == 'Overseas': supply_type = 'EXPWOP' - elif invoice.gst_category == 'Deemed Export': supply_type = 'DEXP' - - if not supply_type: - return _('Invalid invoice transaction category.') - - return frappe._dict(dict( - tax_scheme='GST', supply_type=supply_type, reverse_charge=invoice.reverse_charge - )) - -def get_doc_details(invoice): - if invoice.doctype == 'Purchase Invoice' and invoice.is_return: - invoice_type = 'DBN' - else: - invoice_type = 'CRN' if invoice.is_return else 'INV' - - invoice_name = invoice.name - invoice_date = format_date(invoice.posting_date, 'dd/mm/yyyy') - - return frappe._dict(dict(invoice_type=invoice_type, invoice_name=invoice_name, invoice_date=invoice_date)) - -def get_party_gstin_details(address_name): - address = frappe.get_all('Address', filters={'name': address_name}, fields=['*'])[0] - - gstin = address.get('gstin') - gstin_details = get_gstin_details(gstin) - legal_name = gstin_details.get('LegalName') - trade_name = gstin_details.get('TradeName') - location = gstin_details.get('AddrLoc') - state_code = gstin_details.get('StateCode') - pincode = cint(gstin_details.get('AddrPncd')) - address_line1 = '{} {}'.format(gstin_details.get('AddrBno'), gstin_details.get('AddrFlno')) - address_line2 = '{} {}'.format(gstin_details.get('AddrBnm'), gstin_details.get('AddrSt')) - email_id = address.get('email_id') - phone = address.get('phone') - if state_code == 97: - pincode = 999999 - - return frappe._dict(dict( - gstin=gstin, legal_name=legal_name, location=location, - pincode=pincode, state_code=state_code, address_line1=address_line1, - address_line2=address_line2, email=email_id, phone=phone - )) - -def get_overseas_address_details(address_name): - address_title, address_line1, address_line2, city, phone, email_id = frappe.db.get_value( - 'Address', address_name, ['address_title', 'address_line1', 'address_line2', 'city', 'phone', 'email_id'] - ) - - return frappe._dict(dict( - gstin='URP', legal_name=address_title, address_line1=address_line1, - address_line2=address_line2, email=email_id, phone=phone, - pincode=999999, state_code=96, place_of_supply=96, location=city - )) - -def get_item_list(invoice): - item_list = [] - gst_accounts = get_gst_accounts(invoice.company) - gst_accounts_list = [d for accounts in gst_accounts.values() for d in accounts if d] - - for d in invoice.items: - item_schema = read_json('einv_item_template') - item = frappe._dict({}) - item.update(d.as_dict()) - item.sr_no = d.idx - item.description = d.item_name - item.is_service_item = 'N' if frappe.db.get_value('Item', d.item_code, 'is_stock_item') else 'Y' - item.batch_expiry_date = frappe.db.get_value('Batch', d.batch_no, 'expiry_date') if d.batch_no else None - item.batch_expiry_date = format_date(item.batch_expiry_date, 'dd/mm/yyyy') if item.batch_expiry_date else None - item.qty = abs(item.qty) - item.unit_rate = abs(item.base_price_list_rate) if item.discount_amount else abs(item.base_rate) - item.total_amount = abs(item.unit_rate * item.qty) - item.discount_amount = abs(item.discount_amount * item.qty) - item.base_amount = abs(item.base_amount) - item.tax_rate = 0 - item.igst_amount = 0 - item.cgst_amount = 0 - item.sgst_amount = 0 - item.cess_rate = 0 - item.cess_amount = 0 - for t in invoice.taxes: - if t.account_head in gst_accounts_list: - item_tax_detail = json.loads(t.item_wise_tax_detail).get(item.item_code) - if t.account_head in gst_accounts.cess_account: - item.cess_rate += item_tax_detail[0] - item.cess_amount += abs(item_tax_detail[1]) - elif t.account_head in gst_accounts.igst_account: - item.tax_rate += item_tax_detail[0] - item.igst_amount += abs(item_tax_detail[1]) - elif t.account_head in gst_accounts.sgst_account: - item.tax_rate += item_tax_detail[0] - item.sgst_amount += abs(item_tax_detail[1]) - elif t.account_head in gst_accounts.cgst_account: - item.tax_rate += item_tax_detail[0] - item.cgst_amount += abs(item_tax_detail[1]) - - item.total_value = abs(item.base_amount + item.igst_amount + item.sgst_amount + item.cgst_amount + item.cess_amount) - einv_item = item_schema.format(item=item) - item_list.append(einv_item) - - return ', '.join(item_list) - -def get_value_details(invoice): - gst_accounts = get_gst_accounts(invoice.company) - gst_accounts_list = [d for accounts in gst_accounts.values() for d in accounts if d] - - value_details = frappe._dict(dict()) - value_details.base_net_total = abs(invoice.base_net_total) - value_details.invoice_discount_amt = abs(invoice.discount_amount) - value_details.round_off = 0 - value_details.base_grand_total = abs(invoice.base_rounded_total) - value_details.grand_total = abs(invoice.rounded_total) - value_details.total_cgst_amt = 0 - value_details.total_sgst_amt = 0 - value_details.total_igst_amt = 0 - value_details.total_cess_amt = 0 - for t in invoice.taxes: - if t.account_head in gst_accounts_list: - if t.account_head in gst_accounts.cess_account: - value_details.total_cess_amt += abs(t.base_tax_amount_after_discount_amount) - elif t.account_head in gst_accounts.igst_account: - value_details.total_igst_amt += abs(t.base_tax_amount_after_discount_amount) - elif t.account_head in gst_accounts.sgst_account: - value_details.total_sgst_amt += abs(t.base_tax_amount_after_discount_amount) - elif t.account_head in gst_accounts.cgst_account: - value_details.total_cgst_amt += abs(t.base_tax_amount_after_discount_amount) - - return value_details - -def get_payment_details(invoice): - payee_name = invoice.company - mode_of_payment = ', '.join([d.mode_of_payment for d in invoice.payments]) - paid_amount = invoice.base_paid_amount - outstanding_amount = invoice.outstanding_amount - - return frappe._dict(dict( - payee_name=payee_name, mode_of_payment=mode_of_payment, - paid_amount=paid_amount, outstanding_amount=outstanding_amount - )) - -def get_return_doc_reference(invoice): - invoice_date = frappe.db.get_value('Sales Invoice', invoice.return_against, 'posting_date') - return frappe._dict(dict( - invoice_name=invoice.return_against, invoice_date=format_date(invoice_date, 'dd/mm/yyyy') - )) - -def get_eway_bill_details(invoice): - if not invoice.distance: - frappe.throw(_('Distance is mandatory for E-Way Bill generation'), title=_('E Invoice Validation Failed')) - - mode_of_transport = { 'Road': '1', 'Air': '2', 'Rail': '3', 'Ship': '4' } - vehicle_type = { 'Regular': 'R', 'Over Dimensional Cargo (ODC)': 'O' } - - return frappe._dict(dict( - gstin=invoice.gst_transporter_id, - name=invoice.transporter_name, - mode_of_transport=mode_of_transport[invoice.mode_of_transport], - distance=invoice.distance, - document_name=invoice.lr_no, - document_date=format_date(invoice.lr_date, 'dd/mm/yyyy'), - vehicle_no=invoice.vehicle_no, - vehicle_type=vehicle_type[invoice.gst_vehicle_type] - )) - -@frappe.whitelist() -def make_einvoice(doctype, name): - invoice = frappe.get_doc(doctype, name) - schema = read_json('einv_template') - - item_list = get_item_list(invoice) - doc_details = get_doc_details(invoice) - value_details = get_value_details(invoice) - trans_details = get_trans_details(invoice) - seller_details = get_party_gstin_details(invoice.company_address) - - if invoice.gst_category == 'Overseas': - buyer_details = get_overseas_address_details(invoice.customer_address) - else: - buyer_details = get_party_gstin_details(invoice.customer_address) - place_of_supply = get_place_of_supply(invoice, doctype) or invoice.billing_address_gstin - place_of_supply = place_of_supply[:2] - buyer_details.update(dict(place_of_supply=place_of_supply)) - - shipping_details = payment_details = prev_doc_details = eway_bill_details = frappe._dict({}) - if invoice.shipping_address_name and invoice.customer_address != invoice.shipping_address_name: - shipping_details = get_party_gstin_details(invoice.shipping_address_name) - - if invoice.is_pos and invoice.base_paid_amount: - payment_details = get_payment_details(invoice) - - if invoice.is_return and invoice.return_against: - prev_doc_details = get_return_doc_reference(invoice) - - if invoice.transporter: - eway_bill_details = get_eway_bill_details(invoice) - - # not yet implemented - dispatch_details = period_details = export_details = frappe._dict({}) - - einvoice = schema.format( - trans_details=trans_details, doc_details=doc_details, dispatch_details=dispatch_details, - seller_details=seller_details, buyer_details=buyer_details, shipping_details=shipping_details, - item_list=item_list, value_details=value_details, payment_details=payment_details, - period_details=period_details, prev_doc_details=prev_doc_details, - export_details=export_details, eway_bill_details=eway_bill_details - ) - einvoice = json.loads(einvoice) - - validations = json.loads(read_json('einv_validation')) - errors = validate_einvoice(validations, einvoice, []) - if errors: - frappe.log_error(title="E Invoice Validation Failed", message=json.dumps(errors, default=str, indent=4)) - if len(errors) > 1: - li = ['
  • '+ d +'
  • ' for d in errors] - frappe.throw("".format(''.join(li)), title=_('E Invoice Validation Failed')) - else: - frappe.throw(errors[0], title=_('E Invoice Validation Failed')) - - return einvoice - -def validate_einvoice(validations, einvoice, errors=[]): - for fieldname, field_validation in validations.items(): - value = einvoice.get(fieldname, None) - if not value or value == "None": - # remove keys with empty values - einvoice.pop(fieldname, None) - continue - - value_type = field_validation.get("type").lower() - if value_type in ['object', 'array']: - child_validations = field_validation.get('properties') - - if isinstance(value, list): - for d in value: - validate_einvoice(child_validations, d, errors) - if not d: - # remove empty dicts - einvoice.pop(fieldname, None) - else: - validate_einvoice(child_validations, value, errors) - if not value: - # remove empty dicts - einvoice.pop(fieldname, None) - continue - - # convert to int or str - if value_type == 'string': - einvoice[fieldname] = str(value) - elif value_type == 'number': - einvoice[fieldname] = flt(value, 2) if fieldname != 'Pin' else int(value) - - max_length = field_validation.get('maxLength') - minimum = flt(field_validation.get('minimum')) - maximum = flt(field_validation.get('maximum')) - pattern_str = field_validation.get('pattern') - pattern = re.compile(pattern_str or '') - - label = field_validation.get('label') or fieldname - - if value_type == 'string' and len(value) > max_length: - errors.append(_('{} should not exceed {} characters').format(label, max_length)) - if value_type == 'number' and not (flt(value) <= maximum): - errors.append(_('{} should be less than {}').format(label, maximum)) - if pattern_str and not pattern.match(value): - errors.append(field_validation.get('validationMsg')) - - return errors - -def update_einvoice_fields(doctype, name, signed_einvoice): - enc_signed_invoice = signed_einvoice.get('SignedInvoice') - decrypted_signed_invoice = jwt_decrypt(enc_signed_invoice)['data'] - - if json.loads(decrypted_signed_invoice)['DocDtls']['No'] != name: - frappe.throw( - _("Document number of uploaded Signed E-Invoice doesn't matches with Sales Invoice"), - title=_("Inappropriate E-Invoice") - ) - - frappe.db.set_value(doctype, name, 'irn', signed_einvoice.get('Irn')) - frappe.db.set_value(doctype, name, 'ewaybill', signed_einvoice.get('EwbNo')) - frappe.db.set_value(doctype, name, 'signed_qr_code', signed_einvoice.get('SignedQRCode').split('.')[1]) - frappe.db.set_value(doctype, name, 'signed_einvoice', decrypted_signed_invoice) - -@frappe.whitelist() -def download_einvoice(): - data = frappe._dict(frappe.local.form_dict) - einvoice = data['einvoice'] - name = data['name'] - - frappe.response['filename'] = 'E-Invoice-' + name + '.json' - frappe.response['filecontent'] = einvoice - frappe.response['content_type'] = 'application/json' - frappe.response['type'] = 'download' - -@frappe.whitelist() -def upload_einvoice(): - signed_einvoice = json.loads(frappe.local.uploaded_file) - data = frappe._dict(frappe.local.form_dict) - doctype = data['doctype'] - name = data['docname'] - - update_einvoice_fields(doctype, name, signed_einvoice) - attach_qrcode_image(doctype, name) - -@frappe.whitelist() -def download_cancel_einvoice(): - data = frappe._dict(frappe.local.form_dict) - name = data['name'] - irn = data['irn'] - reason = data['reason'] - remark = data['remark'] - - cancel_einvoice = json.dumps([dict(Irn=irn, CnlRsn=reason, CnlRem=remark)]) - - frappe.response['filename'] = 'Cancel E-Invoice ' + name + '.json' - frappe.response['filecontent'] = cancel_einvoice - frappe.response['content_type'] = 'application/json' - frappe.response['type'] = 'download' - -@frappe.whitelist() -def upload_cancel_ack(): - cancel_ack = json.loads(frappe.local.uploaded_file) - data = frappe._dict(frappe.local.form_dict) - doctype = data['doctype'] - name = data['docname'] - - frappe.db.set_value(doctype, name, 'irn_cancelled', 1) - -def attach_qrcode_image(doctype, name): - qrcode = frappe.db.get_value(doctype, name, 'signed_qr_code') - - if not qrcode: return - - _file = frappe.get_doc({ - 'doctype': 'File', - 'file_name': 'Signed_QR_{name}.png'.format(name=name), - 'attached_to_doctype': doctype, - 'attached_to_name': name, - 'content': 'qrcode' - }) - _file.save() - frappe.db.commit() - url = qrcreate(qrcode) - abs_file_path = os.path.abspath(_file.get_full_path()) - url.png(abs_file_path, scale=2) - - frappe.db.set_value(doctype, name, 'qrcode_image', _file.file_url) \ No newline at end of file diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py index 4f1ca5012d1..77a466fdff7 100644 --- a/erpnext/regional/india/setup.py +++ b/erpnext/regional/india/setup.py @@ -77,7 +77,7 @@ def add_custom_roles_for_reports(): )).insert() def add_permissions(): - for doctype in ('GST HSN Code', 'GST Settings', 'GSTR 3B Report', 'Lower Deduction Certificate', 'E Invoice Settings'): + for doctype in ('GST HSN Code', 'GST Settings', 'GSTR 3B Report', 'Lower Deduction Certificate'): add_permission(doctype, 'All', 0) for role in ('Accounts Manager', 'Accounts User', 'System Manager'): add_permission(doctype, role, 0) @@ -93,10 +93,9 @@ def add_permissions(): 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', 'GST E-Invoice') """) + name in('GST POS Invoice', 'GST Tax Invoice') """) def make_custom_fields(update=True): hsn_sac_field = dict(fieldname='gst_hsn_code', label='HSN/SAC', @@ -370,30 +369,13 @@ def make_custom_fields(update=True): 'fieldname': 'ewaybill', 'label': 'e-Way Bill No.', 'fieldtype': 'Data', - 'depends_on': 'eval:((doc.docstatus === 1 || doc.ewaybill) && doc.eway_bill_cancelled === 0)', + 'depends_on': 'eval:(doc.docstatus === 1)', '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='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', @@ -406,7 +388,7 @@ def make_custom_fields(update=True): '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 + si_einvoice_fields, + 'Sales Invoice': sales_invoice_gst_category + invoice_gst_fields + sales_invoice_shipping_fields + sales_invoice_gst_fields + si_ewaybill_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, diff --git a/requirements.txt b/requirements.txt index 20e43c44948..f807fa6c29d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,4 +8,3 @@ PyGithub==1.44.1 python-stdnum==1.12 Unidecode==1.1.1 WooCommerce==2.1.1 -pycryptodome==3.9.8 \ No newline at end of file