refactor: remove India specific code

This commit is contained in:
Sagar Vora 2022-02-19 16:58:36 +05:30
parent 83a60a2a17
commit 3936d8b70e
159 changed files with 25 additions and 71825 deletions

View File

@ -1 +0,0 @@
C Form (India specific only) - Will be deprecated.

View File

@ -1,43 +0,0 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
//c-form js file
// -----------------------------
frappe.ui.form.on('C-Form', {
setup(frm) {
frm.fields_dict.invoices.grid.get_field("invoice_no").get_query = function(doc) {
return {
filters: {
"docstatus": 1,
"customer": doc.customer,
"company": doc.company,
"c_form_applicable": 'Yes',
"c_form_no": ''
}
};
}
frm.fields_dict.state.get_query = function() {
return {
filters: {
country: "India"
}
};
}
}
});
frappe.ui.form.on('C-Form Invoice Detail', {
invoice_no(frm, cdt, cdn) {
let d = frappe.get_doc(cdt, cdn);
if (d.invoice_no) {
frm.call('get_invoice_details', {
invoice_no: d.invoice_no
}).then(r => {
frappe.model.set_value(cdt, cdn, r.message);
});
}
}
});

View File

@ -1,511 +0,0 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 1,
"allow_rename": 0,
"autoname": "naming_series:",
"beta": 0,
"creation": "2013-03-07 11:55:06",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"editable_grid": 0,
"fields": [
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "",
"fieldname": "naming_series",
"fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Series",
"length": 0,
"no_copy": 0,
"options": "ACC-CF-.YYYY.-",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 1,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "c_form_no",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "C-Form No",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "received_date",
"fieldtype": "Date",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Received Date",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "customer",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Customer",
"length": 0,
"no_copy": 0,
"options": "Customer",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break1",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"print_width": "50%",
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0,
"width": "50%"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "company",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 1,
"label": "Company",
"length": 0,
"no_copy": 0,
"options": "Company",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "quarter",
"fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 1,
"label": "Quarter",
"length": 0,
"no_copy": 0,
"options": "\nI\nII\nIII\nIV",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "total_amount",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Total Amount",
"length": 0,
"no_copy": 0,
"options": "Company:company:default_currency",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "state",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "State",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "section_break0",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "invoices",
"fieldtype": "Table",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Invoices",
"length": 0,
"no_copy": 0,
"options": "C-Form Invoice Detail",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "total_invoiced_amount",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Total Invoiced Amount",
"length": 0,
"no_copy": 0,
"options": "Company:company:default_currency",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "amended_from",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 1,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Amended From",
"length": 0,
"no_copy": 1,
"options": "C-Form",
"permlevel": 0,
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"icon": "fa fa-file-text",
"idx": 1,
"image_view": 0,
"in_create": 0,
"is_submittable": 1,
"issingle": 0,
"istable": 0,
"max_attachments": 3,
"modified": "2018-08-21 14:44:30.558767",
"modified_by": "Administrator",
"module": "Accounts",
"name": "C-Form",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"cancel": 0,
"create": 1,
"delete": 0,
"email": 1,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts User",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
},
{
"amend": 0,
"cancel": 0,
"create": 1,
"delete": 0,
"email": 1,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
},
{
"amend": 0,
"cancel": 0,
"create": 0,
"delete": 0,
"email": 0,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 1,
"print": 0,
"read": 1,
"report": 1,
"role": "All",
"set_user_permissions": 0,
"share": 0,
"submit": 0,
"write": 0
}
],
"quick_entry": 0,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_order": "DESC",
"timeline_field": "customer",
"track_changes": 0,
"track_seen": 0,
"track_views": 0
}

View File

@ -1,72 +0,0 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
import frappe
from frappe import _
from frappe.model.document import Document
from frappe.utils import flt
class CForm(Document):
def validate(self):
"""Validate invoice that c-form is applicable
and no other c-form is received for that"""
for d in self.get('invoices'):
if d.invoice_no:
inv = frappe.db.sql("""select c_form_applicable, c_form_no from
`tabSales Invoice` where name = %s and docstatus = 1""", d.invoice_no)
if inv and inv[0][0] != 'Yes':
frappe.throw(_("C-form is not applicable for Invoice: {0}").format(d.invoice_no))
elif inv and inv[0][1] and inv[0][1] != self.name:
frappe.throw(_("""Invoice {0} is tagged in another C-form: {1}.
If you want to change C-form no for this invoice,
please remove invoice no from the previous c-form and then try again"""\
.format(d.invoice_no, inv[0][1])))
elif not inv:
frappe.throw(_("Row {0}: Invoice {1} is invalid, it might be cancelled / does not exist. \
Please enter a valid Invoice".format(d.idx, d.invoice_no)))
def on_update(self):
""" Update C-Form No on invoices"""
self.set_total_invoiced_amount()
def on_submit(self):
self.set_cform_in_sales_invoices()
def before_cancel(self):
# remove cform reference
frappe.db.sql("""update `tabSales Invoice` set c_form_no=null where c_form_no=%s""", self.name)
def set_cform_in_sales_invoices(self):
inv = [d.invoice_no for d in self.get('invoices')]
if inv:
frappe.db.sql("""update `tabSales Invoice` set c_form_no=%s, modified=%s where name in (%s)""" %
('%s', '%s', ', '.join(['%s'] * len(inv))), tuple([self.name, self.modified] + inv))
frappe.db.sql("""update `tabSales Invoice` set c_form_no = null, modified = %s
where name not in (%s) and ifnull(c_form_no, '') = %s""" %
('%s', ', '.join(['%s']*len(inv)), '%s'), tuple([self.modified] + inv + [self.name]))
else:
frappe.throw(_("Please enter atleast 1 invoice in the table"))
def set_total_invoiced_amount(self):
total = sum(flt(d.grand_total) for d in self.get('invoices'))
frappe.db.set(self, 'total_invoiced_amount', total)
@frappe.whitelist()
def get_invoice_details(self, invoice_no):
""" Pull details from invoices for referrence """
if invoice_no:
inv = frappe.db.get_value("Sales Invoice", invoice_no,
["posting_date", "territory", "base_net_total", "base_grand_total"], as_dict=True)
return {
'invoice_date' : inv.posting_date,
'territory' : inv.territory,
'net_total' : inv.base_net_total,
'grand_total' : inv.base_grand_total
}

View File

@ -1,9 +0,0 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
import unittest
# test_records = frappe.get_test_records('C-Form')
class TestCForm(unittest.TestCase):
pass

View File

@ -1 +0,0 @@
Invoice detail for parent C-Form.

View File

@ -1,168 +0,0 @@
{
"allow_copy": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
"creation": "2013-02-22 01:27:38",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"editable_grid": 1,
"fields": [
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "invoice_no",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Invoice No",
"length": 0,
"no_copy": 0,
"options": "Sales Invoice",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"print_width": "160px",
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0,
"width": "160px"
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "invoice_date",
"fieldtype": "Date",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Invoice Date",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"print_width": "120px",
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0,
"width": "120px"
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"description": "",
"fieldname": "territory",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Territory",
"length": 0,
"no_copy": 0,
"options": "Territory",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"print_width": "120px",
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0,
"width": "120px"
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "net_total",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Net Total",
"length": 0,
"no_copy": 0,
"options": "Company:company:default_currency",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"print_width": "120px",
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0,
"width": "120px"
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "grand_total",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Grand Total",
"length": 0,
"no_copy": 0,
"options": "Company:company:default_currency",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"print_width": "120px",
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0,
"width": "120px"
}
],
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 1,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2016-07-11 03:27:58.768719",
"modified_by": "Administrator",
"module": "Accounts",
"name": "C-Form Invoice Detail",
"owner": "Administrator",
"permissions": [],
"quick_entry": 0,
"read_only": 0,
"read_only_onload": 0,
"track_seen": 0
}

View File

@ -1,9 +0,0 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from frappe.model.document import Document
class CFormInvoiceDetail(Document):
pass

View File

@ -27,7 +27,6 @@ def test_create_test_data():
"item_name": "_Test Tesla Car",
"apply_warehouse_wise_reorder_level": 0,
"warehouse":"Stores - _TC",
"gst_hsn_code": "999800",
"valuation_rate": 5000,
"standard_rate":5000,
"item_defaults": [{

View File

@ -1,82 +0,0 @@
{
"actions": [],
"creation": "2018-01-02 15:48:58.768352",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"company",
"cgst_account",
"sgst_account",
"igst_account",
"cess_account",
"is_reverse_charge_account"
],
"fields": [
{
"columns": 1,
"fieldname": "company",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Company",
"options": "Company",
"reqd": 1
},
{
"columns": 2,
"fieldname": "cgst_account",
"fieldtype": "Link",
"in_list_view": 1,
"label": "CGST Account",
"options": "Account",
"reqd": 1
},
{
"columns": 2,
"fieldname": "sgst_account",
"fieldtype": "Link",
"in_list_view": 1,
"label": "SGST Account",
"options": "Account",
"reqd": 1
},
{
"columns": 2,
"fieldname": "igst_account",
"fieldtype": "Link",
"in_list_view": 1,
"label": "IGST Account",
"options": "Account",
"reqd": 1
},
{
"columns": 2,
"fieldname": "cess_account",
"fieldtype": "Link",
"in_list_view": 1,
"label": "CESS Account",
"options": "Account"
},
{
"columns": 1,
"default": "0",
"fieldname": "is_reverse_charge_account",
"fieldtype": "Check",
"in_list_view": 1,
"label": "Is Reverse Charge Account"
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2021-04-09 12:30:25.889993",
"modified_by": "Administrator",
"module": "Accounts",
"name": "GST Account",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}

View File

@ -1,9 +0,0 @@
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from frappe.model.document import Document
class GSTAccount(Document):
pass

View File

@ -1,17 +0,0 @@
frappe.ui.form.on("Journal Entry", {
refresh: function(frm) {
frm.set_query('company_address', function(doc) {
if(!doc.company) {
frappe.throw(__('Please set Company'));
}
return {
query: 'frappe.contacts.doctype.address.address.address_query',
filters: {
link_doctype: 'Company',
link_name: doc.company
}
};
});
}
});

View File

@ -1,29 +0,0 @@
frappe.ui.form.on("Payment Entry", {
company: function(frm) {
frappe.call({
'method': 'frappe.contacts.doctype.address.address.get_default_address',
'args': {
'doctype': 'Company',
'name': frm.doc.company
},
'callback': function(r) {
frm.set_value('company_address', r.message);
}
});
},
party: function(frm) {
if (frm.doc.party_type == "Customer" && frm.doc.party) {
frappe.call({
'method': 'frappe.contacts.doctype.address.address.get_default_address',
'args': {
'doctype': 'Customer',
'name': frm.doc.party
},
'callback': function(r) {
frm.set_value('customer_address', r.message);
}
});
}
}
});

View File

@ -164,8 +164,6 @@
"debit_to",
"party_account_currency",
"is_opening",
"c_form_applicable",
"c_form_no",
"column_break8",
"remarks",
"sales_team_section_break",
@ -1400,23 +1398,6 @@
"options": "No\nYes",
"print_hide": 1
},
{
"fieldname": "c_form_applicable",
"fieldtype": "Select",
"label": "C-Form Applicable",
"no_copy": 1,
"options": "No\nYes",
"print_hide": 1
},
{
"fieldname": "c_form_no",
"fieldtype": "Link",
"label": "C-Form No",
"no_copy": 1,
"options": "C-Form",
"print_hide": 1,
"read_only": 1
},
{
"fieldname": "column_break8",
"fieldtype": "Column Break",
@ -1573,7 +1554,7 @@
"icon": "fa fa-file-text",
"is_submittable": 1,
"links": [],
"modified": "2021-10-05 12:11:53.871828",
"modified": "2022-02-19 06:25:00.983936",
"modified_by": "Administrator",
"module": "Accounts",
"name": "POS Invoice",
@ -1623,6 +1604,7 @@
"show_name_in_global_search": 1,
"sort_field": "modified",
"sort_order": "DESC",
"states": [],
"timeline_field": "customer",
"title_field": "title",
"track_changes": 1,

View File

@ -1,3 +0,0 @@
{% include "erpnext/regional/india/taxes.js" %}
erpnext.setup_auto_gst_taxation('Purchase Invoice');

View File

@ -1,53 +0,0 @@
{% 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) {
frm.set_query('transporter', function() {
return {
filters: {
'is_transporter': 1
}
};
});
frm.set_query('driver', function(doc) {
return {
filters: {
'transporter': doc.transporter
}
};
});
},
refresh: function(frm) {
if(frm.doc.docstatus == 1 && !frm.is_dirty()
&& !frm.doc.is_return && !frm.doc.ewaybill) {
frm.add_custom_button('E-Way Bill JSON', () => {
frappe.call({
method: 'erpnext.regional.india.utils.generate_ewb_json',
args: {
'dt': frm.doc.doctype,
'dn': [frm.doc.name]
},
callback: function(r) {
if (r.message) {
const args = {
cmd: 'erpnext.regional.india.utils.download_ewb_json',
data: r.message,
docname: frm.doc.name
};
open_url_post(frappe.request.url, args);
}
}
});
}, __("Create"));
}
}
});

View File

@ -1,174 +0,0 @@
var globalOnload = frappe.listview_settings['Sales Invoice'].onload;
frappe.listview_settings['Sales Invoice'].onload = function (list_view) {
// Provision in case onload event is added to sales_invoice.js in future
if (globalOnload) {
globalOnload(list_view);
}
const action = () => {
const selected_docs = list_view.get_checked_items();
const docnames = list_view.get_checked_items(true);
for (let doc of selected_docs) {
if (doc.docstatus !== 1) {
frappe.throw(__("E-Way Bill JSON can only be generated from a submitted document"));
}
}
frappe.call({
method: 'erpnext.regional.india.utils.generate_ewb_json',
args: {
'dt': list_view.doctype,
'dn': docnames
},
callback: function(r) {
if (r.message) {
const args = {
cmd: 'erpnext.regional.india.utils.download_ewb_json',
data: r.message,
docname: docnames
};
open_url_post(frappe.request.url, args);
}
}
});
};
list_view.page.add_actions_menu_item(__('Generate E-Way Bill JSON'), action, false);
const generate_irns = () => {
const docnames = list_view.get_checked_items(true);
if (docnames && docnames.length) {
frappe.call({
method: 'erpnext.regional.india.e_invoice.utils.generate_einvoices',
args: { docnames },
freeze: true,
freeze_message: __('Generating E-Invoices...')
});
} else {
frappe.msgprint({
message: __('Please select at least one sales invoice to generate IRN'),
title: __('No Invoice Selected'),
indicator: 'red'
});
}
};
const cancel_irns = () => {
const docnames = list_view.get_checked_items(true);
const 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
}
];
const d = new frappe.ui.Dialog({
title: __("Cancel IRN"),
fields: fields,
primary_action: function() {
const data = d.get_values();
frappe.call({
method: 'erpnext.regional.india.e_invoice.utils.cancel_irns',
args: {
doctype: list_view.doctype,
docnames,
reason: data.reason.split('-')[0],
remark: data.remark
},
freeze: true,
freeze_message: __('Cancelling E-Invoices...'),
});
d.hide();
},
primary_action_label: __('Submit')
});
d.show();
};
let einvoicing_enabled = false;
frappe.db.get_single_value("E Invoice Settings", "enable").then(enabled => {
einvoicing_enabled = enabled;
});
list_view.$result.on("change", "input[type=checkbox]", () => {
if (einvoicing_enabled) {
const docnames = list_view.get_checked_items(true);
// show/hide e-invoicing actions when no sales invoices are checked
if (docnames && docnames.length) {
// prevent adding actions twice if e-invoicing action group already exists
if (list_view.page.get_inner_group_button(__('E-Invoicing')).length == 0) {
list_view.page.add_inner_button(__('Generate IRNs'), generate_irns, __('E-Invoicing'));
list_view.page.add_inner_button(__('Cancel IRNs'), cancel_irns, __('E-Invoicing'));
}
} else {
list_view.page.remove_inner_button(__('Generate IRNs'), __('E-Invoicing'));
list_view.page.remove_inner_button(__('Cancel IRNs'), __('E-Invoicing'));
}
}
});
frappe.realtime.on("bulk_einvoice_generation_complete", (data) => {
const { failures, user, invoices } = data;
if (invoices.length != failures.length) {
frappe.msgprint({
message: __('{0} e-invoices generated successfully', [invoices.length]),
title: __('Bulk E-Invoice Generation Complete'),
indicator: 'orange'
});
}
if (failures && failures.length && user == frappe.session.user) {
let message = `
Failed to generate IRNs for following ${failures.length} sales invoices:
<ul style="padding-left: 20px; padding-top: 5px;">
${failures.map(d => `<li>${d.docname}</li>`).join('')}
</ul>
`;
frappe.msgprint({
message: message,
title: __('Bulk E-Invoice Generation Complete'),
indicator: 'orange'
});
}
});
frappe.realtime.on("bulk_einvoice_cancellation_complete", (data) => {
const { failures, user, invoices } = data;
if (invoices.length != failures.length) {
frappe.msgprint({
message: __('{0} e-invoices cancelled successfully', [invoices.length]),
title: __('Bulk E-Invoice Cancellation Complete'),
indicator: 'orange'
});
}
if (failures && failures.length && user == frappe.session.user) {
let message = `
Failed to cancel IRNs for following ${failures.length} sales invoices:
<ul style="padding-left: 20px; padding-top: 5px;">
${failures.map(d => `<li>${d.docname}</li>`).join('')}
</ul>
`;
frappe.msgprint({
message: message,
title: __('Bulk E-Invoice Cancellation Complete'),
indicator: 'orange'
});
}
});
};

View File

@ -779,10 +779,6 @@ frappe.ui.form.on('Sales Invoice', {
}
}
// India related fields
if (frappe.boot.sysdefaults.country == 'India') unhide_field(['c_form_applicable', 'c_form_no']);
else hide_field(['c_form_applicable', 'c_form_no']);
frm.refresh_fields();
},

View File

@ -174,8 +174,6 @@
"debit_to",
"party_account_currency",
"is_opening",
"c_form_applicable",
"c_form_no",
"column_break8",
"unrealized_profit_loss_account",
"remarks",
@ -651,7 +649,6 @@
"hide_seconds": 1,
"label": "Ignore Pricing Rule",
"no_copy": 1,
"permlevel": 0,
"print_hide": 1
},
{
@ -1717,28 +1714,6 @@
"options": "No\nYes",
"print_hide": 1
},
{
"fieldname": "c_form_applicable",
"fieldtype": "Select",
"hide_days": 1,
"hide_seconds": 1,
"label": "C-Form Applicable",
"length": 4,
"no_copy": 1,
"options": "No\nYes",
"print_hide": 1
},
{
"fieldname": "c_form_no",
"fieldtype": "Link",
"hide_days": 1,
"hide_seconds": 1,
"label": "C-Form No",
"no_copy": 1,
"options": "C-Form",
"print_hide": 1,
"read_only": 1
},
{
"fieldname": "column_break8",
"fieldtype": "Column Break",
@ -2038,7 +2013,7 @@
"link_fieldname": "consolidated_invoice"
}
],
"modified": "2021-12-23 20:19:38.667508",
"modified": "2022-02-19 06:25:10.079943",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice",
@ -2089,6 +2064,7 @@
"show_name_in_global_search": 1,
"sort_field": "modified",
"sort_order": "DESC",
"states": [],
"timeline_field": "customer",
"title_field": "title",
"track_changes": 1,

View File

@ -135,7 +135,6 @@ class SalesInvoice(SellingController):
self.loyalty_redemption_cost_center = lp.cost_center if not self.loyalty_redemption_cost_center else self.loyalty_redemption_cost_center
self.set_against_income_account()
self.validate_c_form()
self.validate_time_sheets_are_submitted()
self.validate_multiple_billing("Delivery Note", "dn_detail", "amount", "items")
if not self.is_return:
@ -318,8 +317,6 @@ class SalesInvoice(SellingController):
self.update_billing_status_for_zero_amount_refdoc("Sales Order")
self.update_serial_no(in_cancel=True)
self.validate_c_form_on_cancel()
# Updating stock ledger should always be called after updating prevdoc status,
# because updating reserved qty in bin depends upon updated delivered qty in SO
if self.update_stock == 1:
@ -701,20 +698,6 @@ class SalesInvoice(SellingController):
if flt(self.change_amount) and not self.account_for_change_amount:
msgprint(_("Please enter Account for Change Amount"), raise_exception=1)
def validate_c_form(self):
""" Blank C-form no if C-form applicable marked as 'No'"""
if self.amended_from and self.c_form_applicable == 'No' and self.c_form_no:
frappe.db.sql("""delete from `tabC-Form Invoice Detail` where invoice_no = %s
and parent = %s""", (self.amended_from, self.c_form_no))
frappe.db.set(self, 'c_form_no', '')
def validate_c_form_on_cancel(self):
""" Display message if C-Form no exists on cancellation of Sales Invoice"""
if self.c_form_applicable == 'Yes' and self.c_form_no:
msgprint(_("Please remove this Invoice {0} from C-Form {1}")
.format(self.name, self.c_form_no), raise_exception = 1)
def validate_dropship_item(self):
for item in self.items:
if item.sales_order:
@ -1265,9 +1248,7 @@ class SalesInvoice(SellingController):
frappe.get_doc("Delivery Note", dn).update_billing_percentage(update_modified=update_modified)
def on_recurring(self, reference_doc, auto_repeat_doc):
for fieldname in ("c_form_applicable", "c_form_no", "write_off_amount"):
self.set(fieldname, reference_doc.get(fieldname))
self.set("write_off_amount", reference_doc.get("write_off_amount"))
self.due_date = None
def update_serial_no(self, in_cancel=False):

View File

