GSTR1 for B2B (#12296)

This commit is contained in:
Nabin Hait 2018-01-10 17:48:03 +05:30 committed by GitHub
parent 0099a09e9b
commit 619c42b934
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 549 additions and 4 deletions

View File

@ -0,0 +1,196 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
"creation": "2018-01-02 15:48:58.768352",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 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": 1,
"in_standard_filter": 0,
"label": "Company",
"length": 0,
"no_copy": 0,
"options": "Company",
"permlevel": 0,
"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,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "cgst_account",
"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": "CGST Account",
"length": 0,
"no_copy": 0,
"options": "Account",
"permlevel": 0,
"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,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "sgst_account",
"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": "SGST Account",
"length": 0,
"no_copy": 0,
"options": "Account",
"permlevel": 0,
"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,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "igst_account",
"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": "IGST Account",
"length": 0,
"no_copy": 0,
"options": "Account",
"permlevel": 0,
"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,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "cess_account",
"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": "CESS Account",
"length": 0,
"no_copy": 0,
"options": "Account",
"permlevel": 0,
"precision": "",
"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,
"unique": 0
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2018-01-02 15:52:22.335988",
"modified_by": "Administrator",
"module": "Accounts",
"name": "GST Account",
"name_case": "",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 0
}

View File

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

View File

@ -1,7 +1,7 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
frappe.query_reports["Item-wise Sales Register"] = frappe.query_reports["Sales Register"] = {
frappe.query_reports["Item-wise Sales Register"] = {
"filters": [
{
"fieldname":"from_date",

View File

@ -203,6 +203,9 @@ doc_events = {
},
'Address': {
'validate': 'erpnext.regional.india.utils.validate_gstin_for_india'
},
'Sales Invoice': {
'validate': 'erpnext.regional.india.utils.set_place_of_supply'
}
}

View File

@ -42,6 +42,35 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_2",
"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,
"precision": "",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@ -71,6 +100,66 @@
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "section_break_4",
"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,
"precision": "",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "gst_accounts",
"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": "GST Accounts",
"length": 0,
"no_copy": 0,
"options": "GST Account",
"permlevel": 0,
"precision": "",
"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,
"unique": 0
}
],
"has_web_view": 0,
@ -83,7 +172,7 @@
"issingle": 1,
"istable": 0,
"max_attachments": 0,
"modified": "2017-09-29 14:39:15.625952",
"modified": "2018-01-02 15:53:13.489144",
"modified_by": "Administrator",
"module": "Regional",
"name": "GST Settings",

View File

@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
import frappe
import unittest
class TestGSTSettings(unittest.TestCase):
pass

View File

@ -123,8 +123,8 @@ def make_custom_fields():
fieldtype='Data', insert_after='shipping_address',
options='shipping_address_name.gstin', print_hide=1),
dict(fieldname='place_of_supply', label='Place of Supply',
fieldtype='Data', insert_after='customer_gstin', print_hide=1,
options='shipping_address_name.gst_state_number', read_only=0),
fieldtype='Data', insert_after='customer_gstin',
print_hide=1, read_only=0),
dict(fieldname='company_gstin', label='Company GSTIN',
fieldtype='Data', insert_after='company_address',
options='company_address.gstin', print_hide=1)

View File

@ -60,6 +60,14 @@ def get_itemised_tax_breakup_data(doc):
return hsn_tax, hsn_taxable_amount
def set_place_of_supply(doc, method):
if not hasattr(doc, 'customer_gstin'):
return
address_name = doc.shipping_address_name or doc.customer_address
address = frappe.db.get_value("Address", address_name, ["gst_state", "gst_state_number"], as_dict=1)
doc.place_of_supply = address.gst_state_number + "-" + address.gst_state
# don't remove this function it is used in tests
def test_method():
'''test function'''

View File

@ -0,0 +1,38 @@
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
frappe.query_reports["GSTR-1"] = {
"filters": [
{
"fieldname":"company",
"label": __("Company"),
"fieldtype": "Link",
"options": "Company",
"reqd": 1,
"default": frappe.defaults.get_user_default("Company")
},
{
"fieldname":"from_date",
"label": __("From Date"),
"fieldtype": "Date",
"reqd": 1,
"default": frappe.datetime.add_months(frappe.datetime.get_today(), -3),
"width": "80"
},
{
"fieldname":"to_date",
"label": __("To Date"),
"fieldtype": "Date",
"reqd": 1,
"default": frappe.datetime.get_today()
},
{
"fieldname":"type_of_business",
"label": __("Type of Business"),
"fieldtype": "Select",
"reqd": 1,
"options": ["B2B", "B2C Large", "B2C Small"],
"default": "B2B"
}
]
}

View File

