GSTR1 for B2B (#12296)

diff --git a/erpnext/accounts/doctype/gst_account/__init__.py b/erpnext/accounts/doctype/gst_account/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/accounts/doctype/gst_account/__init__.py
diff --git a/erpnext/accounts/doctype/gst_account/gst_account.json b/erpnext/accounts/doctype/gst_account/gst_account.json
new file mode 100644
index 0000000..7067338
--- /dev/null
+++ b/erpnext/accounts/doctype/gst_account/gst_account.json
@@ -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
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/gst_account/gst_account.py b/erpnext/accounts/doctype/gst_account/gst_account.py
new file mode 100644
index 0000000..d784849
--- /dev/null
+++ b/erpnext/accounts/doctype/gst_account/gst_account.py
@@ -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
diff --git a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.js b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.js
index b57a7fc..6a8cc6a 100644
--- a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.js
+++ b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.js
@@ -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",
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index 6265e1a..ebc1921 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -203,6 +203,9 @@
 	},
 	'Address': {
 		'validate': 'erpnext.regional.india.utils.validate_gstin_for_india'
+	},
+	'Sales Invoice': {
+		'validate': 'erpnext.regional.india.utils.set_place_of_supply'
 	}
 }
 
diff --git a/erpnext/regional/doctype/gst_settings/gst_settings.json b/erpnext/regional/doctype/gst_settings/gst_settings.json
index 67084b4..ebd0865 100644
--- a/erpnext/regional/doctype/gst_settings/gst_settings.json
+++ b/erpnext/regional/doctype/gst_settings/gst_settings.json
@@ -48,6 +48,35 @@
    "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, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
    "fieldname": "gstin_email_sent_on", 
    "fieldtype": "Date", 
    "hidden": 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", 
diff --git a/erpnext/regional/doctype/gst_settings/test_gst_settings.py b/erpnext/regional/doctype/gst_settings/test_gst_settings.py
new file mode 100644
index 0000000..d118dee
--- /dev/null
+++ b/erpnext/regional/doctype/gst_settings/test_gst_settings.py
@@ -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
diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py
index 4ef9b11..7143bd3 100644
--- a/erpnext/regional/india/setup.py
+++ b/erpnext/regional/india/setup.py
@@ -123,8 +123,8 @@
 				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)
diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py
index 2cd71a5..10a9c97 100644
--- a/erpnext/regional/india/utils.py
+++ b/erpnext/regional/india/utils.py
@@ -60,6 +60,14 @@
 
 	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'''
diff --git a/erpnext/regional/report/gstr_1/__init__.py b/erpnext/regional/report/gstr_1/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/regional/report/gstr_1/__init__.py
diff --git a/erpnext/regional/report/gstr_1/gstr_1.js b/erpnext/regional/report/gstr_1/gstr_1.js
new file mode 100644
index 0000000..9437786
--- /dev/null
+++ b/erpnext/regional/report/gstr_1/gstr_1.js
@@ -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"
+		}
+	]
+}
diff --git a/erpnext/regional/report/gstr_1/gstr_1.json b/erpnext/regional/report/gstr_1/gstr_1.json
new file mode 100644
index 0000000..a71d89e
--- /dev/null
+++ b/erpnext/regional/report/gstr_1/gstr_1.json
@@ -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"
+  }
+ ]
+}
\ No newline at end of file
diff --git a/erpnext/regional/report/gstr_1/gstr_1.py b/erpnext/regional/report/gstr_1/gstr_1.py
new file mode 100644
index 0000000..6dd872a
--- /dev/null
+++ b/erpnext/regional/report/gstr_1/gstr_1.py
@@ -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
\ No newline at end of file
diff --git a/erpnext/regional/report/gstr_1/utils.py b/erpnext/regional/report/gstr_1/utils.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/regional/report/gstr_1/utils.py