@ -23,7 +23,6 @@ from erpnext.assets.doctype.asset.test_asset import create_asset, create_asset_d
from erpnext.controllers.accounts_controller import update_invoice_status
from erpnext.controllers.taxes_and_totals import get_itemised_tax_breakup_data
from erpnext.exceptions import InvalidAccountCurrency, InvalidCurrency
from erpnext.regional.india.utils import get_ewb_data
from erpnext.stock.doctype.delivery_note.delivery_note import make_sales_invoice
from erpnext.stock.doctype.item.test_item import create_item
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt
@ -1412,37 +1411,7 @@ class TestSalesInvoice(unittest.TestCase):
for i, k in enumerate(expected_values["keys"]):
self.assertEqual(d.get(k), expected_values[d.item_code][i])
def test_item_wise_tax_breakup_india(self):
frappe.flags.country = "India"
si = self.create_si_to_test_tax_breakup()
itemised_tax, itemised_taxable_amount = get_itemised_tax_breakup_data(si)
expected_itemised_tax = {
"_Test Item": {
"Service Tax": {
"tax_rate": 10.0,
"tax_amount": 1000.0
}
},
"_Test Item 2": {
"Service Tax": {
"tax_rate": 10.0,
"tax_amount": 500.0
}
}
}
expected_itemised_taxable_amount = {
"_Test Item": 10000.0,
"_Test Item 2": 5000.0
}
self.assertEqual(itemised_tax, expected_itemised_tax)
self.assertEqual(itemised_taxable_amount, expected_itemised_taxable_amount)
frappe.flags.country = None
def test_item_wise_tax_breakup_outside_india(self):
def test_item_wise_tax_breakup(self):
frappe.flags.country = "United States"
si = self.create_si_to_test_tax_breakup()
@ -1477,7 +1446,6 @@ class TestSalesInvoice(unittest.TestCase):
si = create_sales_invoice(qty=100, rate=50, do_not_save=True)
si.append("items", {
"item_code": "_Test Item",
"gst_hsn_code": "999800",
"warehouse": "_Test Warehouse - _TC",
"qty": 100,
"rate": 50,
@ -1487,7 +1455,6 @@ class TestSalesInvoice(unittest.TestCase):
})
si.append("items", {
"item_code": "_Test Item 2",
"gst_hsn_code": "999800",
"warehouse": "_Test Warehouse - _TC",
"qty": 100,
"rate": 50,
@ -1556,7 +1523,6 @@ class TestSalesInvoice(unittest.TestCase):
for rate in [400, 600, 100]:
si.append("items", {
"item_code": "_Test Item",
"gst_hsn_code": "999800",
"warehouse": "_Test Warehouse - _TC",
"qty": 1,
"rate": rate,
@ -2080,74 +2046,6 @@ class TestSalesInvoice(unittest.TestCase):
check_gl_entries(self, target_doc.name, pi_gl_entries, add_days(nowdate(), -1))
def test_eway_bill_json(self):
si = make_sales_invoice_for_ewaybill()
si.submit()
data = get_ewb_data("Sales Invoice", [si.name])
self.assertEqual(data['version'], '1.0.0421')
self.assertEqual(data['billLists'][0]['fromGstin'], '27AAECE4835E1ZR')
self.assertEqual(data['billLists'][0]['fromTrdName'], '_Test Company')
self.assertEqual(data['billLists'][0]['toTrdName'], '_Test Customer')
self.assertEqual(data['billLists'][0]['vehicleType'], 'R')
self.assertEqual(data['billLists'][0]['totalValue'], 60000)
self.assertEqual(data['billLists'][0]['cgstValue'], 5400)
self.assertEqual(data['billLists'][0]['sgstValue'], 5400)
self.assertEqual(data['billLists'][0]['vehicleNo'], 'KA12KA1234')
self.assertEqual(data['billLists'][0]['itemList'][0]['taxableAmount'], 60000)
self.assertEqual(data['billLists'][0]['actualFromStateCode'],7)
self.assertEqual(data['billLists'][0]['fromStateCode'],27)
def test_einvoice_submission_without_irn(self):
# init
einvoice_settings = frappe.get_doc('E Invoice Settings')
einvoice_settings.enable = 1
einvoice_settings.applicable_from = nowdate()
einvoice_settings.append('credentials', {
'company': '_Test Company',
'gstin': '27AAECE4835E1ZR',
'username': 'test',
'password': 'test'
})
einvoice_settings.save()
country = frappe.flags.country
frappe.flags.country = 'India'
si = make_sales_invoice_for_ewaybill()
self.assertRaises(frappe.ValidationError, si.submit)
si.irn = 'test_irn'
si.submit()
# reset
einvoice_settings = frappe.get_doc('E Invoice Settings')
einvoice_settings.enable = 0
frappe.flags.country = country
def test_einvoice_json(self):
from erpnext.regional.india.e_invoice.utils import make_einvoice, validate_totals
si = get_sales_invoice_for_e_invoice()
si.discount_amount = 100
si.save()
einvoice = make_einvoice(si)
self.assertTrue(einvoice['EwbDtls'])
validate_totals(einvoice)
si.apply_discount_on = 'Net Total'
si.save()
einvoice = make_einvoice(si)
validate_totals(einvoice)
[d.set('included_in_print_rate', 1) for d in si.taxes]
si.save()
einvoice = make_einvoice(si)
validate_totals(einvoice)
def test_item_tax_net_range(self):
item = create_item("T Shirt")
@ -2585,164 +2483,6 @@ def get_sales_invoice_for_e_invoice():
return si
def make_test_address_for_ewaybill():
if not frappe.db.exists('Address', '_Test Address for Eway bill-Billing'):
address = frappe.get_doc({
"address_line1": "_Test Address Line 1",
"address_line2": "_Test Address Line 2",
"address_title": "_Test Address for Eway bill",
"address_type": "Billing",
"city": "_Test City",
"state": "Test State",
"country": "India",
"doctype": "Address",
"is_primary_address": 1,
"phone": "+910000000000",
"gstin": "27AAECE4835E1ZR",
"gst_state": "Maharashtra",
"gst_state_number": "27",
"pincode": "401108"
}).insert()
address.append("links", {
"link_doctype": "Company",
"link_name": "_Test Company"
})
address.save()
if not frappe.db.exists('Address', '_Test Customer-Address for Eway bill-Billing'):
address = frappe.get_doc({
"address_line1": "_Test Address Line 1",
"address_line2": "_Test Address Line 2",
"address_title": "_Test Customer-Address for Eway bill",
"address_type": "Billing",
"city": "_Test City",
"state": "Test State",
"country": "India",
"doctype": "Address",
"is_primary_address": 1,
"phone": "+910000000000",
"gstin": "27AACCM7806M1Z3",
"gst_state": "Maharashtra",
"gst_state_number": "27",
"pincode": "410038"
}).insert()
address.append("links", {
"link_doctype": "Customer",
"link_name": "_Test Customer"
})
address.save()
if not frappe.db.exists('Address', '_Test Customer-Address for Eway bill-Shipping'):
address = frappe.get_doc({
"address_line1": "_Test Address Line 1",
"address_line2": "_Test Address Line 2",
"address_title": "_Test Customer-Address for Eway bill",
"address_type": "Shipping",
"city": "_Test City",
"state": "Test State",
"country": "India",
"doctype": "Address",
"is_primary_address": 1,
"phone": "+910000000000",
"gst_state": "Maharashtra",
"gst_state_number": "27",
"pincode": "410098"
}).insert()
address.append("links", {
"link_doctype": "Customer",
"link_name": "_Test Customer"
})
address.save()
if not frappe.db.exists('Address', '_Test Dispatch-Address for Eway bill-Shipping'):
address = frappe.get_doc({
"address_line1": "_Test Dispatch Address Line 1",
"address_line2": "_Test Dispatch Address Line 2",
"address_title": "_Test Dispatch-Address for Eway bill",
"address_type": "Shipping",
"city": "_Test City",
"state": "Test State",
"country": "India",
"doctype": "Address",
"is_primary_address": 0,
"phone": "+910000000000",
"gstin": "07AAACC1206D1ZI",
"gst_state": "Delhi",
"gst_state_number": "07",
"pincode": "1100101"
}).insert()
address.save()
def make_test_transporter_for_ewaybill():
if not frappe.db.exists('Supplier', '_Test Transporter'):
frappe.get_doc({
"doctype": "Supplier",
"supplier_name": "_Test Transporter",
"country": "India",
"supplier_group": "_Test Supplier Group",
"supplier_type": "Company",
"is_transporter": 1
}).insert()
def make_sales_invoice_for_ewaybill():
make_test_address_for_ewaybill()
make_test_transporter_for_ewaybill()
gst_settings = frappe.get_doc("GST Settings")
gst_account = frappe.get_all(
"GST Account",
fields=["cgst_account", "sgst_account", "igst_account"],
filters = {"company": "_Test Company"}
)
if not gst_account:
gst_settings.append("gst_accounts", {
"company": "_Test Company",
"cgst_account": "Output Tax CGST - _TC",
"sgst_account": "Output Tax SGST - _TC",
"igst_account": "Output Tax IGST - _TC",
})
gst_settings.save()
si = create_sales_invoice(do_not_save=1, rate='60000')
si.distance = 2000
si.company_address = "_Test Address for Eway bill-Billing"
si.customer_address = "_Test Customer-Address for Eway bill-Billing"
si.shipping_address_name = "_Test Customer-Address for Eway bill-Shipping"
si.dispatch_address_name = "_Test Dispatch-Address for Eway bill-Shipping"
si.vehicle_no = "KA12KA1234"
si.gst_category = "Registered Regular"
si.mode_of_transport = 'Road'
si.transporter = '_Test Transporter'
si.append("taxes", {
"charge_type": "On Net Total",
"account_head": "Output Tax CGST - _TC",
"cost_center": "Main - _TC",
"description": "CGST @ 9.0",
"rate": 9
})
si.append("taxes", {
"charge_type": "On Net Total",
"account_head": "Output Tax SGST - _TC",
"cost_center": "Main - _TC",
"description": "SGST @ 9.0",
"rate": 9
})
return si
def check_gl_entries(doc, voucher_no, expected_gle, posting_date):
gl_entries = frappe.db.sql("""select account, debit, credit, posting_date
from `tabGL Entry`
@ -2778,7 +2518,6 @@ def create_sales_invoice(**args):
"item_code": args.item or args.item_code or "_Test Item",
"item_name": args.item_name or "_Test Item",
"description": args.description or "_Test Item",
"gst_hsn_code": "999800",
"warehouse": args.warehouse or "_Test Warehouse - _TC",
"qty": args.qty or 1,
"uom": args.uom or "Nos",
@ -2827,7 +2566,6 @@ def create_sales_invoice_against_cost_center(**args):
si.append("items", {
"item_code": args.item or args.item_code or "_Test Item",
"gst_hsn_code": "999800",
"warehouse": args.warehouse or "_Test Warehouse - _TC",
"qty": args.qty or 1,
"rate": args.rate or 100,

View File

@ -1,173 +0,0 @@
{%- from "templates/print_formats/standard_macros.html" import add_header, render_field, print_value -%}
{%- set einvoice = json.loads(doc.signed_einvoice) -%}
<div class="page-break">
<div {% if print_settings.repeat_header_footer %} id="header-html" class="hidden-pdf" {% endif %}>
{% if letter_head and not no_letterhead %}
<div class="letter-head">{{ letter_head }}</div>
{% endif %}
<div class="print-heading">
<h2>E Invoice<br><small>{{ doc.name }}</small></h2>
</div>
</div>
{% if print_settings.repeat_header_footer %}
<div id="footer-html" class="visible-pdf">
{% if not no_letterhead and footer %}
<div class="letter-head-footer">
{{ footer }}
</div>
{% endif %}
<p class="text-center small page-number visible-pdf">
{{ _("Page {0} of {1}").format('<span class="page"></span>', '<span class="topage"></span>') }}
</p>
</div>
{% endif %}
<h5 class="font-bold" style="margin-top: 0px;">1. Transaction Details</h5>
<div class="row section-break" style="border-bottom: 1px solid #d1d8dd; padding-bottom: 10px;">
<div class="col-xs-8 column-break">
<div class="row data-field">
<div class="col-xs-4"><label>IRN</label></div>
<div class="col-xs-8 value">{{ einvoice.Irn }}</div>
</div>
<div class="row data-field">
<div class="col-xs-4"><label>Ack. No</label></div>
<div class="col-xs-8 value">{{ einvoice.AckNo }}</div>
</div>
<div class="row data-field">
<div class="col-xs-4"><label>Ack. Date</label></div>
<div class="col-xs-8 value">{{ frappe.utils.format_datetime(einvoice.AckDt, "dd/MM/yyyy hh:mm:ss") }}</div>
</div>
<div class="row data-field">
<div class="col-xs-4"><label>Category</label></div>
<div class="col-xs-8 value">{{ einvoice.TranDtls.SupTyp }}</div>
</div>
<div class="row data-field">
<div class="col-xs-4"><label>Document Type</label></div>
<div class="col-xs-8 value">{{ einvoice.DocDtls.Typ }}</div>
</div>
<div class="row data-field">
<div class="col-xs-4"><label>Document No</label></div>
<div class="col-xs-8 value">{{ einvoice.DocDtls.No }}</div>
</div>
</div>
<div class="col-xs-4 column-break">
<img src="{{ doc.qrcode_image }}" width="175px" style="float: right;">
</div>
</div>
<h5 class="font-bold" style="margin-top: 15px; margin-bottom: 10px;">2. Party Details</h5>
<div class="row section-break" style="border-bottom: 1px solid #d1d8dd; padding-bottom: 10px;">
{%- set seller = einvoice.SellerDtls -%}
<div class="col-xs-6 column-break">
<h5 style="margin-bottom: 5px;">Seller</h5>
<p>{{ seller.Gstin }}</p>
<p>{{ seller.LglNm }}</p>
<p>{{ seller.Addr1 }}</p>
{%- if seller.Addr2 -%} <p>{{ seller.Addr2 }}</p> {% endif %}
<p>{{ seller.Loc }}</p>
<p>{{ frappe.db.get_value("Address", doc.company_address, "gst_state") }} - {{ seller.Pin }}</p>
{%- if einvoice.ShipDtls -%}
{%- set shipping = einvoice.ShipDtls -%}
<h5 style="margin-bottom: 5px;">Shipped From</h5>
<p>{{ shipping.Gstin }}</p>
<p>{{ shipping.LglNm }}</p>
<p>{{ shipping.Addr1 }}</p>
{%- if shipping.Addr2 -%} <p>{{ shipping.Addr2 }}</p> {% endif %}
<p>{{ shipping.Loc }}</p>
<p>{{ frappe.db.get_value("Address", doc.shipping_address_name, "gst_state") }} - {{ shipping.Pin }}</p>
{% endif %}
</div>
{%- set buyer = einvoice.BuyerDtls -%}
<div class="col-xs-6 column-break">
<h5 style="margin-bottom: 5px;">Buyer</h5>
<p>{{ buyer.Gstin }}</p>
<p>{{ buyer.LglNm }}</p>
<p>{{ buyer.Addr1 }}</p>
{%- if buyer.Addr2 -%} <p>{{ buyer.Addr2 }}</p> {% endif %}
<p>{{ buyer.Loc }}</p>
<p>{{ frappe.db.get_value("Address", doc.customer_address, "gst_state") }} - {{ buyer.Pin }}</p>
{%- if einvoice.DispDtls -%}
{%- set dispatch = einvoice.DispDtls -%}
<h5 style="margin-bottom: 5px;">Dispatched From</h5>
{%- if dispatch.Gstin -%} <p>{{ dispatch.Gstin }}</p> {% endif %}
<p>{{ dispatch.LglNm }}</p>
<p>{{ dispatch.Addr1 }}</p>
{%- if dispatch.Addr2 -%} <p>{{ dispatch.Addr2 }}</p> {% endif %}
<p>{{ dispatch.Loc }}</p>
<p>{{ frappe.db.get_value("Address", doc.dispatch_address_name, "gst_state") }} - {{ dispatch.Pin }}</p>
{% endif %}
</div>
</div>
<div style="overflow-x: auto;">
<h5 class="font-bold" style="margin-top: 15px; margin-bottom: 10px;">3. Item Details</h5>
<table class="table table-bordered">
<thead>
<tr>
<th class="text-left" style="width: 3%;">Sr. No.</th>
<th class="text-left">Item</th>
<th class="text-left" style="width: 10%;">HSN Code</th>
<th class="text-left" style="width: 5%;">Qty</th>
<th class="text-left" style="width: 5%;">UOM</th>
<th class="text-left">Rate</th>
<th class="text-left" style="width: 5%;">Discount</th>
<th class="text-left">Taxable Amount</th>
<th class="text-left" style="width: 7%;">Tax Rate</th>
<th class="text-left" style="width: 5%;">Other Charges</th>
<th class="text-left">Total</th>
</tr>
</thead>
<tbody>
{% for item in einvoice.ItemList %}
<tr>
<td class="text-left" style="width: 3%;">{{ item.SlNo }}</td>
<td class="text-left">{{ item.PrdDesc }}</td>
<td class="text-left" style="width: 10%;">{{ item.HsnCd }}</td>
<td class="text-right" style="width: 5%;">{{ item.Qty }}</td>
<td class="text-left" style="width: 5%;">{{ item.Unit }}</td>
<td class="text-right">{{ frappe.utils.fmt_money(item.UnitPrice, None, "INR") }}</td>
<td class="text-right" style="width: 5%;">{{ frappe.utils.fmt_money(item.Discount, None, "INR") }}</td>
<td class="text-right">{{ frappe.utils.fmt_money(item.AssAmt, None, "INR") }}</td>
<td class="text-right" style="width: 7%;">{{ item.GstRt + item.CesRt }} %</td>
<td class="text-right" style="width: 5%;">{{ frappe.utils.fmt_money(0, None, "INR") }}</td>
<td class="text-right">{{ frappe.utils.fmt_money(item.TotItemVal, None, "INR") }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div style="overflow-x: auto;">
<h5 class="font-bold" style="margin-bottom: 0px;">4. Value Details</h5>
<table class="table table-bordered">
<thead>
<tr>
<th class="text-left">Taxable Amount</th>
<th class="text-left">CGST</th>
<th class="text-left"">SGST</th>
<th class="text-left">IGST</th>
<th class="text-left">CESS</th>
<th class="text-left" style="width: 10%;">State CESS</th>
<th class="text-left">Discount</th>
<th class="text-left" style="width: 10%;">Other Charges</th>
<th class="text-left" style="width: 10%;">Round Off</th>
<th class="text-left">Total Value</th>
</tr>
</thead>
<tbody>
{%- set value_details = einvoice.ValDtls -%}
<tr>
<td class="text-right">{{ frappe.utils.fmt_money(value_details.AssVal, None, "INR") }}</td>
<td class="text-right">{{ frappe.utils.fmt_money(value_details.CgstVal, None, "INR") }}</td>
<td class="text-right">{{ frappe.utils.fmt_money(value_details.SgstVal, None, "INR") }}</td>
<td class="text-right">{{ frappe.utils.fmt_money(value_details.IgstVal, None, "INR") }}</td>
<td class="text-right">{{ frappe.utils.fmt_money(value_details.CesVal, None, "INR") }}</td>
<td class="text-right">{{ frappe.utils.fmt_money(0, None, "INR") }}</td>
<td class="text-right">{{ frappe.utils.fmt_money(value_details.Discount, None, "INR") }}</td>
<td class="text-right">{{ frappe.utils.fmt_money(value_details.OthChrg, None, "INR") }}</td>
<td class="text-right">{{ frappe.utils.fmt_money(value_details.RndOffAmt, None, "INR") }}</td>
<td class="text-right">{{ frappe.utils.fmt_money(value_details.TotInvVal, None, "INR") }}</td>
</tr>
</tbody>
</table>
</div>
</div>

View File

@ -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"
}

File diff suppressed because one or more lines are too long

View File

@ -5,7 +5,7 @@
"label": "Profit and Loss"
}
],
"content": "[{\"type\":\"onboarding\",\"data\":{\"onboarding_name\":\"Accounts\",\"col\":12}},{\"type\":\"chart\",\"data\":{\"chart_name\":\"Profit and Loss\",\"col\":12}},{\"type\":\"spacer\",\"data\":{\"col\":12}},{\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Your Shortcuts</b></span>\",\"col\":12}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Chart of Accounts\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Sales Invoice\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Purchase Invoice\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Journal Entry\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Payment Entry\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Accounts Receivable\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"General Ledger\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Trial Balance\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Dashboard\",\"col\":3}},{\"type\":\"spacer\",\"data\":{\"col\":12}},{\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Reports & Masters</b></span>\",\"col\":12}},{\"type\":\"card\",\"data\":{\"card_name\":\"Accounting Masters\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"General Ledger\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Accounts Receivable\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Accounts Payable\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Reports\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Financial Statements\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Multi Currency\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Settings\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Bank Statement\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Subscription Management\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Goods and Services Tax (GST India)\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Share Management\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Cost Center and Budgeting\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Opening and Closing\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Taxes\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Profitability\",\"col\":4}}]",
"content": "[{\"type\":\"onboarding\",\"data\":{\"onboarding_name\":\"Accounts\",\"col\":12}},{\"type\":\"chart\",\"data\":{\"chart_name\":\"Profit and Loss\",\"col\":12}},{\"type\":\"spacer\",\"data\":{\"col\":12}},{\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Your Shortcuts</b></span>\",\"col\":12}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Chart of Accounts\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Sales Invoice\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Purchase Invoice\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Journal Entry\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Payment Entry\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Accounts Receivable\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"General Ledger\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Trial Balance\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Dashboard\",\"col\":3}},{\"type\":\"spacer\",\"data\":{\"col\":12}},{\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Reports & Masters</b></span>\",\"col\":12}},{\"type\":\"card\",\"data\":{\"card_name\":\"Accounting Masters\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"General Ledger\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Accounts Receivable\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Accounts Payable\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Reports\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Financial Statements\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Multi Currency\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Settings\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Bank Statement\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Subscription Management\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Share Management\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Cost Center and Budgeting\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Opening and Closing\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Taxes\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Profitability\",\"col\":4}}]",
"creation": "2020-03-02 15:41:59.515192",
"docstatus": 0,
"doctype": "Workspace",
@ -789,147 +789,6 @@
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Goods and Services Tax (GST India)",
"link_count": 0,
"onboard": 0,
"only_for": "India",
"type": "Card Break"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "GST Settings",
"link_count": 0,
"link_to": "GST Settings",
"link_type": "DocType",
"onboard": 0,
"only_for": "India",
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "GST HSN Code",
"link_count": 0,
"link_to": "GST HSN Code",
"link_type": "DocType",
"onboard": 0,
"only_for": "India",
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 1,
"label": "GSTR-1",
"link_count": 0,
"link_to": "GSTR-1",
"link_type": "Report",
"onboard": 0,
"only_for": "India",
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 1,
"label": "GSTR-2",
"link_count": 0,
"link_to": "GSTR-2",
"link_type": "Report",
"onboard": 0,
"only_for": "India",
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "GSTR 3B Report",
"link_count": 0,
"link_to": "GSTR 3B Report",
"link_type": "DocType",
"onboard": 0,
"only_for": "India",
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 1,
"label": "GST Sales Register",
"link_count": 0,
"link_to": "GST Sales Register",
"link_type": "Report",
"onboard": 0,
"only_for": "India",
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 1,
"label": "GST Purchase Register",
"link_count": 0,
"link_to": "GST Purchase Register",
"link_type": "Report",
"onboard": 0,
"only_for": "India",
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 1,
"label": "GST Itemised Sales Register",
"link_count": 0,
"link_to": "GST Itemised Sales Register",
"link_type": "Report",
"onboard": 0,
"only_for": "India",
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 1,
"label": "GST Itemised Purchase Register",
"link_count": 0,
"link_to": "GST Itemised Purchase Register",
"link_type": "Report",
"onboard": 0,
"only_for": "India",
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "C-Form",
"link_count": 0,
"link_to": "C-Form",
"link_type": "DocType",
"onboard": 0,
"only_for": "India",
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Lower Deduction Certificate",
"link_count": 0,
"link_to": "Lower Deduction Certificate",
"link_type": "DocType",
"onboard": 0,
"only_for": "India",
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
@ -1235,7 +1094,7 @@
"type": "Link"
}
],
"modified": "2022-01-13 17:25:09.835345",
"modified": "2022-02-19 06:22:18.091827",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounting",

View File

@ -629,45 +629,6 @@ class TestDepreciationMethods(AssetSetup):
self.assertEqual(schedules, expected_schedules)
def test_discounted_wdv_depreciation_rate_for_indian_region(self):
# set indian company
company_flag = frappe.flags.company
frappe.flags.company = "_Test Company"
finance_book = frappe.new_doc("Finance Book")
finance_book.finance_book_name = "Income Tax"
finance_book.for_income_tax = 1
finance_book.insert(ignore_if_duplicate = True)
asset = create_asset(
calculate_depreciation = 1,
available_for_use_date = "2030-07-12",
purchase_date = "2030-01-01",
finance_book = finance_book.name,
depreciation_method = "Written Down Value",
expected_value_after_useful_life = 12500,
depreciation_start_date = "2030-12-31",
total_number_of_depreciations = 3,
frequency_of_depreciation = 12
)
self.assertEqual(asset.finance_books[0].rate_of_depreciation, 50.0)
expected_schedules = [
["2030-12-31", 11849.32, 11849.32],
["2031-12-31", 44075.34, 55924.66],
["2032-12-31", 22037.67, 77962.33],
["2033-07-12", 9537.67, 87500.0]
]
schedules = [[cstr(d.schedule_date), flt(d.depreciation_amount, 2), flt(d.accumulated_depreciation_amount, 2)]
for d in asset.get("schedules")]
self.assertEqual(schedules, expected_schedules)
# reset indian company
frappe.flags.company = company_flag
class TestDepreciationBasics(AssetSetup):
def test_depreciation_without_pro_rata(self):
asset = create_asset(

View File

@ -12,9 +12,6 @@ from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
)
from erpnext.assets.doctype.asset.asset import get_depreciation_amount
from erpnext.assets.doctype.asset.depreciation import get_depreciation_accounts
from erpnext.regional.india.utils import (
get_depreciation_amount as get_depreciation_amount_for_india,
)
class AssetValueAdjustment(Document):
@ -115,9 +112,6 @@ class AssetValueAdjustment(Document):
days = date_diff(data.schedule_date, from_date)
depreciation_amount = days * rate_per_day
from_date = data.schedule_date
else:
if country == "India":
depreciation_amount = get_depreciation_amount_for_india(asset, value_after_depreciation, d)
else:
depreciation_amount = get_depreciation_amount(asset, value_after_depreciation, d)

View File

@ -1,3 +0,0 @@
{% include "erpnext/regional/india/taxes.js" %}
erpnext.setup_auto_gst_taxation('Purchase Order');

View File

@ -1,3 +0,0 @@
{% include "erpnext/regional/india/party.js" %}
erpnext.setup_gst_reminder_button('Supplier');

View File

@ -239,9 +239,6 @@ doc_events = {
"Sales Taxes and Charges Template": {
"on_update": "erpnext.e_commerce.doctype.e_commerce_settings.e_commerce_settings.validate_cart_settings"
},
"Tax Category": {
"validate": "erpnext.regional.india.utils.validate_tax_category"
},
"Sales Invoice": {
"on_submit": [
"erpnext.regional.create_transaction_log",
@ -255,41 +252,25 @@ doc_events = {
"erpnext.regional.saudi_arabia.utils.delete_qr_code_file"
],
"on_trash": "erpnext.regional.check_deletion_permission",
"validate": [
"erpnext.regional.india.utils.validate_document_name",
"erpnext.regional.india.utils.update_taxable_values"
]
},
"POS Invoice": {
"on_submit": ["erpnext.regional.saudi_arabia.utils.create_qr_code"]
},
"Purchase Invoice": {
"validate": [
"erpnext.regional.india.utils.validate_reverse_charge_transaction",
"erpnext.regional.india.utils.update_itc_availed_fields",
"erpnext.regional.united_arab_emirates.utils.update_grand_total_for_rcm",
"erpnext.regional.united_arab_emirates.utils.validate_returns",
"erpnext.regional.india.utils.update_taxable_values"
]
},
"Payment Entry": {
"validate": "erpnext.regional.india.utils.update_place_of_supply",
"on_submit": ["erpnext.regional.create_transaction_log", "erpnext.accounts.doctype.payment_request.payment_request.update_payment_req_status", "erpnext.accounts.doctype.dunning.dunning.resolve_dunning"],
"on_trash": "erpnext.regional.check_deletion_permission"
},
'Address': {
'validate': [
'erpnext.regional.india.utils.validate_gstin_for_india',
'erpnext.regional.italy.utils.set_state_code',
'erpnext.regional.india.utils.update_gst_category',
],
},
'Supplier': {
'validate': 'erpnext.regional.india.utils.validate_pan_for_india'
},
('Sales Invoice', 'Sales Order', 'Delivery Note', 'Purchase Invoice', 'Purchase Order', 'Purchase Receipt'): {
'validate': ['erpnext.regional.india.utils.set_place_of_supply']
},
"Contact": {
"on_trash": "erpnext.support.doctype.issue.issue.update_issue",
"after_insert": "erpnext.telephony.doctype.call_log.call_log.link_existing_conversations",
@ -302,8 +283,7 @@ doc_events = {
'validate': ["erpnext.erpnext_integrations.taxjar_integration.set_sales_tax"]
},
"Company": {
"on_trash": ["erpnext.regional.india.utils.delete_gst_settings_for_company",
"erpnext.regional.saudi_arabia.utils.delete_vat_settings_for_company"]
"on_trash": ["erpnext.regional.saudi_arabia.utils.delete_vat_settings_for_company"]
},
"Integration Request": {
"validate": "erpnext.accounts.doctype.payment_request.payment_request.validate_payment"
@ -432,18 +412,6 @@ regional_overrides = {
'France': {
'erpnext.tests.test_regional.test_method': 'erpnext.regional.france.utils.test_method'
},
'India': {
'erpnext.tests.test_regional.test_method': 'erpnext.regional.india.utils.test_method',
'erpnext.controllers.taxes_and_totals.get_itemised_tax_breakup_header': 'erpnext.regional.india.utils.get_itemised_tax_breakup_header',
'erpnext.controllers.taxes_and_totals.get_itemised_tax_breakup_data': 'erpnext.regional.india.utils.get_itemised_tax_breakup_data',
'erpnext.accounts.party.get_regional_address_details': 'erpnext.regional.india.utils.get_regional_address_details',
'erpnext.controllers.taxes_and_totals.get_regional_round_off_accounts': 'erpnext.regional.india.utils.get_regional_round_off_accounts',
'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.controllers.accounts_controller.validate_einvoice_fields': 'erpnext.regional.india.e_invoice.utils.validate_einvoice_fields',
'erpnext.assets.doctype.asset.asset.get_depreciation_amount': 'erpnext.regional.india.utils.get_depreciation_amount',
'erpnext.stock.doctype.item.item.set_item_tax_from_hsn_code': 'erpnext.regional.india.utils.set_item_tax_from_hsn_code'
},
'United Arab Emirates': {
'erpnext.controllers.taxes_and_totals.update_itemised_tax_data': 'erpnext.regional.united_arab_emirates.utils.update_itemised_tax_data',
'erpnext.accounts.doctype.purchase_invoice.purchase_invoice.make_regional_gl_entries': 'erpnext.regional.united_arab_emirates.utils.make_regional_gl_entries',

View File

@ -12,7 +12,6 @@ doctype_series_map = {
'Attendance': 'HR-ATT-.YYYY.-',
'Auto Repeat': 'SYS-ARP-.YYYY.-',
'Blanket Order': 'MFG-BLR-.YYYY.-',
'C-Form': 'ACC-CF-.YYYY.-',
'Campaign': 'SAL-CAM-.YYYY.-',
'Course Schedule': 'EDU-CSH-.YYYY.-',
'Customer': 'CUST-.YYYY.-',

View File

@ -5,8 +5,6 @@
import frappe
from frappe import _
import erpnext
def execute(filters=None):
data = get_data(filters)
@ -31,14 +29,6 @@ def get_columns(filters):
"width": 160
}]
if erpnext.get_region() == "India":
columns.append({
"label": _("PAN Number"),
"fieldname": "pan_number",
"fieldtype": "Data",
"width": 140
})
columns += [{
"label": _("Income Tax Component"),
"fieldname": "it_comp",
@ -94,9 +84,6 @@ def get_data(filters):
data = []
if erpnext.get_region() == "India":
employee_pan_dict = frappe._dict(frappe.db.sql(""" select employee, pan_number from `tabEmployee`"""))
component_types = frappe.db.sql(""" select name from `tabSalary Component`
where is_income_tax_component = 1 """)
@ -117,20 +104,13 @@ def get_data(filters):
""" % (conditions , ", ".join(['%s']*len(component_types))), tuple(component_types), as_dict=1)
for d in entry:
employee = {
data.append({
"employee": d.employee,
"employee_name": d.employee_name,
"it_comp": d.salary_component,
"posting_date": d.posting_date,
# "pan_number": employee_pan_dict.get(d.employee),
"it_amount": d.amount,
"gross_pay": d.gross_pay
}
if erpnext.get_region() == "India":
employee["pan_number"] = employee_pan_dict.get(d.employee)
data.append(employee)
})
return data

View File

@ -1,8 +0,0 @@
// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('E Invoice Request Log', {
// refresh: function(frm) {
// }
});

View File

@ -1,102 +0,0 @@
{
"actions": [],
"autoname": "EINV-REQ-.#####",
"creation": "2020-12-08 12:54:08.175992",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"user",
"url",
"headers",
"response",
"column_break_7",
"timestamp",
"reference_invoice",
"data"
],
"fields": [
{
"fieldname": "user",
"fieldtype": "Link",
"label": "User",
"options": "User"
},
{
"fieldname": "reference_invoice",
"fieldtype": "Data",
"label": "Reference Invoice"
},
{
"fieldname": "headers",
"fieldtype": "Code",
"label": "Headers",
"options": "JSON"
},
{
"fieldname": "data",
"fieldtype": "Code",
"label": "Data",
"options": "JSON"
},
{
"default": "Now",
"fieldname": "timestamp",
"fieldtype": "Datetime",
"label": "Timestamp"
},
{
"fieldname": "response",
"fieldtype": "Code",
"label": "Response",
"options": "JSON"
},
{
"fieldname": "url",
"fieldtype": "Data",
"label": "URL"
},
{
"fieldname": "column_break_7",
"fieldtype": "Column Break"
}
],
"index_web_pages_for_search": 1,
"links": [],
"modified": "2021-01-13 12:06:57.253111",
"modified_by": "Administrator",
"module": "Regional",
"name": "E Invoice Request Log",
"owner": "Administrator",
"permissions": [
{
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"share": 1
},
{
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts User",
"share": 1
},
{
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts Manager",
"share": 1
}
],
"sort_field": "modified",
"sort_order": "DESC"
}

View File

@ -1,10 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
# import frappe
from frappe.model.document import Document
class EInvoiceRequestLog(Document):
pass

View File

@ -1,11 +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 TestEInvoiceRequestLog(unittest.TestCase):
pass

View File

@ -1,11 +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(frm) {
const docs_link = 'https://docs.erpnext.com/docs/v13/user/manual/en/regional/india/setup-e-invoicing';
frm.dashboard.set_headline(
__("Read {0} for more information on E Invoicing features.", [`<a href='${docs_link}'>documentation</a>`])
);
}
});