@ -0,0 +1,30 @@
{
"add_total_row": 0,
"apply_user_permissions": 1,
"creation": "2018-01-02 15:54:41.424225",
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"idx": 0,
"is_standard": "Yes",
"letter_head": "test",
"modified": "2018-01-02 17:56:15.379347",
"modified_by": "Administrator",
"module": "Regional",
"name": "GSTR-1",
"owner": "Administrator",
"ref_doctype": "GL Entry",
"report_name": "GSTR-1",
"report_type": "Script Report",
"roles": [
{
"role": "Accounts User"
},
{
"role": "Accounts Manager"
},
{
"role": "Auditor"
}
]
}

View File

@ -0,0 +1,161 @@
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe, json
from frappe import _
def execute(filters=None):
columns, data = get_columns(filters), get_data(filters)
return columns, data
def get_columns(filters):
return [
"GSTIN/UIN of Recipient::150",
"Receiver Name::120",
"Invoice Number:Link/Sales Invoice:120",
"Invoice date:Date:120",
"Invoice Value:Currency:120",
"Place of Supply::120",
"Reverse Charge::120",
"Invoice Type::120",
"E-Commerce GSTIN::120",
"Rate:Int:80",
"Taxable Value:Currency:120",
"Cess Amount:Currency:120"
]
def get_data(filters):
gst_accounts = get_gst_accounts(filters)
invoices = get_invoice_data(filters)
invoice_items = get_invoice_items(invoices)
items_based_on_tax_rate, invoice_cess = get_items_based_on_tax_rate(invoices.keys(), gst_accounts)
data = []
for inv, items_based_on_rate in items_based_on_tax_rate.items():
invoice_details = invoices.get(inv)
for rate, items in items_based_on_rate.items():
row = [
invoice_details.customer_gstin,
invoice_details.customer_name,
inv,
invoice_details.posting_date,
invoice_details.base_rounded_total or invoice_details.base_grand_total,
invoice_details.place_of_supply,
invoice_details.reverse_charge,
invoice_details.invoice_type,
invoice_details.ecommerce_gstin,
rate,
sum([net_amount for item_code, net_amount in invoice_items.get(inv).items()
if item_code in items]),
invoice_cess.get(inv)
]
data.append(row)
return data
def get_gst_accounts(filters):
gst_accounts = frappe._dict()
gst_settings_accounts = frappe.get_list("GST Account",
filters={"parent": "GST Settings", "company": filters.company},
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():
gst_accounts.setdefault(acc, []).append(val)
return gst_accounts
def get_invoice_data(filters):
invoices = frappe._dict()
conditions = get_conditions(filters)
match_conditions = frappe.build_match_conditions("Sales Invoice")
if match_conditions:
match_conditions = " and {0} ".format(match_conditions)
invoice_data = frappe.db.sql("""
select
`tabSales Invoice`.name,
`tabSales Invoice`.customer_name,
`tabSales Invoice`.posting_date,
`tabSales Invoice`.base_grand_total,
`tabSales Invoice`.base_rounded_total,
`tabSales Invoice`.customer_gstin,
`tabSales Invoice`.place_of_supply,
`tabSales Invoice`.ecommerce_gstin,
`tabSales Invoice`.reverse_charge,
`tabSales Invoice`.invoice_type
from `tabSales Invoice`
where `tabSales Invoice`.docstatus = 1 %s %s
order by `tabSales Invoice`.posting_date desc
""" % (conditions, match_conditions), filters, as_dict=1)
for d in invoice_data:
invoices.setdefault(d.name, d)
return invoices
def get_conditions(filters):
conditions = ""
for opts in (("company", " and company=%(company)s"),
("from_date", " and `tabSales Invoice`.posting_date>=%(from_date)s"),
("to_date", " and `tabSales Invoice`.posting_date<=%(to_date)s")):
if filters.get(opts[0]):
conditions += opts[1]
return conditions
def get_invoice_items(invoices):
invoice_items = frappe._dict()
items = frappe.db.sql("""
select item_code, parent, base_net_amount
from `tabSales Invoice Item`
where parent in (%s)
""" % (', '.join(['%s']*len(invoices))), tuple(invoices), as_dict=1)
for d in items:
invoice_items.setdefault(d.parent, {}).setdefault(d.item_code, d.base_net_amount)
return invoice_items
def get_items_based_on_tax_rate(invoices, gst_accounts):
tax_details = frappe.db.sql("""
select
parent, account_head, item_wise_tax_detail, base_tax_amount_after_discount_amount
from `tabSales Taxes and Charges`
where
parenttype = 'Sales Invoice' and docstatus = 1
and parent in (%s)
and tax_amount_after_discount_amount > 0
order by account_head
""" % (', '.join(['%s']*len(invoices))), tuple(invoices))
items_based_on_tax_rate = {}
invoice_cess = frappe._dict()
for parent, account, item_wise_tax_detail, tax_amount in tax_details:
if account in gst_accounts.cess_account:
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 gst_accounts.cgst_account or account in gst_accounts.sgst_account:
cgst_or_sgst = True
for item_code, tax_amounts in item_wise_tax_detail.items():
tax_rate = tax_amounts[0]
if cgst_or_sgst:
tax_rate *= 2
rate_based_dict = 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
return items_based_on_tax_rate, invoice_cess

View File