Skip to content

Commit

Permalink
feat: accounting automations for ineligible ITC (#1168)
Browse files Browse the repository at this point in the history
  • Loading branch information
vorasmit authored Oct 26, 2023
1 parent dbb5444 commit 212f179
Show file tree
Hide file tree
Showing 23 changed files with 1,825 additions and 69 deletions.
62 changes: 53 additions & 9 deletions india_compliance/gst_india/constants/custom_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,13 @@
"options": "Account",
"insert_after": "default_finance_book",
},
{
"fieldname": "default_gst_expense_account",
"label": "Default GST Expense Account",
"fieldtype": "Link",
"options": "Account",
"insert_after": "default_customs_expense_account",
},
],
("Customer", "Supplier"): party_fields,
# Purchase Fields
Expand Down Expand Up @@ -308,6 +315,7 @@
"Sales Invoice Item",
"POS Invoice Item",
"Purchase Invoice Item",
"Purchase Receipt Item",
): [
{
"fieldname": "taxable_value",
Expand All @@ -320,6 +328,22 @@
"no_copy": 1,
},
],
(
"Supplier Quotation Item",
"Purchase Order Item",
"Purchase Receipt Item",
"Purchase Invoice Item",
): [
{
"fieldname": "is_ineligible_for_itc",
"label": "Is Ineligible for Input Tax Credit",
"fieldtype": "Check",
"fetch_from": "item_code.is_ineligible_for_itc",
"insert_after": "is_nil_exempt",
"fetch_if_empty": 1,
"print_hide": 1,
},
],
"Sales Invoice": [
{
"fieldname": "port_address",
Expand Down Expand Up @@ -377,24 +401,34 @@
"collapsible": 1,
},
{
"fieldname": "eligibility_for_itc",
"label": "Eligibility For ITC",
"fieldname": "itc_classification",
"label": "ITC Classification",
"fieldtype": "Select",
"insert_after": "gst_section",
"print_hide": 1,
"options": (
"Input Service Distributor\nImport Of Service\nImport Of"
" Goods\nITC on Reverse Charge\nIneligible As Per Section"
" 17(5)\nIneligible Others\nAll Other ITC"
" Goods\nITC on Reverse Charge\nAll Other ITC"
),
"default": "All Other ITC",
"translatable": 0,
},
{
"fieldname": "ineligibility_reason",
"label": "Reason for Ineligibility",
"fieldtype": "Select",
"insert_after": "itc_classification",
"options": (
"\nIneligible As Per Section 17(5)\nITC restricted due to PoS rules"
),
"read_only": 1,
"print_hide": 1,
},
{
"fieldname": "reconciliation_status",
"label": "Reconciliation Status",
"fieldtype": "Select",
"insert_after": "eligibility_for_itc",
"insert_after": "ineligibility_reason",
"print_hide": 1,
"options": ("\nNot Applicable\nReconciled\nUnreconciled\nIgnored"),
"no_copy": 1,
Expand All @@ -407,26 +441,29 @@
},
{
"fieldname": "itc_integrated_tax",
"label": "Availed ITC Integrated Tax",
"label": "Integrated Tax",
"fieldtype": "Currency",
"insert_after": "gst_col_break",
"options": "Company:company:default_currency",
"read_only": 1,
"print_hide": 1,
},
{
"fieldname": "itc_central_tax",
"label": "Availed ITC Central Tax",
"label": "Central Tax",
"fieldtype": "Currency",
"insert_after": "itc_integrated_tax",
"options": "Company:company:default_currency",
"read_only": 1,
"print_hide": 1,
},
{
"fieldname": "itc_state_tax",
"label": "Availed ITC State/UT Tax",
"label": "State/UT Tax",
"fieldtype": "Currency",
"insert_after": "itc_central_tax",
"options": "Company:company:default_currency",
"read_only": 1,
"print_hide": 1,
},
{
Expand All @@ -435,6 +472,7 @@
"fieldtype": "Currency",
"insert_after": "itc_state_tax",
"options": "Company:company:default_currency",
"read_only": 1,
"print_hide": 1,
},
],
Expand Down Expand Up @@ -584,7 +622,7 @@
],
"Journal Entry": [
{
"fieldname": "reversal_type",
"fieldname": "ineligibility_reason",
"label": "Reversal Type",
"fieldtype": "Select",
"insert_after": "voucher_type",
Expand Down Expand Up @@ -647,6 +685,12 @@
"fieldtype": "Check",
"insert_after": "is_nil_exempt",
},
{
"fieldname": "is_ineligible_for_itc",
"label": "Is Ineligible for Input Tax Credit",
"fieldtype": "Check",
"insert_after": "item_tax_section_break",
},
],
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,14 @@ frappe.ui.form.on("Bill of Entry", {
);
}