View File

@ -1,97 +0,0 @@
{
"actions": [],
"creation": "2020-09-24 16:23:16.235722",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"enable",
"section_break_2",
"sandbox_mode",
"applicable_from",
"credentials",
"advanced_settings_section",
"client_id",
"column_break_8",
"client_secret",
"auth_token",
"token_expiry"
],
"fields": [
{
"default": "0",
"fieldname": "enable",
"fieldtype": "Check",
"label": "Enable"
},
{
"depends_on": "enable",
"fieldname": "section_break_2",
"fieldtype": "Section Break"
},
{
"fieldname": "auth_token",
"fieldtype": "Data",
"hidden": 1,
"read_only": 1
},
{
"fieldname": "token_expiry",
"fieldtype": "Datetime",
"hidden": 1,
"read_only": 1
},
{
"fieldname": "credentials",
"fieldtype": "Table",
"label": "Credentials",
"mandatory_depends_on": "enable",
"options": "E Invoice User"
},
{
"default": "0",
"fieldname": "sandbox_mode",
"fieldtype": "Check",
"label": "Sandbox Mode"
},
{
"fieldname": "applicable_from",
"fieldtype": "Date",
"in_list_view": 1,
"label": "Applicable From",
"reqd": 1
},
{
"collapsible": 1,
"fieldname": "advanced_settings_section",
"fieldtype": "Section Break",
"label": "Advanced Settings"
},
{
"fieldname": "client_id",
"fieldtype": "Data",
"label": "Client ID"
},
{
"fieldname": "client_secret",
"fieldtype": "Password",
"label": "Client Secret"
},
{
"fieldname": "column_break_8",
"fieldtype": "Column Break"
}
],
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
"modified": "2021-11-16 19:50:28.029517",
"modified_by": "Administrator",
"module": "Regional",
"name": "E Invoice Settings",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}

View File

@ -1,13 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
import frappe
from frappe import _
from frappe.model.document import Document
class EInvoiceSettings(Document):
def validate(self):
if self.enable and not self.credentials:
frappe.throw(_('You must add atleast one credentials to be able to use E Invoicing.'))

View File

@ -1,11 +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

View File

@ -1,57 +0,0 @@
{
"actions": [],
"creation": "2020-12-22 15:02:46.229474",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"company",
"gstin",
"username",
"password"
],
"fields": [
{
"fieldname": "gstin",
"fieldtype": "Data",
"in_list_view": 1,
"label": "GSTIN",
"reqd": 1
},
{
"fieldname": "username",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Username",
"reqd": 1
},
{
"fieldname": "password",
"fieldtype": "Password",
"in_list_view": 1,
"label": "Password",
"reqd": 1
},
{
"fieldname": "company",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Company",
"options": "Company",
"reqd": 1
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2021-03-22 12:16:56.365616",
"modified_by": "Administrator",
"module": "Regional",
"name": "E Invoice User",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}

View File

@ -1,10 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
# import frappe
from frappe.model.document import Document
class EInvoiceUser(Document):
pass

View File

@ -1,28 +0,0 @@
// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('GST HSN Code', {
refresh: function(frm) {
if(! frm.doc.__islocal && frm.doc.taxes.length){
frm.add_custom_button(__('Update Taxes for Items'), function(){
frappe.confirm(
'Are you sure? It will overwrite taxes for all items with HSN Code <b>'+frm.doc.name+'</b>.',
function(){
frappe.call({
args:{
taxes: frm.doc.taxes,
hsn_code: frm.doc.name
},
method: 'erpnext.regional.doctype.gst_hsn_code.gst_hsn_code.update_taxes_in_item_master',
callback: function(r) {
if(r.message){
frappe.show_alert(__('Item taxes updated'));
}
}
});
}
);
});
}
}
});

View File

@ -1,46 +0,0 @@
{
"autoname": "field:hsn_code",
"creation": "2017-06-21 10:48:56.422086",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"hsn_code",
"description",
"taxes"
],
"fields": [
{
"fieldname": "hsn_code",
"fieldtype": "Data",
"in_list_view": 1,
"label": "HSN Code",
"reqd": 1,
"unique": 1
},
{
"fieldname": "description",
"fieldtype": "Small Text",
"in_list_view": 1,
"label": "Description"
},
{
"fieldname": "taxes",
"fieldtype": "Table",
"label": "Taxes",
"options": "Item Tax"
}
],
"modified": "2019-11-01 11:18:59.556931",
"modified_by": "Administrator",
"module": "Regional",
"name": "GST HSN Code",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
"search_fields": "hsn_code, description",
"sort_field": "modified",
"sort_order": "DESC",
"title_field": "hsn_code",
"track_changes": 1
}

View File

@ -1,33 +0,0 @@
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
import frappe
from frappe.model.document import Document
class GSTHSNCode(Document):
pass
@frappe.whitelist()
def update_taxes_in_item_master(taxes, hsn_code):
items = frappe.get_list("Item", filters={
'gst_hsn_code': hsn_code
})
taxes = frappe.parse_json(taxes)
frappe.enqueue(update_item_document, items=items, taxes=taxes)
return 1
def update_item_document(items, taxes):
for item in items:
item_to_be_updated=frappe.get_doc("Item", item.name)
item_to_be_updated.taxes = []
for tax in taxes:
tax = frappe._dict(tax)
item_to_be_updated.append("taxes", {
'item_tax_template': tax.item_tax_template,
'tax_category': tax.tax_category,
'valid_from': tax.valid_from
})
item_to_be_updated.save()

View File

@ -1,8 +0,0 @@
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
import unittest
class TestGSTHSNCode(unittest.TestCase):
pass

View File

@ -1,44 +0,0 @@
// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('GST Settings', {
refresh: function(frm) {
frm.add_custom_button('Send GST Update Reminder', () => {
return new Promise((resolve) => {
return frappe.call({
method: 'erpnext.regional.doctype.gst_settings.gst_settings.send_reminder'
}).always(() => { resolve(); });
});
});
$(frm.fields_dict.gst_summary.wrapper).empty().html(
`<table class="table table-bordered">
<tbody>
<tr>
<td>Total Addresses</td><td>${frm.doc.__onload.data.total_addresses}</td>
</tr><tr>
<td>Total Addresses with GST</td><td>${frm.doc.__onload.data.total_addresses_with_gstin}</td>
</tr>
</tbody></table>`
);
},
setup: function(frm) {
$.each(["cgst_account", "sgst_account", "igst_account", "cess_account"], function(i, field) {
frm.events.filter_accounts(frm, field);
});
},
filter_accounts: function(frm, account_field) {
frm.set_query(account_field, "gst_accounts", function(doc, cdt, cdn) {
var row = locals[cdt][cdn];
return {
filters: {
company: row.company,
account_type: "Tax",
is_group: 0
}
};
});
}
});

View File

@ -1,85 +0,0 @@
{
"actions": [],
"creation": "2017-06-27 15:09:01.318003",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"gst_summary",
"gst_tax_settings_section",
"round_off_gst_values",
"column_break_4",
"hsn_wise_tax_breakup",
"gstin_email_sent_on",
"section_break_4",
"gst_accounts",
"b2c_limit"
],
"fields": [
{
"fieldname": "gst_summary",
"fieldtype": "HTML",
"label": "GST Summary"
},
{
"fieldname": "gstin_email_sent_on",
"fieldtype": "Date",
"label": "GSTIN Email Sent On",
"read_only": 1
},
{
"fieldname": "section_break_4",
"fieldtype": "Section Break"
},
{
"fieldname": "gst_accounts",
"fieldtype": "Table",
"label": "GST Accounts",
"options": "GST Account"
},
{
"default": "250000",
"description": "Set Invoice Value for B2C. B2CL and B2CS calculated based on this invoice value.",
"fieldname": "b2c_limit",
"fieldtype": "Data",
"in_list_view": 1,
"label": "B2C Limit",
"reqd": 1
},
{
"default": "0",
"description": "Enabling this option will round off individual GST components in all the Invoices",
"fieldname": "round_off_gst_values",
"fieldtype": "Check",
"label": "Round Off GST Values"
},
{
"default": "0",
"fieldname": "hsn_wise_tax_breakup",
"fieldtype": "Check",
"label": "Tax Breakup Table Based On HSN Code"
},
{
"fieldname": "gst_tax_settings_section",
"fieldtype": "Section Break",
"label": "GST Tax Settings"
},
{
"fieldname": "column_break_4",
"fieldtype": "Column Break"
}
],
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
"modified": "2021-10-11 18:10:14.242614",
"modified_by": "Administrator",
"module": "Regional",
"name": "GST Settings",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}

View File

@ -1,115 +0,0 @@
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
import os
import frappe
from frappe import _
from frappe.contacts.doctype.contact.contact import get_default_contact
from frappe.model.document import Document
from frappe.utils import date_diff, get_url, nowdate
class EmailMissing(frappe.ValidationError): pass
class GSTSettings(Document):
def onload(self):
data = frappe._dict()
data.total_addresses = frappe.db.sql('''select count(*) from tabAddress where country = "India"''')
data.total_addresses_with_gstin = frappe.db.sql('''select distinct count(*)
from tabAddress where country = "India" and ifnull(gstin, '')!='' ''')
self.set_onload('data', data)
def validate(self):
# Validate duplicate accounts
self.validate_duplicate_accounts()
def validate_duplicate_accounts(self):
account_list = []
for account in self.get('gst_accounts'):
for fieldname in ['cgst_account', 'sgst_account', 'igst_account', 'cess_account']:
if account.get(fieldname) in account_list:
frappe.throw(_("Account {0} appears multiple times").format(
frappe.bold(account.get(fieldname))))
if account.get(fieldname):
account_list.append(account.get(fieldname))
@frappe.whitelist()
def send_reminder():
frappe.has_permission('GST Settings', throw=True)
last_sent = frappe.db.get_single_value('GST Settings', 'gstin_email_sent_on')
if last_sent and date_diff(nowdate(), last_sent) < 3:
frappe.throw(_("Please wait 3 days before resending the reminder."))
frappe.db.set_value('GST Settings', 'GST Settings', 'gstin_email_sent_on', nowdate())
# enqueue if large number of customers, suppliser
frappe.enqueue('erpnext.regional.doctype.gst_settings.gst_settings.send_gstin_reminder_to_all_parties')
frappe.msgprint(_('Email Reminders will be sent to all parties with email contacts'))
def send_gstin_reminder_to_all_parties():
parties = []
for address_name in frappe.db.sql('''select name
from tabAddress where country = "India" and ifnull(gstin, '')='' '''):
address = frappe.get_doc('Address', address_name[0])
for link in address.links:
party = frappe.get_doc(link.link_doctype, link.link_name)
if link.link_doctype in ('Customer', 'Supplier'):
t = (link.link_doctype, link.link_name, address.email_id)
if not t in parties:
parties.append(t)
sent_to = []
for party in parties:
# get email from default contact
try:
email_id = _send_gstin_reminder(party[0], party[1], party[2], sent_to)
sent_to.append(email_id)
except EmailMissing:
pass
@frappe.whitelist()
def send_gstin_reminder(party_type, party):
'''Send GSTIN reminder to one party (called from Customer, Supplier form)'''
frappe.has_permission(party_type, throw=True)
email = _send_gstin_reminder(party_type ,party)
if email:
frappe.msgprint(_('Reminder to update GSTIN Sent'), title='Reminder sent', indicator='green')
def _send_gstin_reminder(party_type, party, default_email_id=None, sent_to=None):
'''Send GST Reminder email'''
email_id = frappe.db.get_value('Contact', get_default_contact(party_type, party), 'email_id')
if not email_id:
# get email from address
email_id = default_email_id
if not email_id:
frappe.throw(_('Email not found in default contact'), exc=EmailMissing)
if sent_to and email_id in sent_to:
return
frappe.sendmail(
subject='Please update your GSTIN',
recipients=email_id,
message='''
<p>Hello,</p>
<p>Please help us send you GST Ready Invoices.</p>
<p>
<a href="{0}?party={1}">
Click here to update your GSTIN Number in our system
</a>
</p>
<p style="color: #aaa; font-size: 11px; margin-top: 30px;">
Get your GST Ready ERP system at <a href="https://erpnext.com">https://erpnext.com</a>
<br>
ERPNext is a free and open source ERP system.
</p>
'''.format(os.path.join(get_url(), '/regional/india/update-gstin'), party)
)
return email_id

View File

@ -1,8 +0,0 @@
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
import unittest
class TestGSTSettings(unittest.TestCase):
pass

View File

@ -1,297 +0,0 @@
<style>
.print-format {
padding: 15mm;
font-size: 8.0pt !important;
font-family: Tahoma, sans-serif;
}
.disabled {
background-color: #d9d9d9;
}
</style>
<div>
<h3 class="text-center">{{ __("GSTR3B-Form")}}</h3>
<h5>{{__("GSTIN")}}: &nbsp {{ data.gstin }}</h5>
<h5>{{__("Period")}}: &nbsp {{ data.ret_period }}</h5>
</div>
<h5>3.1&nbsp&nbsp{{__("Details of Outward Supplies and inward supplies liable to reverse charge")}}</h5>
<table class="table table-bordered">
<thead>
<tr>
<th>{{__("Nature Of Supplies")}}</th>
<th>{{__("Total Taxable value")}}</th>
<th>{{__("Integrated Tax")}}</th>
<th>{{__("Central Tax")}}</th>
<th>{{__("State/UT Tax")}}</th>
<th>{{__("Cess")}}</th>
</tr>
</thead>
<tbody>
<tr>
<td>(a) {{__("Outward taxable supplies(other than zero rated, nil rated and exempted)")}}</td>
<td class="right">{{ flt(data.sup_details.osup_det.txval, 2) }}</td>
<td class="right">{{ flt(data.sup_details.osup_det.iamt, 2) }}</td>
<td class="right">{{ flt(data.sup_details.osup_det.camt, 2) }}</td>
<td class="right">{{ flt(data.sup_details.osup_det.samt, 2) }}</td>
<td class="right">{{ flt(data.sup_details.osup_det.csamt, 2) }}</td>
</tr>
<tr>
<td>(b) {{__("Outward taxable supplies(zero rated)")}}</td>
<td class="right">{{ flt(data.sup_details.osup_zero.txval, 2) }}</td>
<td class="right">{{ flt(data.sup_details.osup_zero.iamt, 2) }}</td>
<td class="disabled"></td>
<td class="disabled"></td>
<td class="right">{{ flt(data.sup_details.osup_zero.csamt, 2) }}</td>
</tr>
<tr>
<td>(b) {{__("Other outward supplies(Nil rated,Exempted)")}}</td>
<td class="right">{{ data.sup_details.osup_nil_exmp.txval }}</td>
<td class="disabled"></td>
<td class="disabled"></td>
<td class="disabled"></td>
<td class="disabled"></td>
<tr>
<td>(d) {{__("Inward Supplies(liable to reverse charge)")}}</td>
<td class="right">{{ flt(data.sup_details.isup_rev.txval, 2) }}</td>
<td class="right">{{ flt(data.sup_details.isup_rev.iamt, 2) }}</td>
<td class="right">{{ flt(data.sup_details.isup_rev.camt, 2) }}</td>
<td class="right">{{ flt(data.sup_details.isup_rev.samt, 2) }}</td>
<td class="right">{{ flt(data.sup_details.isup_rev.csamt,2) }}</td>
</tr>
<tr>
<td>(e) {{__("Non-GST outward supplies")}}</td>
<td class="right">{{ data.sup_details.osup_nongst.txval }}</td>
<td class="disabled"></td>
<td class="disabled"></td>
<td class="disabled"></td>
<td class="disabled"></td>
</tr>
</tbody>
</table>
<h5>
3.2&nbsp&nbsp{{__("Of the supplies shown in 3.1 (a) above, details of inter-State supplies made to unregisterd
persons, composition taxable persons and UIN holders")}}
</h5>
<table class="table table-bordered">
<thead>
<tr>
<th></th>
<th>{{__("Place Of Supply (State/UT)")}}</th>
<th>{{__("Total Taxable Value")}}</th>
<th>{{__("Amount of Integrated Tax")}}</th>
</tr>
</thead>
<tbody>
<tr>
<td>{{__("Supplies made to Unregistered Persons")}}</td>
<td class="right">
{% for row in data.inter_sup.unreg_details %}
{% if row %}
{{ row.pos }}<br>
{% endif %}
{% endfor %}
</td>
<td class="right">
{% for row in data.inter_sup.unreg_details %}
{% if row %}
{{ flt(row.txval, 2) }}<br>
{% endif %}
{% endfor %}
</td>
<td class="right">
{% for row in data.inter_sup.unreg_details %}
{% if row %}
{{ flt(row.iamt, 2) }}<br>
{% endif %}
{% endfor %}
</td>
</tr>
<tr>
<td>{{__("Supplies made to Composition Taxable Persons")}}</td>
<td class="right">
{% for row in data.inter_sup.comp_details %}
{% if row %}
{{ row.pos }}<br>
{% endif %}
{% endfor %}
</td>
<td class="right">
{% for row in data.inter_sup.comp_details %}
{% if row %}
{{ flt(row.txval, 2) }}<br>
{% endif %}
{% endfor %}
</td>
<td class="right">
{% for row in data.inter_sup.comp_details %}
{% if row %}
{{ flt(row.iamt, 2) }}<br>
{% endif %}
{% endfor %}
</td>
</tr>
<tr>
<td>{{__("Supplies made to UIN holders")}}</td>
<td class="right">
{% for row in data.inter_sup.uin_details %}
{% if row %}
{{ row.pos }}<br>
{% endif %}
{% endfor %}
</td>
<td class="right">
{% for row in data.inter_sup.uin_details %}
{% if row %}
{{ flt(row.txval, 2) }}<br>
{% endif %}
{% endfor %}
</td>
<td class="right">
{% for row in data.inter_sup.uin_details %}
{% if row %}
{{ flt(row.iamt, 2) }}<br>
{% endif %}
{% endfor %}
</td>
</tr>
</tbody>
</table>
<h5>4. &nbsp {{__("Eligible ITC")}}</h5>
<table class="table table-bordered">
<thead>
<tr>
<th>Details</th>
<th>Integrated Tax</th>
<th>Central Tax</th>
<th>State/UT tax</th>
<th>Cess</th>
</tr>
</thead>
<tbody>
<tr>
<td><b>(A) {{__("ITC Available (whether in full or part)")}}</b></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>&nbsp (1) {{__("Import of goods")}} </td>
<td class="right">{{ flt(data.itc_elg.itc_avl[0].iamt, 2) }}</td>
<td class="right">{{ flt(data.itc_elg.itc_avl[0].camt, 2) }}</td>
<td class="right">{{ flt(data.itc_elg.itc_avl[0].samt, 2) }}</td>
<td class="right">{{ flt(data.itc_elg.itc_avl[0].csamt, 2) }}</td>
</tr>
<tr>
<td>&nbsp (2) {{__("Import of services")}}</td>
<td class="right">{{ flt(data.itc_elg.itc_avl[1].iamt, 2) }}</td>
<td class="right">{{ flt(data.itc_elg.itc_avl[1].camt, 2) }}</td>
<td class="right">{{ flt(data.itc_elg.itc_avl[1].samt, 2) }}</td>
<td class="right">{{ flt(data.itc_elg.itc_avl[1].csamt, 2) }}</td>
</tr>
<tr>
<td>&nbsp (3) {{__("Inward supplies liable to reverse charge (other than 1 & 2 above)")}}</td>
<td class="right">{{ flt(data.itc_elg.itc_avl[2].iamt, 2) }}</td>
<td class="right">{{ flt(data.itc_elg.itc_avl[2].camt, 2) }}</td>
<td class="right">{{ flt(data.itc_elg.itc_avl[2].samt, 2) }}</td>
<td class="right">{{ flt(data.itc_elg.itc_avl[2].csamt, 2) }}</td>
</tr>
<tr>
<td>&nbsp (4) {{__("Inward supplies from ISD")}}</td>
<td class="right">{{ flt(data.itc_elg.itc_avl[3].iamt, 2) }}</td>
<td class="right">{{ flt(data.itc_elg.itc_avl[3].camt, 2) }}</td>
<td class="right">{{ flt(data.itc_elg.itc_avl[3].samt, 2) }}</td>
<td class="right">{{ flt(data.itc_elg.itc_avl[3].csamt, 2) }}</td>
</tr>
<tr>
<td>&nbsp (5) {{__("All other ITC")}}</td>
<td class="right">{{ flt(data.itc_elg.itc_avl[4].iamt, 2) }}</td>
<td class="right">{{ flt(data.itc_elg.itc_avl[4].camt, 2) }}</td>
<td class="right">{{ flt(data.itc_elg.itc_avl[4].samt, 2) }}</td>
<td class="right">{{ flt(data.itc_elg.itc_avl[4].csamt, 2) }}</td>
</tr>
<tr>
<td><b>(B) {{__("ITC Reversed")}}</b></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>&nbsp (1) {{__("As per rules 42 & 43 of CGST Rules")}}</td>
<td class="right">{{ flt(data.itc_elg.itc_rev[0].iamt, 2) }}</td>
<td class="right">{{ flt(data.itc_elg.itc_rev[0].camt, 2) }}</td>
<td class="right">{{ flt(data.itc_elg.itc_rev[0].samt, 2) }}</td>
<td class="right">{{ flt(data.itc_elg.itc_rev[0].csamt, 2) }}</td>
</tr>
<tr>
<td>&nbsp (2) {{__("Others")}}</td>
<td class="right">{{ flt(data.itc_elg.itc_rev[1].iamt, 2) }}</td>
<td class="right">{{ flt(data.itc_elg.itc_rev[1].camt, 2) }}</td>
<td class="right">{{ flt(data.itc_elg.itc_rev[1].samt, 2) }}</td>
<td class="right">{{ flt(data.itc_elg.itc_rev[1].csamt, 2) }}</td>
</tr>
<tr>
<td><b>(C) {{__("Net ITC Available(A) - (B)")}}</b></td>
<td class="right">{{ flt(data.itc_elg.itc_net.iamt, 2) }}</td>
<td class="right">{{ flt(data.itc_elg.itc_net.camt, 2) }}</td>
<td class="right">{{ flt(data.itc_elg.itc_net.samt, 2) }}</td>
<td class="right">{{ flt(data.itc_elg.itc_net.csamt, 2) }}</td>
</tr>
<tr>
<td><b>(D) {{__("Ineligible ITC")}}</b></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>&nbsp (1) {{__("As per section 17(5)")}}</td>
<td class="right">{{ flt(data.itc_elg.itc_inelg[0].iamt, 2) }}</td>
<td class="right">{{ flt(data.itc_elg.itc_inelg[0].camt, 2) }}</td>
<td class="right">{{ flt(data.itc_elg.itc_inelg[0].samt, 2) }}</td>
<td class="right">{{ flt(data.itc_elg.itc_inelg[0].csamt, 2) }}</td>
</tr>
<tr>
<td>&nbsp (2) {{__("Others")}}</td>
<td class="right">{{ flt(data.itc_elg.itc_inelg[1].iamt, 2) }}</td>
<td class="right">{{ flt(data.itc_elg.itc_inelg[1].camt, 2) }}</td>
<td class="right">{{ flt(data.itc_elg.itc_inelg[1].samt, 2) }}</td>
<td class="right">{{ flt(data.itc_elg.itc_inelg[1].csamt, 2) }}</td>
</tr>
</tbody>
</table>
<h5>5. &nbsp&nbsp {{__("Values of exempt, nil rated and non-GST inward supplies")}}</h5>
<table class="table table-bordered">
<thead>
<tr>
<th>{{__("Nature of Supplies")}}</th>
<th>{{__("Inter-State Supplies")}}</th>
<th>{{__("Intra-State Supplies")}}</th>
</tr>
</thead>
<tbody>
<tr>
<td>{{__("From a supplier under composition scheme, Exempt and Nil rated")}}</td>
<td class="right">{{ flt(data.inward_sup.isup_details[0].inter, 2) }}</td>
<td class="right">{{ flt(data.inward_sup.isup_details[0].intra, 2) }}</td>
</tr>
<tr>
<td>{{__("Non GST Inward Supplies")}}</td>
<td class="right">{{ flt(data.inward_sup.isup_details[1].inter, 2) }}</td>
<td class="right">{{ flt(data.inward_sup.isup_details[1].intra, 2) }}</td>
</tr>
</tbody>
</table>
<style>
.right{
text-align: right;
}
</style>

View File

@ -1,64 +0,0 @@
// Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('GSTR 3B Report', {
refresh : function(frm) {
frm.doc.__unsaved = 1;
if(!frm.is_new()) {
frm.set_intro(__("Please save the report again to rebuild or update"));
frm.add_custom_button(__('Download JSON'), function() {
var w = window.open(
frappe.urllib.get_full_url(
"/api/method/erpnext.regional.doctype.gstr_3b_report.gstr_3b_report.make_json?"
+"name="+encodeURIComponent(frm.doc.name)));
if(!w) {
frappe.msgprint(__("Please enable pop-ups")); return;
}
});
frm.add_custom_button(__('View Form'), function() {
frappe.call({
"method" : "erpnext.regional.doctype.gstr_3b_report.gstr_3b_report.view_report",
"args" : {
name : frm.doc.name,
},
"callback" : function(r){
let data = r.message;
frappe.ui.get_print_settings(false, print_settings => {
frappe.render_grid({
template: 'gstr_3b_report',
title: __(this.doctype),
print_settings: print_settings,
data: data,
columns:[]
});
});
}
});
});
}
let current_year = new Date().getFullYear();
let options = [current_year, current_year-1, current_year-2];
frm.set_df_property('year', 'options', options);
},
setup: function(frm) {
frm.set_query('company_address', function(doc) {
if(!doc.company) {
frappe.throw(__('Please set Company'));
}
return {
query: 'frappe.contacts.doctype.address.address.address_query',
filters: {
link_doctype: 'Company',
link_name: doc.company
}
};
});
},
});

View File

@ -1,62 +0,0 @@
{
"actions": [],
"autoname": "format:GSTR3B-{month}-{year}-{company_address}",
"creation": "2019-02-04 11:35:55.964639",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"company",
"company_address",
"year",
"month",
"json_output",
"missing_field_invoices"
],
"fields": [
{
"fieldname": "company",
"fieldtype": "Link",
"label": "Company",
"options": "Company"
},
{
"fieldname": "company_address",
"fieldtype": "Link",
"label": "Company Address",
"options": "Address"
},
{
"fieldname": "year",
"fieldtype": "Select",
"label": "Year"
},
{
"fieldname": "month",
"fieldtype": "Select",
"label": "Month",
"options": "January\nFebruary\nMarch\nApril\nMay\nJune\nJuly\nAugust\nSeptember\nOctober\nNovember\nDecember"
},
{
"fieldname": "json_output",
"fieldtype": "Code",
"label": "JSON Output"
},
{
"fieldname": "missing_field_invoices",
"fieldtype": "Small Text",
"label": "Invoices with no Place Of Supply",
"read_only": 1
}
],
"links": [],
"modified": "2020-04-04 19:32:30.772908",
"modified_by": "Administrator",
"module": "Regional",
"name": "GSTR 3B Report",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}

