mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-28 01:14:46 +00:00
feat(India): Multiple GST enhancement and fixes (#25249)
* fix: RCM tax calculation * feat(India): ITC Reversal via Journal Entry * fix: Reverse Charge booking logic and validation * fix: Addd patch for availed ITC fields * fix: Hooks method to update availed ITC field * fix: Cleanup and fixes in GSTR3B report * fix: Update params in GSTR-1 report * fix: Debit note using Sales Invoice * fix: Setup and patch * fix: GSTR 3B report cleanup and updates * fix: Add method to get invoices liable to reverse charge * fix: Add taxable value in Purchase Invoice Item * fix: Inward supplies liable to reverse charge * fix: Linting issues * fix: GSTR3B report test
This commit is contained in:
@@ -1,196 +1,82 @@
|
|||||||
{
|
{
|
||||||
"allow_copy": 0,
|
"actions": [],
|
||||||
"allow_guest_to_view": 0,
|
|
||||||
"allow_import": 0,
|
|
||||||
"allow_rename": 0,
|
|
||||||
"beta": 0,
|
|
||||||
"creation": "2018-01-02 15:48:58.768352",
|
"creation": "2018-01-02 15:48:58.768352",
|
||||||
"custom": 0,
|
|
||||||
"docstatus": 0,
|
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "",
|
|
||||||
"editable_grid": 1,
|
"editable_grid": 1,
|
||||||
"engine": "InnoDB",
|
"engine": "InnoDB",
|
||||||
|
"field_order": [
|
||||||
|
"company",
|
||||||
|
"cgst_account",
|
||||||
|
"sgst_account",
|
||||||
|
"igst_account",
|
||||||
|
"cess_account",
|
||||||
|
"is_reverse_charge_account"
|
||||||
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"columns": 1,
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "company",
|
"fieldname": "company",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Company",
|
"label": "Company",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Company",
|
"options": "Company",
|
||||||
"permlevel": 0,
|
"reqd": 1
|
||||||
"precision": "",
|
|
||||||
"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,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"columns": 2,
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "cgst_account",
|
"fieldname": "cgst_account",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "CGST Account",
|
"label": "CGST Account",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Account",
|
"options": "Account",
|
||||||
"permlevel": 0,
|
"reqd": 1
|
||||||
"precision": "",
|
|
||||||
"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,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"columns": 2,
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "sgst_account",
|
"fieldname": "sgst_account",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "SGST Account",
|
"label": "SGST Account",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Account",
|
"options": "Account",
|
||||||
"permlevel": 0,
|
"reqd": 1
|
||||||
"precision": "",
|
|
||||||
"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,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"columns": 2,
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "igst_account",
|
"fieldname": "igst_account",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "IGST Account",
|
"label": "IGST Account",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Account",
|
"options": "Account",
|
||||||
"permlevel": 0,
|
"reqd": 1
|
||||||
"precision": "",
|
|
||||||
"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,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"columns": 2,
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "cess_account",
|
"fieldname": "cess_account",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "CESS Account",
|
"label": "CESS Account",
|
||||||
"length": 0,
|
"options": "Account"
|
||||||
"no_copy": 0,
|
},
|
||||||
"options": "Account",
|
{
|
||||||
"permlevel": 0,
|
"columns": 1,
|
||||||
"precision": "",
|
"default": "0",
|
||||||
"print_hide": 0,
|
"fieldname": "is_reverse_charge_account",
|
||||||
"print_hide_if_no_value": 0,
|
"fieldtype": "Check",
|
||||||
"read_only": 0,
|
"in_list_view": 1,
|
||||||
"remember_last_selected_value": 0,
|
"label": "Is Reverse Charge Account"
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"unique": 0
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"has_web_view": 0,
|
"index_web_pages_for_search": 1,
|
||||||
"hide_heading": 0,
|
|
||||||
"hide_toolbar": 0,
|
|
||||||
"idx": 0,
|
|
||||||
"image_view": 0,
|
|
||||||
"in_create": 0,
|
|
||||||
"is_submittable": 0,
|
|
||||||
"issingle": 0,
|
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"max_attachments": 0,
|
"links": [],
|
||||||
"modified": "2018-01-02 15:52:22.335988",
|
"modified": "2021-04-09 12:30:25.889993",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "GST Account",
|
"name": "GST Account",
|
||||||
"name_case": "",
|
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
"permissions": [],
|
"permissions": [],
|
||||||
"quick_entry": 1,
|
"quick_entry": 1,
|
||||||
"read_only": 0,
|
|
||||||
"read_only_onload": 0,
|
|
||||||
"show_name_in_global_search": 0,
|
|
||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
"sort_order": "DESC",
|
"sort_order": "DESC",
|
||||||
"track_changes": 1,
|
"track_changes": 1
|
||||||
"track_seen": 0
|
|
||||||
}
|
}
|
||||||
@@ -582,6 +582,16 @@ frappe.ui.form.on('Sales Invoice', {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
frm.set_query("adjustment_against", function() {
|
||||||
|
return {
|
||||||
|
filters: {
|
||||||
|
company: frm.doc.company,
|
||||||
|
customer: frm.doc.customer,
|
||||||
|
docstatus: 1
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
frm.custom_make_buttons = {
|
frm.custom_make_buttons = {
|
||||||
'Delivery Note': 'Delivery',
|
'Delivery Note': 'Delivery',
|
||||||
'Sales Invoice': 'Return / Credit Note',
|
'Sales Invoice': 'Return / Credit Note',
|
||||||
@@ -867,6 +877,10 @@ frappe.ui.form.on('Sales Invoice', {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (frm.doc.is_debit_note) {
|
||||||
|
frm.set_df_property('return_against', 'label', 'Adjustment Against');
|
||||||
|
}
|
||||||
|
|
||||||
if (frappe.boot.active_domains.includes("Healthcare")) {
|
if (frappe.boot.active_domains.includes("Healthcare")) {
|
||||||
frm.set_df_property("patient", "hidden", 0);
|
frm.set_df_property("patient", "hidden", 0);
|
||||||
frm.set_df_property("patient_name", "hidden", 0);
|
frm.set_df_property("patient_name", "hidden", 0);
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
"is_pos",
|
"is_pos",
|
||||||
"is_consolidated",
|
"is_consolidated",
|
||||||
"is_return",
|
"is_return",
|
||||||
|
"is_debit_note",
|
||||||
"update_billed_amount_in_sales_order",
|
"update_billed_amount_in_sales_order",
|
||||||
"column_break1",
|
"column_break1",
|
||||||
"company",
|
"company",
|
||||||
@@ -392,7 +393,7 @@
|
|||||||
"read_only": 1
|
"read_only": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"depends_on": "return_against",
|
"depends_on": "eval:doc.return_against || doc.is_debit_note",
|
||||||
"fieldname": "return_against",
|
"fieldname": "return_against",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hide_days": 1,
|
"hide_days": 1,
|
||||||
@@ -401,7 +402,7 @@
|
|||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"options": "Sales Invoice",
|
"options": "Sales Invoice",
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"read_only": 1,
|
"read_only_depends_on": "eval:doc.is_return",
|
||||||
"search_index": 1
|
"search_index": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -1953,6 +1954,12 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "0",
|
"default": "0",
|
||||||
|
"fieldname": "is_debit_note",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"label": "Is Debit Note"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": 0,
|
||||||
"depends_on": "grand_total",
|
"depends_on": "grand_total",
|
||||||
"fieldname": "disable_rounded_total",
|
"fieldname": "disable_rounded_total",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
@@ -1969,7 +1976,7 @@
|
|||||||
"link_fieldname": "consolidated_invoice"
|
"link_fieldname": "consolidated_invoice"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"modified": "2021-04-15 23:57:58.766651",
|
"modified": "2021-04-23 22:36:32.916354",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Sales Invoice",
|
"name": "Sales Invoice",
|
||||||
|
|||||||
@@ -268,10 +268,12 @@ doc_events = {
|
|||||||
},
|
},
|
||||||
"Purchase Invoice": {
|
"Purchase Invoice": {
|
||||||
"validate": [
|
"validate": [
|
||||||
"erpnext.regional.india.utils.update_grand_total_for_rcm",
|
"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.update_grand_total_for_rcm",
|
||||||
"erpnext.regional.united_arab_emirates.utils.validate_returns"
|
"erpnext.regional.united_arab_emirates.utils.validate_returns",
|
||||||
]
|
"erpnext.regional.india.utils.update_taxable_values"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"Payment Entry": {
|
"Payment Entry": {
|
||||||
"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_submit": ["erpnext.regional.create_transaction_log", "erpnext.accounts.doctype.payment_request.payment_request.update_payment_req_status", "erpnext.accounts.doctype.dunning.dunning.resolve_dunning"],
|
||||||
@@ -423,7 +425,6 @@ regional_overrides = {
|
|||||||
'erpnext.controllers.taxes_and_totals.get_regional_round_off_accounts': 'erpnext.regional.india.utils.get_regional_round_off_accounts',
|
'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_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.hr.utils.calculate_hra_exemption_for_period': 'erpnext.regional.india.utils.calculate_hra_exemption_for_period',
|
||||||
'erpnext.accounts.doctype.purchase_invoice.purchase_invoice.make_regional_gl_entries': 'erpnext.regional.india.utils.make_regional_gl_entries',
|
|
||||||
'erpnext.controllers.accounts_controller.validate_einvoice_fields': 'erpnext.regional.india.e_invoice.utils.validate_einvoice_fields',
|
'erpnext.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.assets.doctype.asset.asset.get_depreciation_amount': 'erpnext.regional.india.utils.get_depreciation_amount'
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -769,6 +769,7 @@ erpnext.patches.v13_0.rename_discharge_date_in_ip_record
|
|||||||
erpnext.patches.v12_0.create_taxable_value_field
|
erpnext.patches.v12_0.create_taxable_value_field
|
||||||
erpnext.patches.v12_0.add_gst_category_in_delivery_note
|
erpnext.patches.v12_0.add_gst_category_in_delivery_note
|
||||||
erpnext.patches.v12_0.purchase_receipt_status
|
erpnext.patches.v12_0.purchase_receipt_status
|
||||||
|
erpnext.patches.v12_0.create_itc_reversal_custom_fields
|
||||||
erpnext.patches.v13_0.fix_non_unique_represents_company
|
erpnext.patches.v13_0.fix_non_unique_represents_company
|
||||||
erpnext.patches.v12_0.add_document_type_field_for_italy_einvoicing
|
erpnext.patches.v12_0.add_document_type_field_for_italy_einvoicing
|
||||||
erpnext.patches.v13_0.make_non_standard_user_type #13-04-2021
|
erpnext.patches.v13_0.make_non_standard_user_type #13-04-2021
|
||||||
|
|||||||
115
erpnext/patches/v12_0/create_itc_reversal_custom_fields.py
Normal file
115
erpnext/patches/v12_0/create_itc_reversal_custom_fields.py
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
from __future__ import unicode_literals
|
||||||
|
import frappe
|
||||||
|
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
|
||||||
|
from frappe.custom.doctype.property_setter.property_setter import make_property_setter
|
||||||
|
from erpnext.regional.india.utils import get_gst_accounts
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
company = frappe.get_all('Company', filters = {'country': 'India'}, fields=['name'])
|
||||||
|
if not company:
|
||||||
|
return
|
||||||
|
|
||||||
|
frappe.reload_doc("regional", "doctype", "gst_settings")
|
||||||
|
frappe.reload_doc("accounts", "doctype", "gst_account")
|
||||||
|
|
||||||
|
journal_entry_types = frappe.get_meta("Journal Entry").get_options("voucher_type").split("\n") + ['Reversal Of ITC']
|
||||||
|
make_property_setter('Journal Entry', 'voucher_type', 'options', '\n'.join(journal_entry_types), '')
|
||||||
|
|
||||||
|
custom_fields = {
|
||||||
|
'Journal Entry': [
|
||||||
|
dict(fieldname='reversal_type', label='Reversal Type',
|
||||||
|
fieldtype='Select', insert_after='voucher_type', print_hide=1,
|
||||||
|
options="As per rules 42 & 43 of CGST Rules\nOthers",
|
||||||
|
depends_on="eval:doc.voucher_type=='Reversal Of ITC'",
|
||||||
|
mandatory_depends_on="eval:doc.voucher_type=='Reversal Of ITC'"),
|
||||||
|
dict(fieldname='company_address', label='Company Address',
|
||||||
|
fieldtype='Link', options='Address', insert_after='reversal_type',
|
||||||
|
print_hide=1, depends_on="eval:doc.voucher_type=='Reversal Of ITC'",
|
||||||
|
mandatory_depends_on="eval:doc.voucher_type=='Reversal Of ITC'"),
|
||||||
|
dict(fieldname='company_gstin', label='Company GSTIN',
|
||||||
|
fieldtype='Data', read_only=1, insert_after='company_address', print_hide=1,
|
||||||
|
fetch_from='company_address.gstin',
|
||||||
|
depends_on="eval:doc.voucher_type=='Reversal Of ITC'",
|
||||||
|
mandatory_depends_on="eval:doc.voucher_type=='Reversal Of ITC'")
|
||||||
|
],
|
||||||
|
'Purchase Invoice': [
|
||||||
|
dict(fieldname='eligibility_for_itc', label='Eligibility For ITC',
|
||||||
|
fieldtype='Select', insert_after='reason_for_issuing_document', print_hide=1,
|
||||||
|
options='Input Service Distributor\nImport Of Service\nImport Of Capital Goods\nITC on Reverse Charge\nIneligible As Per Section 17(5)\nIneligible Others\nAll Other ITC',
|
||||||
|
default="All Other ITC")
|
||||||
|
],
|
||||||
|
'Purchase Invoice Item': [
|
||||||
|
dict(fieldname='taxable_value', label='Taxable Value',
|
||||||
|
fieldtype='Currency', insert_after='base_net_amount', hidden=1, options="Company:company:default_currency",
|
||||||
|
print_hide=1)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
create_custom_fields(custom_fields, update=True)
|
||||||
|
|
||||||
|
# Patch ITC Availed fields from Data to Currency
|
||||||
|
# Patch Availed ITC for current fiscal_year
|
||||||
|
|
||||||
|
gst_accounts = get_gst_accounts(only_non_reverse_charge=1)
|
||||||
|
|
||||||
|
frappe.db.sql("""
|
||||||
|
UPDATE `tabCustom Field` SET fieldtype='Currency', options='Company:company:default_currency'
|
||||||
|
WHERE dt = 'Purchase Invoice' and fieldname in ('itc_integrated_tax', 'itc_state_tax', 'itc_central_tax',
|
||||||
|
'itc_cess_amount')
|
||||||
|
""")
|
||||||
|
|
||||||
|
frappe.db.sql("""UPDATE `tabPurchase Invoice` set itc_integrated_tax = '0'
|
||||||
|
WHERE trim(coalesce(itc_integrated_tax, '')) = '' """)
|
||||||
|
|
||||||
|
frappe.db.sql("""UPDATE `tabPurchase Invoice` set itc_state_tax = '0'
|
||||||
|
WHERE trim(coalesce(itc_state_tax, '')) = '' """)
|
||||||
|
|
||||||
|
frappe.db.sql("""UPDATE `tabPurchase Invoice` set itc_central_tax = '0'
|
||||||
|
WHERE trim(coalesce(itc_central_tax, '')) = '' """)
|
||||||
|
|
||||||
|
frappe.db.sql("""UPDATE `tabPurchase Invoice` set itc_cess_amount = '0'
|
||||||
|
WHERE trim(coalesce(itc_cess_amount, '')) = '' """)
|
||||||
|
|
||||||
|
# Get purchase invoices
|
||||||
|
invoices = frappe.get_all('Purchase Invoice',
|
||||||
|
{'posting_date': ('>=', '2021-04-01'), 'eligibility_for_itc': ('!=', 'Ineligible')},
|
||||||
|
['name'])
|
||||||
|
|
||||||
|
amount_map = {}
|
||||||
|
|
||||||
|
if invoices:
|
||||||
|
invoice_list = set([d.name for d in invoices])
|
||||||
|
|
||||||
|
# Get GST applied
|
||||||
|
amounts = frappe.db.sql("""
|
||||||
|
SELECT parent, account_head, sum(base_tax_amount_after_discount_amount) as amount
|
||||||
|
FROM `tabPurchase Taxes and Charges`
|
||||||
|
where parent in %s
|
||||||
|
GROUP BY parent, account_head
|
||||||
|
""", (invoice_list), as_dict=1)
|
||||||
|
|
||||||
|
for d in amounts:
|
||||||
|
amount_map.setdefault(d.parent,
|
||||||
|
{
|
||||||
|
'itc_integrated_tax': 0,
|
||||||
|
'itc_state_tax': 0,
|
||||||
|
'itc_central_tax': 0,
|
||||||
|
'itc_cess_amount': 0
|
||||||
|
})
|
||||||
|
|
||||||
|
if d.account_head in gst_accounts.get('igst_account'):
|
||||||
|
amount_map[d.parent]['itc_integrated_tax'] += d.amount
|
||||||
|
if d.account_head in gst_accounts.get('cgst_account'):
|
||||||
|
amount_map[d.parent]['itc_central_tax'] += d.amount
|
||||||
|
if d.account_head in gst_accounts.get('sgst_account'):
|
||||||
|
amount_map[d.parent]['itc_state_tax'] += d.amount
|
||||||
|
if d.account_head in gst_accounts.get('cess_account'):
|
||||||
|
amount_map[d.parent]['itc_cess_amount'] += d.amount
|
||||||
|
|
||||||
|
for invoice, values in amount_map.items():
|
||||||
|
frappe.db.set_value('Purchase Invoice', invoice, {
|
||||||
|
'itc_integrated_tax': values.get('itc_integrated_tax'),
|
||||||
|
'itc_central_tax': values.get('itc_central_tax'),
|
||||||
|
'itc_state_tax': values['itc_state_tax'],
|
||||||
|
'itc_cess_amount': values['itc_cess_amount'],
|
||||||
|
})
|
||||||
@@ -172,7 +172,7 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td><b>(A) {{__("ITC Available (whether in full op part)")}}</b></td>
|
<td><b>(A) {{__("ITC Available (whether in full or part)")}}</b></td>
|
||||||
<td></td>
|
<td></td>
|
||||||
<td></td>
|
<td></td>
|
||||||
<td></td>
|
<td></td>
|
||||||
|
|||||||
@@ -3,148 +3,21 @@
|
|||||||
# For license information, please see license.txt
|
# For license information, please see license.txt
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
import os
|
||||||
|
import json
|
||||||
import frappe
|
import frappe
|
||||||
|
from six import iteritems
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
import json
|
from frappe.utils import flt, cstr
|
||||||
from six import iteritems
|
|
||||||
from frappe.utils import flt, getdate
|
|
||||||
from erpnext.regional.india import state_numbers
|
from erpnext.regional.india import state_numbers
|
||||||
|
|
||||||
class GSTR3BReport(Document):
|
class GSTR3BReport(Document):
|
||||||
def before_save(self):
|
def validate(self):
|
||||||
|
|
||||||
self.get_data()
|
self.get_data()
|
||||||
|
|
||||||
def get_data(self):
|
def get_data(self):
|
||||||
|
self.report_dict = json.loads(get_json('gstr_3b_report_template'))
|
||||||
self.report_dict = {
|
|
||||||
"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
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.gst_details = self.get_company_gst_details()
|
self.gst_details = self.get_company_gst_details()
|
||||||
self.report_dict["gstin"] = self.gst_details.get("gstin")
|
self.report_dict["gstin"] = self.gst_details.get("gstin")
|
||||||
@@ -152,23 +25,19 @@ class GSTR3BReport(Document):
|
|||||||
self.month_no = get_period(self.month)
|
self.month_no = get_period(self.month)
|
||||||
self.account_heads = self.get_account_heads()
|
self.account_heads = self.get_account_heads()
|
||||||
|
|
||||||
outward_supply_tax_amounts = self.get_tax_amounts("Sales Invoice")
|
self.get_outward_supply_details("Sales Invoice")
|
||||||
inward_supply_tax_amounts = self.get_tax_amounts("Purchase Invoice", reverse_charge="Y")
|
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()
|
itc_details = self.get_itc_details()
|
||||||
|
|
||||||
self.prepare_data("Sales Invoice", outward_supply_tax_amounts, "sup_details", "osup_det", ["Registered Regular"])
|
|
||||||
self.prepare_data("Sales Invoice", outward_supply_tax_amounts, "sup_details", "osup_zero", ["SEZ", "Deemed Export", "Overseas"])
|
|
||||||
self.prepare_data("Purchase Invoice", inward_supply_tax_amounts, "sup_details", "isup_rev", ["Unregistered", "Overseas"], reverse_charge="Y")
|
|
||||||
self.report_dict["sup_details"]["osup_nil_exmp"]["txval"] = flt(self.get_nil_rated_supply_value(), 2)
|
|
||||||
self.set_itc_details(itc_details)
|
self.set_itc_details(itc_details)
|
||||||
|
self.get_itc_reversal_entries()
|
||||||
inter_state_supplies = self.get_inter_state_supplies(self.gst_details.get("gst_state_number"))
|
|
||||||
inward_nil_exempt = self.get_inward_nil_exempt(self.gst_details.get("gst_state"))
|
inward_nil_exempt = self.get_inward_nil_exempt(self.gst_details.get("gst_state"))
|
||||||
self.set_inter_state_supply(inter_state_supplies)
|
|
||||||
self.set_inward_nil_exempt(inward_nil_exempt)
|
self.set_inward_nil_exempt(inward_nil_exempt)
|
||||||
|
|
||||||
self.missing_field_invoices = self.get_missing_field_invoices()
|
self.missing_field_invoices = self.get_missing_field_invoices()
|
||||||
|
|
||||||
self.json_output = frappe.as_json(self.report_dict)
|
self.json_output = frappe.as_json(self.report_dict)
|
||||||
|
|
||||||
def set_inward_nil_exempt(self, inward_nil_exempt):
|
def set_inward_nil_exempt(self, inward_nil_exempt):
|
||||||
@@ -178,189 +47,95 @@ class GSTR3BReport(Document):
|
|||||||
self.report_dict["inward_sup"]["isup_details"][1]["intra"] = flt(inward_nil_exempt.get("non_gst").get("intra"), 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):
|
def set_itc_details(self, itc_details):
|
||||||
|
itc_eligible_type_map = {
|
||||||
itc_type_map = {
|
|
||||||
'IMPG': 'Import Of Capital Goods',
|
'IMPG': 'Import Of Capital Goods',
|
||||||
'IMPS': 'Import Of Service',
|
'IMPS': 'Import Of Service',
|
||||||
|
'ISRC': 'ITC on Reverse Charge',
|
||||||
'ISD': 'Input Service Distributor',
|
'ISD': 'Input Service Distributor',
|
||||||
'OTH': 'All Other ITC'
|
'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"]
|
net_itc = self.report_dict["itc_elg"]["itc_net"]
|
||||||
|
|
||||||
for d in self.report_dict["itc_elg"]["itc_avl"]:
|
for d in self.report_dict["itc_elg"]["itc_avl"]:
|
||||||
|
itc_type = itc_eligible_type_map.get(d["ty"])
|
||||||
itc_type = itc_type_map.get(d["ty"])
|
|
||||||
|
|
||||||
if d["ty"] == 'ISRC':
|
|
||||||
reverse_charge = ["Y"]
|
|
||||||
itc_type = 'All Other ITC'
|
|
||||||
gst_category = ['Unregistered', 'Overseas']
|
|
||||||
else:
|
|
||||||
gst_category = ['Unregistered', 'Overseas', 'Registered Regular']
|
|
||||||
reverse_charge = ["N", "Y"]
|
|
||||||
|
|
||||||
for account_head in self.account_heads:
|
|
||||||
for category in gst_category:
|
|
||||||
for charge_type in reverse_charge:
|
|
||||||
for key in [['iamt', 'igst_account'], ['camt', 'cgst_account'], ['samt', 'sgst_account'], ['csamt', 'cess_account']]:
|
|
||||||
d[key[0]] += flt(itc_details.get((category, itc_type, charge_type, account_head.get(key[1])), {}).get("amount"), 2)
|
|
||||||
|
|
||||||
for key in ['iamt', 'camt', 'samt', 'csamt']:
|
for key in ['iamt', 'camt', 'samt', 'csamt']:
|
||||||
|
d[key] = flt(itc_details.get(itc_type, {}).get(key))
|
||||||
net_itc[key] += flt(d[key], 2)
|
net_itc[key] += flt(d[key], 2)
|
||||||
|
|
||||||
for account_head in self.account_heads:
|
for d in self.report_dict["itc_elg"]["itc_inelg"]:
|
||||||
itc_inelg = self.report_dict["itc_elg"]["itc_inelg"][1]
|
itc_type = itc_ineligible_map.get(d["ty"])
|
||||||
for key in [['iamt', 'igst_account'], ['camt', 'cgst_account'], ['samt', 'sgst_account'], ['csamt', 'cess_account']]:
|
for key in ['iamt', 'camt', 'samt', 'csamt']:
|
||||||
itc_inelg[key[0]] = flt(itc_details.get(("Ineligible", "N", account_head.get(key[1])), {}).get("amount"), 2)
|
d[key] = flt(itc_details.get(itc_type, {}).get(key))
|
||||||
|
|
||||||
def prepare_data(self, doctype, tax_details, supply_type, supply_category, gst_category_list, reverse_charge="N"):
|
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)
|
||||||
|
|
||||||
account_map = {
|
net_itc = self.report_dict["itc_elg"]["itc_net"]
|
||||||
'sgst_account': 'samt',
|
|
||||||
'cess_account': 'csamt',
|
|
||||||
'cgst_account': 'camt',
|
|
||||||
'igst_account': 'iamt'
|
|
||||||
}
|
|
||||||
|
|
||||||
txval = 0
|
for entry in reversal_entries:
|
||||||
total_taxable_value = self.get_total_taxable_value(doctype, reverse_charge)
|
if entry.reversal_type == 'As per rules 42 & 43 of CGST Rules':
|
||||||
|
index = 0
|
||||||
|
else:
|
||||||
|
index = 1
|
||||||
|
|
||||||
for gst_category in gst_category_list:
|
for key in ['camt', 'samt', 'iamt', 'csamt']:
|
||||||
txval += total_taxable_value.get(gst_category,0)
|
if entry.account in self.account_heads.get(key):
|
||||||
for account_head in self.account_heads:
|
self.report_dict["itc_elg"]["itc_rev"][index][key] += flt(entry.amount)
|
||||||
for account_type, account_name in iteritems(account_head):
|
net_itc[key] -= flt(entry.amount)
|
||||||
if account_map.get(account_type) in self.report_dict.get(supply_type).get(supply_category):
|
|
||||||
self.report_dict[supply_type][supply_category][account_map.get(account_type)] += \
|
|
||||||
flt(tax_details.get((account_name, gst_category), {}).get("amount"), 2)
|
|
||||||
|
|
||||||
self.report_dict[supply_type][supply_category]["txval"] += flt(txval, 2)
|
|
||||||
|
|
||||||
def set_inter_state_supply(self, inter_state_supply):
|
|
||||||
osup_det = self.report_dict["sup_details"]["osup_det"]
|
|
||||||
|
|
||||||
for key, value in iteritems(inter_state_supply):
|
|
||||||
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_total_taxable_value(self, doctype, reverse_charge):
|
|
||||||
|
|
||||||
return frappe._dict(frappe.db.sql("""
|
|
||||||
select gst_category, sum(net_total) as total
|
|
||||||
from `tab{doctype}`
|
|
||||||
where docstatus = 1 and month(posting_date) = %s
|
|
||||||
and year(posting_date) = %s and reverse_charge = %s
|
|
||||||
and company = %s and company_gstin = %s
|
|
||||||
group by gst_category
|
|
||||||
""" #nosec
|
|
||||||
.format(doctype = doctype), (self.month_no, self.year, reverse_charge, self.company, self.gst_details.get("gstin"))))
|
|
||||||
|
|
||||||
def get_itc_details(self):
|
def get_itc_details(self):
|
||||||
itc_amount = frappe.db.sql("""
|
itc_amounts = frappe.db.sql("""
|
||||||
select s.gst_category, sum(t.base_tax_amount_after_discount_amount) as tax_amount,
|
SELECT eligibility_for_itc, sum(itc_integrated_tax) as itc_integrated_tax,
|
||||||
t.account_head, s.eligibility_for_itc, s.reverse_charge
|
sum(itc_central_tax) as itc_central_tax,
|
||||||
from `tabPurchase Invoice` s , `tabPurchase Taxes and Charges` t
|
sum(itc_state_tax) as itc_state_tax,
|
||||||
where s.docstatus = 1 and t.parent = s.name
|
sum(itc_cess_amount) as itc_cess_amount
|
||||||
and month(s.posting_date) = %s and year(s.posting_date) = %s and s.company = %s
|
FROM `tabPurchase Invoice`
|
||||||
and s.company_gstin = %s
|
WHERE docstatus = 1
|
||||||
group by t.account_head, s.gst_category, s.eligibility_for_itc
|
and is_opening = 'No'
|
||||||
""",
|
and month(posting_date) = %s and year(posting_date) = %s and company = %s
|
||||||
(self.month_no, self.year, self.company, self.gst_details.get("gstin")), as_dict=1)
|
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 = {}
|
itc_details = {}
|
||||||
|
for d in itc_amounts:
|
||||||
for d in itc_amount:
|
itc_details.setdefault(d.eligibility_for_itc, {
|
||||||
itc_details.setdefault((d.gst_category, d.eligibility_for_itc, d.reverse_charge, d.account_head),{
|
'iamt': d.itc_integrated_tax,
|
||||||
"amount": d.tax_amount
|
'camt': d.itc_central_tax,
|
||||||
|
'samt': d.itc_state_tax,
|
||||||
|
'csamt': d.itc_cess_amount
|
||||||
})
|
})
|
||||||
|
|
||||||
return itc_details
|
return itc_details
|
||||||
|
|
||||||
def get_nil_rated_supply_value(self):
|
|
||||||
|
|
||||||
return frappe.db.sql("""
|
|
||||||
select sum(i.base_amount) as total from
|
|
||||||
`tabSales Invoice Item` i, `tabSales Invoice` s
|
|
||||||
where s.docstatus = 1 and i.parent = s.name and i.is_nil_exempt = 1
|
|
||||||
and month(s.posting_date) = %s and year(s.posting_date) = %s
|
|
||||||
and s.company = %s and s.company_gstin = %s""",
|
|
||||||
(self.month_no, self.year, self.company, self.gst_details.get("gstin")), as_dict=1)[0].total
|
|
||||||
|
|
||||||
def get_inter_state_supplies(self, state_number):
|
|
||||||
inter_state_supply_tax = frappe.db.sql(""" select t.account_head, t.tax_amount_after_discount_amount as tax_amount,
|
|
||||||
s.name, s.net_total, s.place_of_supply, s.gst_category from `tabSales Invoice` s, `tabSales Taxes and Charges` t
|
|
||||||
where t.parent = s.name and s.docstatus = 1 and month(s.posting_date) = %s and year(s.posting_date) = %s
|
|
||||||
and s.company = %s and s.company_gstin = %s and s.gst_category in ('Unregistered', 'Registered Composition', 'UIN Holders')
|
|
||||||
""", (self.month_no, self.year, self.company, self.gst_details.get("gstin")), as_dict=1)
|
|
||||||
|
|
||||||
inter_state_supply_tax_mapping = {}
|
|
||||||
inter_state_supply_details = {}
|
|
||||||
|
|
||||||
for d in inter_state_supply_tax:
|
|
||||||
inter_state_supply_tax_mapping.setdefault(d.name, {
|
|
||||||
'place_of_supply': d.place_of_supply,
|
|
||||||
'taxable_value': d.net_total,
|
|
||||||
'gst_category': d.gst_category,
|
|
||||||
'camt': 0.0,
|
|
||||||
'samt': 0.0,
|
|
||||||
'iamt': 0.0,
|
|
||||||
'csamt': 0.0
|
|
||||||
})
|
|
||||||
|
|
||||||
if d.account_head in [a.cgst_account for a in self.account_heads]:
|
|
||||||
inter_state_supply_tax_mapping[d.name]['camt'] += d.tax_amount
|
|
||||||
|
|
||||||
if d.account_head in [a.sgst_account for a in self.account_heads]:
|
|
||||||
inter_state_supply_tax_mapping[d.name]['samt'] += d.tax_amount
|
|
||||||
|
|
||||||
if d.account_head in [a.igst_account for a in self.account_heads]:
|
|
||||||
inter_state_supply_tax_mapping[d.name]['iamt'] += d.tax_amount
|
|
||||||
|
|
||||||
if d.account_head in [a.cess_account for a in self.account_heads]:
|
|
||||||
inter_state_supply_tax_mapping[d.name]['csamt'] += d.tax_amount
|
|
||||||
|
|
||||||
for key, value in iteritems(inter_state_supply_tax_mapping):
|
|
||||||
if value.get('place_of_supply'):
|
|
||||||
osup_det = self.report_dict["sup_details"]["osup_det"]
|
|
||||||
osup_det["txval"] = flt(osup_det["txval"] + value['taxable_value'], 2)
|
|
||||||
osup_det["iamt"] = flt(osup_det["iamt"] + value['iamt'], 2)
|
|
||||||
osup_det["camt"] = flt(osup_det["camt"] + value['camt'], 2)
|
|
||||||
osup_det["samt"] = flt(osup_det["samt"] + value['samt'], 2)
|
|
||||||
osup_det["csamt"] = flt(osup_det["csamt"] + value['csamt'], 2)
|
|
||||||
|
|
||||||
if state_number != value.get('place_of_supply').split("-")[0]:
|
|
||||||
inter_state_supply_details.setdefault((value.get('gst_category'), value.get('place_of_supply')), {
|
|
||||||
"txval": 0.0,
|
|
||||||
"pos": value.get('place_of_supply').split("-")[0],
|
|
||||||
"iamt": 0.0
|
|
||||||
})
|
|
||||||
|
|
||||||
inter_state_supply_details[(value.get('gst_category'), value.get('place_of_supply'))]['txval'] += value['taxable_value']
|
|
||||||
inter_state_supply_details[(value.get('gst_category'), value.get('place_of_supply'))]['iamt'] += value['iamt']
|
|
||||||
|
|
||||||
return inter_state_supply_details
|
|
||||||
|
|
||||||
def get_inward_nil_exempt(self, state):
|
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,
|
inward_nil_exempt = frappe.db.sql("""
|
||||||
i.is_nil_exempt, i.is_non_gst from `tabPurchase Invoice` p , `tabPurchase Invoice Item` i
|
SELECT p.place_of_supply, sum(i.base_amount) as base_amount, i.is_nil_exempt, i.is_non_gst
|
||||||
where p.docstatus = 1 and p.name = i.parent
|
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 p.gst_category != 'Registered Composition'
|
||||||
and (i.is_nil_exempt = 1 or i.is_non_gst = 1) and
|
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
|
month(p.posting_date) = %s and year(p.posting_date) = %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)
|
and p.company = %s and p.company_gstin = %s
|
||||||
|
GROUP BY p.place_of_supply, i.is_nil_exempt, i.is_non_gst""",
|
||||||
inward_nil_exempt += frappe.db.sql("""SELECT sum(base_net_total) as base_amount, gst_category, place_of_supply
|
(self.month_no, self.year, self.company, self.gst_details.get("gstin")), as_dict=1)
|
||||||
FROM `tabPurchase Invoice`
|
|
||||||
WHERE docstatus = 1 and gst_category = 'Registered Composition'
|
|
||||||
and month(posting_date) = %s and year(posting_date) = %s
|
|
||||||
and company = %s and company_gstin = %s
|
|
||||||
group by place_of_supply""", (self.month_no, self.year, self.company, self.gst_details.get("gstin")), as_dict=1)
|
|
||||||
|
|
||||||
inward_nil_exempt_details = {
|
inward_nil_exempt_details = {
|
||||||
"gst": {
|
"gst": {
|
||||||
@@ -388,37 +163,193 @@ class GSTR3BReport(Document):
|
|||||||
|
|
||||||
return inward_nil_exempt_details
|
return inward_nil_exempt_details
|
||||||
|
|
||||||
def get_tax_amounts(self, doctype, reverse_charge="N"):
|
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,
|
||||||
|
sum((i.get('taxable_value', 0) or i.get('base_net_amount', 0)) for i in item_details
|
||||||
|
if i.item_code == d.item_code and i.parent == d.parent))
|
||||||
|
|
||||||
|
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":
|
if doctype == "Sales Invoice":
|
||||||
tax_template = 'Sales Taxes and Charges'
|
tax_template = 'Sales Taxes and Charges'
|
||||||
elif doctype == "Purchase Invoice":
|
elif doctype == "Purchase Invoice":
|
||||||
tax_template = 'Purchase Taxes and Charges'
|
tax_template = 'Purchase Taxes and Charges'
|
||||||
|
|
||||||
tax_amounts = frappe.db.sql("""
|
self.items_based_on_tax_rate = {}
|
||||||
select s.gst_category, sum(t.base_tax_amount_after_discount_amount) as tax_amount, t.account_head
|
self.invoice_cess = frappe._dict()
|
||||||
from `tab{doctype}` s , `tab{template}` t
|
self.cgst_sgst_invoices = []
|
||||||
where s.docstatus = 1 and t.parent = s.name and s.reverse_charge = %s
|
|
||||||
and month(s.posting_date) = %s and year(s.posting_date) = %s and s.company = %s
|
|
||||||
and s.company_gstin = %s
|
|
||||||
group by t.account_head, s.gst_category
|
|
||||||
""" #nosec
|
|
||||||
.format(doctype=doctype, template=tax_template),
|
|
||||||
(reverse_charge, self.month_no, self.year, self.company, self.gst_details.get("gstin")), as_dict=1)
|
|
||||||
|
|
||||||
tax_details = {}
|
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 d in tax_amounts:
|
for parent, account, item_wise_tax_detail, tax_amount in tax_details:
|
||||||
tax_details.setdefault(
|
if account in self.account_heads.get('csamt'):
|
||||||
(d.account_head,d.gst_category),{
|
self.invoice_cess.setdefault(parent, tax_amount)
|
||||||
"amount": d.get("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
|
||||||
|
|
||||||
return tax_details
|
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 iteritems(self.invoice_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"):
|
||||||
|
self.items_based_on_tax_rate.setdefault(invoice, {}).setdefault(0, items.keys())
|
||||||
|
|
||||||
|
def set_outward_taxable_supplies(self):
|
||||||
|
inter_state_supply_details = {}
|
||||||
|
|
||||||
|
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 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:
|
||||||
|
self.report_dict['sup_details']['osup_zero']['txval'] += taxable_value
|
||||||
|
#self.report_dict['sup_details']['osup_zero'][key] += tax_amount
|
||||||
|
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
|
||||||
|
|
||||||
|
gst_category = self.invoice_detail_map.get(inv, {}).get('gst_category')
|
||||||
|
place_of_supply = self.invoice_detail_map.get(inv, {}).get('place_of_supply', '00-Other Territory')
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
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 iteritems(inter_state_supply):
|
||||||
|
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):
|
def get_company_gst_details(self):
|
||||||
|
|
||||||
gst_details = frappe.get_all("Address",
|
gst_details = frappe.get_all("Address",
|
||||||
fields=["gstin", "gst_state", "gst_state_number"],
|
fields=["gstin", "gst_state", "gst_state_number"],
|
||||||
filters={
|
filters={
|
||||||
@@ -431,20 +362,28 @@ class GSTR3BReport(Document):
|
|||||||
frappe.throw(_("Please enter GSTIN and state for the Company Address {0}").format(self.company_address))
|
frappe.throw(_("Please enter GSTIN and state for the Company Address {0}").format(self.company_address))
|
||||||
|
|
||||||
def get_account_heads(self):
|
def get_account_heads(self):
|
||||||
|
account_map = {
|
||||||
|
'sgst_account': 'samt',
|
||||||
|
'cess_account': 'csamt',
|
||||||
|
'cgst_account': 'camt',
|
||||||
|
'igst_account': 'iamt'
|
||||||
|
}
|
||||||
|
|
||||||
account_heads = frappe.get_all("GST Account",
|
account_heads = {}
|
||||||
fields=["cgst_account", "sgst_account", "igst_account", "cess_account"],
|
gst_settings_accounts = frappe.get_all("GST Account",
|
||||||
filters={
|
filters={'company': self.company, 'is_reverse_charge_account': 0},
|
||||||
"company":self.company
|
fields=["cgst_account", "sgst_account", "igst_account", "cess_account"])
|
||||||
})
|
|
||||||
|
|
||||||
if account_heads:
|
if not gst_settings_accounts:
|
||||||
return account_heads
|
frappe.throw(_("Please set GST Accounts in GST Settings"))
|
||||||
else:
|
|
||||||
frappe.throw(_("Please set account heads in GST Settings for Compnay {0}").format(self.company))
|
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):
|
def get_missing_field_invoices(self):
|
||||||
|
|
||||||
missing_field_invoices = []
|
missing_field_invoices = []
|
||||||
|
|
||||||
for doctype in ["Sales Invoice", "Purchase Invoice"]:
|
for doctype in ["Sales Invoice", "Purchase Invoice"]:
|
||||||
@@ -456,26 +395,32 @@ class GSTR3BReport(Document):
|
|||||||
party_type = 'Supplier'
|
party_type = 'Supplier'
|
||||||
party = 'supplier'
|
party = 'supplier'
|
||||||
|
|
||||||
docnames = frappe.db.sql("""
|
docnames = frappe.db.sql(
|
||||||
select t1.name from `tab{doctype}` t1, `tab{party_type}` t2
|
"""
|
||||||
where t1.docstatus = 1 and month(t1.posting_date) = %s and year(t1.posting_date) = %s
|
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
|
and t1.company = %s and t1.place_of_supply IS NULL and t1.{party} = t2.name and
|
||||||
t2.gst_category != 'Overseas'
|
t2.gst_category != 'Overseas'
|
||||||
""".format(doctype = doctype, party_type = party_type, party=party), (self.month_no, self.year, self.company), as_dict=1) #nosec
|
""".format(doctype = doctype, party_type = party_type,
|
||||||
|
party=party) ,(self.month_no, self.year, self.company), as_dict=1) #nosec
|
||||||
|
|
||||||
for d in docnames:
|
for d in docnames:
|
||||||
missing_field_invoices.append(d.name)
|
missing_field_invoices.append(d.name)
|
||||||
|
|
||||||
return ",".join(missing_field_invoices)
|
return ",".join(missing_field_invoices)
|
||||||
|
|
||||||
def get_state_code(state):
|
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)
|
state_code = state_numbers.get(state)
|
||||||
|
|
||||||
return state_code
|
return state_code
|
||||||
|
|
||||||
def get_period(month, year=None):
|
def get_period(month, year=None):
|
||||||
|
|
||||||
month_no = {
|
month_no = {
|
||||||
"January": 1,
|
"January": 1,
|
||||||
"February": 2,
|
"February": 2,
|
||||||
@@ -499,13 +444,11 @@ def get_period(month, year=None):
|
|||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def view_report(name):
|
def view_report(name):
|
||||||
|
|
||||||
json_data = frappe.get_value("GSTR 3B Report", name, 'json_output')
|
json_data = frappe.get_value("GSTR 3B Report", name, 'json_output')
|
||||||
return json.loads(json_data)
|
return json.loads(json_data)
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def make_json(name):
|
def make_json(name):
|
||||||
|
|
||||||
json_data = frappe.get_value("GSTR 3B Report", name, 'json_output')
|
json_data = frappe.get_value("GSTR 3B Report", name, 'json_output')
|
||||||
file_name = "GST3B.json"
|
file_name = "GST3B.json"
|
||||||
frappe.local.response.filename = file_name
|
frappe.local.response.filename = file_name
|
||||||
|
|||||||
@@ -0,0 +1,127 @@
|
|||||||
|
{
|
||||||
|
"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
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -60,8 +60,7 @@ class TestGSTR3BReport(unittest.TestCase):
|
|||||||
|
|
||||||
output = json.loads(report.json_output)
|
output = json.loads(report.json_output)
|
||||||
|
|
||||||
self.assertEqual(output["sup_details"]["osup_det"]["iamt"], 36),
|
self.assertEqual(output["sup_details"]["osup_det"]["iamt"], 54)
|
||||||
self.assertEqual(output["sup_details"]["osup_zero"]["iamt"], 18),
|
|
||||||
self.assertEqual(output["inter_sup"]["unreg_details"][0]["iamt"], 18),
|
self.assertEqual(output["inter_sup"]["unreg_details"][0]["iamt"], 18),
|
||||||
self.assertEqual(output["sup_details"]["osup_nil_exmp"]["txval"], 100),
|
self.assertEqual(output["sup_details"]["osup_nil_exmp"]["txval"], 100),
|
||||||
self.assertEqual(output["inward_sup"]["isup_details"][0]["intra"], 250)
|
self.assertEqual(output["inward_sup"]["isup_details"][0]["intra"], 250)
|
||||||
|
|||||||
@@ -114,9 +114,12 @@ def add_print_formats():
|
|||||||
|
|
||||||
def make_property_setters(patch=False):
|
def make_property_setters(patch=False):
|
||||||
# GST rules do not allow for an invoice no. bigger than 16 characters
|
# GST rules do not allow for an invoice no. bigger than 16 characters
|
||||||
|
journal_entry_types = frappe.get_meta("Journal Entry").get_options("voucher_type").split("\n") + ['Reversal Of ITC']
|
||||||
|
|
||||||
if not patch:
|
if not patch:
|
||||||
make_property_setter('Sales Invoice', 'naming_series', 'options', 'SINV-.YY.-\nSRET-.YY.-', '')
|
make_property_setter('Sales Invoice', 'naming_series', 'options', 'SINV-.YY.-\nSRET-.YY.-', '')
|
||||||
make_property_setter('Purchase Invoice', 'naming_series', 'options', 'PINV-.YY.-\nPRET-.YY.-', '')
|
make_property_setter('Purchase Invoice', 'naming_series', 'options', 'PINV-.YY.-\nPRET-.YY.-', '')
|
||||||
|
make_property_setter('Journal Entry', 'voucher_type', 'options', '\n'.join(journal_entry_types), '')
|
||||||
|
|
||||||
def make_custom_fields(update=True):
|
def make_custom_fields(update=True):
|
||||||
hsn_sac_field = dict(fieldname='gst_hsn_code', label='HSN/SAC',
|
hsn_sac_field = dict(fieldname='gst_hsn_code', label='HSN/SAC',
|
||||||
@@ -198,15 +201,20 @@ def make_custom_fields(update=True):
|
|||||||
purchase_invoice_itc_fields = [
|
purchase_invoice_itc_fields = [
|
||||||
dict(fieldname='eligibility_for_itc', label='Eligibility For ITC',
|
dict(fieldname='eligibility_for_itc', label='Eligibility For ITC',
|
||||||
fieldtype='Select', insert_after='reason_for_issuing_document', print_hide=1,
|
fieldtype='Select', insert_after='reason_for_issuing_document', print_hide=1,
|
||||||
options='Input Service Distributor\nImport Of Service\nImport Of Capital Goods\nIneligible\nAll Other ITC', default="All Other ITC"),
|
options='Input Service Distributor\nImport Of Service\nImport Of Capital Goods\nITC on Reverse Charge\nIneligible As Per Section 17(5)\nIneligible Others\nAll Other ITC',
|
||||||
|
default="All Other ITC"),
|
||||||
dict(fieldname='itc_integrated_tax', label='Availed ITC Integrated Tax',
|
dict(fieldname='itc_integrated_tax', label='Availed ITC Integrated Tax',
|
||||||
fieldtype='Data', insert_after='eligibility_for_itc', print_hide=1),
|
fieldtype='Currency', insert_after='eligibility_for_itc',
|
||||||
|
options='Company:company:default_currency', print_hide=1),
|
||||||
dict(fieldname='itc_central_tax', label='Availed ITC Central Tax',
|
dict(fieldname='itc_central_tax', label='Availed ITC Central Tax',
|
||||||
fieldtype='Data', insert_after='itc_integrated_tax', print_hide=1),
|
fieldtype='Currency', insert_after='itc_integrated_tax',
|
||||||
|
options='Company:company:default_currency', print_hide=1),
|
||||||
dict(fieldname='itc_state_tax', label='Availed ITC State/UT Tax',
|
dict(fieldname='itc_state_tax', label='Availed ITC State/UT Tax',
|
||||||
fieldtype='Data', insert_after='itc_central_tax', print_hide=1),
|
fieldtype='Currency', insert_after='itc_central_tax',
|
||||||
|
options='Company:company:default_currency', print_hide=1),
|
||||||
dict(fieldname='itc_cess_amount', label='Availed ITC Cess',
|
dict(fieldname='itc_cess_amount', label='Availed ITC Cess',
|
||||||
fieldtype='Data', insert_after='itc_state_tax', print_hide=1),
|
fieldtype='Currency', insert_after='itc_state_tax',
|
||||||
|
options='Company:company:default_currency', print_hide=1),
|
||||||
]
|
]
|
||||||
|
|
||||||
sales_invoice_gst_fields = [
|
sales_invoice_gst_fields = [
|
||||||
@@ -236,6 +244,23 @@ def make_custom_fields(update=True):
|
|||||||
depends_on="eval:doc.gst_category=='Overseas' "),
|
depends_on="eval:doc.gst_category=='Overseas' "),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
journal_entry_fields = [
|
||||||
|
dict(fieldname='reversal_type', label='Reversal Type',
|
||||||
|
fieldtype='Select', insert_after='voucher_type', print_hide=1,
|
||||||
|
options="As per rules 42 & 43 of CGST Rules\nOthers",
|
||||||
|
depends_on="eval:doc.voucher_type=='Reversal Of ITC'",
|
||||||
|
mandatory_depends_on="eval:doc.voucher_type=='Reversal Of ITC'"),
|
||||||
|
dict(fieldname='company_address', label='Company Address',
|
||||||
|
fieldtype='Link', options='Address', insert_after='reversal_type',
|
||||||
|
print_hide=1, depends_on="eval:doc.voucher_type=='Reversal Of ITC'",
|
||||||
|
mandatory_depends_on="eval:doc.voucher_type=='Reversal Of ITC'"),
|
||||||
|
dict(fieldname='company_gstin', label='Company GSTIN',
|
||||||
|
fieldtype='Data', read_only=1, insert_after='company_address', print_hide=1,
|
||||||
|
fetch_from='company_address.gstin',
|
||||||
|
depends_on="eval:doc.voucher_type=='Reversal Of ITC'",
|
||||||
|
mandatory_depends_on="eval:doc.voucher_type=='Reversal Of ITC'")
|
||||||
|
]
|
||||||
|
|
||||||
inter_state_gst_field = [
|
inter_state_gst_field = [
|
||||||
dict(fieldname='is_inter_state', label='Is Inter State',
|
dict(fieldname='is_inter_state', label='Is Inter State',
|
||||||
fieldtype='Check', insert_after='disabled', print_hide=1),
|
fieldtype='Check', insert_after='disabled', print_hide=1),
|
||||||
@@ -469,6 +494,7 @@ def make_custom_fields(update=True):
|
|||||||
'Purchase Receipt': purchase_invoice_gst_fields,
|
'Purchase Receipt': purchase_invoice_gst_fields,
|
||||||
'Sales Invoice': sales_invoice_gst_category + invoice_gst_fields + sales_invoice_shipping_fields + sales_invoice_gst_fields + si_ewaybill_fields + si_einvoice_fields,
|
'Sales Invoice': sales_invoice_gst_category + invoice_gst_fields + sales_invoice_shipping_fields + sales_invoice_gst_fields + si_ewaybill_fields + si_einvoice_fields,
|
||||||
'Delivery Note': sales_invoice_gst_fields + ewaybill_fields + sales_invoice_shipping_fields + delivery_note_gst_category,
|
'Delivery Note': sales_invoice_gst_fields + ewaybill_fields + sales_invoice_shipping_fields + delivery_note_gst_category,
|
||||||
|
'Journal Entry': journal_entry_fields,
|
||||||
'Sales Order': sales_invoice_gst_fields,
|
'Sales Order': sales_invoice_gst_fields,
|
||||||
'Tax Category': inter_state_gst_field,
|
'Tax Category': inter_state_gst_field,
|
||||||
'Item': [
|
'Item': [
|
||||||
@@ -486,7 +512,7 @@ def make_custom_fields(update=True):
|
|||||||
'Sales Invoice Item': [hsn_sac_field, nil_rated_exempt, is_non_gst, taxable_value],
|
'Sales Invoice Item': [hsn_sac_field, nil_rated_exempt, is_non_gst, taxable_value],
|
||||||
'Purchase Order Item': [hsn_sac_field, nil_rated_exempt, is_non_gst],
|
'Purchase Order Item': [hsn_sac_field, nil_rated_exempt, is_non_gst],
|
||||||
'Purchase Receipt Item': [hsn_sac_field, nil_rated_exempt, is_non_gst],
|
'Purchase Receipt Item': [hsn_sac_field, nil_rated_exempt, is_non_gst],
|
||||||
'Purchase Invoice Item': [hsn_sac_field, nil_rated_exempt, is_non_gst],
|
'Purchase Invoice Item': [hsn_sac_field, nil_rated_exempt, is_non_gst, taxable_value],
|
||||||
'Material Request Item': [hsn_sac_field, nil_rated_exempt, is_non_gst],
|
'Material Request Item': [hsn_sac_field, nil_rated_exempt, is_non_gst],
|
||||||
'Salary Component': [
|
'Salary Component': [
|
||||||
dict(fieldname= 'component_type',
|
dict(fieldname= 'component_type',
|
||||||
|
|||||||
@@ -204,8 +204,6 @@ def get_regional_address_details(party_details, doctype, company):
|
|||||||
|
|
||||||
if doctype in ("Sales Invoice", "Delivery Note", "Sales Order"):
|
if doctype in ("Sales Invoice", "Delivery Note", "Sales Order"):
|
||||||
master_doctype = "Sales Taxes and Charges Template"
|
master_doctype = "Sales Taxes and Charges Template"
|
||||||
|
|
||||||
get_tax_template_for_sez(party_details, master_doctype, company, 'Customer')
|
|
||||||
get_tax_template_based_on_category(master_doctype, company, party_details)
|
get_tax_template_based_on_category(master_doctype, company, party_details)
|
||||||
|
|
||||||
if party_details.get('taxes_and_charges'):
|
if party_details.get('taxes_and_charges'):
|
||||||
@@ -216,7 +214,6 @@ def get_regional_address_details(party_details, doctype, company):
|
|||||||
|
|
||||||
elif doctype in ("Purchase Invoice", "Purchase Order", "Purchase Receipt"):
|
elif doctype in ("Purchase Invoice", "Purchase Order", "Purchase Receipt"):
|
||||||
master_doctype = "Purchase Taxes and Charges Template"
|
master_doctype = "Purchase Taxes and Charges Template"
|
||||||
get_tax_template_for_sez(party_details, master_doctype, company, 'Supplier')
|
|
||||||
get_tax_template_based_on_category(master_doctype, company, party_details)
|
get_tax_template_based_on_category(master_doctype, company, party_details)
|
||||||
|
|
||||||
if party_details.get('taxes_and_charges'):
|
if party_details.get('taxes_and_charges'):
|
||||||
@@ -283,20 +280,6 @@ def get_tax_template(master_doctype, company, is_inter_state, state_code):
|
|||||||
{'company': company, 'disabled': 0, 'tax_category': tax_category.name}, 'name')
|
{'company': company, 'disabled': 0, 'tax_category': tax_category.name}, 'name')
|
||||||
return default_tax
|
return default_tax
|
||||||
|
|
||||||
def get_tax_template_for_sez(party_details, master_doctype, company, party_type):
|
|
||||||
|
|
||||||
gst_details = frappe.db.get_value(party_type, {'name': party_details.get(frappe.scrub(party_type))},
|
|
||||||
['gst_category', 'export_type'], as_dict=1)
|
|
||||||
|
|
||||||
if gst_details:
|
|
||||||
if gst_details.gst_category == 'SEZ' and gst_details.export_type == 'With Payment of Tax':
|
|
||||||
default_tax = frappe.db.get_value(master_doctype, {"company": company, "is_inter_state":1, "disabled":0,
|
|
||||||
"gst_state": number_state_mapping[party_details.company_gstin[:2]]})
|
|
||||||
|
|
||||||
party_details["taxes_and_charges"] = default_tax
|
|
||||||
party_details.taxes = get_taxes_and_charges(master_doctype, default_tax)
|
|
||||||
|
|
||||||
|
|
||||||
def calculate_annual_eligible_hra_exemption(doc):
|
def calculate_annual_eligible_hra_exemption(doc):
|
||||||
basic_component, hra_component = frappe.db.get_value('Company', doc.company, ["basic_component", "hra_component"])
|
basic_component, hra_component = frappe.db.get_value('Company', doc.company, ["basic_component", "hra_component"])
|
||||||
if not (basic_component and hra_component):
|
if not (basic_component and hra_component):
|
||||||
@@ -697,10 +680,19 @@ def validate_state_code(state_code, address):
|
|||||||
return int(state_code)
|
return int(state_code)
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_gst_accounts(company, account_wise=False):
|
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_accounts = frappe._dict()
|
||||||
gst_settings_accounts = frappe.get_all("GST Account",
|
gst_settings_accounts = frappe.get_all("GST Account",
|
||||||
filters={"parent": "GST Settings", "company": company},
|
filters=filters,
|
||||||
fields=["cgst_account", "sgst_account", "igst_account", "cess_account"])
|
fields=["cgst_account", "sgst_account", "igst_account", "cess_account"])
|
||||||
|
|
||||||
if not gst_settings_accounts and not frappe.flags.in_test:
|
if not gst_settings_accounts and not frappe.flags.in_test:
|
||||||
@@ -715,101 +707,63 @@ def get_gst_accounts(company, account_wise=False):
|
|||||||
|
|
||||||
return gst_accounts
|
return gst_accounts
|
||||||
|
|
||||||
def update_grand_total_for_rcm(doc, method):
|
def validate_reverse_charge_transaction(doc, method):
|
||||||
country = frappe.get_cached_value('Company', doc.company, 'country')
|
country = frappe.get_cached_value('Company', doc.company, 'country')
|
||||||
|
|
||||||
if country != 'India':
|
if country != 'India':
|
||||||
return
|
return
|
||||||
|
|
||||||
gst_tax, base_gst_tax = get_gst_tax_amount(doc)
|
base_gst_tax = 0
|
||||||
|
base_reverse_charge_booked = 0
|
||||||
if not base_gst_tax:
|
|
||||||
return
|
|
||||||
|
|
||||||
if doc.reverse_charge == 'Y':
|
if doc.reverse_charge == 'Y':
|
||||||
doc.taxes_and_charges_added -= gst_tax
|
gst_accounts = get_gst_accounts(doc.company, only_reverse_charge=1)
|
||||||
doc.total_taxes_and_charges -= gst_tax
|
reverse_charge_accounts = gst_accounts.get('cgst_account') + gst_accounts.get('sgst_account') \
|
||||||
doc.base_taxes_and_charges_added -= base_gst_tax
|
+ gst_accounts.get('igst_account')
|
||||||
doc.base_total_taxes_and_charges -= base_gst_tax
|
|
||||||
|
|
||||||
update_totals(gst_tax, base_gst_tax, doc)
|
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') \
|
||||||
def update_totals(gst_tax, base_gst_tax, doc):
|
|
||||||
doc.base_grand_total -= base_gst_tax
|
|
||||||
doc.grand_total -= gst_tax
|
|
||||||
|
|
||||||
if doc.meta.get_field("rounded_total"):
|
|
||||||
if doc.is_rounded_total_disabled():
|
|
||||||
doc.outstanding_amount = doc.grand_total
|
|
||||||
else:
|
|
||||||
doc.rounded_total = round_based_on_smallest_currency_fraction(doc.grand_total,
|
|
||||||
doc.currency, doc.precision("rounded_total"))
|
|
||||||
|
|
||||||
doc.rounding_adjustment += flt(doc.rounded_total - doc.grand_total,
|
|
||||||
doc.precision("rounding_adjustment"))
|
|
||||||
|
|
||||||
doc.outstanding_amount = doc.rounded_total or doc.grand_total
|
|
||||||
|
|
||||||
doc.in_words = money_in_words(doc.grand_total, doc.currency)
|
|
||||||
doc.base_in_words = money_in_words(doc.base_grand_total, erpnext.get_company_currency(doc.company))
|
|
||||||
doc.set_payment_schedule()
|
|
||||||
|
|
||||||
def make_regional_gl_entries(gl_entries, doc):
|
|
||||||
country = frappe.get_cached_value('Company', doc.company, 'country')
|
|
||||||
|
|
||||||
if country != 'India':
|
|
||||||
return gl_entries
|
|
||||||
|
|
||||||
gst_tax, base_gst_tax = get_gst_tax_amount(doc)
|
|
||||||
|
|
||||||
if not base_gst_tax:
|
|
||||||
return gl_entries
|
|
||||||
|
|
||||||
if doc.reverse_charge == 'Y':
|
|
||||||
gst_accounts = get_gst_accounts(doc.company)
|
|
||||||
gst_account_list = gst_accounts.get('cgst_account') + gst_accounts.get('sgst_account') \
|
|
||||||
+ gst_accounts.get('igst_account')
|
+ gst_accounts.get('igst_account')
|
||||||
|
|
||||||
for tax in doc.get('taxes'):
|
for tax in doc.get('taxes'):
|
||||||
if tax.category not in ("Total", "Valuation and Total"):
|
if tax.account_head in non_reverse_charge_accounts:
|
||||||
continue
|
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
|
||||||
|
|
||||||
dr_or_cr = "credit" if tax.add_deduct_tax == "Add" else "debit"
|
if base_gst_tax != base_reverse_charge_booked:
|
||||||
if flt(tax.base_tax_amount_after_discount_amount) and tax.account_head in gst_account_list:
|
msg = _("Booked reverse charge is not equal to applied tax amount")
|
||||||
account_currency = get_account_currency(tax.account_head)
|
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>')
|
||||||
|
|
||||||
gl_entries.append(doc.get_gl_dict(
|
frappe.throw(msg)
|
||||||
{
|
|
||||||
"account": tax.account_head,
|
|
||||||
"cost_center": tax.cost_center,
|
|
||||||
"posting_date": doc.posting_date,
|
|
||||||
"against": doc.supplier,
|
|
||||||
dr_or_cr: tax.base_tax_amount_after_discount_amount,
|
|
||||||
dr_or_cr + "_in_account_currency": tax.base_tax_amount_after_discount_amount \
|
|
||||||
if account_currency==doc.company_currency \
|
|
||||||
else tax.tax_amount_after_discount_amount
|
|
||||||
}, account_currency, item=tax)
|
|
||||||
)
|
|
||||||
|
|
||||||
return gl_entries
|
def update_itc_availed_fields(doc, method):
|
||||||
|
country = frappe.get_cached_value('Company', doc.company, 'country')
|
||||||
|
|
||||||
def get_gst_tax_amount(doc):
|
if country != 'India':
|
||||||
gst_accounts = get_gst_accounts(doc.company)
|
return
|
||||||
gst_account_list = gst_accounts.get('cgst_account', []) + gst_accounts.get('sgst_account', []) \
|
|
||||||
+ gst_accounts.get('igst_account', [])
|
|
||||||
|
|
||||||
base_gst_tax = 0
|
# Initialize values
|
||||||
gst_tax = 0
|
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'):
|
for tax in doc.get('taxes'):
|
||||||
if tax.category not in ("Total", "Valuation and Total"):
|
if tax.account_head in gst_accounts.get('igst_account', []):
|
||||||
continue
|
doc.itc_integrated_tax += flt(tax.base_tax_amount_after_discount_amount)
|
||||||
|
if tax.account_head in gst_accounts.get('sgst_account', []):
|
||||||
if flt(tax.base_tax_amount_after_discount_amount) and tax.account_head in gst_account_list:
|
doc.itc_state_tax += flt(tax.base_tax_amount_after_discount_amount)
|
||||||
base_gst_tax += tax.base_tax_amount_after_discount_amount
|
if tax.account_head in gst_accounts.get('cgst_account', []):
|
||||||
gst_tax += tax.tax_amount_after_discount_amount
|
doc.itc_central_tax += flt(tax.base_tax_amount_after_discount_amount)
|
||||||
|
if tax.account_head in gst_accounts.get('cess_account', []):
|
||||||
return gst_tax, base_gst_tax
|
doc.itc_cess_amount += flt(tax.base_tax_amount_after_discount_amount)
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_regional_round_off_accounts(company, account_list):
|
def get_regional_round_off_accounts(company, account_list):
|
||||||
|
|||||||
@@ -46,7 +46,13 @@ frappe.query_reports["GSTR-1"] = {
|
|||||||
"label": __("Type of Business"),
|
"label": __("Type of Business"),
|
||||||
"fieldtype": "Select",
|
"fieldtype": "Select",
|
||||||
"reqd": 1,
|
"reqd": 1,
|
||||||
"options": ["B2B", "B2C Large", "B2C Small", "CDNR", "EXPORT"],
|
"options": [
|
||||||
|
{ "value": "B2B", "label": __("B2B Invoices - 4A, 4B, 4C, 6B, 6C") },
|
||||||
|
{ "value": "B2C Large", "label": __("B2C(Large) Invoices - 5A, 5B") },
|
||||||
|
{ "value": "B2C Small", "label": __("B2C(Small) Invoices - 7") },
|
||||||
|
{ "value": "CDNR-REG", "label": __("Credit/Debit Notes (Registered) - 9B") },
|
||||||
|
{ "value": "EXPORT", "label": __("Export Invoice - 6A") }
|
||||||
|
],
|
||||||
"default": "B2B"
|
"default": "B2B"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ class Gstr1Report(object):
|
|||||||
reverse_charge,
|
reverse_charge,
|
||||||
return_against,
|
return_against,
|
||||||
is_return,
|
is_return,
|
||||||
|
is_debit_note,
|
||||||
gst_category,
|
gst_category,
|
||||||
export_type,
|
export_type,
|
||||||
port_code,
|
port_code,
|
||||||
@@ -42,7 +43,7 @@ class Gstr1Report(object):
|
|||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
self.get_columns()
|
self.get_columns()
|
||||||
self.gst_accounts = get_gst_accounts(self.filters.company)
|
self.gst_accounts = get_gst_accounts(self.filters.company, only_non_reverse_charge=1)
|
||||||
self.get_invoice_data()
|
self.get_invoice_data()
|
||||||
|
|
||||||
if self.invoices:
|
if self.invoices:
|
||||||
@@ -62,9 +63,9 @@ class Gstr1Report(object):
|
|||||||
for rate, items in items_based_on_rate.items():
|
for rate, items in items_based_on_rate.items():
|
||||||
row, taxable_value = self.get_row_data_for_invoice(inv, invoice_details, rate, items)
|
row, taxable_value = self.get_row_data_for_invoice(inv, invoice_details, rate, items)
|
||||||
|
|
||||||
if self.filters.get("type_of_business") == "CDNR":
|
if self.filters.get("type_of_business") == "CDNR-REG":
|
||||||
row.append("Y" if invoice_details.posting_date <= date(2017, 7, 1) else "N")
|
row.append("Y" if invoice_details.posting_date <= date(2017, 7, 1) else "N")
|
||||||
row.append("C" if invoice_details.return_against else "R")
|
row.append("C" if invoice_details.is_return else "D")
|
||||||
|
|
||||||
if taxable_value:
|
if taxable_value:
|
||||||
self.data.append(row)
|
self.data.append(row)
|
||||||
@@ -105,7 +106,7 @@ class Gstr1Report(object):
|
|||||||
def get_row_data_for_invoice(self, invoice, invoice_details, tax_rate, items):
|
def get_row_data_for_invoice(self, invoice, invoice_details, tax_rate, items):
|
||||||
row = []
|
row = []
|
||||||
for fieldname in self.invoice_fields:
|
for fieldname in self.invoice_fields:
|
||||||
if self.filters.get("type_of_business") == "CDNR" and fieldname == "invoice_value":
|
if self.filters.get("type_of_business") == "CDNR-REG" and fieldname == "invoice_value":
|
||||||
row.append(abs(invoice_details.base_rounded_total) or abs(invoice_details.base_grand_total))
|
row.append(abs(invoice_details.base_rounded_total) or abs(invoice_details.base_grand_total))
|
||||||
elif fieldname == "invoice_value":
|
elif fieldname == "invoice_value":
|
||||||
row.append(invoice_details.base_rounded_total or invoice_details.base_grand_total)
|
row.append(invoice_details.base_rounded_total or invoice_details.base_grand_total)
|
||||||
@@ -171,7 +172,7 @@ class Gstr1Report(object):
|
|||||||
|
|
||||||
|
|
||||||
if self.filters.get("type_of_business") == "B2B":
|
if self.filters.get("type_of_business") == "B2B":
|
||||||
conditions += "and ifnull(gst_category, '') in ('Registered Regular', 'Deemed Export', 'SEZ') and is_return != 1"
|
conditions += "AND IFNULL(gst_category, '') in ('Registered Regular', 'Deemed Export', 'SEZ') AND is_return != 1"
|
||||||
|
|
||||||
if self.filters.get("type_of_business") in ("B2C Large", "B2C Small"):
|
if self.filters.get("type_of_business") in ("B2C Large", "B2C Small"):
|
||||||
b2c_limit = frappe.db.get_single_value('GST Settings', 'b2c_limit')
|
b2c_limit = frappe.db.get_single_value('GST Settings', 'b2c_limit')
|
||||||
@@ -179,19 +180,19 @@ class Gstr1Report(object):
|
|||||||
frappe.throw(_("Please set B2C Limit in GST Settings."))
|
frappe.throw(_("Please set B2C Limit in GST Settings."))
|
||||||
|
|
||||||
if self.filters.get("type_of_business") == "B2C Large":
|
if self.filters.get("type_of_business") == "B2C Large":
|
||||||
conditions += """ and ifnull(SUBSTR(place_of_supply, 1, 2),'') != ifnull(SUBSTR(company_gstin, 1, 2),'')
|
conditions += """ AND ifnull(SUBSTR(place_of_supply, 1, 2),'') != ifnull(SUBSTR(company_gstin, 1, 2),'')
|
||||||
and grand_total > {0} and is_return != 1 and gst_category ='Unregistered' """.format(flt(b2c_limit))
|
AND grand_total > {0} AND is_return != 1 and gst_category ='Unregistered' """.format(flt(b2c_limit))
|
||||||
|
|
||||||
elif self.filters.get("type_of_business") == "B2C Small":
|
elif self.filters.get("type_of_business") == "B2C Small":
|
||||||
conditions += """ and (
|
conditions += """ AND (
|
||||||
SUBSTR(place_of_supply, 1, 2) = SUBSTR(company_gstin, 1, 2)
|
SUBSTR(place_of_supply, 1, 2) = SUBSTR(company_gstin, 1, 2)
|
||||||
or grand_total <= {0}) and is_return != 1 and gst_category ='Unregistered' """.format(flt(b2c_limit))
|
OR grand_total <= {0}) and is_return != 1 AND gst_category ='Unregistered' """.format(flt(b2c_limit))
|
||||||
|
|
||||||
elif self.filters.get("type_of_business") == "CDNR":
|
elif self.filters.get("type_of_business") == "CDNR-REG":
|
||||||
conditions += """ and is_return = 1 """
|
conditions += """ AND (is_return = 1 OR is_debit_note = 1) AND IFNULL(gst_category, '') in ('Registered Regular', 'Deemed Export', 'SEZ')"""
|
||||||
|
|
||||||
elif self.filters.get("type_of_business") == "EXPORT":
|
elif self.filters.get("type_of_business") == "EXPORT":
|
||||||
conditions += """ and is_return !=1 and gst_category = 'Overseas' """
|
conditions += """ AND is_return !=1 and gst_category = 'Overseas' """
|
||||||
return conditions
|
return conditions
|
||||||
|
|
||||||
def get_invoice_items(self):
|
def get_invoice_items(self):
|
||||||
@@ -403,7 +404,7 @@ class Gstr1Report(object):
|
|||||||
"width": 100
|
"width": 100
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
elif self.filters.get("type_of_business") == "CDNR":
|
elif self.filters.get("type_of_business") == "CDNR-REG":
|
||||||
self.invoice_columns = [
|
self.invoice_columns = [
|
||||||
{
|
{
|
||||||
"fieldname": "customer_gstin",
|
"fieldname": "customer_gstin",
|
||||||
@@ -437,6 +438,17 @@ class Gstr1Report(object):
|
|||||||
"options": "Sales Invoice",
|
"options": "Sales Invoice",
|
||||||
"width":120
|
"width":120
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "reverse_charge",
|
||||||
|
"label": "Reverse Charge",
|
||||||
|
"fieldtype": "Data"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "export_type",
|
||||||
|
"label": "Export Type",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"hidden": 1
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "reason_for_issuing_document",
|
"fieldname": "reason_for_issuing_document",
|
||||||
"label": "Reason For Issuing document",
|
"label": "Reason For Issuing document",
|
||||||
@@ -449,6 +461,11 @@ class Gstr1Report(object):
|
|||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"width": 120
|
"width": 120
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "gst_category",
|
||||||
|
"label": "GST Category",
|
||||||
|
"fieldtype": "Data"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "invoice_value",
|
"fieldname": "invoice_value",
|
||||||
"label": "Invoice Value",
|
"label": "Invoice Value",
|
||||||
@@ -458,10 +475,10 @@ class Gstr1Report(object):
|
|||||||
]
|
]
|
||||||
self.other_columns = [
|
self.other_columns = [
|
||||||
{
|
{
|
||||||
"fieldname": "cess_amount",
|
"fieldname": "cess_amount",
|
||||||
"label": "Cess Amount",
|
"label": "Cess Amount",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"width": 100
|
"width": 100
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "pre_gst",
|
"fieldname": "pre_gst",
|
||||||
@@ -589,6 +606,12 @@ def get_json(filters, report_name, data):
|
|||||||
|
|
||||||
out = get_export_json(res)
|
out = get_export_json(res)
|
||||||
gst_json["exp"] = out
|
gst_json["exp"] = out
|
||||||
|
elif filters["type_of_business"] == 'CDNR-REG':
|
||||||
|
for item in report_data[:-1]:
|
||||||
|
res.setdefault(item["customer_gstin"], {}).setdefault(item["invoice_number"],[]).append(item)
|
||||||
|
|
||||||
|
out = get_cdnr_reg_json(res, gstin)
|
||||||
|
gst_json["cdnr"] = out
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'report_name': report_name,
|
'report_name': report_name,
|
||||||
@@ -628,7 +651,6 @@ def get_b2b_json(res, gstin):
|
|||||||
return out
|
return out
|
||||||
|
|
||||||
def get_b2cs_json(data, gstin):
|
def get_b2cs_json(data, gstin):
|
||||||
|
|
||||||
company_state_number = gstin[0:2]
|
company_state_number = gstin[0:2]
|
||||||
|
|
||||||
out = []
|
out = []
|
||||||
@@ -713,6 +735,54 @@ def get_export_json(res):
|
|||||||
|
|
||||||
return out
|
return out
|
||||||
|
|
||||||
|
def get_cdnr_reg_json(res, gstin):
|
||||||
|
out = []
|
||||||
|
|
||||||
|
for gst_in in res:
|
||||||
|
cdnr_item, inv = {"ctin": gst_in, "nt": []}, []
|
||||||
|
if not gst_in: continue
|
||||||
|
|
||||||
|
for number, invoice in iteritems(res[gst_in]):
|
||||||
|
if not invoice[0]["place_of_supply"]:
|
||||||
|
frappe.throw(_("""{0} not entered in Invoice {1}.
|
||||||
|
Please update and try again""").format(frappe.bold("Place Of Supply"),
|
||||||
|
frappe.bold(invoice[0]['invoice_number'])))
|
||||||
|
|
||||||
|
inv_item = {
|
||||||
|
"nt_num": invoice[0]["invoice_number"],
|
||||||
|
"nt_dt": getdate(invoice[0]["posting_date"]).strftime('%d-%m-%Y'),
|
||||||
|
"val": abs(flt(invoice[0]["invoice_value"])),
|
||||||
|
"ntty": invoice[0]["document_type"],
|
||||||
|
"pos": "%02d" % int(invoice[0]["place_of_supply"].split('-')[0]),
|
||||||
|
"rchrg": invoice[0]["reverse_charge"],
|
||||||
|
"inv_type": get_invoice_type_for_cdnr(invoice[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
inv_item["itms"] = []
|
||||||
|
for item in invoice:
|
||||||
|
inv_item["itms"].append(get_rate_and_tax_details(item, gstin))
|
||||||
|
|
||||||
|
inv.append(inv_item)
|
||||||
|
|
||||||
|
if not inv: continue
|
||||||
|
cdnr_item["nt"] = inv
|
||||||
|
out.append(cdnr_item)
|
||||||
|
|
||||||
|
return out
|
||||||
|
|
||||||
|
def get_invoice_type_for_cdnr(row):
|
||||||
|
if row.get('gst_category') == 'SEZ':
|
||||||
|
if row.get('export_type') == 'WPAY':
|
||||||
|
invoice_type = 'SEWP'
|
||||||
|
else:
|
||||||
|
invoice_type = 'SEWOP'
|
||||||
|
elif row.get('gst_category') == 'Deemed Export':
|
||||||
|
row.invoice_type = 'DE'
|
||||||
|
elif row.get('gst_category') == 'Registered Regular':
|
||||||
|
invoice_type = 'R'
|
||||||
|
|
||||||
|
return invoice_type
|
||||||
|
|
||||||
def get_basic_invoice_detail(row):
|
def get_basic_invoice_detail(row):
|
||||||
return {
|
return {
|
||||||
"inum": row["invoice_number"],
|
"inum": row["invoice_number"],
|
||||||
|
|||||||
Reference in New Issue
Block a user