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
This commit is contained in:
Nabin Hait 2017-07-05 12:58:19 +05:30 committed by Makarand Bauskar
parent b66fb9a4c0
commit 852cb64e4f
18 changed files with 425 additions and 147 deletions

View File

@ -305,6 +305,23 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
} }
this.frm.refresh_fields(); 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", "");
}
} }
}); });

View File

@ -190,7 +190,7 @@
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
"precision": "", "precision": "",
"print_hide": 0, "print_hide": 1,
"print_hide_if_no_value": 0, "print_hide_if_no_value": 0,
"read_only": 1, "read_only": 1,
"remember_last_selected_value": 0, "remember_last_selected_value": 0,
@ -200,37 +200,6 @@
"set_only_once": 0, "set_only_once": 0,
"unique": 0 "unique": 0
}, },
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"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_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
@ -253,7 +222,7 @@
"oldfieldtype": "Link", "oldfieldtype": "Link",
"options": "Project", "options": "Project",
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 1,
"print_hide_if_no_value": 0, "print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"remember_last_selected_value": 0, "remember_last_selected_value": 0,
@ -314,7 +283,7 @@
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
"precision": "", "precision": "",
"print_hide": 0, "print_hide": 1,
"print_hide_if_no_value": 0, "print_hide_if_no_value": 0,
"read_only": 1, "read_only": 1,
"remember_last_selected_value": 0, "remember_last_selected_value": 0,
@ -345,7 +314,7 @@
"options": "POS Profile", "options": "POS Profile",
"permlevel": 0, "permlevel": 0,
"precision": "", "precision": "",
"print_hide": 0, "print_hide": 1,
"print_hide_if_no_value": 0, "print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"remember_last_selected_value": 0, "remember_last_selected_value": 0,
@ -510,6 +479,37 @@
"set_only_once": 0, "set_only_once": 0,
"unique": 0 "unique": 0
}, },
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"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_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
@ -844,6 +844,37 @@
"set_only_once": 0, "set_only_once": 0,
"unique": 0 "unique": 0
}, },
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"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_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
@ -949,13 +980,13 @@
"in_global_search": 0, "in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Company Address", "label": "Company Address Name",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
"options": "Address", "options": "Address",
"permlevel": 0, "permlevel": 0,
"precision": "", "precision": "",
"print_hide": 0, "print_hide": 1,
"print_hide_if_no_value": 0, "print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"remember_last_selected_value": 0, "remember_last_selected_value": 0,
@ -971,24 +1002,23 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fieldname": "territory", "fieldname": "company_address_display",
"fieldtype": "Link", "fieldtype": "Small Text",
"hidden": 0, "hidden": 1,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0, "in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Territory", "label": "Company Address",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
"options": "Territory",
"permlevel": 0, "permlevel": 0,
"precision": "", "precision": "",
"print_hide": 1, "print_hide": 1,
"print_hide_if_no_value": 0, "print_hide_if_no_value": 0,
"read_only": 0, "read_only": 1,
"remember_last_selected_value": 0, "remember_last_selected_value": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -1479,7 +1509,7 @@
"options": "Sales Invoice Timesheet", "options": "Sales Invoice Timesheet",
"permlevel": 0, "permlevel": 0,
"precision": "", "precision": "",
"print_hide": 0, "print_hide": 1,
"print_hide_if_no_value": 0, "print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"remember_last_selected_value": 0, "remember_last_selected_value": 0,
@ -1882,6 +1912,36 @@
"set_only_once": 0, "set_only_once": 0,
"unique": 0 "unique": 0
}, },
{
"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_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
@ -1889,7 +1949,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fieldname": "other_charges_calculation", "fieldname": "other_charges_calculation",
"fieldtype": "HTML", "fieldtype": "Text",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
@ -1899,12 +1959,12 @@
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Taxes and Charges Calculation", "label": "Taxes and Charges Calculation",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 1,
"oldfieldtype": "HTML", "oldfieldtype": "HTML",
"permlevel": 0, "permlevel": 0,
"print_hide": 1, "print_hide": 1,
"print_hide_if_no_value": 0, "print_hide_if_no_value": 0,
"read_only": 0, "read_only": 1,
"remember_last_selected_value": 0, "remember_last_selected_value": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -2984,7 +3044,7 @@
"options": "Account", "options": "Account",
"permlevel": 0, "permlevel": 0,
"precision": "", "precision": "",
"print_hide": 0, "print_hide": 1,
"print_hide_if_no_value": 0, "print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"remember_last_selected_value": 0, "remember_last_selected_value": 0,
@ -4450,7 +4510,7 @@
"options": "Print Format", "options": "Print Format",
"permlevel": 0, "permlevel": 0,
"precision": "", "precision": "",
"print_hide": 0, "print_hide": 1,
"print_hide_if_no_value": 0, "print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"remember_last_selected_value": 0, "remember_last_selected_value": 0,
@ -4511,7 +4571,7 @@
"length": 0, "length": 0,
"no_copy": 1, "no_copy": 1,
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 1,
"print_hide_if_no_value": 0, "print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"remember_last_selected_value": 0, "remember_last_selected_value": 0,
@ -4542,7 +4602,7 @@
"length": 0, "length": 0,
"no_copy": 1, "no_copy": 1,
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 1,
"print_hide_if_no_value": 0, "print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"remember_last_selected_value": 0, "remember_last_selected_value": 0,
@ -4627,7 +4687,7 @@
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"menu_index": 0, "menu_index": 0,
"modified": "2017-06-29 10:47:49.522969", "modified": "2017-07-04 17:11:09.477003",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Sales Invoice", "name": "Sales Invoice",

View File

@ -1105,6 +1105,22 @@ class TestSalesInvoice(unittest.TestCase):
for i, k in enumerate(expected_values["keys"]): for i, k in enumerate(expected_values["keys"]):
self.assertEquals(d.get(k), expected_values[d.item_code][i]) 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): def create_sales_invoice(**args):
si = frappe.new_doc("Sales Invoice") si = frappe.new_doc("Sales Invoice")
args = frappe._dict(args) args = frappe._dict(args)