View File

@ -1,465 +0,0 @@
# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
import json
import os
import frappe
from frappe import _
from frappe.model.document import Document
from frappe.utils import cstr, flt
from erpnext.regional.india import state_numbers
class GSTR3BReport(Document):
def validate(self):
self.get_data()
def get_data(self):
self.report_dict = json.loads(get_json('gstr_3b_report_template'))
self.gst_details = self.get_company_gst_details()
self.report_dict["gstin"] = self.gst_details.get("gstin")
self.report_dict["ret_period"] = get_period(self.month, self.year)
self.month_no = get_period(self.month)
self.account_heads = self.get_account_heads()
self.get_outward_supply_details("Sales Invoice")
self.set_outward_taxable_supplies()
self.get_outward_supply_details("Purchase Invoice", reverse_charge=True)
self.set_supplies_liable_to_reverse_charge()
itc_details = self.get_itc_details()
self.set_itc_details(itc_details)
self.get_itc_reversal_entries()
inward_nil_exempt = self.get_inward_nil_exempt(self.gst_details.get("gst_state"))
self.set_inward_nil_exempt(inward_nil_exempt)
self.missing_field_invoices = self.get_missing_field_invoices()
self.json_output = frappe.as_json(self.report_dict)
def set_inward_nil_exempt(self, inward_nil_exempt):
self.report_dict["inward_sup"]["isup_details"][0]["inter"] = flt(inward_nil_exempt.get("gst").get("inter"), 2)
self.report_dict["inward_sup"]["isup_details"][0]["intra"] = flt(inward_nil_exempt.get("gst").get("intra"), 2)
self.report_dict["inward_sup"]["isup_details"][1]["inter"] = flt(inward_nil_exempt.get("non_gst").get("inter"), 2)
self.report_dict["inward_sup"]["isup_details"][1]["intra"] = flt(inward_nil_exempt.get("non_gst").get("intra"), 2)
def set_itc_details(self, itc_details):
itc_eligible_type_map = {
'IMPG': 'Import Of Capital Goods',
'IMPS': 'Import Of Service',
'ISRC': 'ITC on Reverse Charge',
'ISD': 'Input Service Distributor',
'OTH': 'All Other ITC'
}
itc_ineligible_map = {
'RUL': 'Ineligible As Per Section 17(5)',
'OTH': 'Ineligible Others'
}
net_itc = self.report_dict["itc_elg"]["itc_net"]
for d in self.report_dict["itc_elg"]["itc_avl"]:
itc_type = itc_eligible_type_map.get(d["ty"])
for key in ['iamt', 'camt', 'samt', 'csamt']:
d[key] = flt(itc_details.get(itc_type, {}).get(key))
net_itc[key] += flt(d[key], 2)
for d in self.report_dict["itc_elg"]["itc_inelg"]:
itc_type = itc_ineligible_map.get(d["ty"])
for key in ['iamt', 'camt', 'samt', 'csamt']:
d[key] = flt(itc_details.get(itc_type, {}).get(key))
def get_itc_reversal_entries(self):
reversal_entries = frappe.db.sql("""
SELECT ja.account, j.reversal_type, sum(credit_in_account_currency) as amount
FROM `tabJournal Entry` j, `tabJournal Entry Account` ja
where j.docstatus = 1
and j.is_opening = 'No'
and ja.parent = j.name
and j.voucher_type = 'Reversal Of ITC'
and month(j.posting_date) = %s and year(j.posting_date) = %s
and j.company = %s and j.company_gstin = %s
GROUP BY ja.account, j.reversal_type""", (self.month_no, self.year, self.company,
self.gst_details.get("gstin")), as_dict=1)
net_itc = self.report_dict["itc_elg"]["itc_net"]
for entry in reversal_entries:
if entry.reversal_type == 'As per rules 42 & 43 of CGST Rules':
index = 0
else:
index = 1
for key in ['camt', 'samt', 'iamt', 'csamt']:
if entry.account in self.account_heads.get(key):
self.report_dict["itc_elg"]["itc_rev"][index][key] += flt(entry.amount)
net_itc[key] -= flt(entry.amount)
def get_itc_details(self):
itc_amounts = frappe.db.sql("""
SELECT eligibility_for_itc, sum(itc_integrated_tax) as itc_integrated_tax,
sum(itc_central_tax) as itc_central_tax,
sum(itc_state_tax) as itc_state_tax,
sum(itc_cess_amount) as itc_cess_amount
FROM `tabPurchase Invoice`
WHERE docstatus = 1
and is_opening = 'No'
and month(posting_date) = %s and year(posting_date) = %s and company = %s
and company_gstin = %s
GROUP BY eligibility_for_itc
""", (self.month_no, self.year, self.company, self.gst_details.get("gstin")), as_dict=1)
itc_details = {}
for d in itc_amounts:
itc_details.setdefault(d.eligibility_for_itc, {
'iamt': d.itc_integrated_tax,
'camt': d.itc_central_tax,
'samt': d.itc_state_tax,
'csamt': d.itc_cess_amount
})
return itc_details
def get_inward_nil_exempt(self, state):
inward_nil_exempt = frappe.db.sql("""
SELECT p.place_of_supply, sum(i.base_amount) as base_amount, i.is_nil_exempt, i.is_non_gst
FROM `tabPurchase Invoice` p , `tabPurchase Invoice Item` i
WHERE p.docstatus = 1 and p.name = i.parent
and p.is_opening = 'No'
and p.gst_category != 'Registered Composition'
and (i.is_nil_exempt = 1 or i.is_non_gst = 1 or p.gst_category = 'Registered Composition') and
month(p.posting_date) = %s and year(p.posting_date) = %s
and p.company = %s and p.company_gstin = %s
GROUP BY p.place_of_supply, i.is_nil_exempt, i.is_non_gst""",
(self.month_no, self.year, self.company, self.gst_details.get("gstin")), as_dict=1)
inward_nil_exempt_details = {
"gst": {
"intra": 0.0,
"inter": 0.0
},
"non_gst": {
"intra": 0.0,
"inter": 0.0
}
}
for d in inward_nil_exempt:
if d.place_of_supply:
if (d.is_nil_exempt == 1 or d.get('gst_category') == 'Registered Composition') \
and state == d.place_of_supply.split("-")[1]:
inward_nil_exempt_details["gst"]["intra"] += d.base_amount
elif (d.is_nil_exempt == 1 or d.get('gst_category') == 'Registered Composition') \
and state != d.place_of_supply.split("-")[1]:
inward_nil_exempt_details["gst"]["inter"] += d.base_amount
elif d.is_non_gst == 1 and state == d.place_of_supply.split("-")[1]:
inward_nil_exempt_details["non_gst"]["intra"] += d.base_amount
elif d.is_non_gst == 1 and state != d.place_of_supply.split("-")[1]:
inward_nil_exempt_details["non_gst"]["inter"] += d.base_amount
return inward_nil_exempt_details
def get_outward_supply_details(self, doctype, reverse_charge=None):
self.get_outward_tax_invoices(doctype, reverse_charge=reverse_charge)
self.get_outward_items(doctype)
self.get_outward_tax_details(doctype)
def get_outward_tax_invoices(self, doctype, reverse_charge=None):
self.invoices = []
self.invoice_detail_map = {}
condition = ''
if reverse_charge:
condition += "AND reverse_charge = 'Y'"
invoice_details = frappe.db.sql("""
SELECT
name, gst_category, export_type, place_of_supply
FROM
`tab{doctype}`
WHERE
docstatus = 1
AND month(posting_date) = %s
AND year(posting_date) = %s
AND company = %s
AND company_gstin = %s
AND is_opening = 'No'
{reverse_charge}
ORDER BY name
""".format(doctype=doctype, reverse_charge=condition), (self.month_no, self.year,
self.company, self.gst_details.get("gstin")), as_dict=1)
for d in invoice_details:
self.invoice_detail_map.setdefault(d.name, d)
self.invoices.append(d.name)
def get_outward_items(self, doctype):
self.invoice_items = frappe._dict()
self.is_nil_exempt = []
self.is_non_gst = []
if self.get('invoices'):
item_details = frappe.db.sql("""
SELECT
item_code, parent, taxable_value, base_net_amount, item_tax_rate,
is_nil_exempt, is_non_gst
FROM
`tab%s Item`
WHERE parent in (%s)
""" % (doctype, ', '.join(['%s']*len(self.invoices))), tuple(self.invoices), as_dict=1)
for d in item_details:
if d.item_code not in self.invoice_items.get(d.parent, {}):
self.invoice_items.setdefault(d.parent, {}).setdefault(d.item_code, 0.0)
self.invoice_items[d.parent][d.item_code] += d.get('taxable_value', 0) or d.get('base_net_amount', 0)
if d.is_nil_exempt and d.item_code not in self.is_nil_exempt:
self.is_nil_exempt.append(d.item_code)
if d.is_non_gst and d.item_code not in self.is_non_gst:
self.is_non_gst.append(d.item_code)
def get_outward_tax_details(self, doctype):
if doctype == "Sales Invoice":
tax_template = 'Sales Taxes and Charges'
elif doctype == "Purchase Invoice":
tax_template = 'Purchase Taxes and Charges'
self.items_based_on_tax_rate = {}
self.invoice_cess = frappe._dict()
self.cgst_sgst_invoices = []
if self.get('invoices'):
tax_details = frappe.db.sql("""
SELECT
parent, account_head, item_wise_tax_detail, base_tax_amount_after_discount_amount
FROM `tab%s`
WHERE
parenttype = %s and docstatus = 1
and parent in (%s)
ORDER BY account_head
""" % (tax_template, '%s', ', '.join(['%s']*len(self.invoices))),
tuple([doctype] + list(self.invoices)))
for parent, account, item_wise_tax_detail, tax_amount in tax_details:
if account in self.account_heads.get('csamt'):
self.invoice_cess.setdefault(parent, tax_amount)
else:
if item_wise_tax_detail:
try:
item_wise_tax_detail = json.loads(item_wise_tax_detail)
cgst_or_sgst = False
if account in self.account_heads.get('camt') \
or account in self.account_heads.get('samt'):
cgst_or_sgst = True
for item_code, tax_amounts in item_wise_tax_detail.items():
if not (cgst_or_sgst or account in self.account_heads.get('iamt') or
(item_code in self.is_non_gst + self.is_nil_exempt)):
continue
tax_rate = tax_amounts[0]
if tax_rate:
if cgst_or_sgst:
tax_rate *= 2
if parent not in self.cgst_sgst_invoices:
self.cgst_sgst_invoices.append(parent)
rate_based_dict = self.items_based_on_tax_rate\
.setdefault(parent, {}).setdefault(tax_rate, [])
if item_code not in rate_based_dict:
rate_based_dict.append(item_code)
except ValueError:
continue
if self.get('invoice_items'):
# Build itemised tax for export invoices, nil and exempted where tax table is blank
for invoice, items in self.invoice_items.items():
if invoice not in self.items_based_on_tax_rate and self.invoice_detail_map.get(invoice, {}).get('export_type') \
== "Without Payment of Tax" and self.invoice_detail_map.get(invoice, {}).get('gst_category') == "Overseas":
self.items_based_on_tax_rate.setdefault(invoice, {}).setdefault(0, items.keys())
else:
for item in items.keys():
if item in self.is_nil_exempt + self.is_non_gst and \
item not in self.items_based_on_tax_rate.get(invoice, {}).get(0, []):
self.items_based_on_tax_rate.setdefault(invoice, {}).setdefault(0, [])
self.items_based_on_tax_rate[invoice][0].append(item)
def set_outward_taxable_supplies(self):
inter_state_supply_details = {}
for inv, items_based_on_rate in self.items_based_on_tax_rate.items():
gst_category = self.invoice_detail_map.get(inv, {}).get('gst_category')
place_of_supply = self.invoice_detail_map.get(inv, {}).get('place_of_supply') or '00-Other Territory'
export_type = self.invoice_detail_map.get(inv, {}).get('export_type')
for rate, items in items_based_on_rate.items():
for item_code, taxable_value in self.invoice_items.get(inv).items():
if item_code in items:
if item_code in self.is_nil_exempt:
self.report_dict['sup_details']['osup_nil_exmp']['txval'] += taxable_value
elif item_code in self.is_non_gst:
self.report_dict['sup_details']['osup_nongst']['txval'] += taxable_value
elif rate == 0 or (gst_category == 'Overseas' and export_type == 'Without Payment of Tax'):
self.report_dict['sup_details']['osup_zero']['txval'] += taxable_value
else:
if inv in self.cgst_sgst_invoices:
tax_rate = rate/2
self.report_dict['sup_details']['osup_det']['camt'] += (taxable_value * tax_rate /100)
self.report_dict['sup_details']['osup_det']['samt'] += (taxable_value * tax_rate /100)
self.report_dict['sup_details']['osup_det']['txval'] += taxable_value
else:
self.report_dict['sup_details']['osup_det']['iamt'] += (taxable_value * rate /100)
self.report_dict['sup_details']['osup_det']['txval'] += taxable_value
if gst_category in ['Unregistered', 'Registered Composition', 'UIN Holders'] and \
self.gst_details.get("gst_state") != place_of_supply.split("-")[1]:
inter_state_supply_details.setdefault((gst_category, place_of_supply), {
"txval": 0.0,
"pos": place_of_supply.split("-")[0],
"iamt": 0.0
})
inter_state_supply_details[(gst_category, place_of_supply)]['txval'] += taxable_value
inter_state_supply_details[(gst_category, place_of_supply)]['iamt'] += (taxable_value * rate /100)
if self.invoice_cess.get(inv):
self.report_dict['sup_details']['osup_det']['csamt'] += flt(self.invoice_cess.get(inv), 2)
self.set_inter_state_supply(inter_state_supply_details)
def set_supplies_liable_to_reverse_charge(self):
for inv, items_based_on_rate in self.items_based_on_tax_rate.items():
for rate, items in items_based_on_rate.items():
for item_code, taxable_value in self.invoice_items.get(inv).items():
if item_code in items:
if inv in self.cgst_sgst_invoices:
tax_rate = rate/2
self.report_dict['sup_details']['isup_rev']['camt'] += (taxable_value * tax_rate /100)
self.report_dict['sup_details']['isup_rev']['samt'] += (taxable_value * tax_rate /100)
self.report_dict['sup_details']['isup_rev']['txval'] += taxable_value
else:
self.report_dict['sup_details']['isup_rev']['iamt'] += (taxable_value * rate /100)
self.report_dict['sup_details']['isup_rev']['txval'] += taxable_value
def set_inter_state_supply(self, inter_state_supply):
for key, value in inter_state_supply.items():
if key[0] == "Unregistered":
self.report_dict["inter_sup"]["unreg_details"].append(value)
if key[0] == "Registered Composition":
self.report_dict["inter_sup"]["comp_details"].append(value)
if key[0] == "UIN Holders":
self.report_dict["inter_sup"]["uin_details"].append(value)
def get_company_gst_details(self):
gst_details = frappe.get_all("Address",
fields=["gstin", "gst_state", "gst_state_number"],
filters={
"name":self.company_address
})
if gst_details:
return gst_details[0]
else:
frappe.throw(_("Please enter GSTIN and state for the Company Address {0}").format(self.company_address))
def get_account_heads(self):
account_map = {
'sgst_account': 'samt',
'cess_account': 'csamt',
'cgst_account': 'camt',
'igst_account': 'iamt'
}
account_heads = {}
gst_settings_accounts = frappe.get_all("GST Account",
filters={'company': self.company, 'is_reverse_charge_account': 0},
fields=["cgst_account", "sgst_account", "igst_account", "cess_account"])
if not gst_settings_accounts:
frappe.throw(_("Please set GST Accounts in GST Settings"))
for d in gst_settings_accounts:
for acc, val in d.items():
account_heads.setdefault(account_map.get(acc), []).append(val)
return account_heads
def get_missing_field_invoices(self):
missing_field_invoices = []
for doctype in ["Sales Invoice", "Purchase Invoice"]:
if doctype == "Sales Invoice":
party_type = 'Customer'
party = 'customer'
else:
party_type = 'Supplier'
party = 'supplier'
docnames = frappe.db.sql(
"""
SELECT t1.name FROM `tab{doctype}` t1, `tab{party_type}` t2
WHERE t1.docstatus = 1 and t1.is_opening = 'No'
and month(t1.posting_date) = %s and year(t1.posting_date) = %s
and t1.company = %s and t1.place_of_supply IS NULL and t1.{party} = t2.name and
t2.gst_category != 'Overseas'
""".format(doctype = doctype, party_type = party_type,
party=party) ,(self.month_no, self.year, self.company), as_dict=1) #nosec
for d in docnames:
missing_field_invoices.append(d.name)
return ",".join(missing_field_invoices)
def get_json(template):
file_path = os.path.join(os.path.dirname(__file__), '{template}.json'.format(template=template))
with open(file_path, 'r') as f:
return cstr(f.read())
def get_state_code(state):
state_code = state_numbers.get(state)
return state_code
def get_period(month, year=None):
month_no = {
"January": 1,
"February": 2,
"March": 3,
"April": 4,
"May": 5,
"June": 6,
"July": 7,
"August": 8,
"September": 9,
"October": 10,
"November": 11,
"December": 12
}.get(month)
if year:
return str(month_no).zfill(2) + str(year)
else:
return month_no
@frappe.whitelist()
def view_report(name):
json_data = frappe.get_value("GSTR 3B Report", name, 'json_output')
return json.loads(json_data)
@frappe.whitelist()
def make_json(name):
json_data = frappe.get_value("GSTR 3B Report", name, 'json_output')
file_name = "GST3B.json"
frappe.local.response.filename = file_name
frappe.local.response.filecontent = json_data
frappe.local.response.type = "download"

View File

@ -1,127 +0,0 @@
{
"gstin": "",
"ret_period": "",
"inward_sup": {
"isup_details": [
{
"ty": "GST",
"intra": 0,
"inter": 0
},
{
"ty": "NONGST",
"inter": 0,
"intra": 0
}
]
},
"sup_details": {
"osup_zero": {
"csamt": 0,
"txval": 0,
"iamt": 0
},
"osup_nil_exmp": {
"txval": 0
},
"osup_det": {
"samt": 0,
"csamt": 0,
"txval": 0,
"camt": 0,
"iamt": 0
},
"isup_rev": {
"samt": 0,
"csamt": 0,
"txval": 0,
"camt": 0,
"iamt": 0
},
"osup_nongst": {
"txval": 0
}
},
"inter_sup": {
"unreg_details": [],
"comp_details": [],
"uin_details": []
},
"itc_elg": {
"itc_avl": [
{
"csamt": 0,
"samt": 0,
"ty": "IMPG",
"camt": 0,
"iamt": 0
},
{
"csamt": 0,
"samt": 0,
"ty": "IMPS",
"camt": 0,
"iamt": 0
},
{
"samt": 0,
"csamt": 0,
"ty": "ISRC",
"camt": 0,
"iamt": 0
},
{
"ty": "ISD",
"iamt": 0,
"camt": 0,
"samt": 0,
"csamt": 0
},
{
"samt": 0,
"csamt": 0,
"ty": "OTH",
"camt": 0,
"iamt": 0
}
],
"itc_rev": [
{
"ty": "RUL",
"iamt": 0,
"camt": 0,
"samt": 0,
"csamt": 0
},
{
"ty": "OTH",
"iamt": 0,
"camt": 0,
"samt": 0,
"csamt": 0
}
],
"itc_net": {
"samt": 0,
"csamt": 0,
"camt": 0,
"iamt": 0
},
"itc_inelg": [
{
"ty": "RUL",
"iamt": 0,
"camt": 0,
"samt": 0,
"csamt": 0
},
{
"ty": "OTH",
"iamt": 0,
"camt": 0,
"samt": 0,
"csamt": 0
}
]
}
}

View File

