GST tax invoice print format and more (#9616)
* GST Tax Invoice print format and more. Fixes #9545 #9566 #9608
* Reload gst print format only for Indian users
* Fixes as Codacy
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index 1a55d84..dc547e3 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -305,6 +305,23 @@
}
this.frm.refresh_fields();
+ },
+
+ company_address: function() {
+ var me = this;
+ if(this.frm.doc.company_address) {
+ frappe.call({
+ method: "frappe.contacts.doctype.address.address.get_address_display",
+ args: {"address_dict": this.frm.doc.company_address },
+ callback: function(r) {
+ if(r.message) {
+ me.frm.set_value("company_address_display", r.message)
+ }
+ }
+ })
+ } else {
+ this.frm.set_value("company_address_display", "");
+ }
}
});
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
index a2e9ddf..4c05b94 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
@@ -190,7 +190,7 @@
"no_copy": 0,
"permlevel": 0,
"precision": "",
- "print_hide": 0,
+ "print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
@@ -206,37 +206,6 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
- "fieldname": "due_date",
- "fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Payment Due Date",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "due_date",
- "oldfieldtype": "Date",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "project",
"fieldtype": "Link",
"hidden": 0,
@@ -253,7 +222,7 @@
"oldfieldtype": "Link",
"options": "Project",
"permlevel": 0,
- "print_hide": 0,
+ "print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
@@ -314,7 +283,7 @@
"no_copy": 0,
"permlevel": 0,
"precision": "",
- "print_hide": 0,
+ "print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
@@ -345,7 +314,7 @@
"options": "POS Profile",
"permlevel": 0,
"precision": "",
- "print_hide": 0,
+ "print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
@@ -516,6 +485,37 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fieldname": "due_date",
+ "fieldtype": "Date",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Payment Due Date",
+ "length": 0,
+ "no_copy": 1,
+ "oldfieldname": "due_date",
+ "oldfieldtype": "Date",
+ "permlevel": 0,
+ "print_hide": 1,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
"fieldname": "amended_from",
"fieldtype": "Link",
"hidden": 0,
@@ -850,6 +850,37 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fieldname": "territory",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Territory",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Territory",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 1,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
"fieldname": "col_break4",
"fieldtype": "Column Break",
"hidden": 0,
@@ -949,13 +980,13 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
- "label": "Company Address",
+ "label": "Company Address Name",
"length": 0,
"no_copy": 0,
"options": "Address",
"permlevel": 0,
"precision": "",
- "print_hide": 0,
+ "print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
@@ -971,24 +1002,23 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
- "fieldname": "territory",
- "fieldtype": "Link",
- "hidden": 0,
+ "fieldname": "company_address_display",
+ "fieldtype": "Small Text",
+ "hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
- "label": "Territory",
+ "label": "Company Address",
"length": 0,
"no_copy": 0,
- "options": "Territory",
"permlevel": 0,
"precision": "",
"print_hide": 1,
"print_hide_if_no_value": 0,
- "read_only": 0,
+ "read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
@@ -1479,7 +1509,7 @@
"options": "Sales Invoice Timesheet",
"permlevel": 0,
"precision": "",
- "print_hide": 0,
+ "print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
@@ -1886,10 +1916,40 @@
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
+ "collapsible": 1,
+ "columns": 0,
+ "fieldname": "sec_tax_breakup",
+ "fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Item-wise Tax Breakup",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "other_charges_calculation",
- "fieldtype": "HTML",
+ "fieldtype": "Text",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
@@ -1899,12 +1959,12 @@
"in_standard_filter": 0,
"label": "Taxes and Charges Calculation",
"length": 0,
- "no_copy": 0,
+ "no_copy": 1,
"oldfieldtype": "HTML",
"permlevel": 0,
"print_hide": 1,
"print_hide_if_no_value": 0,
- "read_only": 0,
+ "read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
@@ -2984,7 +3044,7 @@
"options": "Account",
"permlevel": 0,
"precision": "",
- "print_hide": 0,
+ "print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
@@ -4450,7 +4510,7 @@
"options": "Print Format",
"permlevel": 0,
"precision": "",
- "print_hide": 0,
+ "print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
@@ -4511,7 +4571,7 @@
"length": 0,
"no_copy": 1,
"permlevel": 0,
- "print_hide": 0,
+ "print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
@@ -4542,7 +4602,7 @@
"length": 0,
"no_copy": 1,
"permlevel": 0,
- "print_hide": 0,
+ "print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
@@ -4627,7 +4687,7 @@
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
- "modified": "2017-06-29 10:47:49.522969",
+ "modified": "2017-07-04 17:11:09.477003",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice",
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
index 2e044cc..071e72b 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -1105,6 +1105,22 @@
for i, k in enumerate(expected_values["keys"]):
self.assertEquals(d.get(k), expected_values[d.item_code][i])
+ def test_item_wise_tax_breakup(self):
+ si = create_sales_invoice(qty=100, rate=50, do_not_save=True)
+ si.append("taxes", {
+ "charge_type": "On Net Total",
+ "account_head": "_Test Account Service Tax - _TC",
+ "cost_center": "_Test Cost Center - _TC",
+ "description": "Service Tax",
+ "rate": 10
+ })
+ si.insert()
+
+ tax_breakup_html = '''\n<div class="tax-break-up" style="overflow-x: auto;">\n\t<table class="table table-bordered table-hover">\n\t\t<thead><tr><th class="text-left" style="min-width: 120px;">Item Name</th>\n<th class="text-right" style="min-width: 80px;">Taxable Amount</th>\n<th class="text-right" style="min-width: 80px;">_Test Account Service Tax - _TC</th></tr></thead>\n\t\t<tbody><tr><td>_Test Item</td><td class="text-right">5000.0</td><td class="text-right">(10.0%) \u20b9 500.00</td></tr></tbody>\n\t</table>\n</div>'''
+
+ self.assertEqual(si.other_charges_calculation, tax_breakup_html)
+
+
def create_sales_invoice(**args):
si = frappe.new_doc("Sales Invoice")
args = frappe._dict(args)
diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py
index 50f6b61..b0fe395 100644
--- a/erpnext/controllers/taxes_and_totals.py
+++ b/erpnext/controllers/taxes_and_totals.py
@@ -5,7 +5,7 @@
import json
import frappe, erpnext
from frappe import _, scrub
-from frappe.utils import cint, flt, round_based_on_smallest_currency_fraction
+from frappe.utils import cint, flt, cstr, fmt_money, round_based_on_smallest_currency_fraction
from erpnext.controllers.accounts_controller import validate_conversion_rate, \
validate_taxes_and_charges, validate_inclusive_tax
@@ -24,6 +24,9 @@
if self.doc.doctype in ["Sales Invoice", "Purchase Invoice"]:
self.calculate_total_advance()
+
+ if self.doc.meta.get_field("other_charges_calculation"):
+ self.set_item_wise_tax_breakup()
def _calculate(self):
self.calculate_item_values()
@@ -504,3 +507,106 @@
rate_with_margin = flt(item.price_list_rate) + flt(margin_value)
return rate_with_margin
+
+ def set_item_wise_tax_breakup(self):
+ item_tax = {}
+ tax_accounts = []
+
+ item_tax, tax_accounts = self.get_item_tax(item_tax, tax_accounts)
+
+ headings = get_table_column_headings(tax_accounts)
+
+ distinct_items = self.get_distinct_items()
+
+ rows = get_table_rows(distinct_items, item_tax, tax_accounts)
+
+ if not rows:
+ self.doc.other_charges_calculation = ""
+ else:
+ self.doc.other_charges_calculation = '''
+<div class="tax-break-up" style="overflow-x: auto;">
+ <table class="table table-bordered table-hover">
+ <thead><tr>{headings}</tr></thead>
+ <tbody>{rows}</tbody>
+ </table>
+</div>'''.format(**{
+ "headings": "\n".join(headings),
+ "rows": "\n".join(rows)
+})
+
+ def get_item_tax(self, item_tax, tax_accounts):
+ company_currency = erpnext.get_company_currency(self.doc.company)
+
+ for tax in self.doc.taxes:
+ tax_amount_precision = tax.precision("tax_amount")
+ tax_rate_precision = tax.precision("rate");
+
+ item_tax_map = self._load_item_tax_rate(tax.item_wise_tax_detail)
+ for item_code, tax_data in item_tax_map.items():
+ if not item_tax.get(item_code):
+ item_tax[item_code] = {}
+
+ if isinstance(tax_data, list):
+ tax_rate = ""
+ if tax_data[0]:
+ if tax.charge_type == "Actual":
+ tax_rate = fmt_money(flt(tax_data[0], tax_amount_precision),
+ tax_amount_precision, company_currency)
+ else:
+ tax_rate = cstr(flt(tax_data[0], tax_rate_precision)) + "%"
+
+ tax_amount = fmt_money(flt(tax_data[1], tax_amount_precision),
+ tax_amount_precision, company_currency)
+
+ item_tax[item_code][tax.name] = [tax_rate, tax_amount]
+ else:
+ item_tax[item_code][tax.name] = [cstr(flt(tax_data, tax_rate_precision)) + "%", ""]
+ tax_accounts.append([tax.name, tax.account_head])
+
+ return item_tax, tax_accounts
+
+
+ def get_distinct_items(self):
+ distinct_item_names = []
+ distinct_items = []
+ for item in self.doc.items:
+ item_code = item.item_code or item.item_name
+ if item_code not in distinct_item_names:
+ distinct_item_names.append(item_code)
+ distinct_items.append(item)
+
+ return distinct_items
+
+def get_table_column_headings(tax_accounts):
+ headings_name = [_("Item Name"), _("Taxable Amount")] + [d[1] for d in tax_accounts]
+ headings = []
+ for head in headings_name:
+ if head == _("Item Name"):
+ headings.append('<th style="min-width: 120px;" class="text-left">' + (head or "") + "</th>")
+ else:
+ headings.append('<th style="min-width: 80px;" class="text-right">' + (head or "") + "</th>")
+
+ return headings
+
+def get_table_rows(distinct_items, item_tax, tax_accounts):
+ rows = []
+ for item in distinct_items:
+ item_tax_record = item_tax.get(item.item_code or item.item_name)
+ if not item_tax_record:
+ continue
+
+ taxes = []
+ for head in tax_accounts:
+ if item_tax_record[head[0]]:
+ taxes.append("<td class='text-right'>(" + item_tax_record[head[0]][0] + ") "
+ + item_tax_record[head[0]][1] + "</td>")
+ else:
+ taxes.append("<td></td>")
+
+ rows.append("<tr><td>{item_name}</td><td class='text-right'>{taxable_amount}</td>{taxes}</tr>".format(**{
+ "item_name": item.item_name,
+ "taxable_amount": item.net_amount,
+ "taxes": "\n".join(taxes)
+ }))
+
+ return rows
\ No newline at end of file
diff --git a/erpnext/docs/assets/img/regional/india/address-template-gstin.png b/erpnext/docs/assets/img/regional/india/address-template-gstin.png
new file mode 100644
index 0000000..8740609
--- /dev/null
+++ b/erpnext/docs/assets/img/regional/india/address-template-gstin.png
Binary files differ
diff --git a/erpnext/docs/assets/img/regional/india/sample-gst-tax-invoice.png b/erpnext/docs/assets/img/regional/india/sample-gst-tax-invoice.png
new file mode 100644
index 0000000..4f4a9b1
--- /dev/null
+++ b/erpnext/docs/assets/img/regional/india/sample-gst-tax-invoice.png
Binary files differ
diff --git a/erpnext/docs/license.html b/erpnext/docs/license.html
index 4740c5c..1d50b78 100644
--- a/erpnext/docs/license.html
+++ b/erpnext/docs/license.html
@@ -640,8 +640,8 @@
the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.</p>
-<pre><code> <one line to give the program's name and a brief idea of what it does.>
- Copyright (C) <year> <name of author>
+<pre><code> <one line="" to="" give="" the="" program's="" name="" and="" a="" brief="" idea="" of="" what="" it="" does.="">
+ Copyright (C) <year> <name of="" author="">
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/erpnext/docs/user/manual/en/regional/india/gst-setup.md b/erpnext/docs/user/manual/en/regional/india/gst-setup.md
index 48e5066..0ba8284 100644
--- a/erpnext/docs/user/manual/en/regional/india/gst-setup.md
+++ b/erpnext/docs/user/manual/en/regional/india/gst-setup.md
@@ -14,6 +14,13 @@
<img class="screenshot" alt="GST in Company" src="{{docs_base_url}}/assets/img/regional/india/gstin-company.gif">
+**Include GSTIN number in the Address Template**
+
+Open Address Template record for India, and add GSTIN number there if not exists.
+
+<img class="screenshot" alt="GST in Company" src="{{docs_base_url}}/assets/img/regional/india/address-template-gstin.png">
+
+
### 2. Setting up HSN Codes
According to the GST Law, your itemised invoices must contain the HSN Code related to that Item. ERPNext comes pre-installed with all 12,000+ HSN Codes so that you can easily select the relevant HSN Code in your Item
@@ -54,6 +61,12 @@
<img class="screenshot" alt="GST Invoice" src="{{docs_base_url}}/assets/img/regional/india/gst-invoice.gif">
+### 6. Print GST Tax Invoice
+
+To print Tax Invoice as per GSTN guidelines, please select **GST Tax Invoice** print format. This print format includes company address, GSTIN numbers, HSN/SAC Code and item-wise tax breakup.
+
+<img class="screenshot" alt="Sample GST Tax Invoice" src="{{docs_base_url}}/assets/img/regional/india/sample-gst-tax-invoice.png">
+
### Reports
ERPNext comes with most of your reports you need to prepare your GST Returns. Go to Accounts > GST India head for the list.
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 30a24f8..e7cf5f2 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -410,4 +410,5 @@
erpnext.patches.v8_1.delete_deprecated_reports
erpnext.patches.v8_1.setup_gst_india #2017-06-27
execute:frappe.reload_doc('regional', 'doctype', 'gst_hsn_code')
-erpnext.patches.v8_1.removed_roles_from_gst_report_non_indian_account
\ No newline at end of file
+erpnext.patches.v8_1.removed_roles_from_gst_report_non_indian_account
+erpnext.patches.v8_1.gst_fixes
diff --git a/erpnext/patches/v8_1/gst_fixes.py b/erpnext/patches/v8_1/gst_fixes.py
new file mode 100644
index 0000000..5454f0f
--- /dev/null
+++ b/erpnext/patches/v8_1/gst_fixes.py
@@ -0,0 +1,27 @@
+import frappe
+
+def execute():
+ frappe.db.sql("""update `tabCustom Field` set label = 'HSN/SAC Code'
+ where fieldname='gst_hsn_code' and label='GST HSN Code'
+ """)
+
+ frappe.db.sql("""update `tabCustom Field` set print_hide = 1
+ where fieldname in ('customer_gstin', 'supplier_gstin', 'company_gstin')
+ """)
+
+ frappe.db.sql("""update `tabCustom Field` set insert_after = 'address_display'
+ where fieldname in ('customer_gstin', 'supplier_gstin')
+ """)
+
+ frappe.db.sql("""update `tabCustom Field` set insert_after = 'company_address_display'
+ where fieldname = 'company_gstin'
+ """)
+
+ frappe.db.sql("""update `tabCustom Field` set insert_after = 'description'
+ where fieldname='gst_hsn_code' and dt in ('Sales Invoice Item', 'Purchase Invoice Item')
+ """)
+
+ # reload gst print format for Indian users
+ company = frappe.get_all('Company', filters = {'country': 'India'})
+ if company:
+ frappe.reload_doc("regional", "print_format", "gst_tax_invoice")
\ No newline at end of file
diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js
index c4d8155..642ff1b 100644
--- a/erpnext/public/js/controllers/taxes_and_totals.js
+++ b/erpnext/public/js/controllers/taxes_and_totals.js
@@ -634,5 +634,91 @@
}
this.calculate_outstanding_amount(false)
+ },
+
+ show_item_wise_taxes: function() {
+ if(this.frm.fields_dict.other_charges_calculation) {
+ this.frm.toggle_display("other_charges_calculation", this.frm.doc.other_charges_calculation);
+ }
+ },
+
+ set_item_wise_tax_breakup: function() {
+ if(this.frm.fields_dict.other_charges_calculation) {
+ var html = this.get_item_wise_taxes_html();
+ // console.log(html);
+ this.frm.set_value("other_charges_calculation", html);
+ this.show_item_wise_taxes();
+ }
+ },
+
+ get_item_wise_taxes_html: function() {
+ var item_tax = {};
+ var tax_accounts = [];
+ var company_currency = this.get_company_currency();
+
+ $.each(this.frm.doc["taxes"] || [], function(i, tax) {
+ var tax_amount_precision = precision("tax_amount", tax);
+ var tax_rate_precision = precision("rate", tax);
+ $.each(JSON.parse(tax.item_wise_tax_detail || '{}'),
+ function(item_code, tax_data) {
+ if(!item_tax[item_code]) item_tax[item_code] = {};
+ if($.isArray(tax_data)) {
+ var tax_rate = "";
+ if(tax_data[0] != null) {
+ tax_rate = (tax.charge_type === "Actual") ?
+ format_currency(flt(tax_data[0], tax_amount_precision),
+ company_currency, tax_amount_precision) :
+ (flt(tax_data[0], tax_rate_precision) + "%");
+ }
+ var tax_amount = format_currency(flt(tax_data[1], tax_amount_precision),
+ company_currency, tax_amount_precision);
+
+ item_tax[item_code][tax.name] = [tax_rate, tax_amount];
+ } else {
+ item_tax[item_code][tax.name] = [flt(tax_data, tax_rate_precision) + "%", ""];
+ }
+ });
+ tax_accounts.push([tax.name, tax.account_head]);
+ });
+
+ var headings = $.map([__("Item Name"), __("Taxable Amount")].concat($.map(tax_accounts,
+ function(head) { return head[1]; })), function(head) {
+ if(head==__("Item Name")) {
+ return '<th style="min-width: 100px;" class="text-left">' + (head || "") + "</th>";
+ } else {
+ return '<th style="min-width: 80px;" class="text-right">' + (head || "") + "</th>";
+ }
+ }
+ ).join("\n");
+
+ var distinct_item_names = [];
+ var distinct_items = [];
+ $.each(this.frm.doc["items"] || [], function(i, item) {
+ if(distinct_item_names.indexOf(item.item_code || item.item_name)===-1) {
+ distinct_item_names.push(item.item_code || item.item_name);
+ distinct_items.push(item);
+ }
+ });
+
+ var rows = $.map(distinct_items, function(item) {
+ var item_tax_record = item_tax[item.item_code || item.item_name];
+ if(!item_tax_record) { return null; }
+ return repl("<tr><td>%(item_name)s</td><td class='text-right'>%(taxable_amount)s</td>%(taxes)s</tr>", {
+ item_name: item.item_name,
+ taxable_amount: item.net_amount,
+ taxes: $.map(tax_accounts, function(head) {
+ return item_tax_record[head[0]] ?
+ "<td class='text-right'>(" + item_tax_record[head[0]][0] + ") " + item_tax_record[head[0]][1] + "</td>" :
+ "<td></td>";
+ }).join("\n")
+ });
+ }).join("\n");
+
+ if(!rows) return "";
+ return '<div class="tax-break-up" style="overflow-x: auto;">\
+ <table class="table table-bordered table-hover">\
+ <thead><tr>' + headings + '</tr></thead> \
+ <tbody>' + rows + '</tbody> \
+ </table></div>';
}
})
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index cd8e7bd..c4f9e8a 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -374,6 +374,7 @@
validate: function() {
this.calculate_taxes_and_totals(false);
+ this.set_item_wise_tax_breakup();
},
company: function() {
@@ -936,69 +937,6 @@
});
},
- get_item_wise_taxes_html: function() {
- var item_tax = {};
- var tax_accounts = [];
- var company_currency = this.get_company_currency();
-
- $.each(this.frm.doc["taxes"] || [], function(i, tax) {
- var tax_amount_precision = precision("tax_amount", tax);
- var tax_rate_precision = precision("rate", tax);
- $.each(JSON.parse(tax.item_wise_tax_detail || '{}'),
- function(item_code, tax_data) {
- if(!item_tax[item_code]) item_tax[item_code] = {};
- if($.isArray(tax_data)) {
- var tax_rate = "";
- if(tax_data[0] != null) {
- tax_rate = (tax.charge_type === "Actual") ?
- format_currency(flt(tax_data[0], tax_amount_precision), company_currency, tax_amount_precision) :
- (flt(tax_data[0], tax_rate_precision) + "%");
- }
- var tax_amount = format_currency(flt(tax_data[1], tax_amount_precision), company_currency,
- tax_amount_precision);
-
- item_tax[item_code][tax.name] = [tax_rate, tax_amount];
- } else {
- item_tax[item_code][tax.name] = [flt(tax_data, tax_rate_precision) + "%", ""];
- }
- });
- tax_accounts.push([tax.name, tax.account_head]);
- });
-
- var headings = $.map([__("Item Name")].concat($.map(tax_accounts, function(head) { return head[1]; })),
- function(head) { return '<th style="min-width: 100px;">' + (head || "") + "</th>" }).join("\n");
-
- var distinct_item_names = [];
- var distinct_items = [];
- $.each(this.frm.doc["items"] || [], function(i, item) {
- if(distinct_item_names.indexOf(item.item_code || item.item_name)===-1) {
- distinct_item_names.push(item.item_code || item.item_name);
- distinct_items.push(item);
- }
- });
-
- var rows = $.map(distinct_items, function(item) {
- var item_tax_record = item_tax[item.item_code || item.item_name];
- if(!item_tax_record) { return null; }
- return repl("<tr><td>%(item_name)s</td>%(taxes)s</tr>", {
- item_name: item.item_name,
- taxes: $.map(tax_accounts, function(head) {
- return item_tax_record[head[0]] ?
- "<td>(" + item_tax_record[head[0]][0] + ") " + item_tax_record[head[0]][1] + "</td>" :
- "<td></td>";
- }).join("\n")
- });
- }).join("\n");
-
- if(!rows) return "";
- return '<p><a class="h6 text-muted" href="#" onclick="$(\'.tax-break-up\').toggleClass(\'hide\'); return false;">'
- + __("Show tax break-up") + '</a></p>\
- <div class="tax-break-up hide" style="overflow-x: auto;"><table class="table table-bordered table-hover">\
- <thead><tr>' + headings + '</tr></thead> \
- <tbody>' + rows + '</tbody> \
- </table></div>';
- },
-
validate_company_and_party: function() {
var me = this;
var valid = true;
@@ -1046,18 +984,6 @@
}
},
- show_item_wise_taxes: function() {
- if(this.frm.fields_dict.other_charges_calculation) {
- var html = this.get_item_wise_taxes_html();
- if (html) {
- this.frm.toggle_display("other_charges_calculation", true);
- $(this.frm.fields_dict.other_charges_calculation.wrapper).html(html);
- } else {
- this.frm.toggle_display("other_charges_calculation", false);
- }
- }
- },
-
is_recurring: function() {
// set default values for recurring documents
if(this.frm.doc.is_recurring && this.frm.doc.__islocal) {
diff --git a/erpnext/regional/india/address_template.html b/erpnext/regional/india/address_template.html
index 706c7a4..46879ad 100644
--- a/erpnext/regional/india/address_template.html
+++ b/erpnext/regional/india/address_template.html
@@ -2,7 +2,7 @@
{% if state %}{{ state }}<br>{% endif -%}
{% if pincode %}{{ pincode }}<br>{% endif -%}
{{ country }}<br>
-{% if gstin %}GSTIN: {{ gstin }}<br>{% endif -%}
{% if phone %}Phone: {{ phone }}<br>{% endif -%}
{% if fax %}Fax: {{ fax }}<br>{% endif -%}
-{% if email_id %}Email: {{ email_id }}<br>{% endif -%}
\ No newline at end of file
+{% if email_id %}Email: {{ email_id }}<br>{% endif -%}
+{% if gstin %}GSTIN: {{ gstin }}<br>{% endif -%}
\ No newline at end of file
diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py
index a9f3a30..46cfdb8 100644
--- a/erpnext/regional/india/setup.py
+++ b/erpnext/regional/india/setup.py
@@ -14,6 +14,7 @@
add_custom_roles_for_reports()
add_hsn_codes()
update_address_template()
+ add_print_formats()
if not patch:
make_fixtures()
@@ -69,6 +70,9 @@
add_permission(doctype, 'Accounts Manager', 0)
add_permission(doctype, 'All', 0)
+def add_print_formats():
+ frappe.reload_doc("regional", "print_format", "gst_tax_invoice")
+
def make_custom_fields():
custom_fields = {
'Address': [
@@ -80,39 +84,39 @@
'Purchase Invoice': [
dict(fieldname='supplier_gstin', label='Supplier GSTIN',
fieldtype='Data', insert_after='supplier_address',
- options='supplier_address.gstin'),
+ options='supplier_address.gstin', print_hide=1),
dict(fieldname='company_gstin', label='Company GSTIN',
fieldtype='Data', insert_after='shipping_address',
- options='shipping_address.gstin'),
+ options='shipping_address.gstin', print_hide=1),
],
'Sales Invoice': [
dict(fieldname='customer_gstin', label='Customer GSTIN',
fieldtype='Data', insert_after='shipping_address',
- options='shipping_address_name.gstin'),
+ options='shipping_address_name.gstin', print_hide=1),
dict(fieldname='company_gstin', label='Company GSTIN',
fieldtype='Data', insert_after='company_address',
- options='company_address.gstin'),
+ options='company_address.gstin', print_hide=1),
],
'Item': [
- dict(fieldname='gst_hsn_code', label='GST HSN Code',
+ dict(fieldname='gst_hsn_code', label='HSN/SAC Code',
fieldtype='Link', options='GST HSN Code', insert_after='item_group'),
],
'Sales Invoice Item': [
- dict(fieldname='gst_hsn_code', label='GST HSN Code',
+ dict(fieldname='gst_hsn_code', label='HSN/SAC Code',
fieldtype='Data', options='item_code.gst_hsn_code',
- insert_after='income_account'),
+ insert_after='description'),
],
'Purchase Invoice Item': [
- dict(fieldname='gst_hsn_code', label='GST HSN Code',
+ dict(fieldname='gst_hsn_code', label='HSN/SAC Code',
fieldtype='Data', options='item_code.gst_hsn_code',
- insert_after='expense_account'),
+ insert_after='description'),
]
}
for doctype, fields in custom_fields.items():
for df in fields:
create_custom_field(doctype, df)
-
+
def make_fixtures():
docs = [
{'doctype': 'Salary Component', 'salary_component': 'Professional Tax', 'description': 'Professional Tax', 'type': 'Deduction'},
diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py
index 4d37498..c4acafc 100644
--- a/erpnext/regional/india/utils.py
+++ b/erpnext/regional/india/utils.py
@@ -16,7 +16,7 @@
if doc.state in states:
doc.gst_state = doc.state
- if doc.gst_state:
- state_number = state_numbers[doc.gst_state]
- if state_number != doc.gstin[:2]:
- frappe.throw(_("First 2 digits of GSTIN should match with State number {0}").format(state_number))
+ if doc.gst_state:
+ state_number = state_numbers[doc.gst_state]
+ if state_number != doc.gstin[:2]:
+ frappe.throw(_("First 2 digits of GSTIN should match with State number {0}").format(state_number))
diff --git a/erpnext/regional/print_format/__init__.py b/erpnext/regional/print_format/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/regional/print_format/__init__.py
diff --git a/erpnext/regional/print_format/gst_tax_invoice/__init__.py b/erpnext/regional/print_format/gst_tax_invoice/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/regional/print_format/gst_tax_invoice/__init__.py
diff --git a/erpnext/regional/print_format/gst_tax_invoice/gst_tax_invoice.json b/erpnext/regional/print_format/gst_tax_invoice/gst_tax_invoice.json
new file mode 100644
index 0000000..b16aada
--- /dev/null
+++ b/erpnext/regional/print_format/gst_tax_invoice/gst_tax_invoice.json
@@ -0,0 +1,22 @@
+{
+ "align_labels_left": 0,
+ "creation": "2017-07-04 16:26:21.120187",
+ "custom_format": 0,
+ "disabled": 0,
+ "doc_type": "Sales Invoice",
+ "docstatus": 0,
+ "doctype": "Print Format",
+ "font": "Default",
+ "format_data": "[{\"fieldname\": \"print_heading_template\", \"fieldtype\": \"Custom HTML\", \"options\": \"<div class=\\\"print-heading\\\">\\t\\t\\t\\t<h2>Sales Invoice<br><small>{{ doc.name }}</small>\\t\\t\\t\\t</h2></div>\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"company\", \"label\": \"Company\"}, {\"print_hide\": 0, \"fieldname\": \"company_address_display\", \"label\": \"Company Address\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"posting_date\", \"label\": \"Date\"}, {\"print_hide\": 0, \"fieldname\": \"due_date\", \"label\": \"Payment Due Date\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"options\": \"<hr>\", \"fieldname\": \"_custom_html\", \"fieldtype\": \"HTML\", \"label\": \"Custom HTML\"}, {\"fieldtype\": \"Section Break\", \"label\": \"Address\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"customer_name\", \"label\": \"Customer Name\"}, {\"print_hide\": 0, \"fieldname\": \"address_display\", \"label\": \"Address\"}, {\"print_hide\": 0, \"fieldname\": \"contact_display\", \"label\": \"Contact\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"shipping_address\", \"label\": \"Shipping Address\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"visible_columns\": [{\"print_hide\": 0, \"fieldname\": \"item_code\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"description\", \"print_width\": \"200px\"}, {\"print_hide\": 0, \"fieldname\": \"gst_hsn_code\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"qty\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"uom\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"rate\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"amount\", \"print_width\": \"\"}], \"print_hide\": 0, \"fieldname\": \"items\", \"label\": \"Items\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"total\", \"label\": \"Total\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"visible_columns\": [{\"print_hide\": 0, \"fieldname\": \"description\", \"print_width\": \"300px\"}], \"print_hide\": 0, \"fieldname\": \"taxes\", \"label\": \"Sales Taxes and Charges\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"grand_total\", \"label\": \"Grand Total\"}, {\"print_hide\": 0, \"fieldname\": \"rounded_total\", \"label\": \"Rounded Total\"}, {\"print_hide\": 0, \"fieldname\": \"in_words\", \"label\": \"In Words\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"other_charges_calculation\", \"align\": \"left\", \"label\": \"Item-wise Tax Breakup\"}, {\"fieldtype\": \"Section Break\", \"label\": \"Terms\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"terms\", \"label\": \"Terms and Conditions Details\"}]",
+ "idx": 0,
+ "line_breaks": 0,
+ "modified": "2017-07-04 17:13:44.911156",
+ "modified_by": "Administrator",
+ "module": "Regional",
+ "name": "GST Tax Invoice",
+ "owner": "Administrator",
+ "print_format_builder": 1,
+ "print_format_type": "Server",
+ "show_section_headings": 0,
+ "standard": "Yes"
+}
\ No newline at end of file