Skip to content

Commit

Permalink
Merge pull request #1950 from resilient-tech/version-14-hotfix
Browse files Browse the repository at this point in the history
chore: release v14
  • Loading branch information
mergify[bot] authored Mar 29, 2024
2 parents 9ae772e + 9346db7 commit 17cf5dc
Show file tree
Hide file tree
Showing 16 changed files with 1,179 additions and 57 deletions.
2 changes: 1 addition & 1 deletion india_compliance/gst_india/api_classes/returns.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ def decrypt_response(self, response):
)

# cache of parent doctype GST Settings is not cleared by default so clear it manually
frappe.clear_document_cache("GST Settings")
frappe.clear_document_cache("GST Settings", "GST Settings")

return response

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,9 @@ def set_outward_taxable_supplies(self):
place_of_supply = (
invoice_details.get("place_of_supply") or "00-Other Territory"
)
is_overseas_invoice = is_overseas_transaction(
"Sales Invoice", gst_category, place_of_supply
)

for rate, items in items_based_on_rate.items():
for item_code, taxable_value in self.invoice_items.get(inv).items():
Expand All @@ -476,15 +479,14 @@ def set_outward_taxable_supplies(self):
self.report_dict["sup_details"]["osup_nongst"][
"txval"
] += taxable_value
elif rate == 0 or (
is_overseas_transaction(
"Sales Invoice", gst_category, place_of_supply
)
and not invoice_details.get("is_export_with_gst")
):
elif rate == 0 or (is_overseas_invoice):
self.report_dict["sup_details"]["osup_zero"][
"txval"
] += taxable_value

self.report_dict["sup_details"]["osup_zero"]["iamt"] += flt(
taxable_value * rate / 100, 2
)
else:
if inv in self.cgst_sgst_invoices:
tax_rate = rate / 2
Expand Down Expand Up @@ -531,7 +533,10 @@ def set_outward_taxable_supplies(self):
]["iamt"] += flt(taxable_value * rate / 100, 2)