@ -1,491 +0,0 @@
# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
import json
import unittest
import frappe
from frappe.utils import getdate
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
from erpnext.stock.doctype.item.test_item import make_item
test_dependencies = ["Territory", "Customer Group", "Supplier Group", "Item"]
class TestGSTR3BReport(unittest.TestCase):
def setUp(self):
frappe.set_user("Administrator")
frappe.db.sql("delete from `tabSales Invoice` where company='_Test Company GST'")
frappe.db.sql("delete from `tabPurchase Invoice` where company='_Test Company GST'")
frappe.db.sql("delete from `tabGSTR 3B Report` where company='_Test Company GST'")
make_company()
make_item("Milk", properties = {"is_nil_exempt": 1, "standard_rate": 0.000000})
set_account_heads()
make_customers()
make_suppliers()
def test_gstr_3b_report(self):
month_number_mapping = {
1: "January",
2: "February",
3: "March",
4: "April",
5: "May",
6: "June",
7: "July",
8: "August",
9: "September",
10: "October",
11: "November",
12: "December"
}
make_sales_invoice()
create_purchase_invoices()
if frappe.db.exists("GSTR 3B Report", "GSTR3B-March-2019-_Test Address GST-Billing"):
report = frappe.get_doc("GSTR 3B Report", "GSTR3B-March-2019-_Test Address GST-Billing")
report.save()
else:
report = frappe.get_doc({
"doctype": "GSTR 3B Report",
"company": "_Test Company GST",
"company_address": "_Test Address GST-Billing",
"year": getdate().year,
"month": month_number_mapping.get(getdate().month)
}).insert()
output = json.loads(report.json_output)
self.assertEqual(output["sup_details"]["osup_det"]["iamt"], 54)
self.assertEqual(output["inter_sup"]["unreg_details"][0]["iamt"], 18),
self.assertEqual(output["sup_details"]["osup_nil_exmp"]["txval"], 100),
self.assertEqual(output["inward_sup"]["isup_details"][0]["intra"], 250)
self.assertEqual(output["itc_elg"]["itc_avl"][4]["samt"], 22.50)
self.assertEqual(output["itc_elg"]["itc_avl"][4]["camt"], 22.50)
def test_gst_rounding(self):
gst_settings = frappe.get_doc('GST Settings')
gst_settings.round_off_gst_values = 1
gst_settings.save()
current_country = frappe.flags.country
frappe.flags.country = 'India'
si = create_sales_invoice(company="_Test Company GST",
customer = '_Test GST Customer',
currency = 'INR',
warehouse = 'Finished Goods - _GST',
debit_to = 'Debtors - _GST',
income_account = 'Sales - _GST',
expense_account = 'Cost of Goods Sold - _GST',
cost_center = 'Main - _GST',
rate=216,
do_not_save=1
)
si.append("taxes", {
"charge_type": "On Net Total",
"account_head": "Output Tax IGST - _GST",
"cost_center": "Main - _GST",
"description": "IGST @ 18.0",
"rate": 18
})
si.save()
# Check for 39 instead of 38.88
self.assertEqual(si.taxes[0].base_tax_amount_after_discount_amount, 39)
frappe.flags.country = current_country
gst_settings.round_off_gst_values = 1
gst_settings.save()
def test_gst_category_auto_update(self):
if not frappe.db.exists("Customer", "_Test GST Customer With GSTIN"):
customer = frappe.get_doc({
"customer_group": "_Test Customer Group",
"customer_name": "_Test GST Customer With GSTIN",
"customer_type": "Individual",
"doctype": "Customer",
"territory": "_Test Territory"
}).insert()
self.assertEqual(customer.gst_category, 'Unregistered')
if not frappe.db.exists('Address', '_Test GST Category-1-Billing'):
address = frappe.get_doc({
"address_line1": "_Test Address Line 1",
"address_title": "_Test GST Category-1",
"address_type": "Billing",
"city": "_Test City",
"state": "Test State",
"country": "India",
"doctype": "Address",
"is_primary_address": 1,
"phone": "+91 0000000000",
"gstin": "29AZWPS7135H1ZG",
"gst_state": "Karnataka",
"gst_state_number": "29"
}).insert()
address.append("links", {
"link_doctype": "Customer",
"link_name": "_Test GST Customer With GSTIN"
})
address.save()
customer.load_from_db()
self.assertEqual(customer.gst_category, 'Registered Regular')
def make_sales_invoice():
si = create_sales_invoice(company="_Test Company GST",
customer = '_Test GST Customer',
currency = 'INR',
warehouse = 'Finished Goods - _GST',
debit_to = 'Debtors - _GST',
income_account = 'Sales - _GST',
expense_account = 'Cost of Goods Sold - _GST',
cost_center = 'Main - _GST',
do_not_save=1
)
si.append("taxes", {
"charge_type": "On Net Total",
"account_head": "Output Tax IGST - _GST",
"cost_center": "Main - _GST",
"description": "IGST @ 18.0",
"rate": 18
})
si.submit()
si1 = create_sales_invoice(company="_Test Company GST",
customer = '_Test GST SEZ Customer',
currency = 'INR',
warehouse = 'Finished Goods - _GST',
debit_to = 'Debtors - _GST',
income_account = 'Sales - _GST',
expense_account = 'Cost of Goods Sold - _GST',
cost_center = 'Main - _GST',
do_not_save=1
)
si1.append("taxes", {
"charge_type": "On Net Total",
"account_head": "Output Tax IGST - _GST",
"cost_center": "Main - _GST",
"description": "IGST @ 18.0",
"rate": 18
})
si1.submit()
si2 = create_sales_invoice(company="_Test Company GST",
customer = '_Test Unregistered Customer',
currency = 'INR',
warehouse = 'Finished Goods - _GST',
debit_to = 'Debtors - _GST',
income_account = 'Sales - _GST',
expense_account = 'Cost of Goods Sold - _GST',
cost_center = 'Main - _GST',
do_not_save=1
)
si2.append("taxes", {
"charge_type": "On Net Total",
"account_head": "Output Tax IGST - _GST",
"cost_center": "Main - _GST",
"description": "IGST @ 18.0",
"rate": 18
})
si2.submit()
si3 = create_sales_invoice(company="_Test Company GST",
customer = '_Test GST Customer',
currency = 'INR',
item = 'Milk',
warehouse = 'Finished Goods - _GST',
debit_to = 'Debtors - _GST',
income_account = 'Sales - _GST',
expense_account = 'Cost of Goods Sold - _GST',
cost_center = 'Main - _GST',
do_not_save=1
)
si3.submit()
def create_purchase_invoices():
pi = make_purchase_invoice(
company="_Test Company GST",
supplier = '_Test Registered Supplier',
currency = 'INR',
warehouse = 'Finished Goods - _GST',
cost_center = 'Main - _GST',
expense_account = 'Cost of Goods Sold - _GST',
do_not_save=1,
)
pi.eligibility_for_itc = "All Other ITC"
pi.append("taxes", {
"charge_type": "On Net Total",
"account_head": "Input Tax CGST - _GST",
"cost_center": "Main - _GST",
"description": "CGST @ 9.0",
"rate": 9
})
pi.append("taxes", {
"charge_type": "On Net Total",
"account_head": "Input Tax SGST - _GST",
"cost_center": "Main - _GST",
"description": "SGST @ 9.0",
"rate": 9
})
pi.submit()
pi1 = make_purchase_invoice(
company="_Test Company GST",
supplier = '_Test Registered Supplier',
currency = 'INR',
warehouse = 'Finished Goods - _GST',
cost_center = 'Main - _GST',
expense_account = 'Cost of Goods Sold - _GST',
item = "Milk",
do_not_save=1
)
pi1.shipping_address = "_Test Supplier GST-1-Billing"
pi1.save()
pi1.submit()
pi2 = make_purchase_invoice(company="_Test Company GST",
customer = '_Test Registered Supplier',
currency = 'INR',
item = 'Milk',
warehouse = 'Finished Goods - _GST',
expense_account = 'Cost of Goods Sold - _GST',
cost_center = 'Main - _GST',
rate=250,
qty=1,
do_not_save=1
)
pi2.submit()
def make_suppliers():
if not frappe.db.exists("Supplier", "_Test Registered Supplier"):
frappe.get_doc({
"supplier_group": "_Test Supplier Group",
"supplier_name": "_Test Registered Supplier",
"gst_category": "Registered Regular",
"supplier_type": "Individual",
"doctype": "Supplier",
}).insert()
if not frappe.db.exists("Supplier", "_Test Unregistered Supplier"):
frappe.get_doc({
"supplier_group": "_Test Supplier Group",
"supplier_name": "_Test Unregistered Supplier",
"gst_category": "Unregistered",
"supplier_type": "Individual",
"doctype": "Supplier",
}).insert()
if not frappe.db.exists('Address', '_Test Supplier GST-1-Billing'):
address = frappe.get_doc({
"address_line1": "_Test Address Line 1",
"address_title": "_Test Supplier GST-1",
"address_type": "Billing",
"city": "_Test City",
"state": "Test State",
"country": "India",
"doctype": "Address",
"is_primary_address": 1,
"phone": "+91 0000000000",
"gstin": "29AACCV0498C1Z9",
"gst_state": "Karnataka",
}).insert()
address.append("links", {
"link_doctype": "Supplier",
"link_name": "_Test Registered Supplier"
})
address.is_shipping_address = 1
address.save()
if not frappe.db.exists('Address', '_Test Supplier GST-2-Billing'):
address = frappe.get_doc({
"address_line1": "_Test Address Line 1",
"address_title": "_Test Supplier GST-2",
"address_type": "Billing",
"city": "_Test City",
"state": "Test State",
"country": "India",
"doctype": "Address",
"is_primary_address": 1,
"phone": "+91 0000000000",
"gst_state": "Karnataka",
}).insert()
address.append("links", {
"link_doctype": "Supplier",
"link_name": "_Test Unregistered Supplier"
})
address.save()
def make_customers():
if not frappe.db.exists("Customer", "_Test GST Customer"):
frappe.get_doc({
"customer_group": "_Test Customer Group",
"customer_name": "_Test GST Customer",
"gst_category": "Registered Regular",
"customer_type": "Individual",
"doctype": "Customer",
"territory": "_Test Territory"
}).insert()
if not frappe.db.exists("Customer", "_Test GST SEZ Customer"):
frappe.get_doc({
"customer_group": "_Test Customer Group",
"customer_name": "_Test GST SEZ Customer",
"gst_category": "SEZ",
"customer_type": "Individual",
"doctype": "Customer",
"territory": "_Test Territory"
}).insert()
if not frappe.db.exists("Customer", "_Test Unregistered Customer"):
frappe.get_doc({
"customer_group": "_Test Customer Group",
"customer_name": "_Test Unregistered Customer",
"gst_category": "Unregistered",
"customer_type": "Individual",
"doctype": "Customer",
"territory": "_Test Territory"
}).insert()
if not frappe.db.exists('Address', '_Test GST-1-Billing'):
address = frappe.get_doc({
"address_line1": "_Test Address Line 1",
"address_title": "_Test GST-1",
"address_type": "Billing",
"city": "_Test City",
"state": "Test State",
"country": "India",
"doctype": "Address",
"is_primary_address": 1,
"phone": "+91 0000000000",
"gstin": "29AZWPS7135H1ZG",
"gst_state": "Karnataka",
"gst_state_number": "29"
}).insert()
address.append("links", {
"link_doctype": "Customer",
"link_name": "_Test GST Customer"
})
address.save()
if not frappe.db.exists('Address', '_Test GST-2-Billing'):
address = frappe.get_doc({
"address_line1": "_Test Address Line 1",
"address_title": "_Test GST-2",
"address_type": "Billing",
"city": "_Test City",
"state": "Test State",
"country": "India",
"doctype": "Address",
"is_primary_address": 1,
"phone": "+91 0000000000",
"gst_state": "Haryana",
}).insert()
address.append("links", {
"link_doctype": "Customer",
"link_name": "_Test Unregistered Customer"
})
address.save()
if not frappe.db.exists('Address', '_Test GST-3-Billing'):
address = frappe.get_doc({
"address_line1": "_Test Address Line 1",
"address_title": "_Test GST-3",
"address_type": "Billing",
"city": "_Test City",
"state": "Test State",
"country": "India",
"doctype": "Address",
"is_primary_address": 1,
"phone": "+91 0000000000",
"gst_state": "Gujarat",
}).insert()
address.append("links", {
"link_doctype": "Customer",
"link_name": "_Test GST SEZ Customer"
})
address.save()
def make_company():
if frappe.db.exists("Company", "_Test Company GST"):
return
company = frappe.new_doc("Company")
company.company_name = "_Test Company GST"
company.abbr = "_GST"
company.default_currency = "INR"
company.country = "India"
company.insert()
if not frappe.db.exists('Address', '_Test Address GST-Billing'):
address = frappe.get_doc({
"address_title": "_Test Address GST",
"address_line1": "_Test Address Line 1",
"address_type": "Billing",
"city": "_Test City",
"state": "Test State",
"country": "India",
"doctype": "Address",
"is_primary_address": 1,
"phone": "+91 0000000000",
"gstin": "27AAECE4835E1ZR",
"gst_state": "Maharashtra",
"gst_state_number": "27"
}).insert()
address.append("links", {
"link_doctype": "Company",
"link_name": "_Test Company GST"
})
address.save()
def set_account_heads():
gst_settings = frappe.get_doc("GST Settings")
gst_account = frappe.get_all(
"GST Account",
fields=["cgst_account", "sgst_account", "igst_account"],
filters = {"company": "_Test Company GST"})
if not gst_account:
gst_settings.append("gst_accounts", {
"company": "_Test Company GST",
"cgst_account": "Output Tax CGST - _GST",
"sgst_account": "Output Tax SGST - _GST",
"igst_account": "Output Tax IGST - _GST"
})
gst_settings.save()

View File

@ -1,8 +0,0 @@
// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('Lower Deduction Certificate', {
// refresh: function(frm) {
// }
});

View File

@ -1,140 +0,0 @@
{
"actions": [],
"autoname": "field:certificate_no",
"creation": "2020-03-10 23:12:10.072631",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"certificate_details_section",
"tax_withholding_category",
"fiscal_year",
"column_break_3",
"certificate_no",
"section_break_3",
"supplier",
"column_break_7",
"pan_no",
"validity_details_section",
"valid_from",
"column_break_10",
"valid_upto",
"section_break_9",
"rate",
"column_break_14",
"certificate_limit"
],
"fields": [
{
"fieldname": "certificate_no",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Certificate No",
"reqd": 1,
"unique": 1
},
{
"fieldname": "section_break_3",
"fieldtype": "Section Break",
"label": "Deductee Details"
},
{
"fieldname": "supplier",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Supplier",
"options": "Supplier",
"reqd": 1
},
{
"fetch_from": "supplier.pan",
"fetch_if_empty": 1,
"fieldname": "pan_no",
"fieldtype": "Data",
"in_list_view": 1,
"label": "PAN No",
"reqd": 1
},
{
"fieldname": "validity_details_section",
"fieldtype": "Section Break",
"label": "Validity Details"
},
{
"fieldname": "valid_upto",
"fieldtype": "Date",
"label": "Valid Upto",
"reqd": 1
},
{
"fieldname": "section_break_9",
"fieldtype": "Section Break"
},
{
"fieldname": "rate",
"fieldtype": "Percent",
"label": "Rate Of TDS As Per Certificate",
"reqd": 1
},
{
"fieldname": "certificate_limit",
"fieldtype": "Currency",
"label": "Certificate Limit",
"reqd": 1
},
{
"fieldname": "certificate_details_section",
"fieldtype": "Section Break",
"label": "Certificate Details"
},
{
"fieldname": "column_break_3",
"fieldtype": "Column Break"
},
{
"fieldname": "column_break_10",
"fieldtype": "Column Break"
},
{
"fieldname": "column_break_14",
"fieldtype": "Column Break"
},
{
"fieldname": "column_break_7",
"fieldtype": "Column Break"
},
{
"fieldname": "valid_from",
"fieldtype": "Date",
"in_list_view": 1,
"label": "Valid From",
"reqd": 1
},
{
"fieldname": "fiscal_year",
"fieldtype": "Link",
"label": "Fiscal Year",
"options": "Fiscal Year",
"reqd": 1
},
{
"fieldname": "tax_withholding_category",
"fieldtype": "Link",
"label": "Tax Withholding Category",
"options": "Tax Withholding Category",
"reqd": 1
}
],
"index_web_pages_for_search": 1,
"links": [],
"modified": "2021-10-23 18:33:38.962622",
"modified_by": "Administrator",
"module": "Regional",
"name": "Lower Deduction Certificate",
"naming_rule": "By fieldname",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}

View File

@ -1,50 +0,0 @@
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
import frappe
from frappe import _
from frappe.model.document import Document
from frappe.utils import get_link_to_form, getdate
from erpnext.accounts.utils import get_fiscal_year
class LowerDeductionCertificate(Document):
def validate(self):
self.validate_dates()
self.validate_supplier_against_tax_category()
def validate_dates(self):
if getdate(self.valid_upto) < getdate(self.valid_from):
frappe.throw(_("Valid Upto date cannot be before Valid From date"))
fiscal_year = get_fiscal_year(fiscal_year=self.fiscal_year, as_dict=True)
if not (fiscal_year.year_start_date <= getdate(self.valid_from) \
<= fiscal_year.year_end_date):
frappe.throw(_("Valid From date not in Fiscal Year {0}").format(frappe.bold(self.fiscal_year)))
if not (fiscal_year.year_start_date <= getdate(self.valid_upto) \
<= fiscal_year.year_end_date):
frappe.throw(_("Valid Upto date not in Fiscal Year {0}").format(frappe.bold(self.fiscal_year)))
def validate_supplier_against_tax_category(self):
duplicate_certificate = frappe.db.get_value('Lower Deduction Certificate',
{'supplier': self.supplier, 'tax_withholding_category': self.tax_withholding_category, 'name': ("!=", self.name)},
['name', 'valid_from', 'valid_upto'], as_dict=True)
if duplicate_certificate and self.are_dates_overlapping(duplicate_certificate):
certificate_link = get_link_to_form('Lower Deduction Certificate', duplicate_certificate.name)
frappe.throw(_("There is already a valid Lower Deduction Certificate {0} for Supplier {1} against category {2} for this time period.")
.format(certificate_link, frappe.bold(self.supplier), frappe.bold(self.tax_withholding_category)))
def are_dates_overlapping(self,duplicate_certificate):
valid_from = duplicate_certificate.valid_from
valid_upto = duplicate_certificate.valid_upto
if valid_from <= getdate(self.valid_from) <= valid_upto:
return True
elif valid_from <= getdate(self.valid_upto) <= valid_upto:
return True
elif getdate(self.valid_from) <= valid_from and valid_upto <= getdate(self.valid_upto):
return True
return False

View File

@ -1,9 +0,0 @@
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
# import frappe
import unittest
class TestLowerDeductionCertificate(unittest.TestCase):
pass

View File

@ -1,67 +0,0 @@
// Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('Tax Exemption 80G Certificate', {
refresh: function(frm) {
if (frm.doc.donor) {
frm.set_query('donation', function() {
return {
filters: {
docstatus: 1,
donor: frm.doc.donor
}
};
});
}
},
recipient: function(frm) {
if (frm.doc.recipient === 'Donor') {
frm.set_value({
'member': '',
'member_name': '',
'member_email': '',
'member_pan_number': '',
'fiscal_year': '',
'total': 0,
'payments': []
});
} else {
frm.set_value({
'donor': '',
'donor_name': '',
'donor_email': '',
'donor_pan_number': '',
'donation': '',
'date_of_donation': '',
'amount': 0,
'mode_of_payment': '',
'razorpay_payment_id': ''
});
}
},
get_payments: function(frm) {
frm.call({
doc: frm.doc,
method: 'get_payments',
freeze: true
});
},
company: function(frm) {
if ((frm.doc.member || frm.doc.donor) && frm.doc.company) {
frm.call({
doc: frm.doc,
method: 'set_company_address',
freeze: true
});
}
},
donation: function(frm) {
if (frm.doc.recipient === 'Donor' && !frm.doc.donor) {
frappe.msgprint(__('Please select donor first'));
}
}
});

View File

@ -1,297 +0,0 @@
{
"actions": [],
"autoname": "naming_series:",
"creation": "2021-02-15 12:37:21.577042",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"naming_series",
"recipient",
"member",
"member_name",
"member_email",
"member_pan_number",
"donor",
"donor_name",
"donor_email",
"donor_pan_number",
"column_break_4",
"date",
"fiscal_year",
"section_break_11",
"company",
"company_address",
"company_address_display",
"column_break_14",
"company_pan_number",
"company_80g_number",
"company_80g_wef",
"title",
"section_break_6",
"get_payments",
"payments",
"total",
"donation_details_section",
"donation",
"date_of_donation",
"amount",
"column_break_27",
"mode_of_payment",
"razorpay_payment_id"
],
"fields": [
{
"fieldname": "recipient",
"fieldtype": "Select",
"in_list_view": 1,
"label": "Certificate Recipient",
"options": "Member\nDonor",
"reqd": 1
},
{
"depends_on": "eval:doc.recipient === \"Member\";",
"fieldname": "member",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Member",
"mandatory_depends_on": "eval:doc.recipient === \"Member\";",
"options": "Member"
},
{
"depends_on": "eval:doc.recipient === \"Member\";",
"fetch_from": "member.member_name",
"fieldname": "member_name",
"fieldtype": "Data",
"label": "Member Name",
"read_only": 1
},
{
"depends_on": "eval:doc.recipient === \"Donor\";",
"fieldname": "donor",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Donor",
"mandatory_depends_on": "eval:doc.recipient === \"Donor\";",
"options": "Donor"
},
{
"fieldname": "column_break_4",
"fieldtype": "Column Break"
},
{
"fieldname": "date",
"fieldtype": "Date",
"label": "Date",
"reqd": 1
},
{
"depends_on": "eval:doc.recipient === \"Member\";",
"fieldname": "section_break_6",
"fieldtype": "Section Break"
},
{
"fieldname": "payments",
"fieldtype": "Table",
"label": "Payments",
"options": "Tax Exemption 80G Certificate Detail"
},
{
"fieldname": "total",
"fieldtype": "Currency",
"in_list_view": 1,
"label": "Total",
"read_only": 1
},
{
"depends_on": "eval:doc.recipient === \"Member\";",
"fieldname": "fiscal_year",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Fiscal Year",
"options": "Fiscal Year"
},
{
"fieldname": "company",
"fieldtype": "Link",
"label": "Company",
"options": "Company",
"reqd": 1
},
{
"fieldname": "get_payments",
"fieldtype": "Button",
"label": "Get Memberships"
},
{
"fieldname": "naming_series",
"fieldtype": "Select",
"label": "Naming Series",
"options": "NPO-80G-.YYYY.-"
},
{
"fieldname": "section_break_11",
"fieldtype": "Section Break",
"label": "Company Details"
},
{
"fieldname": "company_address",
"fieldtype": "Link",
"label": "Company Address",
"options": "Address"
},
{
"fieldname": "column_break_14",
"fieldtype": "Column Break"
},
{
"fetch_from": "company.pan_details",
"fieldname": "company_pan_number",
"fieldtype": "Data",
"label": "PAN Number",
"read_only": 1
},
{
"fieldname": "company_address_display",
"fieldtype": "Small Text",
"hidden": 1,
"label": "Company Address Display",
"print_hide": 1,
"read_only": 1
},
{
"fetch_from": "company.company_80g_number",
"fieldname": "company_80g_number",
"fieldtype": "Data",
"label": "80G Number",
"read_only": 1
},
{
"fetch_from": "company.with_effect_from",
"fieldname": "company_80g_wef",
"fieldtype": "Date",
"label": "80G With Effect From",
"read_only": 1
},
{
"depends_on": "eval:doc.recipient === \"Donor\";",
"fieldname": "donation_details_section",
"fieldtype": "Section Break",
"label": "Donation Details"
},
{
"fieldname": "donation",
"fieldtype": "Link",
"label": "Donation",
"mandatory_depends_on": "eval:doc.recipient === \"Donor\";",
"options": "Donation"
},
{
"fetch_from": "donation.amount",
"fieldname": "amount",
"fieldtype": "Currency",
"label": "Amount",
"read_only": 1
},
{
"fetch_from": "donation.mode_of_payment",
"fieldname": "mode_of_payment",
"fieldtype": "Link",
"label": "Mode of Payment",
"options": "Mode of Payment",
"read_only": 1
},
{
"fetch_from": "donation.razorpay_payment_id",
"fieldname": "razorpay_payment_id",
"fieldtype": "Data",
"label": "RazorPay Payment ID",
"read_only": 1
},
{
"fetch_from": "donation.date",
"fieldname": "date_of_donation",
"fieldtype": "Date",
"label": "Date of Donation",
"read_only": 1
},
{
"fieldname": "column_break_27",
"fieldtype": "Column Break"
},
{
"depends_on": "eval:doc.recipient === \"Donor\";",
"fetch_from": "donor.donor_name",
"fieldname": "donor_name",
"fieldtype": "Data",
"label": "Donor Name",
"read_only": 1
},
{
"depends_on": "eval:doc.recipient === \"Donor\";",
"fetch_from": "donor.email",
"fieldname": "donor_email",
"fieldtype": "Data",
"label": "Email",
"read_only": 1
},
{
"depends_on": "eval:doc.recipient === \"Member\";",
"fetch_from": "member.email_id",
"fieldname": "member_email",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Email",
"read_only": 1
},
{
"depends_on": "eval:doc.recipient === \"Member\";",
"fetch_from": "member.pan_number",
"fieldname": "member_pan_number",
"fieldtype": "Data",
"label": "PAN Details",
"read_only": 1
},
{
"depends_on": "eval:doc.recipient === \"Donor\";",
"fetch_from": "donor.pan_number",
"fieldname": "donor_pan_number",
"fieldtype": "Data",
"label": "PAN Details",
"read_only": 1
},
{
"fieldname": "title",
"fieldtype": "Data",
"hidden": 1,
"label": "Title",
"print_hide": 1
}
],
"index_web_pages_for_search": 1,
"links": [],
"modified": "2021-02-22 00:03:34.215633",
"modified_by": "Administrator",
"module": "Regional",
"name": "Tax Exemption 80G Certificate",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"share": 1,
"write": 1
}
],
"search_fields": "member, member_name",
"sort_field": "modified",
"sort_order": "DESC",
"title_field": "title",
"track_changes": 1
}

View File

@ -1,104 +0,0 @@
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
import frappe
from frappe import _
from frappe.contacts.doctype.address.address import get_company_address
from frappe.model.document import Document
from frappe.utils import flt, get_link_to_form, getdate
from erpnext.accounts.utils import get_fiscal_year
class TaxExemption80GCertificate(Document):
def validate(self):
self.validate_date()
self.validate_duplicates()
self.validate_company_details()
self.set_company_address()
self.calculate_total()
self.set_title()
def validate_date(self):
if self.recipient == 'Member':
if getdate(self.date):
fiscal_year = get_fiscal_year(fiscal_year=self.fiscal_year, as_dict=True)
if not (fiscal_year.year_start_date <= getdate(self.date) \
<= fiscal_year.year_end_date):
frappe.throw(_('The Certificate Date is not in the Fiscal Year {0}').format(frappe.bold(self.fiscal_year)))
def validate_duplicates(self):
if self.recipient == 'Donor':
certificate = frappe.db.exists(self.doctype, {
'donation': self.donation,
'name': ('!=', self.name)
})
if certificate:
frappe.throw(_('An 80G Certificate {0} already exists for the donation {1}').format(
get_link_to_form(self.doctype, certificate), frappe.bold(self.donation)
), title=_('Duplicate Certificate'))
def validate_company_details(self):
fields = ['company_80g_number', 'with_effect_from', 'pan_details']
company_details = frappe.db.get_value('Company', self.company, fields, as_dict=True)
if not company_details.company_80g_number:
frappe.throw(_('Please set the {0} for company {1}').format(frappe.bold('80G Number'),
get_link_to_form('Company', self.company)))
if not company_details.pan_details:
frappe.throw(_('Please set the {0} for company {1}').format(frappe.bold('PAN Number'),
get_link_to_form('Company', self.company)))
@frappe.whitelist()
def set_company_address(self):
address = get_company_address(self.company)
self.company_address = address.company_address
self.company_address_display = address.company_address_display
def calculate_total(self):
if self.recipient == 'Donor':
return
total = 0
for entry in self.payments:
total += flt(entry.amount)
self.total = total
def set_title(self):
if self.recipient == 'Member':
self.title = self.member_name
else:
self.title = self.donor_name
@frappe.whitelist()
def get_payments(self):
if not self.member:
frappe.throw(_('Please select a Member first.'))
fiscal_year = get_fiscal_year(fiscal_year=self.fiscal_year, as_dict=True)
memberships = frappe.db.get_all('Membership', {
'member': self.member,
'from_date': ['between', (fiscal_year.year_start_date, fiscal_year.year_end_date)],
'membership_status': ('!=', 'Cancelled')
}, ['from_date', 'amount', 'name', 'invoice', 'payment_id'], order_by='from_date')
if not memberships:
frappe.msgprint(_('No Membership Payments found against the Member {0}').format(self.member))
total = 0
self.payments = []
for doc in memberships:
self.append('payments', {
'date': doc.from_date,
'amount': doc.amount,
'invoice_id': doc.invoice,
'razorpay_payment_id': doc.payment_id,
'membership': doc.name
})
total += flt(doc.amount)
self.total = total

View File