View File

@ -5,7 +5,7 @@ from __future__ import unicode_literals
import json import json
import frappe, erpnext import frappe, erpnext
from frappe import _, scrub 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, \ from erpnext.controllers.accounts_controller import validate_conversion_rate, \
validate_taxes_and_charges, validate_inclusive_tax validate_taxes_and_charges, validate_inclusive_tax
@ -24,6 +24,9 @@ class calculate_taxes_and_totals(object):
if self.doc.doctype in ["Sales Invoice", "Purchase Invoice"]: if self.doc.doctype in ["Sales Invoice", "Purchase Invoice"]:
self.calculate_total_advance() self.calculate_total_advance()
if self.doc.meta.get_field("other_charges_calculation"):
self.set_item_wise_tax_breakup()
def _calculate(self): def _calculate(self):
self.calculate_item_values() self.calculate_item_values()
@ -504,3 +507,106 @@ class calculate_taxes_and_totals(object):
rate_with_margin = flt(item.price_list_rate) + flt(margin_value) rate_with_margin = flt(item.price_list_rate) + flt(margin_value)
return rate_with_margin 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 222 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 356 KiB

View File

@ -640,8 +640,8 @@ attach them to the start of each source file to most effectively state
the exclusion of warranty; and each file should have at least the 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> "copyright" line and a pointer to where the full notice is found.</p>
<pre><code> &lt;one line to give the program's name and a brief idea of what it does.&gt; <pre><code> &lt;one line="" to="" give="" the="" program's="" name="" and="" a="" brief="" idea="" of="" what="" it="" does.=""&gt;
Copyright (C) &lt;year&gt; &lt;name of author&gt; Copyright (C) &lt;year&gt; &lt;name of="" author=""&gt;
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by

View File

@ -14,6 +14,13 @@ Go to the Company master and add the GSTIN to your default address.
<img class="screenshot" alt="GST in Company" src="{{docs_base_url}}/assets/img/regional/india/gstin-company.gif"> <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 ### 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 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 @@ For **Sales Invoice**,
<img class="screenshot" alt="GST Invoice" src="{{docs_base_url}}/assets/img/regional/india/gst-invoice.gif"> <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 ### Reports
ERPNext comes with most of your reports you need to prepare your GST Returns. Go to Accounts > GST India head for the list. ERPNext comes with most of your reports you need to prepare your GST Returns. Go to Accounts > GST India head for the list.

View File

@ -410,4 +410,5 @@ erpnext.patches.v8_0.save_system_settings
erpnext.patches.v8_1.delete_deprecated_reports erpnext.patches.v8_1.delete_deprecated_reports
erpnext.patches.v8_1.setup_gst_india #2017-06-27 erpnext.patches.v8_1.setup_gst_india #2017-06-27
execute:frappe.reload_doc('regional', 'doctype', 'gst_hsn_code') execute:frappe.reload_doc('regional', 'doctype', 'gst_hsn_code')
erpnext.patches.v8_1.removed_roles_from_gst_report_non_indian_account erpnext.patches.v8_1.removed_roles_from_gst_report_non_indian_account
erpnext.patches.v8_1.gst_fixes

View File

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

View File

@ -634,5 +634,91 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
} }
this.calculate_outstanding_amount(false) 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>';
} }
}) })

View File

