2018-01-10 17:48:03 +05:30

161 lines
4.9 KiB
Python

# 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