@ -1,106 +0,0 @@
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
import unittest
import frappe
from frappe.utils import getdate
from erpnext.accounts.utils import get_fiscal_year
from erpnext.non_profit.doctype.donation.donation import create_donation
from erpnext.non_profit.doctype.donation.test_donation import (
create_donor,
create_donor_type,
create_mode_of_payment,
)
from erpnext.non_profit.doctype.member.member import create_member
from erpnext.non_profit.doctype.membership.test_membership import make_membership, setup_membership
class TestTaxExemption80GCertificate(unittest.TestCase):
def setUp(self):
frappe.db.sql('delete from `tabTax Exemption 80G Certificate`')
frappe.db.sql('delete from `tabMembership`')
create_donor_type()
settings = frappe.get_doc('Non Profit Settings')
settings.company = '_Test Company'
settings.donation_company = '_Test Company'
settings.default_donor_type = '_Test Donor'
settings.creation_user = 'Administrator'
settings.save()
company = frappe.get_doc('Company', '_Test Company')
company.pan_details = 'BBBTI3374C'
company.company_80g_number = 'NQ.CIT(E)I2018-19/DEL-IE28615-27062018/10087'
company.with_effect_from = getdate()
company.save()
def test_duplicate_donation_certificate(self):
donor = create_donor()
create_mode_of_payment()
payment = frappe._dict({
'amount': 100,
'method': 'Debit Card',
'id': 'pay_MeXAmsgeKOhq7O'
})
donation = create_donation(donor, payment)
args = frappe._dict({
'recipient': 'Donor',
'donor': donor.name,
'donation': donation.name
})
certificate = create_80g_certificate(args)
certificate.insert()
# check company details
self.assertEqual(certificate.company_pan_number, 'BBBTI3374C')
self.assertEqual(certificate.company_80g_number, 'NQ.CIT(E)I2018-19/DEL-IE28615-27062018/10087')
# check donation details
self.assertEqual(certificate.amount, donation.amount)
duplicate_certificate = create_80g_certificate(args)
# duplicate validation
self.assertRaises(frappe.ValidationError, duplicate_certificate.insert)
def test_membership_80g_certificate(self):
plan = setup_membership()
# make test member
member_doc = create_member(frappe._dict({
'fullname': "_Test_Member",
'email': "_test_member_erpnext@example.com",
'plan_id': plan.name
}))
member_doc.make_customer_and_link()
member = member_doc.name
membership = make_membership(member, { "from_date": getdate() })
invoice = membership.generate_invoice(save=True)
args = frappe._dict({
'recipient': 'Member',
'member': member,
'fiscal_year': get_fiscal_year(getdate(), as_dict=True).get('name')
})
certificate = create_80g_certificate(args)
certificate.get_payments()
certificate.insert()
self.assertEqual(len(certificate.payments), 1)
self.assertEqual(certificate.payments[0].amount, membership.amount)
self.assertEqual(certificate.payments[0].invoice_id, invoice.name)
def create_80g_certificate(args):
certificate = frappe.get_doc({
'doctype': 'Tax Exemption 80G Certificate',
'recipient': args.recipient,
'date': getdate(),
'company': '_Test Company'
})
certificate.update(args)
return certificate

View File

@ -1,66 +0,0 @@
{
"actions": [],
"creation": "2021-02-15 12:43:52.754124",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"date",
"amount",
"invoice_id",
"column_break_4",
"razorpay_payment_id",
"membership"
],
"fields": [
{
"fieldname": "date",
"fieldtype": "Date",
"in_list_view": 1,
"label": "Date",
"reqd": 1
},
{
"fieldname": "amount",
"fieldtype": "Currency",
"in_list_view": 1,
"label": "Amount",
"reqd": 1
},
{
"fieldname": "invoice_id",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Invoice ID",
"options": "Sales Invoice",
"reqd": 1
},
{
"fieldname": "razorpay_payment_id",
"fieldtype": "Data",
"label": "Razorpay Payment ID"
},
{
"fieldname": "membership",
"fieldtype": "Link",
"label": "Membership",
"options": "Membership"
},
{
"fieldname": "column_break_4",
"fieldtype": "Column Break"
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2021-02-15 16:35:10.777587",
"modified_by": "Administrator",
"module": "Regional",
"name": "Tax Exemption 80G Certificate Detail",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}

View File

@ -1,10 +0,0 @@
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
# import frappe
from frappe.model.document import Document
class TaxExemption80GCertificateDetail(Document):
pass

View File

@ -1,83 +0,0 @@
states = [
'',
'Andaman and Nicobar Islands',
'Andhra Pradesh',
'Arunachal Pradesh',
'Assam',
'Bihar',
'Chandigarh',
'Chhattisgarh',
'Dadra and Nagar Haveli and Daman and Diu',
'Delhi',
'Goa',
'Gujarat',
'Haryana',
'Himachal Pradesh',
'Jammu and Kashmir',
'Jharkhand',
'Karnataka',
'Kerala',
'Ladakh',
'Lakshadweep Islands',
'Madhya Pradesh',
'Maharashtra',
'Manipur',
'Meghalaya',
'Mizoram',
'Nagaland',
'Odisha',
'Other Territory',
'Pondicherry',
'Punjab',
'Rajasthan',
'Sikkim',
'Tamil Nadu',
'Telangana',
'Tripura',
'Uttar Pradesh',
'Uttarakhand',
'West Bengal',
]
state_numbers = {
"Andaman and Nicobar Islands": "35",
"Andhra Pradesh": "37",
"Arunachal Pradesh": "12",
"Assam": "18",
"Bihar": "10",
"Chandigarh": "04",
"Chhattisgarh": "22",
"Dadra and Nagar Haveli and Daman and Diu": "26",
"Delhi": "07",
"Goa": "30",
"Gujarat": "24",
"Haryana": "06",
"Himachal Pradesh": "02",
"Jammu and Kashmir": "01",
"Jharkhand": "20",
"Karnataka": "29",
"Kerala": "32",
"Ladakh": "38",
"Lakshadweep Islands": "31",
"Madhya Pradesh": "23",
"Maharashtra": "27",
"Manipur": "14",
"Meghalaya": "17",
"Mizoram": "15",
"Nagaland": "13",
"Odisha": "21",
"Other Territory": "97",
"Pondicherry": "34",
"Punjab": "03",
"Rajasthan": "08",
"Sikkim": "11",
"Tamil Nadu": "33",
"Telangana": "36",
"Tripura": "16",
"Uttar Pradesh": "09",
"Uttarakhand": "05",
"West Bengal": "19",
}
number_state_mapping = {v: k for k, v in state_numbers.items()}

View File

@ -1,31 +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.gross_amount}",
"Discount": "{item.discount_amount}",
"AssAmt": "{item.taxable_value}",
"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}",
"CesNonAdvlAmt": "{item.cess_nadv_amount}",
"StateCesRt": "{item.state_cess_rate}",
"StateCesAmt": "{item.state_cess_amount}",
"StateCesNonAdvlAmt": "{item.state_cess_nadv_amount}",
"OthChrg": "{item.other_charges}",
"TotItemVal": "{item.total_value}",
"BchDtls": {{
"Nm": "{item.batch_no}",
"ExpDt": "{item.batch_expiry_date}"
}}
}}

View File

@ -1,110 +0,0 @@
{{
"Version": "1.1",
"TranDtls": {{
"TaxSch": "{transaction_details.tax_scheme}",
"SupTyp": "{transaction_details.supply_type}",
"RegRev": "{transaction_details.reverse_charge}",
"EcmGstin": "{transaction_details.ecom_gstin}",
"IgstOnIntra": "{transaction_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.legal_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": "{invoice_value_details.base_total}",
"CgstVal": "{invoice_value_details.total_cgst_amt}",
"SgstVal": "{invoice_value_details.total_sgst_amt}",
"IgstVal": "{invoice_value_details.total_igst_amt}",
"CesVal": "{invoice_value_details.total_cess_amt}",
"Discount": "{invoice_value_details.invoice_discount_amt}",
"RndOffAmt": "{invoice_value_details.round_off}",
"OthChrg": "{invoice_value_details.total_other_charges}",
"TotInvVal": "{invoice_value_details.base_grand_total}",
"TotInvValFc": "{invoice_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}"
}}
}}

View File

@ -1,957 +0,0 @@
{
"Version": {
"type": "string",
"minLength": 1,
"maxLength": 6,
"description": "Version of the schema"
},
"Irn": {
"type": "string",
"minLength": 64,
"maxLength": 64,
"description": "Invoice Reference Number"
},
"TranDtls": {
"type": "object",
"properties": {
"TaxSch": {
"type": "string",
"minLength": 3,
"maxLength": 10,
"enum": ["GST"],
"description": "GST- Goods and Services Tax Scheme"
},
"SupTyp": {
"type": "string",
"minLength": 3,
"maxLength": 10,
"enum": ["B2B", "SEZWP", "SEZWOP", "EXPWP", "EXPWOP", "DEXP"],
"description": "Type of Supply: B2B-Business to Business, SEZWP - SEZ with payment, SEZWOP - SEZ without payment, EXPWP - Export with Payment, EXPWOP - Export without payment,DEXP - Deemed Export"
},
"RegRev": {
"type": "string",
"minLength": 1,
"maxLength": 1,
"enum": ["Y", "N"],
"description": "Y- whether the tax liability is payable under reverse charge"
},
"EcmGstin": {
"type": "string",
"minLength": 15,
"maxLength": 15,
"pattern": "([0-9]{2}[0-9A-Z]{13})",
"description": "E-Commerce GSTIN",
"validationMsg": "E-Commerce GSTIN is invalid"
},
"IgstOnIntra": {
"type": "string",
"minLength": 1,
"maxLength": 1,
"enum": ["Y", "N"],
"description": "Y- indicates the supply is intra state but chargeable to IGST"
}
},
"required": ["TaxSch", "SupTyp"]
},
"DocDtls": {
"type": "object",
"properties": {
"Typ": {
"type": "string",
"minLength": 3,
"maxLength": 3,
"enum": ["INV", "CRN", "DBN"],
"description": "Document Type"
},
"No": {
"type": "string",
"minLength": 1,
"maxLength": 16,
"pattern": "^([A-Z1-9]{1}[A-Z0-9/-]{0,15})$",
"description": "Document Number",
"validationMsg": "Document Number 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]",
"description": "Document Date"
}
},
"required": ["Typ", "No", "Dt"]
},
"SellerDtls": {
"type": "object",
"properties": {
"Gstin": {
"type": "string",
"minLength": 15,
"maxLength": 15,
"pattern": "([0-9]{2}[0-9A-Z]{13})",
"description": "Supplier GSTIN",
"validationMsg": "Company GSTIN is invalid"
},
"LglNm": {
"type": "string",
"minLength": 3,
"maxLength": 100,
"description": "Legal Name"
},
"TrdNm": {
"type": "string",
"minLength": 3,
"maxLength": 100,
"description": "Tradename"
},
"Addr1": {
"type": "string",
"minLength": 1,
"maxLength": 100,
"description": "Address Line 1"
},
"Addr2": {
"type": "string",
"minLength": 3,
"maxLength": 100,
"description": "Address Line 2"
},
"Loc": {
"type": "string",
"minLength": 3,
"maxLength": 50,
"description": "Location"
},
"Pin": {
"type": "number",
"minimum": 100000,
"maximum": 999999,
"description": "Pincode"
},
"Stcd": {
"type": "string",
"minLength": 1,
"maxLength": 2,
"description": "Supplier State Code"
},
"Ph": {
"type": "string",
"minLength": 6,
"maxLength": 12,
"description": "Phone"
},
"Em": {
"type": "string",
"minLength": 6,
"maxLength": 100,
"description": "Email-Id"
}
},
"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)$",
"description": "Buyer GSTIN",
"validationMsg": "Customer GSTIN is invalid"
},
"LglNm": {
"type": "string",
"minLength": 3,
"maxLength": 100,
"description": "Legal Name"
},
"TrdNm": {
"type": "string",
"minLength": 3,
"maxLength": 100,
"description": "Trade Name"
},
"Pos": {
"type": "string",
"minLength": 1,
"maxLength": 2,
"description": "Place of Supply State code"
},
"Addr1": {
"type": "string",
"minLength": 1,
"maxLength": 100,
"description": "Address Line 1"
},
"Addr2": {
"type": "string",
"minLength": 3,
"maxLength": 100,
"description": "Address Line 2"
},
"Loc": {
"type": "string",
"minLength": 3,
"maxLength": 100,
"description": "Location"
},
"Pin": {
"type": "number",
"minimum": 100000,
"maximum": 999999,
"description": "Pincode"
},
"Stcd": {
"type": "string",
"minLength": 1,
"maxLength": 2,
"description": "Buyer State Code"
},
"Ph": {
"type": "string",
"minLength": 6,
"maxLength": 12,
"description": "Phone"
},
"Em": {
"type": "string",
"minLength": 6,
"maxLength": 100,
"description": "Email-Id"
}
},
"required": ["Gstin", "LglNm", "Pos", "Addr1", "Loc", "Stcd"]
},
"DispDtls": {
"type": "object",
"properties": {
"Nm": {
"type": "string",
"minLength": 3,
"maxLength": 100,
"description": "Dispatch Address Name"
},
"Addr1": {
"type": "string",
"minLength": 1,
"maxLength": 100,
"description": "Address Line 1"
},
"Addr2": {
"type": "string",
"minLength": 3,
"maxLength": 100,
"description": "Address Line 2"
},
"Loc": {
"type": "string",
"minLength": 3,
"maxLength": 100,
"description": "Location"
},
"Pin": {
"type": "number",
"minimum": 100000,
"maximum": 999999,
"description": "Pincode"
},
"Stcd": {
"type": "string",
"minLength": 1,
"maxLength": 2,
"description": "State Code"
}
},
"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)$",
"description": "Shipping Address GSTIN",
"validationMsg": "Shipping Address GSTIN is invalid"
},
"LglNm": {
"type": "string",
"minLength": 3,
"maxLength": 100,
"description": "Legal Name"
},
"TrdNm": {
"type": "string",
"minLength": 3,
"maxLength": 100,
"description": "Trade Name"
},
"Addr1": {
"type": "string",
"minLength": 1,
"maxLength": 100,
"description": "Address Line 1"
},
"Addr2": {
"type": "string",
"minLength": 3,
"maxLength": 100,
"description": "Address Line 2"
},
"Loc": {
"type": "string",
"minLength": 3,
"maxLength": 100,
"description": "Location"
},
"Pin": {
"type": "number",
"minimum": 100000,
"maximum": 999999,
"description": "Pincode"
},
"Stcd": {
"type": "string",
"minLength": 1,
"maxLength": 2,
"description": "State Code"
}
},
"required": ["LglNm", "Addr1", "Loc", "Pin", "Stcd"]
},
"ItemList": {
"type": "Array",
"properties": {
"SlNo": {
"type": "string",
"minLength": 1,
"maxLength": 6,
"description": "Serial No. of Item"
},
"PrdDesc": {
"type": "string",
"minLength": 3,
"maxLength": 300,
"description": "Item Name"
},
"IsServc": {
"type": "string",
"minLength": 1,
"maxLength": 1,
"enum": ["Y", "N"],
"description": "Is Service Item"
},
"HsnCd": {
"type": "string",
"minLength": 4,
"maxLength": 8,
"description": "HSN Code"
},
"Barcde": {
"type": "string",
"minLength": 3,
"maxLength": 30,
"description": "Barcode"
},
"Qty": {
"type": "number",
"minimum": 0,
"maximum": 9999999999.999,
"description": "Quantity"
},
"FreeQty": {
"type": "number",
"minimum": 0,
"maximum": 9999999999.999,
"description": "Free Quantity"
},
"Unit": {
"type": "string",
"minLength": 3,
"maxLength": 8,
"description": "UOM"
},
"UnitPrice": {
"type": "number",
"minimum": 0,
"maximum": 999999999999.999,
"description": "Rate"
},
"TotAmt": {
"type": "number",
"minimum": 0,
"maximum": 999999999999.99,
"description": "Gross Amount"
},
"Discount": {
"type": "number",
"minimum": 0,
"maximum": 999999999999.99,
"description": "Discount"
},
"PreTaxVal": {
"type": "number",
"minimum": 0,
"maximum": 999999999999.99,
"description": "Pre tax value"
},
"AssAmt": {
"type": "number",
"minimum": 0,
"maximum": 999999999999.99,
"description": "Taxable Value"
},
"GstRt": {
"type": "number",
"minimum": 0,
"maximum": 999.999,
"description": "GST Rate"
},
"IgstAmt": {
"type": "number",
"minimum": 0,
"maximum": 999999999999.99,
"description": "IGST Amount"
},
"CgstAmt": {
"type": "number",
"minimum": 0,
"maximum": 999999999999.99,
"description": "CGST Amount"
},
"SgstAmt": {
"type": "number",
"minimum": 0,
"maximum": 999999999999.99,
"description": "SGST Amount"
},
"CesRt": {
"type": "number",
"minimum": 0,
"maximum": 999.999,
"description": "Cess Rate"
},
"CesAmt": {
"type": "number",
"minimum": 0,
"maximum": 999999999999.99,
"description": "Cess Amount (Advalorem)"
},
"CesNonAdvlAmt": {
"type": "number",
"minimum": 0,
"maximum": 999999999999.99,
"description": "Cess Amount (Non-Advalorem)"
},
"StateCesRt": {
"type": "number",
"minimum": 0,
"maximum": 999.999,
"description": "State CESS Rate"
},
"StateCesAmt": {
"type": "number",
"minimum": 0,
"maximum": 999999999999.99,
"description": "State CESS Amount"
},
"StateCesNonAdvlAmt": {
"type": "number",
"minimum": 0,
"maximum": 999999999999.99,
"description": "State CESS Amount (Non Advalorem)"
},
"OthChrg": {
"type": "number",
"minimum": 0,
"maximum": 999999999999.99,
"description": "Other Charges"
},
"TotItemVal": {
"type": "number",
"minimum": 0,
"maximum": 999999999999.99,
"description": "Total Item Value"
},
"OrdLineRef": {
"type": "string",
"minLength": 1,
"maxLength": 50,
"description": "Order line reference"
},
"OrgCntry": {
"type": "string",
"minLength": 2,
"maxLength": 2,
"description": "Origin Country"
},
"PrdSlNo": {
"type": "string",
"minLength": 1,
"maxLength": 20,
"description": "Serial number"
},
"BchDtls": {
"type": "object",
"properties": {
"Nm": {
"type": "string",
"minLength": 3,
"maxLength": 20,
"description": "Batch number"
},
"ExpDt": {
"type": "string",
"maxLength": 10,
"minLength": 10,
"pattern": "[0-3][0-9]/[0-1][0-9]/[2][0][1-2][0-9]",
"description": "Batch Expiry Date"
},
"WrDt": {
"type": "string",
"maxLength": 10,
"minLength": 10,
"pattern": "[0-3][0-9]/[0-1][0-9]/[2][0][1-2][0-9]",
"description": "Warranty Date"
}
},
"required": ["Nm"]
},
"AttribDtls": {
"type": "Array",
"Attribute": {
"type": "object",
"properties": {
"Nm": {
"type": "string",
"minLength": 1,
"maxLength": 100,
"description": "Attribute name of the item"
},
"Val": {
"type": "string",
"minLength": 1,
"maxLength": 100,
"description": "Attribute value of the item"
}
}
}
}
},
"required": [
"SlNo",
"IsServc",
"HsnCd",
"UnitPrice",
"TotAmt",
"AssAmt",
"GstRt",
"TotItemVal"
]
},
"ValDtls": {
"type": "object",
"properties": {
"AssVal": {
"type": "number",
"minimum": 0,
"maximum": 99999999999999.99,
"description": "Total Assessable value of all items"
},
"CgstVal": {
"type": "number",
"maximum": 99999999999999.99,
"minimum": 0,
"description": "Total CGST value of all items"
},
"SgstVal": {
"type": "number",
"minimum": 0,
"maximum": 99999999999999.99,
"description": "Total SGST value of all items"
},
"IgstVal": {
"type": "number",
"minimum": 0,
"maximum": 99999999999999.99,
"description": "Total IGST value of all items"
},
"CesVal": {
"type": "number",
"minimum": 0,
"maximum": 99999999999999.99,
"description": "Total CESS value of all items"
},
"StCesVal": {
"type": "number",
"minimum": 0,
"maximum": 99999999999999.99,
"description": "Total State CESS value of all items"
},
"Discount": {
"type": "number",
"minimum": 0,
"maximum": 99999999999999.99,
"description": "Invoice Discount"
},
"OthChrg": {
"type": "number",
"minimum": 0,
"maximum": 99999999999999.99,
"description": "Other Charges"
},
"RndOffAmt": {
"type": "number",
"minimum": -99.99,
"maximum": 99.99,
"description": "Rounded off Amount"
},
"TotInvVal": {
"type": "number",
"minimum": 0,
"maximum": 99999999999999.99,
"description": "Final Invoice Value "
},
"TotInvValFc": {
"type": "number",
"minimum": 0,
"maximum": 99999999999999.99,
"description": "Final Invoice value in Foreign Currency"
}
},
"required": ["AssVal", "TotInvVal"]
},
"PayDtls": {
"type": "object",
"properties": {
"Nm": {
"type": "string",
"minLength": 1,
"maxLength": 100,
"description": "Payee Name"
},
"AccDet": {
"type": "string",
"minLength": 1,
"maxLength": 18,
"description": "Bank Account Number of Payee"
},
"Mode": {
"type": "string",
"minLength": 1,
"maxLength": 18,
"description": "Mode of Payment"
},
"FinInsBr": {
"type": "string",
"minLength": 1,
"maxLength": 11,
"description": "Branch or IFSC code"
},
"PayTerm": {
"type": "string",
"minLength": 1,
"maxLength": 100,
"description": "Terms of Payment"
},
"PayInstr": {
"type": "string",
"minLength": 1,
"maxLength": 100,
"description": "Payment Instruction"
},
"CrTrn": {
"type": "string",
"minLength": 1,
"maxLength": 100,
"description": "Credit Transfer"
},
"DirDr": {
"type": "string",
"minLength": 1,
"maxLength": 100,
"description": "Direct Debit"
},
"CrDay": {
"type": "number",
"minimum": 0,
"maximum": 9999,
"description": "Credit Days"
},
"PaidAmt": {
"type": "number",
"minimum": 0,
"maximum": 99999999999999.99,
"description": "Advance Amount"
},
"PaymtDue": {
"type": "number",
"minimum": 0,
"maximum": 99999999999999.99,
"description": "Outstanding Amount"
}
}
},
"RefDtls": {
"type": "object",
"properties": {
"InvRm": {
"type": "string",
"maxLength": 100,
"minLength": 3,
"pattern": "^[0-9A-Za-z/-]{3,100}$",
"description": "Remarks/Note"
},
"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]",
"description": "Invoice Period Start Date"
},
"InvEndDt": {
"type": "string",
"maxLength": 10,
"minLength": 10,
"pattern": "[0-3][0-9]/[0-1][0-9]/[2][0][1-2][0-9]",
"description": "Invoice Period End Date"
}
},
"required": ["InvStDt ", "InvEndDt "]
},
"PrecDocDtls": {
"type": "object",
"properties": {
"InvNo": {
"type": "string",
"minLength": 1,
"maxLength": 16,
"pattern": "^[1-9A-Z]{1}[0-9A-Z/-]{1,15}$",
"description": "Reference of Original Invoice"
},
"InvDt": {
"type": "string",
"maxLength": 10,
"minLength": 10,
"pattern": "[0-3][0-9]/[0-1][0-9]/[2][0][1-2][0-9]",
"description": "Date of Orginal Invoice"
},
"OthRefNo": {
"type": "string",
"minLength": 1,
"maxLength": 20,
"description": "Other Reference"
}
}
},
"required": ["InvNo", "InvDt"],
"ContrDtls": {
"type": "object",
"properties": {
"RecAdvRefr": {
"type": "string",
"minLength": 1,
"maxLength": 20,
"pattern": "^([0-9A-Za-z/-]){1,20}$",
"description": "Receipt Advice No."
},
"RecAdvDt": {
"type": "string",
"minLength": 10,
"maxLength": 10,
"pattern": "[0-3][0-9]/[0-1][0-9]/[2][0][1-2][0-9]",
"description": "Date of receipt advice"
},
"TendRefr": {
"type": "string",
"minLength": 1,
"maxLength": 20,
"pattern": "^([0-9A-Za-z/-]){1,20}$",
"description": "Lot/Batch Reference No."
},
"ContrRefr": {
"type": "string",
"minLength": 1,
"maxLength": 20,
"pattern": "^([0-9A-Za-z/-]){1,20}$",
"description": "Contract Reference Number"
},
"ExtRefr": {
"type": "string",
"minLength": 1,
"maxLength": 20,
"pattern": "^([0-9A-Za-z/-]){1,20}$",
"description": "Any other reference"
},
"ProjRefr": {
"type": "string",
"minLength": 1,
"maxLength": 20,
"pattern": "^([0-9A-Za-z/-]){1,20}$",
"description": "Project Reference Number"
},
"PORefr": {
"type": "string",
"minLength": 1,
"maxLength": 16,
"pattern": "^([0-9A-Za-z/-]){1,16}$",
"description": "PO Reference Number"
},
"PORefDt": {
"type": "string",
"minLength": 10,
"maxLength": 10,
"pattern": "[0-3][0-9]/[0-1][0-9]/[2][0][1-2][0-9]",
"description": "PO Reference date"
}
}
}
}
},
"AddlDocDtls": {
"type": "Array",
"properties": {
"Url": {
"type": "string",
"minLength": 3,
"maxLength": 100,
"description": "Supporting document URL"
},
"Docs": {
"type": "string",
"minLength": 3,
"maxLength": 1000,
"description": "Supporting document in Base64 Format"
},
"Info": {
"type": "string",
"minLength": 3,
"maxLength": 1000,
"description": "Any additional information"
}
}
},
"ExpDtls": {
"type": "object",
"properties": {
"ShipBNo": {
"type": "string",
"minLength": 1,
"maxLength": 20,
"description": "Shipping Bill No."
},
"ShipBDt": {
"type": "string",
"minLength": 10,
"maxLength": 10,
"pattern": "[0-3][0-9]/[0-1][0-9]/[2][0][1-2][0-9]",
"description": "Shipping Bill Date"
},
"Port": {
"type": "string",
"minLength": 2,
"maxLength": 10,
"pattern": "^[0-9A-Za-z]{2,10}$",
"description": "Port Code. Refer the master"
},
"RefClm": {
"type": "string",
"minLength": 1,
"maxLength": 1,
"description": "Claiming Refund. Y/N"
},
"ForCur": {
"type": "string",
"minLength": 3,
"maxLength": 16,
"description": "Additional Currency Code. Refer the master"
},
"CntCode": {
"type": "string",
"minLength": 2,
"maxLength": 2,
"description": "Country Code. Refer the master"
},
"ExpDuty": {
"type": "number",
"minimum": 0,
"maximum": 999999999999.99,
"description": "Export Duty"
}
}
},
"EwbDtls": {
"type": "object",
"properties": {
"TransId": {
"type": "string",
"minLength": 15,
"maxLength": 15,
"description": "Transporter GSTIN"
},
"TransName": {
"type": "string",
"minLength": 3,
"maxLength": 100,
"description": "Transporter Name"
},
"TransMode": {
"type": "string",
"maxLength": 1,
"minLength": 1,
"enum": ["1", "2", "3", "4"],
"description": "Mode of Transport"
},
"Distance": {
"type": "number",
"minimum": 1,
"maximum": 9999,
"description": "Distance"
},
"TransDocNo": {
"type": "string",
"minLength": 1,
"maxLength": 15,
"pattern": "^([0-9A-Z/-]){1,15}$",
"description": "Tranport Document Number",
"validationMsg": "Transport Receipt No is invalid"
},
"TransDocDt": {
"type": "string",
"minLength": 10,
"maxLength": 10,
"pattern": "[0-3][0-9]/[0-1][0-9]/[2][0][1-2][0-9]",
"description": "Transport Document Date"
},
"VehNo": {
"type": "string",
"minLength": 4,
"maxLength": 20,
"description": "Vehicle Number"
},
"VehType": {
"type": "string",
"minLength": 1,
"maxLength": 1,
"enum": ["O", "R"],
"description": "Vehicle Type"
}
},
"required": ["Distance"]
},
"required": [
"Version",
"TranDtls",
"DocDtls",
"SellerDtls",
"BuyerDtls",
"ItemList",
"ValDtls"
]
}