if self.invoice_cess.get(inv):
self.report_dict["sup_details"]["osup_det"]["csamt"] += flt(

invoice_category = "osup_zero" if is_overseas_invoice else "osup_det"

self.report_dict["sup_details"][invoice_category]["csamt"] += flt(
self.invoice_cess.get(inv), 2
)

Expand Down
5 changes: 4 additions & 1 deletion india_compliance/gst_india/overrides/ineligible_itc.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,10 @@ def reverse_stock_adjustment_entry(self, item):
This method reverses the Stock Adjustment Entry
"""
stock_account = self.get_item_expense_account(item)
cogs_account = self.company.default_expense_account
cogs_account = (
self.company.default_expense_account
or self.company.stock_received_but_not_billed
)

ineligible_item_tax_amount = item.get("_ineligible_tax_amount", 0)

Expand Down
3 changes: 2 additions & 1 deletion india_compliance/gst_india/overrides/item_tax_template.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import frappe
from frappe import _
from frappe.utils import rounded
from frappe.utils import flt, rounded

from india_compliance.gst_india.overrides.transaction import get_valid_accounts


def validate(doc, method=None):
doc.gst_rate = flt(doc.gst_rate)
validate_zero_tax_options(doc)
validate_tax_rates(doc)

Expand Down
23 changes: 22 additions & 1 deletion india_compliance/gst_india/overrides/test_transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,10 +216,11 @@ def test_missing_hsn_code(self):
"item_code": "_Test Item Without HSN",
"item_name": "_Test Item Without HSN",
"valuation_rate": 100,
"is_sales_item": 0,
},
)
item_without_hsn.flags.ignore_validate = True
item_without_hsn.insert()
item_without_hsn.db_set("is_sales_item", 1)

# create transaction
doc = create_transaction(
Expand Down Expand Up @@ -792,6 +793,26 @@ def test_invalid_row_id_for_taxes(self):
doc.insert,
)

def test_onload_for_non_gst_document(self):
"""
For gst_breakup we are checking for "ignore_gst_validations".
It should return silently for invalid docs.
"""
doc = create_transaction(**self.transaction_details, do_not_save=True)

append_item(doc, frappe._dict(item_tax_template="GST 28% - _TIRC"))

doc.flags.update(
ignore_mandatory=True,
ignore_validate=True,
)

doc.save()
doc.run_method("onload")

print_settings = frappe.get_single("Print Settings").as_dict()
doc.run_method("before_print", print_settings)


class TestQuotationTransaction(FrappeTestCase):
@classmethod
Expand Down
133 changes: 123 additions & 10 deletions india_compliance/gst_india/overrides/transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
from frappe.model import delete_doc
from frappe.utils import cint, flt
from erpnext.controllers.accounts_controller import get_taxes_and_charges
from erpnext.controllers.taxes_and_totals import (
get_itemised_tax,
get_itemised_taxable_amount,
)

from india_compliance.gst_india.constants import (
GST_TAX_TYPES,
Expand Down Expand Up @@ -47,14 +51,7 @@
}


def set_gst_breakup(doc, method=None, print_settings=None):
if (
ignore_gst_validations(doc, throw=False)
or not doc.place_of_supply
or not doc.company_gstin
):
return

def set_gst_breakup(doc):
gst_breakup_html = frappe.render_template(
"templates/gst_breakup.html", dict(doc=doc)
)
Expand Down Expand Up @@ -607,7 +604,7 @@ def get_source_state_code(doc):
return (doc.supplier_gstin or doc.company_gstin)[:2]


def validate_hsn_codes(doc, method=None):
def validate_hsn_codes(doc):
validate_hsn_code, valid_hsn_length = get_hsn_settings()

if not validate_hsn_code:
Expand Down Expand Up @@ -666,7 +663,7 @@ def _validate_hsn_codes(doc, valid_hsn_length, message=None):
)


def validate_overseas_gst_category(doc, method=None):
def validate_overseas_gst_category(doc):
if not is_overseas_doc(doc):
return

Expand All @@ -685,6 +682,77 @@ def validate_overseas_gst_category(doc, method=None):
frappe.throw(_("Cannot set GST Category to SEZ / Overseas in POS Invoice"))


# DEPRECATED IN v16
def get_itemised_tax_breakup_header(item_doctype, tax_accounts):
if is_hsn_wise_breakup_needed(item_doctype):
return [_("HSN/SAC"), _("Taxable Amount")] + tax_accounts
else:
return [_("Item"), _("Taxable Amount")] + tax_accounts


def get_itemised_tax_breakup_data(doc):
itemised_tax = get_itemised_tax(doc.taxes)
taxable_amounts = get_itemised_taxable_amount(doc.items)

if is_hsn_wise_breakup_needed(doc.doctype + " Item"):
return get_hsn_wise_breakup(doc, itemised_tax, taxable_amounts)

return get_item_wise_breakup(itemised_tax, taxable_amounts)


def get_item_wise_breakup(itemised_tax, taxable_amounts):
itemised_tax_data = []
for item_code, taxes in itemised_tax.items():
itemised_tax_data.append(
frappe._dict(
{
"item": item_code,
"taxable_amount": taxable_amounts.get(item_code),
**taxes,
}
)
)

return itemised_tax_data


def get_hsn_wise_breakup(doc, itemised_tax, taxable_amounts):
hsn_tax_data = frappe._dict()
considered_items = set()
for item in doc.items:
item_code = item.item_code or item.item_name
if item_code in considered_items:
continue

hsn_code = item.gst_hsn_code
tax_row = itemised_tax.get(item_code, {})
tax_rate = next(iter(tax_row.values()), {}).get("tax_rate", 0)

hsn_tax = hsn_tax_data.setdefault(
(hsn_code, tax_rate),
frappe._dict({"item": hsn_code, "taxable_amount": 0}),
)

hsn_tax.taxable_amount += taxable_amounts.get(item_code, 0)
for tax_account, tax_details in tax_row.items():
hsn_tax.setdefault(
tax_account, frappe._dict({"tax_rate": 0, "tax_amount": 0})
)
hsn_tax[tax_account].tax_rate = tax_details.get("tax_rate")
hsn_tax[tax_account].tax_amount += tax_details.get("tax_amount")

considered_items.add(item_code)

return list(hsn_tax_data.values())


def is_hsn_wise_breakup_needed(doctype):
if frappe.get_meta(doctype).has_field("gst_hsn_code") and frappe.get_cached_value(
"GST Settings", None, "hsn_wise_tax_breakup"
):
return True


def get_regional_round_off_accounts(company, account_list):
country = frappe.get_cached_value("Company", company, "country")
if country != "India" or not frappe.get_cached_value(
Expand Down Expand Up @@ -1357,6 +1425,31 @@ def validate_transaction(doc, method=None):
validate_item_wise_tax_detail(doc, valid_accounts)


def before_print(doc, method=None, print_settings=None):
if (
ignore_gst_validations(doc, throw=False)
or not doc.place_of_supply
or not doc.company_gstin
):
return

if doc.get("group_same_items"):
ItemGSTDetails().update(doc)

set_gst_breakup(doc)


def onload(doc, method=None):
if (
ignore_gst_validations(doc, throw=False)
or not doc.place_of_supply
or not doc.company_gstin
):
return

set_gst_breakup(doc)


def validate_ecommerce_gstin(doc):
if not doc.get("ecommerce_gstin"):
return
Expand Down Expand Up @@ -1397,6 +1490,26 @@ def ignore_gst_validations(doc, throw=True):
return True


def before_update_after_submit_item(doc, method=None):
frappe.flags.through_update_item = True


def before_update_after_submit(doc, method=None):
if not frappe.flags.through_update_item:
return

if ignore_gst_validations(doc):
return

if is_sales_transaction := doc.doctype in SALES_DOCTYPES:
validate_hsn_codes(doc)

valid_accounts = validate_gst_accounts(doc, is_sales_transaction) or ()
update_taxable_values(doc, valid_accounts)
validate_item_wise_tax_detail(doc, valid_accounts)
update_gst_details(doc)


# Note: This is kept for backwards compatibility with Frappe versions < 14.21.0
def ignore_logs_on_trash(doc, method=None):
if (
Expand Down
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// Copyright (c) 2024, Resilient Tech and contributors
// For license information, please see license.txt
const INVOICE_TYPE = {
"B2B,SEZ,DE": ["B2B Regular", "B2B Reverse Charge", "SEZWP", "SEZWOP", "Deemed Exports"],
"B2C (Large)": ["B2C (Large)"],
"Exports": ["EXPWP", "EXPWOP"],
"B2C (Others)": ["B2C (Others)"],
"Nil-Rated,Exempted,Non-GST": ["Nil-Rated", "Exempted", "Non-GST"],
"Credit/Debit Notes (Registered)": ["CDNR"],
"Credit/Debit Notes (Unregistered)": ["CDNUR"],
}

frappe.query_reports["GST Sales Register Beta"] = {
onload: set_sub_category_options,
filters: [
{
fieldname: "company",
label: __("Company"),
fieldtype: "Link",
options: "Company",
default: frappe.defaults.get_user_default("Company"),
on_change: report => {
report.set_filter_value({
company_gstin: "",
});
},
get_query: function () {
return {
filters: {
country: "India",
},
};
},
reqd: 1,
},
{
fieldname: "company_gstin",
label: __("Company GSTIN"),
fieldtype: "Autocomplete",
get_query() {
const company = frappe.query_report.get_filter_value("company");
return india_compliance.get_gstin_query(company);
},
},
{
fieldname: "date_range",
label: __("Date Range"),
fieldtype: "DateRange",
default: [india_compliance.last_month_start(), india_compliance.last_month_end()],
width: "80"
},
{
fieldtype: "Select",
fieldname: "summary_by",
label: __("Summary By"),
options: "Overview\nSummary by HSN\nSummary by Item",
default: "Summary by Item"
},
{
fieldtype: "Autocomplete",
fieldname: "invoice_category",
label: __("Invoice Category"),
options: "B2B,SEZ,DE\nB2C (Large)\nExports\nB2C (Others)\nNil-Rated,Exempted,Non-GST\nCredit/Debit Notes (Registered)\nCredit/Debit Notes (Unregistered)",
on_change(report) {
report.set_filter_value('invoice_sub_category', "");
set_sub_category_options(report);
},
depends_on: 'eval:doc.summary_by=="Summary by HSN" || doc.summary_by=="Summary by Item"'
},
{
fieldtype: "Autocomplete",
fieldname: "invoice_sub_category",
label: __("Invoice Sub Category"),
depends_on: 'eval:doc.summary_by=="Summary by HSN" || doc.summary_by=="Summary by Item"'
}
]
};

function set_sub_category_options(report) {
const invoice_category = frappe.query_report.get_filter_value("invoice_category");
report.get_filter('invoice_sub_category').set_data(INVOICE_TYPE[invoice_category] || []);

if (invoice_category && INVOICE_TYPE[invoice_category].length === 1) {
report.set_filter_value("invoice_sub_category", INVOICE_TYPE[invoice_category][0])
}
}

Loading

0 comments on commit 17cf5dc

Please sign in to comment.