@ -374,6 +374,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
validate: function() { validate: function() {
this.calculate_taxes_and_totals(false); this.calculate_taxes_and_totals(false);
this.set_item_wise_tax_breakup();
}, },
company: function() { company: function() {
@ -936,69 +937,6 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
}); });
}, },
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() { validate_company_and_party: function() {
var me = this; var me = this;
var valid = true; var valid = true;
@ -1046,18 +984,6 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
} }
}, },
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() { is_recurring: function() {
// set default values for recurring documents // set default values for recurring documents
if(this.frm.doc.is_recurring && this.frm.doc.__islocal) { if(this.frm.doc.is_recurring && this.frm.doc.__islocal) {

View File

@ -2,7 +2,7 @@
{% if state %}{{ state }}<br>{% endif -%} {% if state %}{{ state }}<br>{% endif -%}
{% if pincode %}{{ pincode }}<br>{% endif -%} {% if pincode %}{{ pincode }}<br>{% endif -%}
{{ country }}<br> {{ country }}<br>
{% if gstin %}GSTIN: {{ gstin }}<br>{% endif -%}
{% if phone %}Phone: {{ phone }}<br>{% endif -%} {% if phone %}Phone: {{ phone }}<br>{% endif -%}
{% if fax %}Fax: {{ fax }}<br>{% endif -%} {% if fax %}Fax: {{ fax }}<br>{% endif -%}
{% if email_id %}Email: {{ email_id }}<br>{% endif -%} {% if email_id %}Email: {{ email_id }}<br>{% endif -%}
{% if gstin %}GSTIN: {{ gstin }}<br>{% endif -%}

View File

@ -14,6 +14,7 @@ def setup(company=None, patch=True):
add_custom_roles_for_reports() add_custom_roles_for_reports()
add_hsn_codes() add_hsn_codes()
update_address_template() update_address_template()
add_print_formats()
if not patch: if not patch:
make_fixtures() make_fixtures()
@ -69,6 +70,9 @@ def add_permissions():
add_permission(doctype, 'Accounts Manager', 0) add_permission(doctype, 'Accounts Manager', 0)
add_permission(doctype, 'All', 0) add_permission(doctype, 'All', 0)
def add_print_formats():
frappe.reload_doc("regional", "print_format", "gst_tax_invoice")
def make_custom_fields(): def make_custom_fields():
custom_fields = { custom_fields = {
'Address': [ 'Address': [
@ -80,39 +84,39 @@ def make_custom_fields():
'Purchase Invoice': [ 'Purchase Invoice': [
dict(fieldname='supplier_gstin', label='Supplier GSTIN', dict(fieldname='supplier_gstin', label='Supplier GSTIN',
fieldtype='Data', insert_after='supplier_address', fieldtype='Data', insert_after='supplier_address',
options='supplier_address.gstin'), options='supplier_address.gstin', print_hide=1),
dict(fieldname='company_gstin', label='Company GSTIN', dict(fieldname='company_gstin', label='Company GSTIN',
fieldtype='Data', insert_after='shipping_address', fieldtype='Data', insert_after='shipping_address',
options='shipping_address.gstin'), options='shipping_address.gstin', print_hide=1),
], ],
'Sales Invoice': [ 'Sales Invoice': [
dict(fieldname='customer_gstin', label='Customer GSTIN', dict(fieldname='customer_gstin', label='Customer GSTIN',
fieldtype='Data', insert_after='shipping_address', 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', dict(fieldname='company_gstin', label='Company GSTIN',
fieldtype='Data', insert_after='company_address', fieldtype='Data', insert_after='company_address',
options='company_address.gstin'), options='company_address.gstin', print_hide=1),
], ],
'Item': [ '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'), fieldtype='Link', options='GST HSN Code', insert_after='item_group'),
], ],
'Sales Invoice Item': [ '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', fieldtype='Data', options='item_code.gst_hsn_code',
insert_after='income_account'), insert_after='description'),
], ],
'Purchase Invoice Item': [ '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', fieldtype='Data', options='item_code.gst_hsn_code',
insert_after='expense_account'), insert_after='description'),
] ]
} }
for doctype, fields in custom_fields.items(): for doctype, fields in custom_fields.items():
for df in fields: for df in fields:
create_custom_field(doctype, df) create_custom_field(doctype, df)
def make_fixtures(): def make_fixtures():
docs = [ docs = [
{'doctype': 'Salary Component', 'salary_component': 'Professional Tax', 'description': 'Professional Tax', 'type': 'Deduction'}, {'doctype': 'Salary Component', 'salary_component': 'Professional Tax', 'description': 'Professional Tax', 'type': 'Deduction'},

View File

@ -16,7 +16,7 @@ def validate_gstin_for_india(doc, method):
if doc.state in states: if doc.state in states:
doc.gst_state = doc.state doc.gst_state = doc.state
if doc.gst_state: if doc.gst_state:
state_number = state_numbers[doc.gst_state] state_number = state_numbers[doc.gst_state]
if state_number != doc.gstin[:2]: if state_number != doc.gstin[:2]:
frappe.throw(_("First 2 digits of GSTIN should match with State number {0}").format(state_number)) frappe.throw(_("First 2 digits of GSTIN should match with State number {0}").format(state_number))

View File

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