feat: South Africa VAT report
This commit is contained in:
parent
1823f31f79
commit
1dfb5eb535
@ -0,0 +1,34 @@
|
||||
{
|
||||
"actions": [],
|
||||
"autoname": "account",
|
||||
"creation": "2021-07-08 22:04:24.634967",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"account"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"allow_in_quick_entry": 1,
|
||||
"fieldname": "account",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"in_preview": 1,
|
||||
"label": "Account",
|
||||
"options": "Account"
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2021-07-08 22:35:33.202911",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "South Africa VAT Account",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
# import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class SouthAfricaVATAccount(Document):
|
||||
pass
|
@ -0,0 +1,25 @@
|
||||
// Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('South Africa VAT Settings', {
|
||||
refresh: function(frm) {
|
||||
frm.set_query("company", function() {
|
||||
return {
|
||||
filters: {
|
||||
country: "South Africa",
|
||||
}
|
||||
}
|
||||
});
|
||||
frm.set_query("account", "vat_accounts", function(doc, cdt, cdn) {
|
||||
var row = locals[cdt][cdn];
|
||||
console.log(row);
|
||||
return {
|
||||
filters: {
|
||||
company: frm.doc.company,
|
||||
account_type: "Tax",
|
||||
is_group: 0
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
@ -0,0 +1,76 @@
|
||||
{
|
||||
"actions": [],
|
||||
"autoname": "field:company",
|
||||
"creation": "2021-07-08 22:34:33.668015",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"company",
|
||||
"vat_accounts"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "company",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Company",
|
||||
"options": "Company",
|
||||
"reqd": 1,
|
||||
"unique": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "vat_accounts",
|
||||
"fieldtype": "Table",
|
||||
"label": "VAT Accounts",
|
||||
"options": "South Africa VAT Account",
|
||||
"reqd": 1
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2021-07-14 02:17:52.476762",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Regional",
|
||||
"name": "South Africa VAT Settings",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts User",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Auditor",
|
||||
"share": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
# import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class SouthAfricaVATSettings(Document):
|
||||
pass
|
@ -0,0 +1,8 @@
|
||||
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
class TestSouthAfricaVATSettings(unittest.TestCase):
|
||||
pass
|
31
erpnext/regional/report/vat_audit_report/vat_audit_report.js
Normal file
31
erpnext/regional/report/vat_audit_report/vat_audit_report.js
Normal file
@ -0,0 +1,31 @@
|
||||
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
/* eslint-disable */
|
||||
|
||||
frappe.query_reports["VAT Audit Report"] = {
|
||||
"filters": [
|
||||
{
|
||||
"fieldname": "company",
|
||||
"label": __("Company"),
|
||||
"fieldtype": "Link",
|
||||
"options": "Company",
|
||||
"reqd": 1,
|
||||
"default": frappe.defaults.get_user_default("Company")
|
||||
},
|
||||
{
|
||||
"fieldname": "from_date",
|
||||
"label": __("From Date"),
|
||||
"fieldtype": "Date",
|
||||
"reqd": 1,
|
||||
"default": frappe.datetime.add_months(frappe.datetime.get_today(), -2),
|
||||
"width": "80"
|
||||
},
|
||||
{
|
||||
"fieldname": "to_date",
|
||||
"label": __("To Date"),
|
||||
"fieldtype": "Date",
|
||||
"reqd": 1,
|
||||
"default": frappe.datetime.get_today()
|
||||
}
|
||||
]
|
||||
};
|
@ -0,0 +1,32 @@
|
||||
{
|
||||
"add_total_row": 0,
|
||||
"columns": [],
|
||||
"creation": "2021-07-09 11:07:43.473518",
|
||||
"disable_prepared_report": 0,
|
||||
"disabled": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "Report",
|
||||
"filters": [],
|
||||
"idx": 0,
|
||||
"is_standard": "Yes",
|
||||
"modified": "2021-07-09 11:07:43.473518",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Regional",
|
||||
"name": "VAT Audit Report",
|
||||
"owner": "Administrator",
|
||||
"prepared_report": 0,
|
||||
"ref_doctype": "GL Entry",
|
||||
"report_name": "VAT Audit Report",
|
||||
"report_type": "Script Report",
|
||||
"roles": [
|
||||
{
|
||||
"role": "Accounts User"
|
||||
},
|
||||
{
|
||||
"role": "Accounts Manager"
|
||||
},
|
||||
{
|
||||
"role": "Auditor"
|
||||
}
|
||||
]
|
||||
}
|
246
erpnext/regional/report/vat_audit_report/vat_audit_report.py
Normal file
246
erpnext/regional/report/vat_audit_report/vat_audit_report.py
Normal file
@ -0,0 +1,246 @@
|
||||
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe, json
|
||||
from frappe import _
|
||||
from frappe.utils import flt, formatdate, now_datetime, getdate
|
||||
from datetime import date
|
||||
|
||||
def execute(filters=None):
|
||||
return VATAuditReport(filters).run()
|
||||
|
||||
class VATAuditReport(object):
|
||||
|
||||
def __init__(self, filters=None):
|
||||
self.filters = frappe._dict(filters or {})
|
||||
self.columns = []
|
||||
self.data = []
|
||||
self.doctypes = ["Purchase Invoice", "Sales Invoice"]
|
||||
|
||||
def run(self):
|
||||
self.get_sa_vat_accounts()
|
||||
for doctype in self.doctypes:
|
||||
self.get_columns(doctype)
|
||||
self.select_columns = """
|
||||
name as invoice_number,
|
||||
posting_date, remarks"""
|
||||
columns = ", supplier as party, credit_to as account" if doctype=="Purchase Invoice" \
|
||||
else ", customer as party, debit_to as account"
|
||||
self.select_columns += columns
|
||||
|
||||
self.get_invoice_data(doctype)
|
||||
|
||||
if self.invoices:
|
||||
self.get_invoice_items(doctype)
|
||||
self.get_items_based_on_tax_rate(doctype)
|
||||
self.get_data(doctype)
|
||||
|
||||
return self.columns, self.data
|
||||
|
||||
def get_sa_vat_accounts(self):
|
||||
self.sa_vat_accounts = frappe.get_list("South Africa VAT Account", \
|
||||
filters = {"parent":self.filters.company}, pluck="account")
|
||||
if not self.sa_vat_accounts and not frappe.flags.in_test and not frappe.flags.in_migrate:
|
||||
frappe.throw(_("Please set VAT Accounts in South Africa VAT Settings"))
|
||||
|
||||
def get_invoice_data(self,doctype):
|
||||
conditions = self.get_conditions()
|
||||
self.invoices = frappe._dict()
|
||||
|
||||
invoice_data = frappe.db.sql("""
|
||||
SELECT
|
||||
{select_columns}
|
||||
FROM
|
||||
`tab{doctype}`
|
||||
WHERE
|
||||
docstatus = 1 {where_conditions}
|
||||
and is_opening = 'No'
|
||||
ORDER BY
|
||||
posting_date DESC
|
||||
""".format(select_columns=self.select_columns, doctype=doctype,
|
||||
where_conditions=conditions), self.filters, as_dict=1)
|
||||
|
||||
for d in invoice_data:
|
||||
self.invoices.setdefault(d.invoice_number, d)
|
||||
|
||||
def get_invoice_items(self,doctype):
|
||||
self.invoice_items = frappe._dict()
|
||||
self.item_tax_rate = frappe._dict()
|
||||
|
||||
items = frappe.db.sql("""
|
||||
SELECT
|
||||
item_code, parent, taxable_value, base_net_amount, item_tax_rate
|
||||
FROM
|
||||
`tab%s Item`
|
||||
WHERE
|
||||
parent in (%s)
|
||||
""" % (doctype, ', '.join(['%s']*len(self.invoices))), tuple(self.invoices), as_dict=1)
|
||||
for d in items:
|
||||
if d.item_code not in self.invoice_items.get(d.parent, {}):
|
||||
self.invoice_items.setdefault(d.parent, {}).setdefault(d.item_code,
|
||||
sum((i.get('taxable_value', 0) or i.get('base_net_amount', 0)) for i in items
|
||||
if i.item_code == d.item_code and i.parent == d.parent))
|
||||
|
||||
def get_items_based_on_tax_rate(self,doctype):
|
||||
self.items_based_on_tax_rate = frappe._dict()
|
||||
self.tax_doctype = "Purchase Taxes and Charges" if doctype=="Purchase Invoice" \
|
||||
else "Sales Taxes and Charges"
|
||||
self.tax_details = frappe.db.sql("""
|
||||
SELECT
|
||||
parent, account_head, item_wise_tax_detail, base_tax_amount_after_discount_amount
|
||||
FROM
|
||||
`tab%s`
|
||||
WHERE
|
||||
parenttype = %s and docstatus = 1
|
||||
and parent in (%s)
|
||||
ORDER BY
|
||||
account_head
|
||||
""" % (self.tax_doctype, '%s', ', '.join(['%s']*len(self.invoices.keys()))),
|
||||
tuple([doctype] + list(self.invoices.keys())))
|
||||
|
||||
for parent, account, item_wise_tax_detail, tax_amount in self.tax_details:
|
||||
if item_wise_tax_detail:
|
||||
try:
|
||||
if account in self.sa_vat_accounts:
|
||||
item_wise_tax_detail = json.loads(item_wise_tax_detail)
|
||||
else:
|
||||
continue
|
||||
for item_code, taxes in item_wise_tax_detail.items():
|
||||
tax_rate, item_amount_map = self.get_item_amount_map(parent, item_code, taxes)
|
||||
|
||||
if tax_rate is not None:
|
||||
rate_based_dict = self.items_based_on_tax_rate.setdefault(parent, {}) \
|
||||
.setdefault(tax_rate, [])
|
||||
if item_code not in rate_based_dict:
|
||||
rate_based_dict.append(item_code)
|
||||
except ValueError:
|
||||
continue
|
||||
|
||||
def get_item_amount_map(self, parent, item_code, taxes):
|
||||
net_amount = abs(self.invoice_items.get(parent).get(item_code))
|
||||
tax_rate = taxes[0]
|
||||
tax_amount = taxes[1]
|
||||
gross_amount = net_amount + tax_amount
|
||||
item_amount_map = self.item_tax_rate.setdefault(parent, {}) \
|
||||
.setdefault(item_code, [])
|
||||
amount_dict = {
|
||||
"tax_rate": tax_rate,
|
||||
"gross_amount": gross_amount,
|
||||
"tax_amount": tax_amount,
|
||||
"net_amount": net_amount
|
||||
}
|
||||
item_amount_map.append(amount_dict)
|
||||
|
||||
return tax_rate, item_amount_map
|
||||
|
||||
def get_conditions(self):
|
||||
conditions = ""
|
||||
for opts in (("company", " and company=%(company)s"),
|
||||
("from_date", " and posting_date>=%(from_date)s"),
|
||||
("to_date", " and posting_date<=%(to_date)s")):
|
||||
if self.filters.get(opts[0]):
|
||||
conditions += opts[1]
|
||||
|
||||
return conditions
|
||||
|
||||
def get_data(self,doctype):
|
||||
consolidated_data = self.get_consolidated_data()
|
||||
section_name = _("Purchases ") if doctype == "Purchase Invoice" else _("Sales ")
|
||||
|
||||
for rate, section in consolidated_data.items():
|
||||
rate = int(rate)
|
||||
label = frappe.bold(_("Standard Rate ") + section_name + str(rate) + "%")
|
||||
section_head = {"posting_date": label }
|
||||
total_gross = total_tax = total_net = 0
|
||||
self.data.append(section_head)
|
||||
for row in section.get("data"):
|
||||
self.data.append(row)
|
||||
total_gross += row["gross_amount"]
|
||||
total_tax += row["tax_amount"]
|
||||
total_net += row["net_amount"]
|
||||
|
||||
total = {
|
||||
"posting_date": frappe.bold(_("Total")),
|
||||
"gross_amount": total_gross,
|
||||
"tax_amount": total_tax,
|
||||
"net_amount": total_net,
|
||||
"bold":1
|
||||
}
|
||||
self.data.append(total)
|
||||
self.data.append({})
|
||||
|
||||
def get_consolidated_data(self):
|
||||
consolidated_data_map={}
|
||||
for inv, inv_data in self.invoices.items():
|
||||
for rate, items in self.items_based_on_tax_rate.get(inv).items():
|
||||
consolidated_data_map.setdefault(rate, {"data": []})
|
||||
for item in items:
|
||||
row = {}
|
||||
item_details = self.item_tax_rate.get(inv).get(item)
|
||||
row["account"] = inv_data.get("account")
|
||||
row["posting_date"] = formatdate(inv_data.get("posting_date"), 'dd-mm-yyyy')
|
||||
row["invoice_number"] = inv
|
||||
row["party"] = inv_data.get("party")
|
||||
row["remarks"] = inv_data.get("remarks")
|
||||
row["gross_amount"]= item_details[0].get("gross_amount")
|
||||
row["tax_amount"]= item_details[0].get("tax_amount")
|
||||
row["net_amount"]= item_details[0].get("net_amount")
|
||||
consolidated_data_map[rate]["data"].append(row)
|
||||
|
||||
return consolidated_data_map
|
||||
|
||||
def get_columns(self,doctype):
|
||||
self.columns = [
|
||||
{
|
||||
"fieldname": "posting_date",
|
||||
"label": "Posting Date",
|
||||
"fieldtype": "Data",
|
||||
"width": 200
|
||||
},
|
||||
{
|
||||
"fieldname": "account",
|
||||
"label": "Account",
|
||||
"fieldtype": "Link",
|
||||
"options": "Account",
|
||||
"width": 140
|
||||
},
|
||||
{
|
||||
"fieldname": "invoice_number",
|
||||
"label": "Reference",
|
||||
"fieldtype": "Link",
|
||||
"options": doctype,
|
||||
"width": 140
|
||||
},
|
||||
{
|
||||
"fieldname": "party",
|
||||
"label": "Party",
|
||||
"fieldtype": "Link",
|
||||
"options": "Supplier" if doctype == "Purchase Invoice" else "Customer",
|
||||
"width": 140
|
||||
},
|
||||
{
|
||||
"fieldname": "remarks",
|
||||
"label": "Details",
|
||||
"fieldtype": "Data",
|
||||
"width": 140
|
||||
},
|
||||
{
|
||||
"fieldname": "net_amount",
|
||||
"label": "Net Amount",
|
||||
"fieldtype": "Currency",
|
||||
"width": 140
|
||||
},
|
||||
{
|
||||
"fieldname": "tax_amount",
|
||||
"label": "Tax Amount",
|
||||
"fieldtype": "Currency",
|
||||
"width": 140
|
||||
},
|
||||
{
|
||||
"fieldname": "gross_amount",
|
||||
"label": "Gross Amount",
|
||||
"fieldtype": "Currency",
|
||||
"width": 140
|
||||
},
|
||||
]
|
0
erpnext/regional/south_africa/__init__.py
Normal file
0
erpnext/regional/south_africa/__init__.py
Normal file
19
erpnext/regional/south_africa/setup.py
Normal file
19
erpnext/regional/south_africa/setup.py
Normal file
@ -0,0 +1,19 @@
|
||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import frappe, os, json
|
||||
from frappe.permissions import add_permission, update_permission_property
|
||||
|
||||
def setup():
|
||||
add_permissions()
|
||||
|
||||
def add_permissions():
|
||||
"""Add Permissions for South Africa VAT Settings and South Africa VAT Account"""
|
||||
for doctype in ('South Africa VAT Settings', 'South Africa VAT Account'):
|
||||
add_permission(doctype, 'All', 0)
|
||||
for role in ('Accounts Manager', 'Accounts User', 'System Manager'):
|
||||
add_permission(doctype, role, 0)
|
||||
update_permission_property(doctype, role, 0, 'write', 1)
|
||||
update_permission_property(doctype, role, 0, 'create', 1)
|
Loading…
Reference in New Issue
Block a user