if (frm.doc.docstatus === 1 && frm.doc.total_customs_duty > 0) {
const has_ineligible_items = frm.doc.items.some(
item => item.is_ineligible_for_itc
);

if (
(frm.doc.docstatus === 1 && frm.doc.total_customs_duty > 0) ||
has_ineligible_items
) {
frm.add_custom_button(
__("Landed Cost Voucher"),
() => {
Expand Down
47 changes: 44 additions & 3 deletions india_compliance/gst_india/doctype/bill_of_entry/bill_of_entry.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,15 @@
from frappe.model.mapper import get_mapped_doc
from frappe.utils import today
import erpnext
from erpnext.accounts.general_ledger import make_gl_entries
from erpnext.accounts.general_ledger import make_gl_entries, make_reverse_gl_entries
from erpnext.controllers.accounts_controller import AccountsController
from erpnext.controllers.taxes_and_totals import get_round_off_applicable_accounts

from india_compliance.gst_india.overrides.ineligible_itc import (
update_landed_cost_voucher_for_gst_expense,
update_regional_gl_entries,
update_valuation_rate,
)
from india_compliance.gst_india.utils import get_gst_accounts_by_type


Expand Down Expand Up @@ -45,13 +50,16 @@ def validate(self):
self.validate_purchase_invoice()
self.validate_taxes()
self.reconciliation_status = "Unreconciled"
update_valuation_rate(self)

def on_submit(self):
make_gl_entries(self.get_gl_entries())
gl_entries = self.get_gl_entries()
update_regional_gl_entries(gl_entries, self)
make_gl_entries(gl_entries)

def on_cancel(self):
self.ignore_linked_doctypes = ("GL Entry",)
make_gl_entries(self.get_gl_entries(), cancel=True)
make_reverse_gl_entries(voucher_type=self.doctype, voucher_no=self.name)

# Code adapted from AccountsController.on_trash
def on_trash(self):
Expand Down Expand Up @@ -305,6 +313,32 @@ def get_rows_to_update(self, item_name=None, tax_name=None):

return items, taxes

def get_stock_items(self):
stock_items = []
item_codes = list(set(item.item_code for item in self.get("items")))
if item_codes:
stock_items = frappe.db.get_values(
"Item",
{"name": ["in", item_codes], "is_stock_item": 1},
pluck="name",
cache=True,
)

return stock_items

def get_asset_items(self):
asset_items = []
item_codes = list(set(item.item_code for item in self.get("items")))
if item_codes:
asset_items = frappe.db.get_values(
"Item",
{"name": ["in", item_codes], "is_fixed_asset": 1},
pluck="name",
cache=True,
)

return asset_items


@frappe.whitelist()
def make_bill_of_entry(source_name, target_doc=None):
Expand Down Expand Up @@ -454,6 +488,7 @@ def set_missing_values(source, target):
for item in target.items:
item.applicable_charges = items[item.purchase_receipt_item].customs_duty
total_customs_duty += item.applicable_charges
item.boe_detail = items[item.purchase_receipt_item].boe_detail

# add taxes
target.append(
Expand All @@ -473,6 +508,8 @@ def set_missing_values(source, target):
)
)

update_landed_cost_voucher_for_gst_expense(source, target)

doc = get_mapped_doc(
"Bill of Entry",
source_name,
Expand Down Expand Up @@ -503,6 +540,7 @@ def get_items_for_landed_cost_voucher(boe):
"""
pi = frappe.get_doc("Purchase Invoice", boe.purchase_invoice)
item_customs_map = {item.pi_detail: item.customs_duty for item in boe.items}
item_name_map = {item.pi_detail: item.name for item in boe.items}

def _item_dict(items):
return frappe._dict({item.name: item for item in items})
Expand All @@ -512,6 +550,7 @@ def _item_dict(items):
pi_items = [pi_item.as_dict() for pi_item in pi.items]
for pi_item in pi_items:
pi_item.customs_duty = item_customs_map.get(pi_item.name)
pi_item.boe_detail = item_name_map.get(pi_item.name)

return _item_dict(pi_items)

Expand All @@ -526,6 +565,7 @@ def _item_dict(items):

for pr_item in pr_items:
pr_item.customs_duty = item_customs_map.get(pr_pi_map.get(pr_item.name))
pr_item.boe_detail = item_name_map.get(pr_pi_map.get(pr_item.name))

return _item_dict(pr_items)

Expand All @@ -542,5 +582,6 @@ def _item_dict(items):
customs_duty_for_item = item_customs_map.get(pr_item.purchase_invoice_item)
total_qty = item_qty_map.get(pr_item.purchase_invoice_item)
pr_item.customs_duty = customs_duty_for_item * pr_item.qty / total_qty
pr_item.boe_detail = item_name_map.get(pr_item.purchase_invoice_item)

return _item_dict(pr_items)
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"column_break_ifxl",
"taxable_value",
"item_tax_template",
"is_ineligible_for_itc",
"accounting_dimensions_section",
"cost_center",
"dimension_col_break",
Expand Down Expand Up @@ -106,12 +107,21 @@
"fieldtype": "Link",
"label": "Project",
"options": "Project"
},
{
"default": "0",
"fetch_from": "item_code.is_ineligible_for_itc",
"fetch_if_empty": 1,
"fieldname": "is_ineligible_for_itc",
"fieldtype": "Check",
"label": "Is Ineligible for Input Tax Credit",
"print_hide": 1
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2023-03-13 14:26:53.580618",
"modified": "2023-10-20 12:24:27.373448",
"modified_by": "Administrator",
"module": "GST India",
"name": "Bill of Entry Item",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ <h5>4. &nbsp {{__("Eligible ITC")}}</h5>
<td></td>
</tr>
<tr>
<td>&nbsp (1) {{__("As per rules 42 & 43 of CGST Rules")}}</td>
<td>&nbsp (1) {{__("As per rules 42 & 43 of CGST Rules and section 17(5)")}}</td>
<td class="right">{{ flt(data.itc_elg.itc_rev[0].iamt, 2) }}</td>
<td class="right">{{ flt(data.itc_elg.itc_rev[0].camt, 2) }}</td>
<td class="right">{{ flt(data.itc_elg.itc_rev[0].samt, 2) }}</td>
Expand Down Expand Up @@ -249,14 +249,14 @@ <h5>4. &nbsp {{__("Eligible ITC")}}</h5>
<td></td>
</tr>
<tr>
<td>&nbsp (1) {{__("As per section 17(5)")}}</td>
<td>&nbsp (1) {{__("ITC reclaimed which was reversed under Table 4(B)(2) in earlier tax period")}}</td>
<td class="right">{{ flt(data.itc_elg.itc_inelg[0].iamt, 2) }}</td>
<td class="right">{{ flt(data.itc_elg.itc_inelg[0].camt, 2) }}</td>
<td class="right">{{ flt(data.itc_elg.itc_inelg[0].samt, 2) }}</td>
<td class="right">{{ flt(data.itc_elg.itc_inelg[0].csamt, 2) }}</td>
</tr>
<tr>
<td>&nbsp (2) {{__("Others")}}</td>
<td>&nbsp (2) {{__("Ineligible ITC under section 16(4) & ITC restricted due to PoS rules")}}</td>
<td class="right">{{ flt(data.itc_elg.itc_inelg[1].iamt, 2) }}</td>
<td class="right">{{ flt(data.itc_elg.itc_inelg[1].camt, 2) }}</td>
<td class="right">{{ flt(data.itc_elg.itc_inelg[1].samt, 2) }}</td>
Expand Down
Loading

0 comments on commit 212f179

Please sign in to comment.