Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: improved item tax templates (backport #227) #1419

Merged
merged 1 commit into from
Dec 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions india_compliance/boot.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ def set_bootinfo(bootinfo):
bootinfo["ic_api_enabled_from_conf"] = bool(frappe.conf.ic_api_secret)

set_trigger_for_audit_trail_notification(bootinfo)
set_trigger_for_item_tax_template_notification(bootinfo)


def set_trigger_for_audit_trail_notification(bootinfo):
Expand All @@ -39,3 +40,12 @@ def set_trigger_for_audit_trail_notification(bootinfo):
return

bootinfo["needs_audit_trail_notification"] = True


def set_trigger_for_item_tax_template_notification(bootinfo):
if not bootinfo.sysdefaults or not cint(
bootinfo.sysdefaults.get("needs_item_tax_template_notification", 0)
):
return

bootinfo["needs_item_tax_template_notification"] = True
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ function is_e_invoice_applicable(frm) {
frm.doc.company_gstin != frm.doc.billing_address_gstin &&
(frm.doc.place_of_supply === "96-Other Countries" ||
frm.doc.billing_address_gstin) &&
!frm.doc.items[0].is_non_gst &&
frm.doc.items[0].gst_treatment != "Non-GST" &&
is_valid_e_invoice_applicability_date(frm)
);
}
Expand Down
95 changes: 95 additions & 0 deletions india_compliance/gst_india/client_scripts/item_tax_template.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
frappe.ui.form.on("Item Tax Template", {
refresh: show_missing_accounts_banner,
fetch_gst_accounts: fetch_and_update_missing_gst_accounts,
async gst_rate(frm) {
if (frm.doc.gst_rate === null) return;

await Promise.all(
frm.doc.taxes.map(async row => {
const tax_rate = await get_tax_rate_for_account(frm, row.tax_type);
if (tax_rate == null) return;

row.tax_rate = tax_rate;
})
);

frm.refresh_field("taxes");
},
});

async function show_missing_accounts_banner(frm) {
if (frm.doc.gst_treatment === "Non-GST" || frm.doc.__islocal) return;

const missing_accounts = await get_missing_gst_accounts(frm);
if (!missing_accounts) return;

// show banner
frm.dashboard.add_comment(
__(`<strong>Missing GST Accounts:</strong> {0}`, [missing_accounts.join(", ")]),
"orange",
true
);
}

async function fetch_and_update_missing_gst_accounts(frm) {
const missing_accounts = await get_missing_gst_accounts(frm);
if (!missing_accounts) return;

// cleanup existing empty rows
frm.doc.taxes = frm.doc.taxes.filter(row => row.tax_type);

// add missing rows
await Promise.all(
missing_accounts.map(async account => {
const tax_rate = await get_tax_rate_for_account(frm, account);
frm.add_child("taxes", { tax_type: account, tax_rate: tax_rate });
})
);

frm.refresh_field("taxes");
}

async function get_tax_rate_for_account(frm, account) {
const gst_rate = frm.doc.gst_rate;
if (!gst_rate) return 0;

const gst_accounts = await get_gst_accounts(frm);
if (!gst_accounts) return null;

const [_, intra_state_accounts, inter_state_accounts] = gst_accounts;

if (intra_state_accounts.includes(account)) return gst_rate / 2;
else if (inter_state_accounts.includes(account)) return gst_rate;
else return null;
}

async function get_missing_gst_accounts(frm) {
let gst_accounts = await get_gst_accounts(frm);
if (!gst_accounts) return;

const all_gst_accounts = gst_accounts[0];
const template_accounts = frm.doc.taxes.map(t => t.tax_type);
const missing_accounts = all_gst_accounts.filter(
a => a && !template_accounts.includes(a)
);

if (missing_accounts.length) return missing_accounts;
}