View File

@ -1,292 +0,0 @@
erpnext.setup_einvoice_actions = (doctype) => {
frappe.ui.form.on(doctype, {
async refresh(frm) {
if (frm.doc.docstatus == 2) return;
const res = await frappe.call({
method: 'erpnext.regional.india.e_invoice.utils.validate_eligibility',
args: { doc: frm.doc }
});
const invoice_eligible = res.message;
if (!invoice_eligible) return;
const { doctype, irn, irn_cancelled, ewaybill, eway_bill_cancelled, name, __unsaved } = frm.doc;
const add_custom_button = (label, action) => {
if (!frm.custom_buttons[label]) {
frm.add_custom_button(label, action, __('E Invoicing'));
}
};
if (!irn && !__unsaved) {
const action = () => {
if (frm.doc.__unsaved) {
frappe.throw(__('Please save the document to generate IRN.'));
}
frappe.call({
method: 'erpnext.regional.india.e_invoice.utils.get_einvoice',
args: { doctype, docname: name },
freeze: true,
callback: (res) => {
const einvoice = res.message;
show_einvoice_preview(frm, einvoice);
}
});
};
add_custom_button(__("Generate IRN"), action);
}
if (irn && !irn_cancelled && !ewaybill) {
const 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
}
];
const action = () => {
const d = new frappe.ui.Dialog({
title: __("Cancel IRN"),
fields: fields,
primary_action: function() {
const data = d.get_values();
frappe.call({
method: 'erpnext.regional.india.e_invoice.utils.cancel_irn',
args: {
doctype,
docname: name,
irn: irn,
reason: data.reason.split('-')[0],
remark: data.remark
},
freeze: true,
callback: () => frm.reload_doc() || d.hide(),
error: () => d.hide()
});
},
primary_action_label: __('Submit')
});
d.show();
};
add_custom_button(__("Cancel IRN"), action);
}
if (irn && !irn_cancelled && !ewaybill) {
const action = () => {
const d = new frappe.ui.Dialog({
title: __('Generate E-Way Bill'),
size: "large",
fields: get_ewaybill_fields(frm),
primary_action: function() {
const data = d.get_values();
frappe.call({
method: 'erpnext.regional.india.e_invoice.utils.generate_eway_bill',
args: {
doctype,
docname: name,
irn,
...data
},
freeze: true,
callback: () => frm.reload_doc() || d.hide(),
error: () => d.hide()
});
},
primary_action_label: __('Submit')
});
d.show();
};
add_custom_button(__("Generate E-Way Bill"), action);
}
if (irn && ewaybill && !irn_cancelled && !eway_bill_cancelled) {
const action = () => {
let message = __('Cancellation of e-way bill is currently not supported.') + ' ';
message += '<br><br>';
message += __('You must first use the portal to cancel the e-way bill and then update the cancelled status in the ERPNext system.');
const dialog = frappe.msgprint({
title: __('Update E-Way Bill Cancelled Status?'),
message: message,
indicator: 'orange',
primary_action: {
action: function() {
frappe.call({
method: 'erpnext.regional.india.e_invoice.utils.cancel_eway_bill',
args: { doctype, docname: name },
freeze: true,
callback: () => frm.reload_doc() || dialog.hide()
});
}
},
primary_action_label: __('Yes')
});
};
add_custom_button(__("Cancel E-Way Bill"), action);
}
}
});
};
const get_ewaybill_fields = (frm) => {
return [
{
'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',
'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 request_irn_generation = (frm) => {
frappe.call({
method: 'erpnext.regional.india.e_invoice.utils.generate_irn',
args: { doctype: frm.doc.doctype, docname: frm.doc.name },
freeze: true,
callback: () => frm.reload_doc()
});
};
const get_preview_dialog = (frm, action) => {
const dialog = new frappe.ui.Dialog({
title: __("Preview"),
size: "large",
fields: [
{
"label": "Preview",
"fieldname": "preview_html",
"fieldtype": "HTML"
}
],
primary_action: () => action(frm) || dialog.hide(),
primary_action_label: __('Generate IRN')
});
return dialog;
};
const show_einvoice_preview = (frm, einvoice) => {
const preview_dialog = get_preview_dialog(frm, request_irn_generation);
// initialize e-invoice fields
einvoice["Irn"] = einvoice["AckNo"] = ''; einvoice["AckDt"] = frappe.datetime.nowdate();
frm.doc.signed_einvoice = JSON.stringify(einvoice);
// initialize preview wrapper
const $preview_wrapper = preview_dialog.get_field("preview_html").$wrapper;
$preview_wrapper.html(
`<div>
<div class="print-preview">
<div class="print-format"></div>
</div>
<div class="page-break-message text-muted text-center text-medium margin-top"></div>
</div>`
);
frappe.call({
method: "frappe.www.printview.get_html_and_style",
args: {
doc: frm.doc,
print_format: "GST E-Invoice",
no_letterhead: 1
},
callback: function (r) {
if (!r.exc) {
$preview_wrapper.find(".print-format").html(r.message.html);
const style = `
.print-format { box-shadow: 0px 0px 5px rgba(0,0,0,0.2); padding: 0.30in; min-height: 80vh; }
.print-preview { min-height: 0px; }
.modal-dialog { width: 720px; }`;
frappe.dom.set_style(style, "custom-print-style");
preview_dialog.show();
}
}
});
};

File diff suppressed because it is too large Load Diff

View File

@ -1,177 +0,0 @@
[
{
"state_number": "33",
"state_code": "TN",
"state_name": "Tamil Nadu"
},
{
"state_number": "35",
"state_code": "UP",
"state_name": "Uttar Pradesh"
},
{
"state_number": "05",
"state_code": "UT",
"state_name": "Uttarakhand"
},
{
"state_number": "19",
"state_code": "WB",
"state_name": "West Bengal"
},
{
"state_number": "16",
"state_code": "TR",
"state_name": "Tripura"
},
{
"state_number": "36",
"state_code": "TS",
"state_name": "Telangana"
},
{
"state_number": "11",
"state_code": "SK",
"state_name": "Sikkim"
},
{
"state_number": "08",
"state_code": "RJ",
"state_name": "Rajasthan"
},
{
"state_number": "03",
"state_code": "PB",
"state_name": "Punjab"
},
{
"state_number": "34",
"state_code": "PY",
"state_name": "Pondicherry"
},
{
"state_number": "21",
"state_code": "OR",
"state_name": "Odisha"
},
{
"state_number": "13",
"state_code": "NL",
"state_name": "Nagaland"
},
{
"state_number": "15",
"state_code": "MI",
"state_name": "Mizoram"
},
{
"state_number": "17",
"state_code": "ME",
"state_name": "Meghalaya"
},
{
"state_number": "14",
"state_code": "MN",
"state_name": "Manipur"
},
{
"state_number": "27",
"state_code": "MH",
"state_name": "Maharashtra"
},
{
"state_number": "23",
"state_code": "MP",
"state_name": "Madhya Pradesh"
},
{
"state_number": "31",
"state_code": "LD",
"state_name": "Lakshadweep Islands"
},
{
"state_number": "32",
"state_code": "KL",
"state_name": "Kerala"
},
{
"state_number": "29",
"state_code": "KA",
"state_name": "Karnataka"
},
{
"state_number": "20",
"state_code": "JH",
"state_name": "Jharkhand"
},
{
"state_number": "01",
"state_code": "JK",
"state_name": "Jammu and Kashmir"
},
{
"state_number": "02",
"state_code": "HP",
"state_name": "Himachal Pradesh"
},
{
"state_number": "06",
"state_code": "HR",
"state_name": "Haryana"
},
{
"state_number": "24",
"state_code": "GJ",
"state_name": "Gujarat"
},
{
"state_number": "30",
"state_code": "GA",
"state_name": "Goa"
},
{
"state_number": "07",
"state_code": "DL",
"state_name": "Delhi"
},
{
"state_number": "26",
"state_code": "DN",
"state_name": "Dadra and Nagar Haveli and Daman and Diu"
},
{
"state_number": "22",
"state_code": "CT",
"state_name": "Chhattisgarh"
},
{
"state_number": "04",
"state_code": "CH",
"state_name": "Chandigarh"
},
{
"state_number": "10",
"state_code": "BH",
"state_name": "Bihar"
},
{
"state_number": "18",
"state_code": "AS",
"state_name": "Assam"
},
{
"state_number": "12",
"state_code": "AR",
"state_name": "Arunachal Pradesh"
},
{
"state_number": "37",
"state_code": "AD",
"state_name": "Andhra Pradesh (New)"
},
{
"state_number": "38",
"state_code": "LA",
"state_name": "Ladakh"
}
]

File diff suppressed because it is too large Load Diff

View File

@ -1,25 +0,0 @@
erpnext.setup_gst_reminder_button = (doctype) => {
frappe.ui.form.on(doctype, {
refresh: (frm) => {
if(!frm.is_new()) {
var missing = false;
frm.doc.__onload.addr_list && frm.doc.__onload.addr_list.forEach((d) => {
if(!d.gstin) missing = true;
});
if (!missing) return;
frm.add_custom_button('Send GST Update Reminder', () => {
return new Promise((resolve) => {
return frappe.call({
method: 'erpnext.regional.doctype.gst_settings.gst_settings.send_gstin_reminder',
args: {
party_type: frm.doc.doctype,
party: frm.doc.name,
}
}).always(() => { resolve(); });
});
});
}
}
});
};

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,51 +0,0 @@
erpnext.setup_auto_gst_taxation = (doctype) => {
frappe.ui.form.on(doctype, {
company_address: function(frm) {
frm.trigger('get_tax_template');
},
shipping_address: function(frm) {
frm.trigger('get_tax_template');
},
supplier_address: function(frm) {
frm.trigger('get_tax_template');
},
tax_category: function(frm) {
frm.trigger('get_tax_template');
},
customer_address: function(frm) {
frm.trigger('get_tax_template');
},
get_tax_template: function(frm) {
if (!frm.doc.company) return;
let party_details = {
'shipping_address': frm.doc.shipping_address || '',
'shipping_address_name': frm.doc.shipping_address_name || '',
'customer_address': frm.doc.customer_address || '',
'supplier_address': frm.doc.supplier_address,
'customer': frm.doc.customer,
'supplier': frm.doc.supplier,
'supplier_gstin': frm.doc.supplier_gstin,
'company_gstin': frm.doc.company_gstin,
'tax_category': frm.doc.tax_category
};
frappe.call({
method: 'erpnext.regional.india.utils.get_regional_address_details',
args: {
party_details: JSON.stringify(party_details),
doctype: frm.doc.doctype,
company: frm.doc.company
},
debounce: 2000,
callback: function(r) {
if(r.message) {
frm.set_value('taxes_and_charges', r.message.taxes_and_charges);
frm.set_value('taxes', r.message.taxes);
frm.set_value('place_of_supply', r.message.place_of_supply);
}
}
});
}
});
}

View File

@ -1,38 +0,0 @@
import unittest
from unittest.mock import patch
import frappe
from erpnext.regional.india.utils import validate_document_name
class TestIndiaUtils(unittest.TestCase):
@patch("frappe.get_cached_value")
def test_validate_document_name(self, mock_get_cached):
mock_get_cached.return_value = "India" # mock country
posting_date = "2021-05-01"
invalid_names = ["SI$1231", "012345678901234567", "SI 2020 05",
"SI.2020.0001", "PI2021 - 001"]
for name in invalid_names:
doc = frappe._dict(name=name, posting_date=posting_date)
self.assertRaises(frappe.ValidationError, validate_document_name, doc)
valid_names = ["012345678901236", "SI/2020/0001", "SI/2020-0001",
"2020-PI-0001", "PI2020-0001"]
for name in valid_names:
doc = frappe._dict(name=name, posting_date=posting_date)
try:
validate_document_name(doc)
except frappe.ValidationError:
self.fail("Valid name {} throwing error".format(name))
@patch("frappe.get_cached_value")
def test_validate_document_name_not_india(self, mock_get_cached):
mock_get_cached.return_value = "Not India"
doc = frappe._dict(name="SI$123", posting_date="2021-05-01")
try:
validate_document_name(doc)
except frappe.ValidationError:
self.fail("Regional validation related to India are being applied to other countries")

View File

@ -1,893 +0,0 @@
import json
import re
import frappe
from frappe import _
from frappe.model.utils import get_fetch_values
from frappe.utils import cint, cstr, date_diff, flt, getdate, nowdate
from erpnext.controllers.accounts_controller import get_taxes_and_charges
from erpnext.controllers.taxes_and_totals import get_itemised_tax, get_itemised_taxable_amount
from erpnext.hr.utils import get_salary_assignment
from erpnext.payroll.doctype.salary_structure.salary_structure import make_salary_slip
from erpnext.regional.india import number_state_mapping, state_numbers, states
GST_INVOICE_NUMBER_FORMAT = re.compile(r"^[a-zA-Z0-9\-/]+$") #alphanumeric and - /
GSTIN_FORMAT = re.compile("^[0-9]{2}[A-Z]{4}[0-9A-Z]{1}[0-9]{4}[A-Z]{1}[1-9A-Z]{1}[1-9A-Z]{1}[0-9A-Z]{1}$")
GSTIN_UIN_FORMAT = re.compile("^[0-9]{4}[A-Z]{3}[0-9]{5}[0-9A-Z]{3}")
PAN_NUMBER_FORMAT = re.compile("[A-Z]{5}[0-9]{4}[A-Z]{1}")
def validate_gstin_for_india(doc, method):
if hasattr(doc, 'gst_state') and doc.gst_state:
doc.gst_state_number = state_numbers[doc.gst_state]
if not hasattr(doc, 'gstin') or not doc.gstin:
return
gst_category = []
if hasattr(doc, 'gst_category'):
if len(doc.links):
link_doctype = doc.links[0].get("link_doctype")
link_name = doc.links[0].get("link_name")
if link_doctype in ["Customer", "Supplier"]:
gst_category = frappe.db.get_value(link_doctype, {'name': link_name}, ['gst_category'])
doc.gstin = doc.gstin.upper().strip()
if not doc.gstin or doc.gstin == 'NA':
return
if len(doc.gstin) != 15:
frappe.throw(_("A GSTIN must have 15 characters."), title=_("Invalid GSTIN"))
if gst_category and gst_category == 'UIN Holders':
if not GSTIN_UIN_FORMAT.match(doc.gstin):
frappe.throw(_("The input you've entered doesn't match the GSTIN format for UIN Holders or Non-Resident OIDAR Service Providers"),
title=_("Invalid GSTIN"))
else:
if not GSTIN_FORMAT.match(doc.gstin):
frappe.throw(_("The input you've entered doesn't match the format of GSTIN."), title=_("Invalid GSTIN"))
validate_gstin_check_digit(doc.gstin)
set_gst_state_and_state_number(doc)
if not doc.gst_state:
frappe.throw(_("Please enter GST state"), title=_("Invalid State"))
if doc.gst_state_number != doc.gstin[:2]:
frappe.throw(_("First 2 digits of GSTIN should match with State number {0}.")
.format(doc.gst_state_number), title=_("Invalid GSTIN"))
def validate_pan_for_india(doc, method):
if doc.get('country') != 'India' or not doc.get('pan'):
return
if not PAN_NUMBER_FORMAT.match(doc.pan):
frappe.throw(_("Invalid PAN No. The input you've entered doesn't match the format of PAN."))
def validate_tax_category(doc, method):
if doc.get('gst_state') and frappe.db.get_value('Tax Category', {'gst_state': doc.gst_state, 'is_inter_state': doc.is_inter_state,
'is_reverse_charge': doc.is_reverse_charge}):
if doc.is_inter_state:
frappe.throw(_("Inter State tax category for GST State {0} already exists").format(doc.gst_state))
else:
frappe.throw(_("Intra State tax category for GST State {0} already exists").format(doc.gst_state))
def update_gst_category(doc, method):
for link in doc.links:
if link.link_doctype in ['Customer', 'Supplier']:
meta = frappe.get_meta(link.link_doctype)
if doc.get('gstin') and meta.has_field('gst_category'):
frappe.db.set_value(link.link_doctype, {'name': link.link_name, 'gst_category': 'Unregistered'}, 'gst_category', 'Registered Regular')
def set_gst_state_and_state_number(doc):
if not doc.gst_state:
if not doc.state:
return
state = doc.state.lower()
states_lowercase = {s.lower():s for s in states}
if state in states_lowercase:
doc.gst_state = states_lowercase[state]
else:
return
doc.gst_state_number = state_numbers[doc.gst_state]
def validate_gstin_check_digit(gstin, label='GSTIN'):
''' Function to validate the check digit of the GSTIN.'''
factor = 1
total = 0
code_point_chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
mod = len(code_point_chars)
input_chars = gstin[:-1]
for char in input_chars:
digit = factor * code_point_chars.find(char)
digit = (digit // mod) + (digit % mod)
total += digit
factor = 2 if factor == 1 else 1
if gstin[-1] != code_point_chars[((mod - (total % mod)) % mod)]:
frappe.throw(_("""Invalid {0}! The check digit validation has failed. Please ensure you've typed the {0} correctly.""").format(label))
def get_itemised_tax_breakup_header(item_doctype, tax_accounts):
hsn_wise_in_gst_settings = frappe.db.get_single_value('GST Settings','hsn_wise_tax_breakup')
if frappe.get_meta(item_doctype).has_field('gst_hsn_code') and hsn_wise_in_gst_settings:
return [_("HSN/SAC"), _("Taxable Amount")] + tax_accounts
else:
return [_("Item"), _("Taxable Amount")] + tax_accounts
def get_itemised_tax_breakup_data(doc, account_wise=False, hsn_wise=False):
itemised_tax = get_itemised_tax(doc.taxes, with_tax_account=account_wise)
itemised_taxable_amount = get_itemised_taxable_amount(doc.items)
if not frappe.get_meta(doc.doctype + " Item").has_field('gst_hsn_code'):
return itemised_tax, itemised_taxable_amount
hsn_wise_in_gst_settings = frappe.db.get_single_value('GST Settings','hsn_wise_tax_breakup')
tax_breakup_hsn_wise = hsn_wise or hsn_wise_in_gst_settings
if tax_breakup_hsn_wise:
item_hsn_map = frappe._dict()
for d in doc.items:
item_hsn_map.setdefault(d.item_code or d.item_name, d.get("gst_hsn_code"))
hsn_tax = {}
for item, taxes in itemised_tax.items():
item_or_hsn = item if not tax_breakup_hsn_wise else item_hsn_map.get(item)
hsn_tax.setdefault(item_or_hsn, frappe._dict())
for tax_desc, tax_detail in taxes.items():
key = tax_desc
if account_wise:
key = tax_detail.get('tax_account')
hsn_tax[item_or_hsn].setdefault(key, {"tax_rate": 0, "tax_amount": 0})
hsn_tax[item_or_hsn][key]["tax_rate"] = tax_detail.get("tax_rate")
hsn_tax[item_or_hsn][key]["tax_amount"] += tax_detail.get("tax_amount")
# set taxable amount
hsn_taxable_amount = frappe._dict()
for item in itemised_taxable_amount:
item_or_hsn = item if not tax_breakup_hsn_wise else item_hsn_map.get(item)
hsn_taxable_amount.setdefault(item_or_hsn, 0)
hsn_taxable_amount[item_or_hsn] += itemised_taxable_amount.get(item)
return hsn_tax, hsn_taxable_amount
def set_place_of_supply(doc, method=None):
doc.place_of_supply = get_place_of_supply(doc, doc.doctype)
def validate_document_name(doc, method=None):
"""Validate GST invoice number requirements."""
country = frappe.get_cached_value("Company", doc.company, "country")
# Date was chosen as start of next FY to avoid irritating current users.
if country != "India" or getdate(doc.posting_date) < getdate("2021-04-01"):
return
if len(doc.name) > 16:
frappe.throw(_("Maximum length of document number should be 16 characters as per GST rules. Please change the naming series."))
if not GST_INVOICE_NUMBER_FORMAT.match(doc.name):
frappe.throw(_("Document name should only contain alphanumeric values, dash(-) and slash(/) characters as per GST rules. Please change the naming series."))
# don't remove this function it is used in tests
def test_method():
'''test function'''
return 'overridden'
def get_place_of_supply(party_details, doctype):
if not frappe.get_meta('Address').has_field('gst_state'): return
if doctype in ("Sales Invoice", "Delivery Note", "Sales Order"):
address_name = party_details.customer_address or party_details.shipping_address_name
elif doctype in ("Purchase Invoice", "Purchase Order", "Purchase Receipt"):
address_name = party_details.shipping_address or party_details.supplier_address
if address_name:
address = frappe.db.get_value("Address", address_name, ["gst_state", "gst_state_number", "gstin"], as_dict=1)
if address and address.gst_state and address.gst_state_number:
party_details.gstin = address.gstin
return cstr(address.gst_state_number) + "-" + cstr(address.gst_state)
@frappe.whitelist()
def get_regional_address_details(party_details, doctype, company):
if isinstance(party_details, str):
party_details = json.loads(party_details)
party_details = frappe._dict(party_details)
update_party_details(party_details, doctype)
party_details.place_of_supply = get_place_of_supply(party_details, doctype)
if is_internal_transfer(party_details, doctype):
party_details.taxes_and_charges = ''
party_details.taxes = []
return party_details
if doctype in ("Sales Invoice", "Delivery Note", "Sales Order"):
master_doctype = "Sales Taxes and Charges Template"
tax_template_by_category = get_tax_template_based_on_category(master_doctype, company, party_details)
elif doctype in ("Purchase Invoice", "Purchase Order", "Purchase Receipt"):
master_doctype = "Purchase Taxes and Charges Template"
tax_template_by_category = get_tax_template_based_on_category(master_doctype, company, party_details)
if tax_template_by_category:
party_details['taxes_and_charges'] = tax_template_by_category
return party_details
if not party_details.place_of_supply: return party_details
if not party_details.company_gstin: return party_details
if ((doctype in ("Sales Invoice", "Delivery Note", "Sales Order") and party_details.company_gstin
and party_details.company_gstin[:2] != party_details.place_of_supply[:2]) or (doctype in ("Purchase Invoice",
"Purchase Order", "Purchase Receipt") and party_details.supplier_gstin and party_details.supplier_gstin[:2] != party_details.place_of_supply[:2])):
default_tax = get_tax_template(master_doctype, company, 1, party_details.company_gstin[:2])
else:
default_tax = get_tax_template(master_doctype, company, 0, party_details.company_gstin[:2])
if not default_tax:
return party_details
party_details["taxes_and_charges"] = default_tax
party_details.taxes = get_taxes_and_charges(master_doctype, default_tax)
return party_details
def update_party_details(party_details, doctype):
for address_field in ['shipping_address', 'company_address', 'supplier_address', 'shipping_address_name', 'customer_address']:
if party_details.get(address_field):
party_details.update(get_fetch_values(doctype, address_field, party_details.get(address_field)))
def is_internal_transfer(party_details, doctype):
if doctype in ("Sales Invoice", "Delivery Note", "Sales Order"):
destination_gstin = party_details.company_gstin
elif doctype in ("Purchase Invoice", "Purchase Order", "Purchase Receipt"):
destination_gstin = party_details.supplier_gstin
if not destination_gstin or party_details.gstin:
return False
if party_details.gstin == destination_gstin:
return True
else:
False
def get_tax_template_based_on_category(master_doctype, company, party_details):
if not party_details.get('tax_category'):
return
default_tax = frappe.db.get_value(master_doctype, {'company': company, 'tax_category': party_details.get('tax_category')},
'name')
return default_tax
def get_tax_template(master_doctype, company, is_inter_state, state_code):
tax_categories = frappe.get_all('Tax Category', fields = ['name', 'is_inter_state', 'gst_state'],
filters = {'is_inter_state': is_inter_state, 'is_reverse_charge': 0})
default_tax = ''
for tax_category in tax_categories:
if tax_category.gst_state == number_state_mapping[state_code] or \
(not default_tax and not tax_category.gst_state):
default_tax = frappe.db.get_value(master_doctype,
{'company': company, 'disabled': 0, 'tax_category': tax_category.name}, 'name')
return default_tax
def calculate_annual_eligible_hra_exemption(doc):
basic_component, hra_component = frappe.db.get_value('Company', doc.company, ["basic_component", "hra_component"])
if not (basic_component and hra_component):
frappe.throw(_("Please mention Basic and HRA component in Company"))
annual_exemption, monthly_exemption, hra_amount = 0, 0, 0
if hra_component and basic_component:
assignment = get_salary_assignment(doc.employee, nowdate())
if assignment:
hra_component_exists = frappe.db.exists("Salary Detail", {
"parent": assignment.salary_structure,
"salary_component": hra_component,
"parentfield": "earnings",
"parenttype": "Salary Structure"
})
if hra_component_exists:
basic_amount, hra_amount = get_component_amt_from_salary_slip(doc.employee,
assignment.salary_structure, basic_component, hra_component)
if hra_amount:
if doc.monthly_house_rent:
annual_exemption = calculate_hra_exemption(assignment.salary_structure,
basic_amount, hra_amount, doc.monthly_house_rent, doc.rented_in_metro_city)
if annual_exemption > 0:
monthly_exemption = annual_exemption / 12
else:
annual_exemption = 0
elif doc.docstatus == 1:
frappe.throw(_("Salary Structure must be submitted before submission of Tax Ememption Declaration"))
return frappe._dict({
"hra_amount": hra_amount,
"annual_exemption": annual_exemption,
"monthly_exemption": monthly_exemption
})
def get_component_amt_from_salary_slip(employee, salary_structure, basic_component, hra_component):
salary_slip = make_salary_slip(salary_structure, employee=employee, for_preview=1, ignore_permissions=True)
basic_amt, hra_amt = 0, 0
for earning in salary_slip.earnings:
if earning.salary_component == basic_component:
basic_amt = earning.amount
elif earning.salary_component == hra_component:
hra_amt = earning.amount
if basic_amt and hra_amt:
return basic_amt, hra_amt
return basic_amt, hra_amt
def calculate_hra_exemption(salary_structure, basic, monthly_hra, monthly_house_rent, rented_in_metro_city):
# TODO make this configurable
exemptions = []
frequency = frappe.get_value("Salary Structure", salary_structure, "payroll_frequency")
# case 1: The actual amount allotted by the employer as the HRA.
exemptions.append(get_annual_component_pay(frequency, monthly_hra))
actual_annual_rent = monthly_house_rent * 12
annual_basic = get_annual_component_pay(frequency, basic)
# case 2: Actual rent paid less 10% of the basic salary.
exemptions.append(flt(actual_annual_rent) - flt(annual_basic * 0.1))
# case 3: 50% of the basic salary, if the employee is staying in a metro city (40% for a non-metro city).
exemptions.append(annual_basic * 0.5 if rented_in_metro_city else annual_basic * 0.4)
# return minimum of 3 cases
return min(exemptions)
def get_annual_component_pay(frequency, amount):
if frequency == "Daily":
return amount * 365
elif frequency == "Weekly":
return amount * 52
elif frequency == "Fortnightly":
return amount * 26
elif frequency == "Monthly":
return amount * 12
elif frequency == "Bimonthly":
return amount * 6
def validate_house_rent_dates(doc):
if not doc.rented_to_date or not doc.rented_from_date:
frappe.throw(_("House rented dates required for exemption calculation"))
if date_diff(doc.rented_to_date, doc.rented_from_date) < 14:
frappe.throw(_("House rented dates should be atleast 15 days apart"))
proofs = frappe.db.sql("""
select name
from `tabEmployee Tax Exemption Proof Submission`
where
docstatus=1 and employee=%(employee)s and payroll_period=%(payroll_period)s
and (rented_from_date between %(from_date)s and %(to_date)s or rented_to_date between %(from_date)s and %(to_date)s)
""", {
"employee": doc.employee,
"payroll_period": doc.payroll_period,
"from_date": doc.rented_from_date,
"to_date": doc.rented_to_date
})
if proofs:
frappe.throw(_("House rent paid days overlapping with {0}").format(proofs[0][0]))
def calculate_hra_exemption_for_period(doc):
monthly_rent, eligible_hra = 0, 0
if doc.house_rent_payment_amount:
validate_house_rent_dates(doc)
# TODO receive rented months or validate dates are start and end of months?
# Calc monthly rent, round to nearest .5
factor = flt(date_diff(doc.rented_to_date, doc.rented_from_date) + 1)/30
factor = round(factor * 2)/2
monthly_rent = doc.house_rent_payment_amount / factor
# update field used by calculate_annual_eligible_hra_exemption
doc.monthly_house_rent = monthly_rent
exemptions = calculate_annual_eligible_hra_exemption(doc)
if exemptions["monthly_exemption"]:
# calc total exemption amount
eligible_hra = exemptions["monthly_exemption"] * factor
exemptions["monthly_house_rent"] = monthly_rent
exemptions["total_eligible_hra_exemption"] = eligible_hra
return exemptions
def get_ewb_data(dt, dn):
ewaybills = []
for doc_name in dn:
doc = frappe.get_doc(dt, doc_name)
validate_doc(doc)
data = frappe._dict({
"transporterId": "",
"TotNonAdvolVal": 0,
})
data.userGstin = data.fromGstin = doc.company_gstin
data.supplyType = 'O'
if dt == 'Delivery Note':
data.subSupplyType = 1
elif doc.gst_category in ['Registered Regular', 'SEZ']:
data.subSupplyType = 1
elif doc.gst_category in ['Overseas', 'Deemed Export']:
data.subSupplyType = 3
else:
frappe.throw(_('Unsupported GST Category for E-Way Bill JSON generation'))
data.docType = 'INV'
data.docDate = frappe.utils.formatdate(doc.posting_date, 'dd/mm/yyyy')
company_address = frappe.get_doc('Address', doc.company_address)
billing_address = frappe.get_doc('Address', doc.customer_address)
#added dispatch address
dispatch_address = frappe.get_doc('Address', doc.dispatch_address_name) if doc.dispatch_address_name else company_address
shipping_address = frappe.get_doc('Address', doc.shipping_address_name)
data = get_address_details(data, doc, company_address, billing_address, dispatch_address)
data.itemList = []
data.totalValue = doc.net_total
data = get_item_list(data, doc, hsn_wise=True)
disable_rounded = frappe.db.get_single_value('Global Defaults', 'disable_rounded_total')
data.totInvValue = doc.grand_total if disable_rounded else doc.rounded_total
data = get_transport_details(data, doc)
fields = {
"/. -": {
'docNo': doc.name,
'fromTrdName': doc.company,
'toTrdName': doc.customer_name,
'transDocNo': doc.lr_no,
},
"@#/,&. -": {
'fromAddr1': company_address.address_line1,
'fromAddr2': company_address.address_line2,
'fromPlace': company_address.city,
'toAddr1': shipping_address.address_line1,
'toAddr2': shipping_address.address_line2,
'toPlace': shipping_address.city,
'transporterName': doc.transporter_name
}
}
for allowed_chars, field_map in fields.items():
for key, value in field_map.items():
if not value:
data[key] = ''
else:
data[key] = re.sub(r'[^\w' + allowed_chars + ']', '', value)
ewaybills.append(data)
data = {
'version': '1.0.0421',
'billLists': ewaybills
}
return data
@frappe.whitelist()
def generate_ewb_json(dt, dn):
dn = json.loads(dn)
return get_ewb_data(dt, dn)
@frappe.whitelist()
def download_ewb_json():
data = json.loads(frappe.local.form_dict.data)
frappe.local.response.filecontent = json.dumps(data, indent=4, sort_keys=True)
frappe.local.response.type = 'download'
filename_prefix = 'Bulk'
docname = frappe.local.form_dict.docname
if docname:
if docname.startswith('['):
docname = json.loads(docname)
if len(docname) == 1:
docname = docname[0]
if not isinstance(docname, list):
# removes characters not allowed in a filename (https://stackoverflow.com/a/38766141/4767738)
filename_prefix = re.sub(r'[^\w_.)( -]', '', docname)
frappe.local.response.filename = '{0}_e-WayBill_Data_{1}.json'.format(filename_prefix, frappe.utils.random_string(5))
@frappe.whitelist()
def get_gstins_for_company(company):
company_gstins =[]
if company:
company_gstins = frappe.db.sql("""select
distinct `tabAddress`.gstin
from
`tabAddress`, `tabDynamic Link`
where
`tabDynamic Link`.parent = `tabAddress`.name and
`tabDynamic Link`.parenttype = 'Address' and
`tabDynamic Link`.link_doctype = 'Company' and
`tabDynamic Link`.link_name = %(company)s""", {"company": company})
return company_gstins
def get_address_details(data, doc, company_address, billing_address, dispatch_address):
data.fromPincode = validate_pincode(company_address.pincode, 'Company Address')
data.fromStateCode = validate_state_code(company_address.gst_state_number, 'Company Address')
data.actualFromStateCode = validate_state_code(dispatch_address.gst_state_number, 'Dispatch Address')
if not doc.billing_address_gstin or len(doc.billing_address_gstin) < 15:
data.toGstin = 'URP'
set_gst_state_and_state_number(billing_address)
else:
data.toGstin = doc.billing_address_gstin
data.toPincode = validate_pincode(billing_address.pincode, 'Customer Address')
data.toStateCode = validate_state_code(billing_address.gst_state_number, 'Customer Address')
if doc.customer_address != doc.shipping_address_name:
data.transType = 2
shipping_address = frappe.get_doc('Address', doc.shipping_address_name)
set_gst_state_and_state_number(shipping_address)
data.toPincode = validate_pincode(shipping_address.pincode, 'Shipping Address')
data.actualToStateCode = validate_state_code(shipping_address.gst_state_number, 'Shipping Address')
else:
data.transType = 1
data.actualToStateCode = data.toStateCode
shipping_address = billing_address
if doc.gst_category == 'SEZ':
data.toStateCode = 99
return data
def get_item_list(data, doc, hsn_wise=False):
for attr in ['cgstValue', 'sgstValue', 'igstValue', 'cessValue', 'OthValue']:
data[attr] = 0
gst_accounts = get_gst_accounts(doc.company, account_wise=True)
tax_map = {
'sgst_account': ['sgstRate', 'sgstValue'],
'cgst_account': ['cgstRate', 'cgstValue'],
'igst_account': ['igstRate', 'igstValue'],
'cess_account': ['cessRate', 'cessValue']
}
item_data_attrs = ['sgstRate', 'cgstRate', 'igstRate', 'cessRate', 'cessNonAdvol']
hsn_wise_charges, hsn_taxable_amount = get_itemised_tax_breakup_data(doc, account_wise=True, hsn_wise=hsn_wise)
for item_or_hsn, taxable_amount in hsn_taxable_amount.items():
item_data = frappe._dict()
if not item_or_hsn:
frappe.throw(_('GST HSN Code does not exist for one or more items'))
item_data.hsnCode = int(item_or_hsn) if hsn_wise else item_or_hsn
item_data.taxableAmount = taxable_amount
item_data.qtyUnit = ""
for attr in item_data_attrs:
item_data[attr] = 0
for account, tax_detail in hsn_wise_charges.get(item_or_hsn, {}).items():
account_type = gst_accounts.get(account, '')
for tax_acc, attrs in tax_map.items():
if account_type == tax_acc:
item_data[attrs[0]] = tax_detail.get('tax_rate')
data[attrs[1]] += tax_detail.get('tax_amount')
break
else:
data.OthValue += tax_detail.get('tax_amount')
data.itemList.append(item_data)
# Tax amounts rounded to 2 decimals to avoid exceeding max character limit
for attr in ['sgstValue', 'cgstValue', 'igstValue', 'cessValue']:
data[attr] = flt(data[attr], 2)
return data
def validate_doc(doc):
if doc.docstatus != 1:
frappe.throw(_('E-Way Bill JSON can only be generated from submitted document'))
if doc.is_return:
frappe.throw(_('E-Way Bill JSON cannot be generated for Sales Return as of now'))
if doc.ewaybill:
frappe.throw(_('e-Way Bill already exists for this document'))
reqd_fields = ['company_gstin', 'company_address', 'customer_address',
'shipping_address_name', 'mode_of_transport', 'distance']
for fieldname in reqd_fields:
if not doc.get(fieldname):
frappe.throw(_('{} is required to generate E-Way Bill JSON').format(
doc.meta.get_label(fieldname)
))
if len(doc.company_gstin) < 15:
frappe.throw(_('You must be a registered supplier to generate e-Way Bill'))
def get_transport_details(data, doc):
if doc.distance > 4000:
frappe.throw(_('Distance cannot be greater than 4000 kms'))
data.transDistance = int(round(doc.distance))
transport_modes = {
'Road': 1,
'Rail': 2,
'Air': 3,
'Ship': 4
}
vehicle_types = {
'Regular': 'R',
'Over Dimensional Cargo (ODC)': 'O'
}
data.transMode = transport_modes.get(doc.mode_of_transport)
if doc.mode_of_transport == 'Road':
if not doc.gst_transporter_id and not doc.vehicle_no:
frappe.throw(_('Either GST Transporter ID or Vehicle No is required if Mode of Transport is Road'))
if doc.vehicle_no:
data.vehicleNo = doc.vehicle_no.replace(' ', '')
if not doc.gst_vehicle_type:
frappe.throw(_('Vehicle Type is required if Mode of Transport is Road'))
else:
data.vehicleType = vehicle_types.get(doc.gst_vehicle_type)
else:
if not doc.lr_no or not doc.lr_date:
frappe.throw(_('Transport Receipt No and Date are mandatory for your chosen Mode of Transport'))
if doc.lr_no:
data.transDocNo = doc.lr_no
if doc.lr_date:
data.transDocDate = frappe.utils.formatdate(doc.lr_date, 'dd/mm/yyyy')
if doc.gst_transporter_id:
if doc.gst_transporter_id[0:2] != "88":
validate_gstin_check_digit(doc.gst_transporter_id, label='GST Transporter ID')
data.transporterId = doc.gst_transporter_id
return data
def validate_pincode(pincode, address):
pin_not_found = "Pin Code doesn't exist for {}"
incorrect_pin = "Pin Code for {} is incorrecty formatted. It must be 6 digits (without spaces)"
if not pincode:
frappe.throw(_(pin_not_found.format(address)))
pincode = pincode.replace(' ', '')
if not pincode.isdigit() or len(pincode) != 6:
frappe.throw(_(incorrect_pin.format(address)))
else:
return int(pincode)
def validate_state_code(state_code, address):
no_state_code = "GST State Code not found for {0}. Please set GST State in {0}"
if not state_code:
frappe.throw(_(no_state_code.format(address)))
else:
return int(state_code)
@frappe.whitelist()
def get_gst_accounts(company=None, account_wise=False, only_reverse_charge=0, only_non_reverse_charge=0):
filters={"parent": "GST Settings"}
if company:
filters.update({'company': company})
if only_reverse_charge:
filters.update({'is_reverse_charge_account': 1})
elif only_non_reverse_charge:
filters.update({'is_reverse_charge_account': 0})
gst_accounts = frappe._dict()
gst_settings_accounts = frappe.get_all("GST Account",
filters=filters,
fields=["cgst_account", "sgst_account", "igst_account", "cess_account"])
if not gst_settings_accounts and not frappe.flags.in_test and not frappe.flags.in_migrate:
frappe.throw(_("Please set GST Accounts in GST Settings"))
for d in gst_settings_accounts:
for acc, val in d.items():
if not account_wise:
gst_accounts.setdefault(acc, []).append(val)
elif val:
gst_accounts[val] = acc
return gst_accounts
def validate_reverse_charge_transaction(doc, method):
country = frappe.get_cached_value('Company', doc.company, 'country')
if country != 'India':
return
base_gst_tax = 0
base_reverse_charge_booked = 0
if doc.reverse_charge == 'Y':
gst_accounts = get_gst_accounts(doc.company, only_reverse_charge=1)
reverse_charge_accounts = gst_accounts.get('cgst_account') + gst_accounts.get('sgst_account') \
+ gst_accounts.get('igst_account')
gst_accounts = get_gst_accounts(doc.company, only_non_reverse_charge=1)
non_reverse_charge_accounts = gst_accounts.get('cgst_account') + gst_accounts.get('sgst_account') \
+ gst_accounts.get('igst_account')
for tax in doc.get('taxes'):
if tax.account_head in non_reverse_charge_accounts:
if tax.add_deduct_tax == 'Add':
base_gst_tax += tax.base_tax_amount_after_discount_amount
else:
base_gst_tax += tax.base_tax_amount_after_discount_amount
elif tax.account_head in reverse_charge_accounts:
if tax.add_deduct_tax == 'Add':
base_reverse_charge_booked += tax.base_tax_amount_after_discount_amount
else:
base_reverse_charge_booked += tax.base_tax_amount_after_discount_amount
if base_gst_tax != base_reverse_charge_booked:
msg = _("Booked reverse charge is not equal to applied tax amount")
msg += "<br>"
msg += _("Please refer {gst_document_link} to learn more about how to setup and create reverse charge invoice").format(
gst_document_link='<a href="https://docs.erpnext.com/docs/user/manual/en/regional/india/gst-setup">GST Documentation</a>')
frappe.throw(msg)
def update_itc_availed_fields(doc, method):
country = frappe.get_cached_value('Company', doc.company, 'country')
if country != 'India':
return
# Initialize values
doc.itc_integrated_tax = doc.itc_state_tax = doc.itc_central_tax = doc.itc_cess_amount = 0
gst_accounts = get_gst_accounts(doc.company, only_non_reverse_charge=1)
for tax in doc.get('taxes'):
if tax.account_head in gst_accounts.get('igst_account', []):
doc.itc_integrated_tax += flt(tax.base_tax_amount_after_discount_amount)
if tax.account_head in gst_accounts.get('sgst_account', []):
doc.itc_state_tax += flt(tax.base_tax_amount_after_discount_amount)
if tax.account_head in gst_accounts.get('cgst_account', []):
doc.itc_central_tax += flt(tax.base_tax_amount_after_discount_amount)
if tax.account_head in gst_accounts.get('cess_account', []):
doc.itc_cess_amount += flt(tax.base_tax_amount_after_discount_amount)
def update_place_of_supply(doc, method):
country = frappe.get_cached_value('Company', doc.company, 'country')
if country != 'India':
return
address = frappe.db.get_value("Address", doc.get('customer_address'), ["gst_state", "gst_state_number"], as_dict=1)
if address and address.gst_state and address.gst_state_number:
doc.place_of_supply = cstr(address.gst_state_number) + "-" + cstr(address.gst_state)
@frappe.whitelist()
def get_regional_round_off_accounts(company, account_list):
country = frappe.get_cached_value('Company', company, 'country')
if country != 'India':
return
if isinstance(account_list, str):
account_list = json.loads(account_list)
if not frappe.db.get_single_value('GST Settings', 'round_off_gst_values'):
return
gst_accounts = get_gst_accounts(company)
gst_account_list = []
for account in ['cgst_account', 'sgst_account', 'igst_account']:
if account in gst_accounts:
gst_account_list += gst_accounts.get(account)
account_list.extend(gst_account_list)
return account_list
def update_taxable_values(doc, method):
country = frappe.get_cached_value('Company', doc.company, 'country')
if country != 'India':
return
gst_accounts = get_gst_accounts(doc.company)
# Only considering sgst account to avoid inflating taxable value
gst_account_list = gst_accounts.get('sgst_account', []) + gst_accounts.get('sgst_account', []) \
+ gst_accounts.get('igst_account', [])
additional_taxes = 0
total_charges = 0
item_count = 0
considered_rows = []
for tax in doc.get('taxes'):
prev_row_id = cint(tax.row_id) - 1
if tax.account_head in gst_account_list and prev_row_id not in considered_rows:
if tax.charge_type == 'On Previous Row Amount':
additional_taxes += doc.get('taxes')[prev_row_id].tax_amount_after_discount_amount
considered_rows.append(prev_row_id)
if tax.charge_type == 'On Previous Row Total':
additional_taxes += doc.get('taxes')[prev_row_id].base_total - doc.base_net_total
considered_rows.append(prev_row_id)
for item in doc.get('items'):
proportionate_value = item.base_net_amount if doc.base_net_total else item.qty
total_value = doc.base_net_total if doc.base_net_total else doc.total_qty
applicable_charges = flt(flt(proportionate_value * (flt(additional_taxes) / flt(total_value)),
item.precision('taxable_value')))
item.taxable_value = applicable_charges + proportionate_value
total_charges += applicable_charges
item_count += 1
if total_charges != additional_taxes:
diff = additional_taxes - total_charges
doc.get('items')[item_count - 1].taxable_value += diff
def get_depreciation_amount(asset, depreciable_value, row):
if row.depreciation_method in ("Straight Line", "Manual"):
# if the Depreciation Schedule is being prepared for the first time
if not asset.flags.increase_in_asset_life:
depreciation_amount = (flt(asset.gross_purchase_amount) -
flt(row.expected_value_after_useful_life)) / flt(row.total_number_of_depreciations)
# if the Depreciation Schedule is being modified after Asset Repair
else:
depreciation_amount = (flt(row.value_after_depreciation) -
flt(row.expected_value_after_useful_life)) / (date_diff(asset.to_date, asset.available_for_use_date) / 365)
else:
rate_of_depreciation = row.rate_of_depreciation
# if its the first depreciation
if depreciable_value == asset.gross_purchase_amount:
if row.finance_book and frappe.db.get_value('Finance Book', row.finance_book, 'for_income_tax'):
# as per IT act, if the asset is purchased in the 2nd half of fiscal year, then rate is divided by 2
diff = date_diff(row.depreciation_start_date, asset.available_for_use_date)
if diff <= 180:
rate_of_depreciation = rate_of_depreciation / 2
frappe.msgprint(
_('As per IT Act, the rate of depreciation for the first depreciation entry is reduced by 50%.'))
depreciation_amount = flt(depreciable_value * (flt(rate_of_depreciation) / 100))
return depreciation_amount
def set_item_tax_from_hsn_code(item):
if not item.taxes and item.gst_hsn_code:
hsn_doc = frappe.get_doc("GST HSN Code", item.gst_hsn_code)
for tax in hsn_doc.taxes:
item.append('taxes', {
'item_tax_template': tax.item_tax_template,
'tax_category': tax.tax_category,
'valid_from': tax.valid_from
})
def delete_gst_settings_for_company(doc, method):
if doc.country != 'India':
return
gst_settings = frappe.get_doc("GST Settings")
records_to_delete = []
for d in reversed(gst_settings.get('gst_accounts')):
if d.company == doc.name:
records_to_delete.append(d)
for d in records_to_delete:
gst_settings.remove(d)
gst_settings.save()

View File

@ -1,22 +0,0 @@
{
"align_labels_right": 0,
"creation": "2017-07-04 16:26:21.120187",
"custom_format": 0,
"disabled": 1,
"doc_type": "Sales Invoice",
"docstatus": 0,
"doctype": "Print Format",
"font": "Default",
"format_data": "[{\"fieldname\": \"print_heading_template\", \"fieldtype\": \"Custom HTML\", \"options\": \"<div class=\\\"print-heading\\\">\\n\\t<h2>\\n\\t\\tTAX INVOICE<br>\\n\\t\\t<small>{{ doc.name }}</small>\\n\\t</h2>\\n</div>\\n<h2 class=\\\"text-center\\\">\\n\\t{% if doc.invoice_copy -%}\\n\\t\\t<small>{{ doc.invoice_copy }}</small>\\n\\t{% endif -%}\\n</h2>\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"company\", \"label\": \"Company\"}, {\"print_hide\": 0, \"fieldname\": \"company_address_display\", \"label\": \"Company Address\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"posting_date\", \"label\": \"Date\"}, {\"print_hide\": 0, \"fieldname\": \"due_date\", \"label\": \"Payment Due Date\"}, {\"print_hide\": 0, \"fieldname\": \"reverse_charge\", \"label\": \"Reverse Charge\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"label\": \"Custom HTML\", \"fieldname\": \"_custom_html\", \"options\": \"<hr>\", \"fieldtype\": \"HTML\"}, {\"fieldtype\": \"Section Break\", \"label\": \"Address\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"customer_name\", \"label\": \"Customer Name\"}, {\"print_hide\": 0, \"fieldname\": \"address_display\", \"label\": \"Address\"}, {\"print_hide\": 0, \"fieldname\": \"contact_display\", \"label\": \"Contact\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"shipping_address\", \"label\": \"Shipping Address\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"visible_columns\": [{\"print_hide\": 0, \"fieldname\": \"item_code\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"description\", \"print_width\": \"200px\"}, {\"print_hide\": 0, \"fieldname\": \"gst_hsn_code\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"serial_no\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"qty\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"uom\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"rate\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"amount\", \"print_width\": \"\"}], \"print_hide\": 0, \"fieldname\": \"items\", \"label\": \"Items\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"total\", \"label\": \"Total\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"visible_columns\": [{\"print_hide\": 0, \"fieldname\": \"description\", \"print_width\": \"300px\"}], \"print_hide\": 0, \"fieldname\": \"taxes\", \"label\": \"Sales Taxes and Charges\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"grand_total\", \"label\": \"Grand Total\"}, {\"print_hide\": 0, \"fieldname\": \"rounded_total\", \"label\": \"Rounded Total\"}, {\"print_hide\": 0, \"fieldname\": \"in_words\", \"label\": \"In Words\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"other_charges_calculation\", \"align\": \"left\", \"label\": \"Tax Breakup\"}, {\"fieldtype\": \"Section Break\", \"label\": \"Terms\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"terms\", \"label\": \"Terms and Conditions Details\"}]",
"idx": 0,
"line_breaks": 0,
"modified": "2017-12-15 11:57:25.477278",
"modified_by": "Administrator",
"module": "Regional",
"name": "GST Tax Invoice",
"owner": "Administrator",
"print_format_builder": 1,
"print_format_type": "Jinja",
"show_section_headings": 0,
"standard": "Yes"
}

View File

@ -1,55 +0,0 @@
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
/* eslint-disable */
frappe.query_reports["E-Invoice Summary"] = {
"filters": [
{
"fieldtype": "Link",
"options": "Company",
"reqd": 1,
"fieldname": "company",
"label": __("Company"),
"default": frappe.defaults.get_user_default("Company"),
},
{
"fieldtype": "Link",
"options": "Customer",
"fieldname": "customer",
"label": __("Customer")
},
{
"fieldtype": "Date",
"reqd": 1,
"fieldname": "from_date",
"label": __("From Date"),
"default": frappe.datetime.add_months(frappe.datetime.get_today(), -1),
},
{
"fieldtype": "Date",
"reqd": 1,
"fieldname": "to_date",
"label": __("To Date"),
"default": frappe.datetime.get_today(),
},
{
"fieldtype": "Select",
"fieldname": "status",
"label": __("Status"),
"options": "\nPending\nGenerated\nCancelled\nFailed"
}
],
"formatter": function (value, row, column, data, default_formatter) {
value = default_formatter(value, row, column, data);
if (column.fieldname == "einvoice_status" && value) {
if (value == 'Pending') value = `<span class="bold" style="color: var(--text-on-orange)">${value}</span>`;
else if (value == 'Generated') value = `<span class="bold" style="color: var(--text-on-green)">${value}</span>`;
else if (value == 'Cancelled') value = `<span class="bold" style="color: var(--text-on-red)">${value}</span>`;
else if (value == 'Failed') value = `<span class="bold" style="color: var(--text-on-red)">${value}</span>`;
}
return value;
}
};

View File

@ -1,28 +0,0 @@
{
"add_total_row": 0,
"columns": [],
"creation": "2021-03-12 11:23:37.312294",
"disable_prepared_report": 0,
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"filters": [],
"idx": 0,
"is_standard": "Yes",
"json": "{}",
"letter_head": "Logo",
"modified": "2021-03-13 12:36:48.689413",
"modified_by": "Administrator",
"module": "Regional",
"name": "E-Invoice Summary",
"owner": "Administrator",
"prepared_report": 0,
"ref_doctype": "Sales Invoice",
"report_name": "E-Invoice Summary",
"report_type": "Script Report",
"roles": [
{
"role": "Administrator"
}
]
}

Some files were not shown because too many files have changed in this diff Show More