fix: Cleanup and fixes in GSTR3B report

This commit is contained in:
Deepesh Garg
2021-04-18 13:30:15 +05:30
parent c7349145c5
commit 5b9e0b5b57
3 changed files with 65 additions and 92 deletions

View File

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

View File

@@ -13,11 +13,9 @@ from erpnext.regional.india import state_numbers
class GSTR3BReport(Document): class GSTR3BReport(Document):
def before_save(self): def before_save(self):
self.get_data() self.get_data()
def get_data(self): def get_data(self):
self.report_dict = { self.report_dict = {
"gstin": "", "gstin": "",
"ret_period": "", "ret_period": "",
@@ -179,8 +177,7 @@ 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', 'ISRC': 'ITC on Reverse Charge',
@@ -188,53 +185,35 @@ class GSTR3BReport(Document):
'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 = ['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 prepare_data(self, doctype, tax_details, supply_type, supply_category, gst_category_list, reverse_charge="N"):
account_map = {
'sgst_account': 'samt',
'cess_account': 'csamt',
'cgst_account': 'camt',
'igst_account': 'iamt'
}
txval = 0 txval = 0
total_taxable_value = self.get_total_taxable_value(doctype, reverse_charge) total_taxable_value = self.get_total_taxable_value(doctype, reverse_charge)
for gst_category in gst_category_list: for gst_category in gst_category_list:
txval += total_taxable_value.get(gst_category,0) txval += total_taxable_value.get(gst_category,0)
for account_head in self.account_heads: for key in ['camt', 'samt', 'iamt', 'csamt']:
for account_type, account_name in iteritems(account_head): for account_head in self.account_heads.get(key):
if account_map.get(account_type) in self.report_dict.get(supply_type).get(supply_category): if key in self.report_dict.get(supply_type).get(supply_category):
self.report_dict[supply_type][supply_category][account_map.get(account_type)] += \ self.report_dict[supply_type][supply_category][key] += \
flt(tax_details.get((account_name, gst_category), {}).get("amount"), 2) flt(tax_details.get((account_head, gst_category), {}).get("amount"), 2)
self.report_dict[supply_type][supply_category]["txval"] += flt(txval, 2) self.report_dict[supply_type][supply_category]["txval"] += flt(txval, 2)
@@ -263,23 +242,20 @@ class GSTR3BReport(Document):
group by ja.account, j.reversal_type""", (self.month_no, self.year, self.company, group by ja.account, j.reversal_type""", (self.month_no, self.year, self.company,
self.gst_details.get("gstin")), as_dict=1) self.gst_details.get("gstin")), as_dict=1)
net_itc = self.report_dict["itc_elg"]["itc_net"]
for entry in reversal_entries: for entry in reversal_entries:
if entry.reversal_type == 'As per rules 42 & 43 of CGST Rules': if entry.reversal_type == 'As per rules 42 & 43 of CGST Rules':
index = 0 index = 0
else: else:
index = 1 index = 1
if entry.account in [a.cgst_account for a in self.account_heads]: for key in ['camt', 'samt', 'iamt', 'csamt']:
self.report_dict["itc_elg"]["itc_rev"][index]["camt"] += flt(entry.amount) if entry.account in self.account_heads.get(key):
if entry.account in [a.sgst_account for a in self.account_heads]: self.report_dict["itc_elg"]["itc_rev"][index][key] += flt(entry.amount)
self.report_dict["itc_elg"]["itc_rev"][index]["samt"] += flt(entry.amount) net_itc[key] -= flt(entry.amount)
if entry.account in [a.igst_account for a in self.account_heads]:
self.report_dict["itc_elg"]["itc_rev"][index]["iamt"] += flt(entry.amount)
if entry.account in [a.cess_account for a in self.account_heads]:
self.report_dict["itc_elg"]["itc_rev"][index]["csamt"] += flt(entry.amount)
def get_total_taxable_value(self, doctype, reverse_charge): def get_total_taxable_value(self, doctype, reverse_charge):
return frappe._dict(frappe.db.sql(""" return frappe._dict(frappe.db.sql("""
select gst_category, sum(net_total) as total select gst_category, sum(net_total) as total
from `tab{doctype}` from `tab{doctype}`
@@ -291,28 +267,30 @@ class GSTR3BReport(Document):
.format(doctype = doctype), (self.month_no, self.year, reverse_charge, self.company, self.gst_details.get("gstin")))) .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 month(posting_date) = %s and year(posting_date) = %s and company = %s
""", and company_gstin = %s
(self.month_no, self.year, self.company, self.gst_details.get("gstin")), as_dict=1) group by eligibility_for_itc
""", (self.month_no, self.year, self.company, self.gst_details.get("gstin")), as_dict=1, debug=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): def get_nil_rated_supply_value(self):
return frappe.db.sql(""" return frappe.db.sql("""
select sum(i.base_amount) as total from select sum(i.base_amount) as total from
`tabSales Invoice Item` i, `tabSales Invoice` s `tabSales Invoice Item` i, `tabSales Invoice` s
@@ -342,17 +320,9 @@ class GSTR3BReport(Document):
'csamt': 0.0 'csamt': 0.0
}) })
if d.account_head in [a.cgst_account for a in self.account_heads]: for key in ['camt', 'samt', 'iamt', 'csamt']:
inter_state_supply_tax_mapping[d.name]['camt'] += d.tax_amount if d.account_head in self.account_heads.get(key):
inter_state_supply_tax_mapping[d.name][key] += 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): for key, value in iteritems(inter_state_supply_tax_mapping):
if value.get('place_of_supply'): if value.get('place_of_supply'):
@@ -408,7 +378,6 @@ class GSTR3BReport(Document):
return inward_nil_exempt_details return inward_nil_exempt_details
def get_tax_amounts(self, doctype, reverse_charge="N"): def get_tax_amounts(self, doctype, reverse_charge="N"):
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":
@@ -429,7 +398,7 @@ class GSTR3BReport(Document):
for d in tax_amounts: for d in tax_amounts:
tax_details.setdefault( tax_details.setdefault(
(d.account_head,d.gst_category),{ (d.account_head, d.gst_category),{
"amount": d.get("tax_amount"), "amount": d.get("tax_amount"),
} }
) )
@@ -437,7 +406,6 @@ class GSTR3BReport(Document):
return tax_details return tax_details
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={
@@ -450,20 +418,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"]:
@@ -488,13 +464,11 @@ class GSTR3BReport(Document):
return ",".join(missing_field_invoices) return ",".join(missing_field_invoices)
def get_state_code(state): 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,
@@ -518,13 +492,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

View File

@@ -190,7 +190,8 @@ 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\nITC on Reverse Charge\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='Data', insert_after='eligibility_for_itc', print_hide=1),
dict(fieldname='itc_central_tax', label='Availed ITC Central Tax', dict(fieldname='itc_central_tax', label='Availed ITC Central Tax',