async function get_gst_accounts(frm) {
const company = frm.doc.company;

// cache company gst accounts
if (!frm._company_gst_accounts?.[company]) {
frm._company_gst_accounts = frm._company_gst_accounts || {};
const { message } = await frappe.call({
method: "india_compliance.gst_india.overrides.transaction.get_valid_gst_accounts",
args: { company: company },
});

frm._company_gst_accounts[company] = message;
}

if (!frm._company_gst_accounts[company]) return;
return frm._company_gst_accounts[company];
}
7 changes: 5 additions & 2 deletions india_compliance/gst_india/client_scripts/sales_invoice.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,11 @@ function is_gst_invoice(frm) {
frm.doc.is_opening != "Yes" &&
frm.doc.company_gstin &&
frm.doc.company_gstin != frm.doc.billing_address_gstin &&
!frm.doc.items.some(item => item.is_non_gst) &&
!frm.doc.items.every(item => item.is_nil_exempt);
!frm.doc.items.some(item => item.gst_treatment == "Non-GST") &&
!frm.doc.items.every(
item =>
item.gst_treatment == "Nil-Rated" || item.gst_treatment == "Exempted"
);

if (frm.doc.place_of_supply === "96-Other Countries") {
return gst_invoice_conditions && frm.doc.is_export_with_gst;
Expand Down
196 changes: 159 additions & 37 deletions india_compliance/gst_india/constants/custom_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -268,9 +268,22 @@
"translatable": 0,
}
],
# Transaction Item Fields
# Transaction Item: Tax Fields
"Material Request Item": [
{
"fieldname": "gst_hsn_code",
"label": "HSN/SAC",
"fieldtype": "Data",
"fetch_from": "item_code.gst_hsn_code",
"insert_after": "description",
"allow_on_submit": 1,
"print_hide": 1,
"fetch_if_empty": 1,
"translatable": 0,
},
],
# Taxable Value and GST Details
(
"Material Request Item",
"Supplier Quotation Item",
"Purchase Order Item",
"Purchase Receipt Item",
Expand All @@ -293,38 +306,134 @@
"translatable": 0,
},
{
"fieldname": "is_nil_exempt",
"label": "Is Nil Rated or Exempted",
"fieldtype": "Check",
"fetch_from": "item_code.is_nil_exempt",
"insert_after": "gst_hsn_code",
"print_hide": 1,
},
{
"fieldname": "is_non_gst",
"label": "Is Non GST",
"fieldtype": "Check",
"fetch_from": "item_code.is_non_gst",
"insert_after": "is_nil_exempt",
"fieldname": "gst_treatment",
"label": "GST Treatment",
"fieldtype": "Autocomplete",
"options": "Taxable\nNil-Rated\nExempted\nNon-GST",
"fetch_from": "item_tax_template.gst_treatment",
"insert_after": "item_tax_template",
"print_hide": 1,
"read_only": 1,
"translatable": 0,
"no_copy": 1,
},
],
# Taxable Value
(
"Delivery Note Item",
"Sales Invoice Item",
"POS Invoice Item",
"Purchase Invoice Item",
"Purchase Receipt Item",
): [
{
"fieldname": "taxable_value",
"label": "Taxable Value",
"fieldtype": "Currency",
"insert_after": "base_net_amount",
"hidden": 1,
"options": "Company:company:default_currency",
"read_only": 1,
"translatable": 0,
"no_copy": 1,
"print_hide": 1,
"hidden": 0,
},
{
"fieldtype": "Section Break",
"label": "GST Details",
"insert_after": "taxable_value",
"fieldname": "gst_details_section",
"collapsible": 1,
},
{
"fieldname": "igst_rate",
"label": "IGST Rate",
"fieldtype": "Float",
"insert_after": "gst_details_section",
"read_only": 1,
"translatable": 0,
"no_copy": 1,
},
{
"fieldname": "cgst_rate",
"label": "CGST Rate",
"fieldtype": "Float",
"insert_after": "igst_rate",
"read_only": 1,
"translatable": 0,
"no_copy": 1,
},
{
"fieldname": "sgst_rate",
"label": "SGST Rate",
"fieldtype": "Float",
"insert_after": "cgst_rate",
"read_only": 1,
"translatable": 0,
"no_copy": 1,
},
{
"fieldname": "cess_rate",
"label": "CESS Rate",
"fieldtype": "Float",
"insert_after": "sgst_rate",
"read_only": 1,
"translatable": 0,
"no_copy": 1,
},
{
"fieldname": "cess_non_advol_rate",
"label": "CESS Non Advol Rate",
"fieldtype": "Float",
"insert_after": "cess_rate",
"read_only": 1,
"translatable": 0,
"no_copy": 1,
},
{
"fieldtype": "Column Break",
"insert_after": "cess_non_advol_rate",
"fieldname": "cb_gst_details",
},
{
"fieldname": "igst_amount",
"label": "IGST Amount",
"fieldtype": "Currency",
"options": "Company:company:default_currency",
"insert_after": "cb_gst_details",
"read_only": 1,
"translatable": 0,
"no_copy": 1,
},
{
"fieldname": "cgst_amount",
"label": "CGST Amount",
"fieldtype": "Currency",
"options": "Company:company:default_currency",
"insert_after": "igst_amount",
"read_only": 1,
"translatable": 0,
"no_copy": 1,
},
{
"fieldname": "sgst_amount",
"label": "SGST Amount",
"fieldtype": "Currency",
"options": "Company:company:default_currency",
"insert_after": "cgst_amount",
"read_only": 1,
"translatable": 0,
"no_copy": 1,
},
{
"fieldname": "cess_amount",
"label": "CESS Amount",
"fieldtype": "Currency",
"options": "Company:company:default_currency",
"insert_after": "sgst_amount",
"read_only": 1,
"translatable": 0,
"no_copy": 1,
},
{
"fieldname": "cess_non_advol_amount",
"label": "CESS Non Advol Amount",
"fieldtype": "Currency",
"options": "Company:company:default_currency",
"insert_after": "cess_amount",
"read_only": 1,
"translatable": 0,
"no_copy": 1,
},
],
Expand All @@ -339,7 +448,7 @@
"label": "Is Ineligible for Input Tax Credit",
"fieldtype": "Check",
"fetch_from": "item_code.is_ineligible_for_itc",
"insert_after": "is_nil_exempt",
"insert_after": "gst_hsn_code",
"fetch_if_empty": 1,
"print_hide": 1,
},
Expand Down Expand Up @@ -674,22 +783,35 @@
"description": "You can search code by the description of the category.",
},
{
"fieldname": "is_nil_exempt",
"label": "Is Nil Rated or Exempted",
"fieldname": "is_ineligible_for_itc",
"label": "Is Ineligible for Input Tax Credit",
"fieldtype": "Check",
"insert_after": "gst_hsn_code",
"insert_after": "item_tax_section_break",
},
],
"Item Tax Template": [
{
"fieldname": "is_non_gst",
"label": "Is Non GST",
"fieldtype": "Check",
"insert_after": "is_nil_exempt",
"fieldname": "gst_treatment",
"label": "GST Treatment",
"fieldtype": "Autocomplete",
"default": "Taxable",
"options": "Taxable\nNil-Rated\nExempted\nNon-GST",
"insert_after": "column_break_3",
"translatable": 0,
},
{
"fieldname": "is_ineligible_for_itc",
"label": "Is Ineligible for Input Tax Credit",
"fieldtype": "Check",
"insert_after": "item_tax_section_break",
"fieldname": "gst_rate",
"label": "GST Rate",
"fieldtype": "Float",
"insert_after": "gst_treatment",
"depends_on": "eval:doc.gst_treatment == 'Taxable'",
"translatable": 0,
},
{
"fieldname": "fetch_gst_accounts",
"label": "Fetch GST Accounts",
"fieldtype": "Button",
"insert_after": "section_break_5",
},
],
}
Expand Down
Loading
Loading