From 9cc451fc7dbffd487316a3407d2eef1eee105d5d Mon Sep 17 00:00:00 2001 From: Ahmad Date: Thu, 26 Aug 2021 07:35:59 +0500 Subject: [PATCH 01/16] feat(Regional): KSA VAT Report --- .../workspace/accounting/accounting.json | 23 ++- .../ksa_vat_purchase_account/__init__.py | 0 .../ksa_vat_purchase_account.json | 49 +++++ .../ksa_vat_purchase_account.py | 8 + .../doctype/ksa_vat_sales_account/__init__.py | 0 .../ksa_vat_sales_account.js | 8 + .../ksa_vat_sales_account.json | 49 +++++ .../ksa_vat_sales_account.py | 8 + .../test_ksa_vat_sales_account.py | 8 + .../doctype/ksa_vat_setting/__init__.py | 0 .../ksa_vat_setting/ksa_vat_setting.js | 8 + .../ksa_vat_setting/ksa_vat_setting.json | 49 +++++ .../ksa_vat_setting/ksa_vat_setting.py | 8 + .../ksa_vat_setting/ksa_vat_setting_list.js | 5 + .../ksa_vat_setting/test_ksa_vat_setting.py | 8 + erpnext/regional/report/ksa_vat/__init__.py | 0 erpnext/regional/report/ksa_vat/ksa_vat.js | 60 ++++++ erpnext/regional/report/ksa_vat/ksa_vat.json | 32 ++++ erpnext/regional/report/ksa_vat/ksa_vat.py | 177 ++++++++++++++++++ erpnext/regional/saudi_arabia/setup.py | 17 ++ .../regional/saudi_arabia/wizard/__init__.py | 0 .../saudi_arabia/wizard/data/__init__.py | 0 .../wizard/data/ksa_vat_settings.json | 47 +++++ .../wizard/operations/__init__.py | 0 .../operations/setup_ksa_vat_setting.py | 45 +++++ 25 files changed, 608 insertions(+), 1 deletion(-) create mode 100644 erpnext/regional/doctype/ksa_vat_purchase_account/__init__.py create mode 100644 erpnext/regional/doctype/ksa_vat_purchase_account/ksa_vat_purchase_account.json create mode 100644 erpnext/regional/doctype/ksa_vat_purchase_account/ksa_vat_purchase_account.py create mode 100644 erpnext/regional/doctype/ksa_vat_sales_account/__init__.py create mode 100644 erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.js create mode 100644 erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.json create mode 100644 erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.py create mode 100644 erpnext/regional/doctype/ksa_vat_sales_account/test_ksa_vat_sales_account.py create mode 100644 erpnext/regional/doctype/ksa_vat_setting/__init__.py create mode 100644 erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.js create mode 100644 erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.json create mode 100644 erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.py create mode 100644 erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting_list.js create mode 100644 erpnext/regional/doctype/ksa_vat_setting/test_ksa_vat_setting.py create mode 100644 erpnext/regional/report/ksa_vat/__init__.py create mode 100644 erpnext/regional/report/ksa_vat/ksa_vat.js create mode 100644 erpnext/regional/report/ksa_vat/ksa_vat.json create mode 100644 erpnext/regional/report/ksa_vat/ksa_vat.py create mode 100644 erpnext/regional/saudi_arabia/wizard/__init__.py create mode 100644 erpnext/regional/saudi_arabia/wizard/data/__init__.py create mode 100644 erpnext/regional/saudi_arabia/wizard/data/ksa_vat_settings.json create mode 100644 erpnext/regional/saudi_arabia/wizard/operations/__init__.py create mode 100644 erpnext/regional/saudi_arabia/wizard/operations/setup_ksa_vat_setting.py diff --git a/erpnext/accounts/workspace/accounting/accounting.json b/erpnext/accounts/workspace/accounting/accounting.json index b5bd14d137..1ee5914d77 100644 --- a/erpnext/accounts/workspace/accounting/accounting.json +++ b/erpnext/accounts/workspace/accounting/accounting.json @@ -515,6 +515,17 @@ "only_for": "United Arab Emirates", "type": "Link" }, + { + "dependencies": "GL Entry", + "hidden": 0, + "is_query_report": 1, + "label": "KSA VAT Report", + "link_to": "KSA VAT", + "link_type": "Report", + "onboard": 0, + "only_for": "Saudi Arabia", + "type": "Link" + }, { "hidden": 0, "is_query_report": 0, @@ -1135,6 +1146,16 @@ "onboard": 0, "type": "Link" }, + { + "hidden": 0, + "is_query_report": 0, + "label": "KSA VAT Setting", + "link_to": "KSA VAT Setting", + "link_type": "DocType", + "onboard": 0, + "only_for": "Saudi Arabia", + "type": "Link" + }, { "hidden": 0, "is_query_report": 0, @@ -1188,7 +1209,7 @@ "type": "Link" } ], - "modified": "2021-08-05 12:15:52.872470", + "modified": "2021-08-26 13:15:52.872470", "modified_by": "Administrator", "module": "Accounts", "name": "Accounting", diff --git a/erpnext/regional/doctype/ksa_vat_purchase_account/__init__.py b/erpnext/regional/doctype/ksa_vat_purchase_account/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/regional/doctype/ksa_vat_purchase_account/ksa_vat_purchase_account.json b/erpnext/regional/doctype/ksa_vat_purchase_account/ksa_vat_purchase_account.json new file mode 100644 index 0000000000..89ba3e977a --- /dev/null +++ b/erpnext/regional/doctype/ksa_vat_purchase_account/ksa_vat_purchase_account.json @@ -0,0 +1,49 @@ +{ + "actions": [], + "creation": "2021-07-13 09:17:09.862163", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "title", + "item_tax_template", + "account" + ], + "fields": [ + { + "fieldname": "account", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Account", + "options": "Account", + "reqd": 1 + }, + { + "fieldname": "title", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Title", + "reqd": 1 + }, + { + "fieldname": "item_tax_template", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Item Tax Template", + "options": "Item Tax Template", + "reqd": 1 + } + ], + "index_web_pages_for_search": 1, + "istable": 1, + "links": [], + "modified": "2021-08-04 06:42:38.205597", + "modified_by": "Administrator", + "module": "Regional", + "name": "KSA VAT Purchase Account", + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1 +} \ No newline at end of file diff --git a/erpnext/regional/doctype/ksa_vat_purchase_account/ksa_vat_purchase_account.py b/erpnext/regional/doctype/ksa_vat_purchase_account/ksa_vat_purchase_account.py new file mode 100644 index 0000000000..1302e314c3 --- /dev/null +++ b/erpnext/regional/doctype/ksa_vat_purchase_account/ksa_vat_purchase_account.py @@ -0,0 +1,8 @@ +# Copyright (c) 2021, Havenir Solutions and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + +class KSAVATPurchaseAccount(Document): + pass diff --git a/erpnext/regional/doctype/ksa_vat_sales_account/__init__.py b/erpnext/regional/doctype/ksa_vat_sales_account/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.js b/erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.js new file mode 100644 index 0000000000..72613f4064 --- /dev/null +++ b/erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.js @@ -0,0 +1,8 @@ +// Copyright (c) 2021, Havenir Solutions and contributors +// For license information, please see license.txt + +frappe.ui.form.on('KSA VAT Sales Account', { + // refresh: function(frm) { + + // } +}); diff --git a/erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.json b/erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.json new file mode 100644 index 0000000000..df2747891d --- /dev/null +++ b/erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.json @@ -0,0 +1,49 @@ +{ + "actions": [], + "creation": "2021-07-13 08:46:33.820968", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "title", + "item_tax_template", + "account" + ], + "fields": [ + { + "fieldname": "account", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Account", + "options": "Account", + "reqd": 1 + }, + { + "fieldname": "title", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Title", + "reqd": 1 + }, + { + "fieldname": "item_tax_template", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Item Tax Template", + "options": "Item Tax Template", + "reqd": 1 + } + ], + "index_web_pages_for_search": 1, + "istable": 1, + "links": [], + "modified": "2021-08-04 06:42:00.081407", + "modified_by": "Administrator", + "module": "Regional", + "name": "KSA VAT Sales Account", + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1 +} \ No newline at end of file diff --git a/erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.py b/erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.py new file mode 100644 index 0000000000..8e437f832b --- /dev/null +++ b/erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.py @@ -0,0 +1,8 @@ +# Copyright (c) 2021, Havenir Solutions and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + +class KSAVATSalesAccount(Document): + pass diff --git a/erpnext/regional/doctype/ksa_vat_sales_account/test_ksa_vat_sales_account.py b/erpnext/regional/doctype/ksa_vat_sales_account/test_ksa_vat_sales_account.py new file mode 100644 index 0000000000..d7f911343b --- /dev/null +++ b/erpnext/regional/doctype/ksa_vat_sales_account/test_ksa_vat_sales_account.py @@ -0,0 +1,8 @@ +# Copyright (c) 2021, Havenir Solutions and Contributors +# See license.txt + +# import frappe +import unittest + +class TestKSAVATSalesAccount(unittest.TestCase): + pass diff --git a/erpnext/regional/doctype/ksa_vat_setting/__init__.py b/erpnext/regional/doctype/ksa_vat_setting/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.js b/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.js new file mode 100644 index 0000000000..0238c7b306 --- /dev/null +++ b/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.js @@ -0,0 +1,8 @@ +// Copyright (c) 2021, Havenir Solutions and contributors +// For license information, please see license.txt + +frappe.ui.form.on('KSA VAT Setting', { + onload: function(frm) { + frappe.breadcrumbs.add('Accounts', 'KSA VAT Setting'); + } +}); diff --git a/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.json b/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.json new file mode 100644 index 0000000000..33619467ed --- /dev/null +++ b/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.json @@ -0,0 +1,49 @@ +{ + "actions": [], + "autoname": "field:company", + "creation": "2021-07-13 08:49:01.100356", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "company", + "ksa_vat_sales_accounts", + "ksa_vat_purchase_accounts" + ], + "fields": [ + { + "fieldname": "company", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Company", + "options": "Company", + "reqd": 1, + "unique": 1 + }, + { + "fieldname": "ksa_vat_sales_accounts", + "fieldtype": "Table", + "label": "KSA VAT Sales Accounts", + "options": "KSA VAT Sales Account", + "reqd": 1 + }, + { + "fieldname": "ksa_vat_purchase_accounts", + "fieldtype": "Table", + "label": "KSA VAT Purchase Accounts", + "options": "KSA VAT Purchase Account", + "reqd": 1 + } + ], + "links": [], + "modified": "2021-08-26 04:29:06.499378", + "modified_by": "Administrator", + "module": "Regional", + "name": "KSA VAT Setting", + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC", + "title_field": "company", + "track_changes": 1 +} \ No newline at end of file diff --git a/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.py b/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.py new file mode 100644 index 0000000000..6db6f9cc59 --- /dev/null +++ b/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.py @@ -0,0 +1,8 @@ +# Copyright (c) 2021, Havenir Solutions and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + +class KSAVATSetting(Document): + pass diff --git a/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting_list.js b/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting_list.js new file mode 100644 index 0000000000..23d28b9e68 --- /dev/null +++ b/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting_list.js @@ -0,0 +1,5 @@ +frappe.listview_settings['KSA VAT Setting'] = { + onload(list) { + frappe.breadcrumbs.add('Accounts'); + } +} \ No newline at end of file diff --git a/erpnext/regional/doctype/ksa_vat_setting/test_ksa_vat_setting.py b/erpnext/regional/doctype/ksa_vat_setting/test_ksa_vat_setting.py new file mode 100644 index 0000000000..ae2defc61d --- /dev/null +++ b/erpnext/regional/doctype/ksa_vat_setting/test_ksa_vat_setting.py @@ -0,0 +1,8 @@ +# Copyright (c) 2021, Havenir Solutions and Contributors +# See license.txt + +# import frappe +import unittest + +class TestKSAVATSetting(unittest.TestCase): + pass diff --git a/erpnext/regional/report/ksa_vat/__init__.py b/erpnext/regional/report/ksa_vat/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/regional/report/ksa_vat/ksa_vat.js b/erpnext/regional/report/ksa_vat/ksa_vat.js new file mode 100644 index 0000000000..5dd9c92bf7 --- /dev/null +++ b/erpnext/regional/report/ksa_vat/ksa_vat.js @@ -0,0 +1,60 @@ +// Copyright (c) 2016, Havenir Solutions and contributors +// For license information, please see license.txt +/* eslint-disable */ + +frappe.query_reports["KSA VAT"] = { + onload() { + frappe.breadcrumbs.add('Accounts'); + }, + "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(), -1), + }, + { + "fieldname": "to_date", + "label": __("To Date"), + "fieldtype": "Date", + "reqd": 1, + "default": frappe.datetime.get_today() + } + ], + "formatter": function(value, row, column, data, default_formatter) { + if (data + && (data.title=='VAT on Sales' || data.title=='VAT on Purchases') + && data.title==value) { + value = $(`${value}`); + var $value = $(value).css("font-weight", "bold"); + value = $value.wrap("

").parent().html(); + return value + }else if (data.title=='Grand Total'){ + if (data.title==value) { + value = $(`${value}`); + var $value = $(value).css("font-weight", "bold"); + value = $value.wrap("

").parent().html(); + return value + }else{ + value = default_formatter(value, row, column, data); + value = $(`${value}`); + var $value = $(value).css("font-weight", "bold"); + value = $value.wrap("

").parent().html(); + console.log($value) + return value + } + }else{ + value = default_formatter(value, row, column, data); + return value; + } + }, +}; diff --git a/erpnext/regional/report/ksa_vat/ksa_vat.json b/erpnext/regional/report/ksa_vat/ksa_vat.json new file mode 100644 index 0000000000..036e260310 --- /dev/null +++ b/erpnext/regional/report/ksa_vat/ksa_vat.json @@ -0,0 +1,32 @@ +{ + "add_total_row": 0, + "columns": [], + "creation": "2021-07-13 08:54:38.000949", + "disable_prepared_report": 1, + "disabled": 1, + "docstatus": 0, + "doctype": "Report", + "filters": [], + "idx": 0, + "is_standard": "Yes", + "modified": "2021-08-26 04:14:37.202594", + "modified_by": "Administrator", + "module": "Regional", + "name": "KSA VAT", + "owner": "Administrator", + "prepared_report": 1, + "ref_doctype": "GL Entry", + "report_name": "KSA VAT", + "report_type": "Script Report", + "roles": [ + { + "role": "System Manager" + }, + { + "role": "Accounts Manager" + }, + { + "role": "Accounts User" + } + ] +} \ No newline at end of file diff --git a/erpnext/regional/report/ksa_vat/ksa_vat.py b/erpnext/regional/report/ksa_vat/ksa_vat.py new file mode 100644 index 0000000000..6828007203 --- /dev/null +++ b/erpnext/regional/report/ksa_vat/ksa_vat.py @@ -0,0 +1,177 @@ +# Copyright (c) 2013, Havenir Solutions and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +import frappe +from frappe import _ +from frappe.utils import get_url_to_list +from erpnext.controllers.taxes_and_totals import get_itemised_tax_breakup_data, get_rounded_tax_amount +import json + +def execute(filters=None): + columns = columns = get_columns() + data = get_data(filters) + return columns, data + +def get_columns(): + return [ + { + "fieldname": "title", + "label": _("Title"), + "fieldtype": "Data", + "width": 300 + }, + { + "fieldname": "amount", + "label": _("Amount (SAR)"), + "fieldtype": "Currency", + "width": 150, + }, + { + "fieldname": "adjustment_amount", + "label": _("Adjustment (SAR)"), + "fieldtype": "Currency", + "width": 150, + }, + { + "fieldname": "vat_amount", + "label": _("VAT Amount (SAR)"), + "fieldtype": "Currency", + "width": 150, + } + ] + +def get_data(filters): + data = [] + + # Validate if vat settings exist + company = filters.get('company') + if frappe.db.exists('KSA VAT Setting', company) is None: + url = get_url_to_list('KSA VAT Setting') + frappe.msgprint(f'Create KSA VAT Setting for this company') + return data + + ksa_vat_setting = frappe.get_doc('KSA VAT Setting', company) + + # Sales Heading + append_data(data, 'VAT on Sales', '', '', '') + + grand_total_taxable_amount = 0 + grand_total_taxable_adjustment_amount = 0 + grand_total_tax = 0 + + for vat_setting in ksa_vat_setting.ksa_vat_sales_accounts: + total_taxable_amount, total_taxable_adjustment_amount, \ + total_tax = get_tax_data_for_each_vat_setting(vat_setting, filters, 'Sales Invoice') + + # Adding results to data + append_data(data, vat_setting.title, total_taxable_amount, + total_taxable_adjustment_amount, total_tax) + + grand_total_taxable_amount += total_taxable_amount + grand_total_taxable_adjustment_amount += total_taxable_adjustment_amount + grand_total_tax += total_tax + + # Sales Grand Total + append_data(data, 'Grand Total', grand_total_taxable_amount, + grand_total_taxable_adjustment_amount, grand_total_tax ) + + # Blank Line + append_data(data, '', '', '', '') + + # Purchase Heading + append_data(data, 'VAT on Purchases', '', '', '') + + grand_total_taxable_amount = 0 + grand_total_taxable_adjustment_amount = 0 + grand_total_tax = 0 + + for vat_setting in ksa_vat_setting.ksa_vat_purchase_accounts: + total_taxable_amount, total_taxable_adjustment_amount, \ + total_tax = get_tax_data_for_each_vat_setting(vat_setting, filters, 'Purchase Invoice') + + # Adding results to data + append_data(data, vat_setting.title, total_taxable_amount, + total_taxable_adjustment_amount, total_tax) + + grand_total_taxable_amount += total_taxable_amount + grand_total_taxable_adjustment_amount += total_taxable_adjustment_amount + grand_total_tax += total_tax + + # Purchase Grand Total + append_data(data, 'Grand Total', grand_total_taxable_amount, + grand_total_taxable_adjustment_amount, grand_total_tax ) + + return data + +def get_tax_data_for_each_vat_setting(vat_setting, filters, doctype): + ''' + (KSA, {filters}, 'Sales Invoice') => 500, 153, 10 \n + calculates and returns \n + total_taxable_amount, total_taxable_adjustment_amount, total_tax''' + from_date = filters.get('from_date') + to_date = filters.get('to_date') + + # Initiate variables + total_taxable_amount = 0 + total_taxable_adjustment_amount = 0 + total_tax = 0 + # Fetch All Invoices + invoices = frappe.get_list(doctype, + filters ={ + 'docstatus': 1, + 'posting_date': ['between', [from_date, to_date]] + }, + fields =['name', 'is_return']) + + for invoice in invoices: + invoice_items = frappe.get_list(f'{doctype} Item', + filters ={ + 'docstatus': 1, + 'parent': invoice.name, + 'item_tax_template': vat_setting.item_tax_template + }, + fields =['item_code', 'net_amount']) + + + for item in invoice_items: + # Summing up total taxable amount + if invoice.is_return == 0: + total_taxable_amount += item.net_amount + + if invoice.is_return == 1: + total_taxable_adjustment_amount += item.net_amount + + # Summing up total tax + total_tax += get_tax_amount(item.item_code, vat_setting.account, doctype, invoice.name) + + return total_taxable_amount, total_taxable_adjustment_amount, total_tax + + + +def append_data(data, title, amount, adjustment_amount, vat_amount): + """Returns data with appended value.""" + data.append({"title":title, "amount": amount, "adjustment_amount": adjustment_amount, "vat_amount": vat_amount}) + +def get_tax_amount(item_code, account_head, doctype, parent): + if doctype == 'Sales Invoice': + tax_doctype = 'Sales Taxes and Charges' + + elif doctype == 'Purchase Invoice': + tax_doctype = 'Purchase Taxes and Charges' + + item_wise_tax_detail = frappe.get_value(tax_doctype, { + 'docstatus': 1, + 'parent': parent, + 'account_head': account_head + }, 'item_wise_tax_detail') + + tax_amount = 0 + if item_wise_tax_detail and len(item_wise_tax_detail) > 0: + item_wise_tax_detail = json.loads(item_wise_tax_detail) + for key, value in item_wise_tax_detail.items(): + if key == item_code: + tax_amount = value[1] + break + + return tax_amount \ No newline at end of file diff --git a/erpnext/regional/saudi_arabia/setup.py b/erpnext/regional/saudi_arabia/setup.py index 9b3677d2c6..053496729f 100644 --- a/erpnext/regional/saudi_arabia/setup.py +++ b/erpnext/regional/saudi_arabia/setup.py @@ -3,9 +3,26 @@ from __future__ import unicode_literals +import frappe +from frappe.permissions import add_permission, update_permission_property from erpnext.regional.united_arab_emirates.setup import make_custom_fields, add_print_formats +from erpnext.regional.saudi_arabia.wizard.operations.setup_ksa_vat_setting import create_ksa_vat_setting def setup(company=None, patch=True): make_custom_fields() add_print_formats() + add_permissions() + create_ksa_vat_setting(company) + + +def add_permissions(): + """Add Permissions for KSA VAT Setting.""" + add_permission('KSA VAT Setting', 'All', 0) + for role in ('Accounts Manager', 'Accounts User', 'System Manager'): + add_permission('KSA VAT Setting', role, 0) + update_permission_property('KSA VAT Setting', role, 0, 'write', 1) + update_permission_property('KSA VAT Setting', role, 0, 'create', 1) + + """Enable KSA VAT Report""" + frappe.db.set_value('Report', 'KSA VAT', 'disabled', 0) diff --git a/erpnext/regional/saudi_arabia/wizard/__init__.py b/erpnext/regional/saudi_arabia/wizard/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/regional/saudi_arabia/wizard/data/__init__.py b/erpnext/regional/saudi_arabia/wizard/data/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/regional/saudi_arabia/wizard/data/ksa_vat_settings.json b/erpnext/regional/saudi_arabia/wizard/data/ksa_vat_settings.json new file mode 100644 index 0000000000..709d65be04 --- /dev/null +++ b/erpnext/regional/saudi_arabia/wizard/data/ksa_vat_settings.json @@ -0,0 +1,47 @@ +[ + { + "type": "Sales Account", + "accounts": [ + { + "title": "Standard rated Sales", + "item_tax_template": "KSA VAT 5%", + "account": "VAT 5%" + }, + { + "title": "Zero rated domestic sales", + "item_tax_template": "KSA VAT Zero", + "account": "VAT Zero" + }, + { + "title": "Exempted sales", + "item_tax_template": "KSA VAT Exempted", + "account": "VAT Zero" + } + ] + }, + { + "type": "Purchase Account", + "accounts": [ + { + "title": "Standard rated domestic purchases", + "item_tax_template": "KSA VAT 5%", + "account": "VAT 5%" + }, + { + "title": "Imports subject to VAT paid at customs", + "item_tax_template": "KSA Excise 50%", + "account": "Excise 50%" + }, + { + "title": "Zero rated purchases", + "item_tax_template": "KSA VAT Zero", + "account": "VAT Zero" + }, + { + "title": "Exempted purchases", + "item_tax_template": "KSA VAT Exempted", + "account": "VAT Zero" + } + ] + } +] \ No newline at end of file diff --git a/erpnext/regional/saudi_arabia/wizard/operations/__init__.py b/erpnext/regional/saudi_arabia/wizard/operations/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/regional/saudi_arabia/wizard/operations/setup_ksa_vat_setting.py b/erpnext/regional/saudi_arabia/wizard/operations/setup_ksa_vat_setting.py new file mode 100644 index 0000000000..4bccdc35bf --- /dev/null +++ b/erpnext/regional/saudi_arabia/wizard/operations/setup_ksa_vat_setting.py @@ -0,0 +1,45 @@ +import frappe +import os +import json +from erpnext.setup.setup_wizard.operations.taxes_setup import setup_taxes_and_charges + +def create_ksa_vat_setting(company): + """ + On creation of first company. Creates KSA VAT Setting""" + + company = frappe.get_doc('Company', company) + setup_taxes_and_charges(company.name, company.country) + + file_path = os.path.join(os.path.dirname(__file__), '..', 'data', 'ksa_vat_settings.json') + with open(file_path, 'r') as json_file: + account_data = json.load(json_file) + + + # Creating KSA VAT Setting + ksa_vat_setting = frappe.get_doc({ + 'doctype': 'KSA VAT Setting', + 'company': company.name + }) + + for data in account_data: + if data['type'] == 'Sales Account': + for row in data['accounts']: + item_tax_template = row['item_tax_template'] + account = row['account'] + ksa_vat_setting.append('ksa_vat_sales_accounts', { + 'title': row['title'], + 'item_tax_template': f'{item_tax_template} - {company.abbr}', + 'account': f'{account} - {company.abbr}' + }) + + elif data['type'] == 'Purchase Account': + for row in data['accounts']: + item_tax_template = row['item_tax_template'] + account = row['account'] + ksa_vat_setting.append('ksa_vat_purchase_accounts', { + 'title': row['title'], + 'item_tax_template': f'{item_tax_template} - {company.abbr}', + 'account': f'{account} - {company.abbr}' + }) + + ksa_vat_setting.save() \ No newline at end of file From cb0c2d1477795566ca8bf5b03ed355791511b654 Mon Sep 17 00:00:00 2001 From: Ahmad Date: Thu, 26 Aug 2021 07:35:59 +0500 Subject: [PATCH 02/16] feat(Regional): KSA VAT Report --- .../workspace/accounting/accounting.json | 21 +++ .../ksa_vat_purchase_account/__init__.py | 0 .../ksa_vat_purchase_account.json | 49 +++++ .../ksa_vat_purchase_account.py | 8 + .../doctype/ksa_vat_sales_account/__init__.py | 0 .../ksa_vat_sales_account.js | 8 + .../ksa_vat_sales_account.json | 49 +++++ .../ksa_vat_sales_account.py | 8 + .../test_ksa_vat_sales_account.py | 8 + .../doctype/ksa_vat_setting/__init__.py | 0 .../ksa_vat_setting/ksa_vat_setting.js | 8 + .../ksa_vat_setting/ksa_vat_setting.json | 49 +++++ .../ksa_vat_setting/ksa_vat_setting.py | 8 + .../ksa_vat_setting/ksa_vat_setting_list.js | 5 + .../ksa_vat_setting/test_ksa_vat_setting.py | 8 + erpnext/regional/report/ksa_vat/__init__.py | 0 erpnext/regional/report/ksa_vat/ksa_vat.js | 60 ++++++ erpnext/regional/report/ksa_vat/ksa_vat.json | 32 ++++ erpnext/regional/report/ksa_vat/ksa_vat.py | 177 ++++++++++++++++++ erpnext/regional/saudi_arabia/setup.py | 17 ++ .../regional/saudi_arabia/wizard/__init__.py | 0 .../saudi_arabia/wizard/data/__init__.py | 0 .../wizard/data/ksa_vat_settings.json | 47 +++++ .../wizard/operations/__init__.py | 0 .../operations/setup_ksa_vat_setting.py | 45 +++++ 25 files changed, 607 insertions(+) create mode 100644 erpnext/regional/doctype/ksa_vat_purchase_account/__init__.py create mode 100644 erpnext/regional/doctype/ksa_vat_purchase_account/ksa_vat_purchase_account.json create mode 100644 erpnext/regional/doctype/ksa_vat_purchase_account/ksa_vat_purchase_account.py create mode 100644 erpnext/regional/doctype/ksa_vat_sales_account/__init__.py create mode 100644 erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.js create mode 100644 erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.json create mode 100644 erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.py create mode 100644 erpnext/regional/doctype/ksa_vat_sales_account/test_ksa_vat_sales_account.py create mode 100644 erpnext/regional/doctype/ksa_vat_setting/__init__.py create mode 100644 erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.js create mode 100644 erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.json create mode 100644 erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.py create mode 100644 erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting_list.js create mode 100644 erpnext/regional/doctype/ksa_vat_setting/test_ksa_vat_setting.py create mode 100644 erpnext/regional/report/ksa_vat/__init__.py create mode 100644 erpnext/regional/report/ksa_vat/ksa_vat.js create mode 100644 erpnext/regional/report/ksa_vat/ksa_vat.json create mode 100644 erpnext/regional/report/ksa_vat/ksa_vat.py create mode 100644 erpnext/regional/saudi_arabia/wizard/__init__.py create mode 100644 erpnext/regional/saudi_arabia/wizard/data/__init__.py create mode 100644 erpnext/regional/saudi_arabia/wizard/data/ksa_vat_settings.json create mode 100644 erpnext/regional/saudi_arabia/wizard/operations/__init__.py create mode 100644 erpnext/regional/saudi_arabia/wizard/operations/setup_ksa_vat_setting.py diff --git a/erpnext/accounts/workspace/accounting/accounting.json b/erpnext/accounts/workspace/accounting/accounting.json index 2b26ac5090..e7210f19ff 100644 --- a/erpnext/accounts/workspace/accounting/accounting.json +++ b/erpnext/accounts/workspace/accounting/accounting.json @@ -533,6 +533,17 @@ "only_for": "United Arab Emirates", "type": "Link" }, + { + "dependencies": "GL Entry", + "hidden": 0, + "is_query_report": 1, + "label": "KSA VAT Report", + "link_to": "KSA VAT", + "link_type": "Report", + "onboard": 0, + "only_for": "Saudi Arabia", + "type": "Link" + }, { "hidden": 0, "is_query_report": 0, @@ -1153,6 +1164,16 @@ "onboard": 0, "type": "Link" }, + { + "hidden": 0, + "is_query_report": 0, + "label": "KSA VAT Setting", + "link_to": "KSA VAT Setting", + "link_type": "DocType", + "onboard": 0, + "only_for": "Saudi Arabia", + "type": "Link" + }, { "hidden": 0, "is_query_report": 0, diff --git a/erpnext/regional/doctype/ksa_vat_purchase_account/__init__.py b/erpnext/regional/doctype/ksa_vat_purchase_account/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/regional/doctype/ksa_vat_purchase_account/ksa_vat_purchase_account.json b/erpnext/regional/doctype/ksa_vat_purchase_account/ksa_vat_purchase_account.json new file mode 100644 index 0000000000..89ba3e977a --- /dev/null +++ b/erpnext/regional/doctype/ksa_vat_purchase_account/ksa_vat_purchase_account.json @@ -0,0 +1,49 @@ +{ + "actions": [], + "creation": "2021-07-13 09:17:09.862163", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "title", + "item_tax_template", + "account" + ], + "fields": [ + { + "fieldname": "account", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Account", + "options": "Account", + "reqd": 1 + }, + { + "fieldname": "title", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Title", + "reqd": 1 + }, + { + "fieldname": "item_tax_template", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Item Tax Template", + "options": "Item Tax Template", + "reqd": 1 + } + ], + "index_web_pages_for_search": 1, + "istable": 1, + "links": [], + "modified": "2021-08-04 06:42:38.205597", + "modified_by": "Administrator", + "module": "Regional", + "name": "KSA VAT Purchase Account", + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1 +} \ No newline at end of file diff --git a/erpnext/regional/doctype/ksa_vat_purchase_account/ksa_vat_purchase_account.py b/erpnext/regional/doctype/ksa_vat_purchase_account/ksa_vat_purchase_account.py new file mode 100644 index 0000000000..1302e314c3 --- /dev/null +++ b/erpnext/regional/doctype/ksa_vat_purchase_account/ksa_vat_purchase_account.py @@ -0,0 +1,8 @@ +# Copyright (c) 2021, Havenir Solutions and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + +class KSAVATPurchaseAccount(Document): + pass diff --git a/erpnext/regional/doctype/ksa_vat_sales_account/__init__.py b/erpnext/regional/doctype/ksa_vat_sales_account/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.js b/erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.js new file mode 100644 index 0000000000..72613f4064 --- /dev/null +++ b/erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.js @@ -0,0 +1,8 @@ +// Copyright (c) 2021, Havenir Solutions and contributors +// For license information, please see license.txt + +frappe.ui.form.on('KSA VAT Sales Account', { + // refresh: function(frm) { + + // } +}); diff --git a/erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.json b/erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.json new file mode 100644 index 0000000000..df2747891d --- /dev/null +++ b/erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.json @@ -0,0 +1,49 @@ +{ + "actions": [], + "creation": "2021-07-13 08:46:33.820968", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "title", + "item_tax_template", + "account" + ], + "fields": [ + { + "fieldname": "account", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Account", + "options": "Account", + "reqd": 1 + }, + { + "fieldname": "title", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Title", + "reqd": 1 + }, + { + "fieldname": "item_tax_template", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Item Tax Template", + "options": "Item Tax Template", + "reqd": 1 + } + ], + "index_web_pages_for_search": 1, + "istable": 1, + "links": [], + "modified": "2021-08-04 06:42:00.081407", + "modified_by": "Administrator", + "module": "Regional", + "name": "KSA VAT Sales Account", + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1 +} \ No newline at end of file diff --git a/erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.py b/erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.py new file mode 100644 index 0000000000..8e437f832b --- /dev/null +++ b/erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.py @@ -0,0 +1,8 @@ +# Copyright (c) 2021, Havenir Solutions and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + +class KSAVATSalesAccount(Document): + pass diff --git a/erpnext/regional/doctype/ksa_vat_sales_account/test_ksa_vat_sales_account.py b/erpnext/regional/doctype/ksa_vat_sales_account/test_ksa_vat_sales_account.py new file mode 100644 index 0000000000..d7f911343b --- /dev/null +++ b/erpnext/regional/doctype/ksa_vat_sales_account/test_ksa_vat_sales_account.py @@ -0,0 +1,8 @@ +# Copyright (c) 2021, Havenir Solutions and Contributors +# See license.txt + +# import frappe +import unittest + +class TestKSAVATSalesAccount(unittest.TestCase): + pass diff --git a/erpnext/regional/doctype/ksa_vat_setting/__init__.py b/erpnext/regional/doctype/ksa_vat_setting/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.js b/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.js new file mode 100644 index 0000000000..0238c7b306 --- /dev/null +++ b/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.js @@ -0,0 +1,8 @@ +// Copyright (c) 2021, Havenir Solutions and contributors +// For license information, please see license.txt + +frappe.ui.form.on('KSA VAT Setting', { + onload: function(frm) { + frappe.breadcrumbs.add('Accounts', 'KSA VAT Setting'); + } +}); diff --git a/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.json b/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.json new file mode 100644 index 0000000000..33619467ed --- /dev/null +++ b/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.json @@ -0,0 +1,49 @@ +{ + "actions": [], + "autoname": "field:company", + "creation": "2021-07-13 08:49:01.100356", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "company", + "ksa_vat_sales_accounts", + "ksa_vat_purchase_accounts" + ], + "fields": [ + { + "fieldname": "company", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Company", + "options": "Company", + "reqd": 1, + "unique": 1 + }, + { + "fieldname": "ksa_vat_sales_accounts", + "fieldtype": "Table", + "label": "KSA VAT Sales Accounts", + "options": "KSA VAT Sales Account", + "reqd": 1 + }, + { + "fieldname": "ksa_vat_purchase_accounts", + "fieldtype": "Table", + "label": "KSA VAT Purchase Accounts", + "options": "KSA VAT Purchase Account", + "reqd": 1 + } + ], + "links": [], + "modified": "2021-08-26 04:29:06.499378", + "modified_by": "Administrator", + "module": "Regional", + "name": "KSA VAT Setting", + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC", + "title_field": "company", + "track_changes": 1 +} \ No newline at end of file diff --git a/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.py b/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.py new file mode 100644 index 0000000000..6db6f9cc59 --- /dev/null +++ b/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.py @@ -0,0 +1,8 @@ +# Copyright (c) 2021, Havenir Solutions and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + +class KSAVATSetting(Document): + pass diff --git a/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting_list.js b/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting_list.js new file mode 100644 index 0000000000..23d28b9e68 --- /dev/null +++ b/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting_list.js @@ -0,0 +1,5 @@ +frappe.listview_settings['KSA VAT Setting'] = { + onload(list) { + frappe.breadcrumbs.add('Accounts'); + } +} \ No newline at end of file diff --git a/erpnext/regional/doctype/ksa_vat_setting/test_ksa_vat_setting.py b/erpnext/regional/doctype/ksa_vat_setting/test_ksa_vat_setting.py new file mode 100644 index 0000000000..ae2defc61d --- /dev/null +++ b/erpnext/regional/doctype/ksa_vat_setting/test_ksa_vat_setting.py @@ -0,0 +1,8 @@ +# Copyright (c) 2021, Havenir Solutions and Contributors +# See license.txt + +# import frappe +import unittest + +class TestKSAVATSetting(unittest.TestCase): + pass diff --git a/erpnext/regional/report/ksa_vat/__init__.py b/erpnext/regional/report/ksa_vat/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/regional/report/ksa_vat/ksa_vat.js b/erpnext/regional/report/ksa_vat/ksa_vat.js new file mode 100644 index 0000000000..5dd9c92bf7 --- /dev/null +++ b/erpnext/regional/report/ksa_vat/ksa_vat.js @@ -0,0 +1,60 @@ +// Copyright (c) 2016, Havenir Solutions and contributors +// For license information, please see license.txt +/* eslint-disable */ + +frappe.query_reports["KSA VAT"] = { + onload() { + frappe.breadcrumbs.add('Accounts'); + }, + "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(), -1), + }, + { + "fieldname": "to_date", + "label": __("To Date"), + "fieldtype": "Date", + "reqd": 1, + "default": frappe.datetime.get_today() + } + ], + "formatter": function(value, row, column, data, default_formatter) { + if (data + && (data.title=='VAT on Sales' || data.title=='VAT on Purchases') + && data.title==value) { + value = $(`${value}`); + var $value = $(value).css("font-weight", "bold"); + value = $value.wrap("

").parent().html(); + return value + }else if (data.title=='Grand Total'){ + if (data.title==value) { + value = $(`${value}`); + var $value = $(value).css("font-weight", "bold"); + value = $value.wrap("

").parent().html(); + return value + }else{ + value = default_formatter(value, row, column, data); + value = $(`${value}`); + var $value = $(value).css("font-weight", "bold"); + value = $value.wrap("

").parent().html(); + console.log($value) + return value + } + }else{ + value = default_formatter(value, row, column, data); + return value; + } + }, +}; diff --git a/erpnext/regional/report/ksa_vat/ksa_vat.json b/erpnext/regional/report/ksa_vat/ksa_vat.json new file mode 100644 index 0000000000..036e260310 --- /dev/null +++ b/erpnext/regional/report/ksa_vat/ksa_vat.json @@ -0,0 +1,32 @@ +{ + "add_total_row": 0, + "columns": [], + "creation": "2021-07-13 08:54:38.000949", + "disable_prepared_report": 1, + "disabled": 1, + "docstatus": 0, + "doctype": "Report", + "filters": [], + "idx": 0, + "is_standard": "Yes", + "modified": "2021-08-26 04:14:37.202594", + "modified_by": "Administrator", + "module": "Regional", + "name": "KSA VAT", + "owner": "Administrator", + "prepared_report": 1, + "ref_doctype": "GL Entry", + "report_name": "KSA VAT", + "report_type": "Script Report", + "roles": [ + { + "role": "System Manager" + }, + { + "role": "Accounts Manager" + }, + { + "role": "Accounts User" + } + ] +} \ No newline at end of file diff --git a/erpnext/regional/report/ksa_vat/ksa_vat.py b/erpnext/regional/report/ksa_vat/ksa_vat.py new file mode 100644 index 0000000000..6828007203 --- /dev/null +++ b/erpnext/regional/report/ksa_vat/ksa_vat.py @@ -0,0 +1,177 @@ +# Copyright (c) 2013, Havenir Solutions and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +import frappe +from frappe import _ +from frappe.utils import get_url_to_list +from erpnext.controllers.taxes_and_totals import get_itemised_tax_breakup_data, get_rounded_tax_amount +import json + +def execute(filters=None): + columns = columns = get_columns() + data = get_data(filters) + return columns, data + +def get_columns(): + return [ + { + "fieldname": "title", + "label": _("Title"), + "fieldtype": "Data", + "width": 300 + }, + { + "fieldname": "amount", + "label": _("Amount (SAR)"), + "fieldtype": "Currency", + "width": 150, + }, + { + "fieldname": "adjustment_amount", + "label": _("Adjustment (SAR)"), + "fieldtype": "Currency", + "width": 150, + }, + { + "fieldname": "vat_amount", + "label": _("VAT Amount (SAR)"), + "fieldtype": "Currency", + "width": 150, + } + ] + +def get_data(filters): + data = [] + + # Validate if vat settings exist + company = filters.get('company') + if frappe.db.exists('KSA VAT Setting', company) is None: + url = get_url_to_list('KSA VAT Setting') + frappe.msgprint(f'Create KSA VAT Setting for this company') + return data + + ksa_vat_setting = frappe.get_doc('KSA VAT Setting', company) + + # Sales Heading + append_data(data, 'VAT on Sales', '', '', '') + + grand_total_taxable_amount = 0 + grand_total_taxable_adjustment_amount = 0 + grand_total_tax = 0 + + for vat_setting in ksa_vat_setting.ksa_vat_sales_accounts: + total_taxable_amount, total_taxable_adjustment_amount, \ + total_tax = get_tax_data_for_each_vat_setting(vat_setting, filters, 'Sales Invoice') + + # Adding results to data + append_data(data, vat_setting.title, total_taxable_amount, + total_taxable_adjustment_amount, total_tax) + + grand_total_taxable_amount += total_taxable_amount + grand_total_taxable_adjustment_amount += total_taxable_adjustment_amount + grand_total_tax += total_tax + + # Sales Grand Total + append_data(data, 'Grand Total', grand_total_taxable_amount, + grand_total_taxable_adjustment_amount, grand_total_tax ) + + # Blank Line + append_data(data, '', '', '', '') + + # Purchase Heading + append_data(data, 'VAT on Purchases', '', '', '') + + grand_total_taxable_amount = 0 + grand_total_taxable_adjustment_amount = 0 + grand_total_tax = 0 + + for vat_setting in ksa_vat_setting.ksa_vat_purchase_accounts: + total_taxable_amount, total_taxable_adjustment_amount, \ + total_tax = get_tax_data_for_each_vat_setting(vat_setting, filters, 'Purchase Invoice') + + # Adding results to data + append_data(data, vat_setting.title, total_taxable_amount, + total_taxable_adjustment_amount, total_tax) + + grand_total_taxable_amount += total_taxable_amount + grand_total_taxable_adjustment_amount += total_taxable_adjustment_amount + grand_total_tax += total_tax + + # Purchase Grand Total + append_data(data, 'Grand Total', grand_total_taxable_amount, + grand_total_taxable_adjustment_amount, grand_total_tax ) + + return data + +def get_tax_data_for_each_vat_setting(vat_setting, filters, doctype): + ''' + (KSA, {filters}, 'Sales Invoice') => 500, 153, 10 \n + calculates and returns \n + total_taxable_amount, total_taxable_adjustment_amount, total_tax''' + from_date = filters.get('from_date') + to_date = filters.get('to_date') + + # Initiate variables + total_taxable_amount = 0 + total_taxable_adjustment_amount = 0 + total_tax = 0 + # Fetch All Invoices + invoices = frappe.get_list(doctype, + filters ={ + 'docstatus': 1, + 'posting_date': ['between', [from_date, to_date]] + }, + fields =['name', 'is_return']) + + for invoice in invoices: + invoice_items = frappe.get_list(f'{doctype} Item', + filters ={ + 'docstatus': 1, + 'parent': invoice.name, + 'item_tax_template': vat_setting.item_tax_template + }, + fields =['item_code', 'net_amount']) + + + for item in invoice_items: + # Summing up total taxable amount + if invoice.is_return == 0: + total_taxable_amount += item.net_amount + + if invoice.is_return == 1: + total_taxable_adjustment_amount += item.net_amount + + # Summing up total tax + total_tax += get_tax_amount(item.item_code, vat_setting.account, doctype, invoice.name) + + return total_taxable_amount, total_taxable_adjustment_amount, total_tax + + + +def append_data(data, title, amount, adjustment_amount, vat_amount): + """Returns data with appended value.""" + data.append({"title":title, "amount": amount, "adjustment_amount": adjustment_amount, "vat_amount": vat_amount}) + +def get_tax_amount(item_code, account_head, doctype, parent): + if doctype == 'Sales Invoice': + tax_doctype = 'Sales Taxes and Charges' + + elif doctype == 'Purchase Invoice': + tax_doctype = 'Purchase Taxes and Charges' + + item_wise_tax_detail = frappe.get_value(tax_doctype, { + 'docstatus': 1, + 'parent': parent, + 'account_head': account_head + }, 'item_wise_tax_detail') + + tax_amount = 0 + if item_wise_tax_detail and len(item_wise_tax_detail) > 0: + item_wise_tax_detail = json.loads(item_wise_tax_detail) + for key, value in item_wise_tax_detail.items(): + if key == item_code: + tax_amount = value[1] + break + + return tax_amount \ No newline at end of file diff --git a/erpnext/regional/saudi_arabia/setup.py b/erpnext/regional/saudi_arabia/setup.py index 9b3677d2c6..053496729f 100644 --- a/erpnext/regional/saudi_arabia/setup.py +++ b/erpnext/regional/saudi_arabia/setup.py @@ -3,9 +3,26 @@ from __future__ import unicode_literals +import frappe +from frappe.permissions import add_permission, update_permission_property from erpnext.regional.united_arab_emirates.setup import make_custom_fields, add_print_formats +from erpnext.regional.saudi_arabia.wizard.operations.setup_ksa_vat_setting import create_ksa_vat_setting def setup(company=None, patch=True): make_custom_fields() add_print_formats() + add_permissions() + create_ksa_vat_setting(company) + + +def add_permissions(): + """Add Permissions for KSA VAT Setting.""" + add_permission('KSA VAT Setting', 'All', 0) + for role in ('Accounts Manager', 'Accounts User', 'System Manager'): + add_permission('KSA VAT Setting', role, 0) + update_permission_property('KSA VAT Setting', role, 0, 'write', 1) + update_permission_property('KSA VAT Setting', role, 0, 'create', 1) + + """Enable KSA VAT Report""" + frappe.db.set_value('Report', 'KSA VAT', 'disabled', 0) diff --git a/erpnext/regional/saudi_arabia/wizard/__init__.py b/erpnext/regional/saudi_arabia/wizard/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/regional/saudi_arabia/wizard/data/__init__.py b/erpnext/regional/saudi_arabia/wizard/data/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/regional/saudi_arabia/wizard/data/ksa_vat_settings.json b/erpnext/regional/saudi_arabia/wizard/data/ksa_vat_settings.json new file mode 100644 index 0000000000..709d65be04 --- /dev/null +++ b/erpnext/regional/saudi_arabia/wizard/data/ksa_vat_settings.json @@ -0,0 +1,47 @@ +[ + { + "type": "Sales Account", + "accounts": [ + { + "title": "Standard rated Sales", + "item_tax_template": "KSA VAT 5%", + "account": "VAT 5%" + }, + { + "title": "Zero rated domestic sales", + "item_tax_template": "KSA VAT Zero", + "account": "VAT Zero" + }, + { + "title": "Exempted sales", + "item_tax_template": "KSA VAT Exempted", + "account": "VAT Zero" + } + ] + }, + { + "type": "Purchase Account", + "accounts": [ + { + "title": "Standard rated domestic purchases", + "item_tax_template": "KSA VAT 5%", + "account": "VAT 5%" + }, + { + "title": "Imports subject to VAT paid at customs", + "item_tax_template": "KSA Excise 50%", + "account": "Excise 50%" + }, + { + "title": "Zero rated purchases", + "item_tax_template": "KSA VAT Zero", + "account": "VAT Zero" + }, + { + "title": "Exempted purchases", + "item_tax_template": "KSA VAT Exempted", + "account": "VAT Zero" + } + ] + } +] \ No newline at end of file diff --git a/erpnext/regional/saudi_arabia/wizard/operations/__init__.py b/erpnext/regional/saudi_arabia/wizard/operations/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/regional/saudi_arabia/wizard/operations/setup_ksa_vat_setting.py b/erpnext/regional/saudi_arabia/wizard/operations/setup_ksa_vat_setting.py new file mode 100644 index 0000000000..4bccdc35bf --- /dev/null +++ b/erpnext/regional/saudi_arabia/wizard/operations/setup_ksa_vat_setting.py @@ -0,0 +1,45 @@ +import frappe +import os +import json +from erpnext.setup.setup_wizard.operations.taxes_setup import setup_taxes_and_charges + +def create_ksa_vat_setting(company): + """ + On creation of first company. Creates KSA VAT Setting""" + + company = frappe.get_doc('Company', company) + setup_taxes_and_charges(company.name, company.country) + + file_path = os.path.join(os.path.dirname(__file__), '..', 'data', 'ksa_vat_settings.json') + with open(file_path, 'r') as json_file: + account_data = json.load(json_file) + + + # Creating KSA VAT Setting + ksa_vat_setting = frappe.get_doc({ + 'doctype': 'KSA VAT Setting', + 'company': company.name + }) + + for data in account_data: + if data['type'] == 'Sales Account': + for row in data['accounts']: + item_tax_template = row['item_tax_template'] + account = row['account'] + ksa_vat_setting.append('ksa_vat_sales_accounts', { + 'title': row['title'], + 'item_tax_template': f'{item_tax_template} - {company.abbr}', + 'account': f'{account} - {company.abbr}' + }) + + elif data['type'] == 'Purchase Account': + for row in data['accounts']: + item_tax_template = row['item_tax_template'] + account = row['account'] + ksa_vat_setting.append('ksa_vat_purchase_accounts', { + 'title': row['title'], + 'item_tax_template': f'{item_tax_template} - {company.abbr}', + 'account': f'{account} - {company.abbr}' + }) + + ksa_vat_setting.save() \ No newline at end of file From 87380d021d589a9717a26ee74db19e3902948c36 Mon Sep 17 00:00:00 2001 From: Ahmad Date: Mon, 6 Sep 2021 23:36:55 +0500 Subject: [PATCH 03/16] feat(regional): QR Code generation for Saudi Arabia Sales Invoices --- erpnext/hooks.py | 6 ++- erpnext/regional/__init__.py | 72 ++++++++++++++++++++++++++ erpnext/regional/saudi_arabia/setup.py | 17 ++++-- 3 files changed, 90 insertions(+), 5 deletions(-) diff --git a/erpnext/hooks.py b/erpnext/hooks.py index 5b6e1eeafc..050ce2e11d 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -262,6 +262,7 @@ doc_events = { "validate": "erpnext.regional.india.utils.validate_tax_category" }, "Sales Invoice": { + "after_insert": "erpnext.regional.create_qr_code", "on_submit": [ "erpnext.regional.create_transaction_log", "erpnext.regional.italy.utils.sales_invoice_on_submit", @@ -271,7 +272,10 @@ doc_events = { "erpnext.regional.italy.utils.sales_invoice_on_cancel", "erpnext.erpnext_integrations.taxjar_integration.delete_transaction" ], - "on_trash": "erpnext.regional.check_deletion_permission", + "on_trash": [ + "erpnext.regional.check_deletion_permission", + "erpnext.regional.delete_qr_code_file" + ], "validate": [ "erpnext.regional.india.utils.validate_document_name", "erpnext.regional.india.utils.update_taxable_values" diff --git a/erpnext/regional/__init__.py b/erpnext/regional/__init__.py index 45a689efa8..3591be07b8 100644 --- a/erpnext/regional/__init__.py +++ b/erpnext/regional/__init__.py @@ -7,6 +7,9 @@ import frappe from frappe import _ from erpnext import get_region +from pyqrcode import create as qr_create +import io +import os def check_deletion_permission(doc, method): @@ -31,3 +34,72 @@ def create_transaction_log(doc, method): "document_name": doc.name, "data": data }).insert(ignore_permissions=True) + + +def create_qr_code(doc, method): + """Create QR Code after inserting Sales Inv + """ + + region = get_region(doc.company) + if region not in ['Saudi Arabia']: + return + + # if QR Code field not present, do nothing + if not hasattr(doc, 'qr_code'): + return + + # Don't create QR Code if it already exists + qr_code = doc.get("qr_code") + if qr_code and frappe.db.exists({"doctype": "File", "file_url": qr_code}): + return + + fields = frappe.get_meta('Sales Invoice').fields + + for field in fields: + if field.fieldname == 'qr_code' and field.fieldtype == 'Attach Image': + # Creating public url to print format + default_print_format = frappe.db.get_value('Property Setter', dict(property='default_print_format', doc_type=doc.doctype), "value") + + # System Language + language = frappe.get_system_settings('language') + + # creating qr code for the url + url = f"{ frappe.utils.get_url() }/{ doc.doctype }/{ doc.name }?format={ default_print_format or 'Standard' }&_lang={ language }&key={ doc.get_signature() }" + qr_image = io.BytesIO() + url = qr_create(url, error='L') + url.png(qr_image, scale=2, quiet_zone=1) + + # making file + filename = f"QR-CODE-{doc.name}.png".replace(os.path.sep, "__") + _file = frappe.get_doc({ + "doctype": "File", + "file_name": filename, + "is_private": 0, + "content": qr_image.getvalue() + }) + + _file.save() + + # assigning to document + doc.db_set('qr_code', _file.file_url) + doc.notify_update() + + break + + else: + pass + +def delete_qr_code_file(doc, method): + """Delete QR Code on deleted sales invoice""" + + region = get_region(doc.company) + if region not in ['Saudi Arabia']: + return + + if hasattr(doc, 'qr_code'): + if doc.get('qr_code'): + file_doc = frappe.get_list('File', { + 'file_url': doc.qr_code + }) + if len(file_doc): + frappe.delete_doc('File', file_doc[0].name) \ No newline at end of file diff --git a/erpnext/regional/saudi_arabia/setup.py b/erpnext/regional/saudi_arabia/setup.py index 053496729f..f55900023d 100644 --- a/erpnext/regional/saudi_arabia/setup.py +++ b/erpnext/regional/saudi_arabia/setup.py @@ -2,18 +2,18 @@ # License: GNU General Public License v3. See license.txt from __future__ import unicode_literals - import frappe from frappe.permissions import add_permission, update_permission_property -from erpnext.regional.united_arab_emirates.setup import make_custom_fields, add_print_formats +from erpnext.regional.united_arab_emirates.setup import make_custom_fields as uae_custom_fields, add_print_formats from erpnext.regional.saudi_arabia.wizard.operations.setup_ksa_vat_setting import create_ksa_vat_setting - +from frappe.custom.doctype.custom_field.custom_field import create_custom_field def setup(company=None, patch=True): - make_custom_fields() + uae_custom_fields() add_print_formats() add_permissions() create_ksa_vat_setting(company) + make_custom_fields() def add_permissions(): @@ -26,3 +26,12 @@ def add_permissions(): """Enable KSA VAT Report""" frappe.db.set_value('Report', 'KSA VAT', 'disabled', 0) + +def make_custom_fields(): + qr_code_field = dict( + fieldname='qr_code', + label='QR Code', + fieldtype='Attach Image', + read_only=1, no_copy=1, hidden=1) + + create_custom_field('Sales Invoice', qr_code_field) From b5b61b3a3d8d46ef9d15af3d631ad407e18e9270 Mon Sep 17 00:00:00 2001 From: Ahmad <7881486+ahmadpak@users.noreply.github.com> Date: Tue, 14 Sep 2021 14:26:44 +0500 Subject: [PATCH 04/16] Update erpnext/regional/report/ksa_vat/ksa_vat.py String made translatable Co-authored-by: Saqib --- erpnext/regional/report/ksa_vat/ksa_vat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/regional/report/ksa_vat/ksa_vat.py b/erpnext/regional/report/ksa_vat/ksa_vat.py index 6828007203..1175fbf11f 100644 --- a/erpnext/regional/report/ksa_vat/ksa_vat.py +++ b/erpnext/regional/report/ksa_vat/ksa_vat.py @@ -48,7 +48,7 @@ def get_data(filters): company = filters.get('company') if frappe.db.exists('KSA VAT Setting', company) is None: url = get_url_to_list('KSA VAT Setting') - frappe.msgprint(f'Create KSA VAT Setting for this company') + frappe.msgprint(_('Create KSA VAT Setting for this company').format(url)) return data ksa_vat_setting = frappe.get_doc('KSA VAT Setting', company) From 6985ca210e6170c55f15d3b3322fa7117a32c2e1 Mon Sep 17 00:00:00 2001 From: Ahmad <7881486+ahmadpak@users.noreply.github.com> Date: Tue, 14 Sep 2021 14:28:57 +0500 Subject: [PATCH 05/16] Refactor erpnext/regional/__init__.py Co-authored-by: Saqib --- erpnext/regional/__init__.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/erpnext/regional/__init__.py b/erpnext/regional/__init__.py index 3591be07b8..6b68bc032b 100644 --- a/erpnext/regional/__init__.py +++ b/erpnext/regional/__init__.py @@ -86,8 +86,6 @@ def create_qr_code(doc, method): break - else: - pass def delete_qr_code_file(doc, method): """Delete QR Code on deleted sales invoice""" From 0950713e4c01a63ae442abb443f9b0441834648b Mon Sep 17 00:00:00 2001 From: Ahmad <7881486+ahmadpak@users.noreply.github.com> Date: Tue, 14 Sep 2021 14:29:33 +0500 Subject: [PATCH 06/16] Update erpnext/regional/saudi_arabia/setup.py Method name updated Co-authored-by: Saqib --- erpnext/regional/saudi_arabia/setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/regional/saudi_arabia/setup.py b/erpnext/regional/saudi_arabia/setup.py index f55900023d..22a050650c 100644 --- a/erpnext/regional/saudi_arabia/setup.py +++ b/erpnext/regional/saudi_arabia/setup.py @@ -13,7 +13,7 @@ def setup(company=None, patch=True): add_print_formats() add_permissions() create_ksa_vat_setting(company) - make_custom_fields() + make_qrcode_field() def add_permissions(): From de01066ef5258e351c61106518dc8c05aa86aa08 Mon Sep 17 00:00:00 2001 From: Ahmad <7881486+ahmadpak@users.noreply.github.com> Date: Tue, 14 Sep 2021 14:29:45 +0500 Subject: [PATCH 07/16] Update erpnext/regional/saudi_arabia/setup.py Method name updated Co-authored-by: Saqib --- erpnext/regional/saudi_arabia/setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/regional/saudi_arabia/setup.py b/erpnext/regional/saudi_arabia/setup.py index 22a050650c..82f2f4fab0 100644 --- a/erpnext/regional/saudi_arabia/setup.py +++ b/erpnext/regional/saudi_arabia/setup.py @@ -27,7 +27,7 @@ def add_permissions(): """Enable KSA VAT Report""" frappe.db.set_value('Report', 'KSA VAT', 'disabled', 0) -def make_custom_fields(): +def make_qrcode_field(): qr_code_field = dict( fieldname='qr_code', label='QR Code', From 8a42570c962af645a49c8631704fb183bb08b79a Mon Sep 17 00:00:00 2001 From: Ahmad Date: Tue, 14 Sep 2021 14:45:23 +0500 Subject: [PATCH 08/16] refactor(regional): moved methos to region specific utils for KSA --- erpnext/hooks.py | 4 +- erpnext/regional/__init__.py | 69 ------------------------ erpnext/regional/saudi_arabia/utils.py | 73 ++++++++++++++++++++++++++ 3 files changed, 75 insertions(+), 71 deletions(-) create mode 100644 erpnext/regional/saudi_arabia/utils.py diff --git a/erpnext/hooks.py b/erpnext/hooks.py index 050ce2e11d..c41a1081de 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -262,7 +262,7 @@ doc_events = { "validate": "erpnext.regional.india.utils.validate_tax_category" }, "Sales Invoice": { - "after_insert": "erpnext.regional.create_qr_code", + "after_insert": "erpnext.regional.saudi_arabia.utils.create_qr_code", "on_submit": [ "erpnext.regional.create_transaction_log", "erpnext.regional.italy.utils.sales_invoice_on_submit", @@ -274,7 +274,7 @@ doc_events = { ], "on_trash": [ "erpnext.regional.check_deletion_permission", - "erpnext.regional.delete_qr_code_file" + "erpnext.regional.saudi_arabia.utils.delete_qr_code_file" ], "validate": [ "erpnext.regional.india.utils.validate_document_name", diff --git a/erpnext/regional/__init__.py b/erpnext/regional/__init__.py index 6b68bc032b..d7dcbf4fe1 100644 --- a/erpnext/regional/__init__.py +++ b/erpnext/regional/__init__.py @@ -7,9 +7,6 @@ import frappe from frappe import _ from erpnext import get_region -from pyqrcode import create as qr_create -import io -import os def check_deletion_permission(doc, method): @@ -35,69 +32,3 @@ def create_transaction_log(doc, method): "data": data }).insert(ignore_permissions=True) - -def create_qr_code(doc, method): - """Create QR Code after inserting Sales Inv - """ - - region = get_region(doc.company) - if region not in ['Saudi Arabia']: - return - - # if QR Code field not present, do nothing - if not hasattr(doc, 'qr_code'): - return - - # Don't create QR Code if it already exists - qr_code = doc.get("qr_code") - if qr_code and frappe.db.exists({"doctype": "File", "file_url": qr_code}): - return - - fields = frappe.get_meta('Sales Invoice').fields - - for field in fields: - if field.fieldname == 'qr_code' and field.fieldtype == 'Attach Image': - # Creating public url to print format - default_print_format = frappe.db.get_value('Property Setter', dict(property='default_print_format', doc_type=doc.doctype), "value") - - # System Language - language = frappe.get_system_settings('language') - - # creating qr code for the url - url = f"{ frappe.utils.get_url() }/{ doc.doctype }/{ doc.name }?format={ default_print_format or 'Standard' }&_lang={ language }&key={ doc.get_signature() }" - qr_image = io.BytesIO() - url = qr_create(url, error='L') - url.png(qr_image, scale=2, quiet_zone=1) - - # making file - filename = f"QR-CODE-{doc.name}.png".replace(os.path.sep, "__") - _file = frappe.get_doc({ - "doctype": "File", - "file_name": filename, - "is_private": 0, - "content": qr_image.getvalue() - }) - - _file.save() - - # assigning to document - doc.db_set('qr_code', _file.file_url) - doc.notify_update() - - break - - -def delete_qr_code_file(doc, method): - """Delete QR Code on deleted sales invoice""" - - region = get_region(doc.company) - if region not in ['Saudi Arabia']: - return - - if hasattr(doc, 'qr_code'): - if doc.get('qr_code'): - file_doc = frappe.get_list('File', { - 'file_url': doc.qr_code - }) - if len(file_doc): - frappe.delete_doc('File', file_doc[0].name) \ No newline at end of file diff --git a/erpnext/regional/saudi_arabia/utils.py b/erpnext/regional/saudi_arabia/utils.py new file mode 100644 index 0000000000..4431ba065e --- /dev/null +++ b/erpnext/regional/saudi_arabia/utils.py @@ -0,0 +1,73 @@ +import frappe +from frappe import _ +from erpnext import get_region +from pyqrcode import create as qr_create +import io +import os + + +def create_qr_code(doc, method): + """Create QR Code after inserting Sales Inv + """ + + region = get_region(doc.company) + if region not in ['Saudi Arabia']: + return + + # if QR Code field not present, do nothing + if not hasattr(doc, 'qr_code'): + return + + # Don't create QR Code if it already exists + qr_code = doc.get("qr_code") + if qr_code and frappe.db.exists({"doctype": "File", "file_url": qr_code}): + return + + fields = frappe.get_meta('Sales Invoice').fields + + for field in fields: + if field.fieldname == 'qr_code' and field.fieldtype == 'Attach Image': + # Creating public url to print format + default_print_format = frappe.db.get_value('Property Setter', dict(property='default_print_format', doc_type=doc.doctype), "value") + + # System Language + language = frappe.get_system_settings('language') + + # creating qr code for the url + url = f"{ frappe.utils.get_url() }/{ doc.doctype }/{ doc.name }?format={ default_print_format or 'Standard' }&_lang={ language }&key={ doc.get_signature() }" + qr_image = io.BytesIO() + url = qr_create(url, error='L') + url.png(qr_image, scale=2, quiet_zone=1) + + # making file + filename = f"QR-CODE-{doc.name}.png".replace(os.path.sep, "__") + _file = frappe.get_doc({ + "doctype": "File", + "file_name": filename, + "is_private": 0, + "content": qr_image.getvalue() + }) + + _file.save() + + # assigning to document + doc.db_set('qr_code', _file.file_url) + doc.notify_update() + + break + + +def delete_qr_code_file(doc, method): + """Delete QR Code on deleted sales invoice""" + + region = get_region(doc.company) + if region not in ['Saudi Arabia']: + return + + if hasattr(doc, 'qr_code'): + if doc.get('qr_code'): + file_doc = frappe.get_list('File', { + 'file_url': doc.qr_code + }) + if len(file_doc): + frappe.delete_doc('File', file_doc[0].name) \ No newline at end of file From 940db71a8292fc9f4f89a00014138fbe6809a474 Mon Sep 17 00:00:00 2001 From: Ahmad Date: Fri, 17 Sep 2021 01:14:41 +0500 Subject: [PATCH 09/16] fix: indentations --- erpnext/hooks.py | 2 +- .../ksa_vat_setting/ksa_vat_setting.js | 2 +- .../ksa_vat_setting/ksa_vat_setting_list.js | 6 +-- erpnext/regional/report/ksa_vat/ksa_vat.py | 51 +++++++++---------- erpnext/regional/saudi_arabia/utils.py | 19 +++---- 5 files changed, 40 insertions(+), 40 deletions(-) diff --git a/erpnext/hooks.py b/erpnext/hooks.py index c41a1081de..1e3ad8e2e9 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -275,7 +275,7 @@ doc_events = { "on_trash": [ "erpnext.regional.check_deletion_permission", "erpnext.regional.saudi_arabia.utils.delete_qr_code_file" - ], + ], "validate": [ "erpnext.regional.india.utils.validate_document_name", "erpnext.regional.india.utils.update_taxable_values" diff --git a/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.js b/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.js index 0238c7b306..00b62b9adf 100644 --- a/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.js +++ b/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.js @@ -2,7 +2,7 @@ // For license information, please see license.txt frappe.ui.form.on('KSA VAT Setting', { - onload: function(frm) { + onload: function () { frappe.breadcrumbs.add('Accounts', 'KSA VAT Setting'); } }); diff --git a/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting_list.js b/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting_list.js index 23d28b9e68..269cbec5fb 100644 --- a/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting_list.js +++ b/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting_list.js @@ -1,5 +1,5 @@ frappe.listview_settings['KSA VAT Setting'] = { - onload(list) { - frappe.breadcrumbs.add('Accounts'); - } + onload () { + frappe.breadcrumbs.add('Accounts'); + } } \ No newline at end of file diff --git a/erpnext/regional/report/ksa_vat/ksa_vat.py b/erpnext/regional/report/ksa_vat/ksa_vat.py index 1175fbf11f..1697bbbd4d 100644 --- a/erpnext/regional/report/ksa_vat/ksa_vat.py +++ b/erpnext/regional/report/ksa_vat/ksa_vat.py @@ -2,11 +2,13 @@ # For license information, please see license.txt from __future__ import unicode_literals + +import json + import frappe from frappe import _ from frappe.utils import get_url_to_list -from erpnext.controllers.taxes_and_totals import get_itemised_tax_breakup_data, get_rounded_tax_amount -import json + def execute(filters=None): columns = columns = get_columns() @@ -52,7 +54,7 @@ def get_data(filters): return data ksa_vat_setting = frappe.get_doc('KSA VAT Setting', company) - + # Sales Heading append_data(data, 'VAT on Sales', '', '', '') @@ -63,19 +65,19 @@ def get_data(filters): for vat_setting in ksa_vat_setting.ksa_vat_sales_accounts: total_taxable_amount, total_taxable_adjustment_amount, \ total_tax = get_tax_data_for_each_vat_setting(vat_setting, filters, 'Sales Invoice') - + # Adding results to data - append_data(data, vat_setting.title, total_taxable_amount, + append_data(data, vat_setting.title, total_taxable_amount, total_taxable_adjustment_amount, total_tax) - + grand_total_taxable_amount += total_taxable_amount grand_total_taxable_adjustment_amount += total_taxable_adjustment_amount grand_total_tax += total_tax # Sales Grand Total - append_data(data, 'Grand Total', grand_total_taxable_amount, - grand_total_taxable_adjustment_amount, grand_total_tax ) - + append_data(data, 'Grand Total', grand_total_taxable_amount, + grand_total_taxable_adjustment_amount, grand_total_tax) + # Blank Line append_data(data, '', '', '', '') @@ -89,9 +91,9 @@ def get_data(filters): for vat_setting in ksa_vat_setting.ksa_vat_purchase_accounts: total_taxable_amount, total_taxable_adjustment_amount, \ total_tax = get_tax_data_for_each_vat_setting(vat_setting, filters, 'Purchase Invoice') - + # Adding results to data - append_data(data, vat_setting.title, total_taxable_amount, + append_data(data, vat_setting.title, total_taxable_amount, total_taxable_adjustment_amount, total_tax) grand_total_taxable_amount += total_taxable_amount @@ -99,8 +101,8 @@ def get_data(filters): grand_total_tax += total_tax # Purchase Grand Total - append_data(data, 'Grand Total', grand_total_taxable_amount, - grand_total_taxable_adjustment_amount, grand_total_tax ) + append_data(data, 'Grand Total', grand_total_taxable_amount, + grand_total_taxable_adjustment_amount, grand_total_tax) return data @@ -117,36 +119,33 @@ def get_tax_data_for_each_vat_setting(vat_setting, filters, doctype): total_taxable_adjustment_amount = 0 total_tax = 0 # Fetch All Invoices - invoices = frappe.get_list(doctype, + invoices = frappe.get_list(doctype, filters ={ 'docstatus': 1, 'posting_date': ['between', [from_date, to_date]] - }, - fields =['name', 'is_return']) + }, fields =['name', 'is_return']) for invoice in invoices: - invoice_items = frappe.get_list(f'{doctype} Item', + invoice_items = frappe.get_list(f'{doctype} Item', filters ={ 'docstatus': 1, 'parent': invoice.name, 'item_tax_template': vat_setting.item_tax_template - }, - fields =['item_code', 'net_amount']) + }, fields =['item_code', 'net_amount']) - for item in invoice_items: # Summing up total taxable amount if invoice.is_return == 0: total_taxable_amount += item.net_amount - + if invoice.is_return == 1: total_taxable_adjustment_amount += item.net_amount # Summing up total tax total_tax += get_tax_amount(item.item_code, vat_setting.account, doctype, invoice.name) - + return total_taxable_amount, total_taxable_adjustment_amount, total_tax - + def append_data(data, title, amount, adjustment_amount, vat_amount): @@ -156,10 +155,10 @@ def append_data(data, title, amount, adjustment_amount, vat_amount): def get_tax_amount(item_code, account_head, doctype, parent): if doctype == 'Sales Invoice': tax_doctype = 'Sales Taxes and Charges' - + elif doctype == 'Purchase Invoice': tax_doctype = 'Purchase Taxes and Charges' - + item_wise_tax_detail = frappe.get_value(tax_doctype, { 'docstatus': 1, 'parent': parent, @@ -173,5 +172,5 @@ def get_tax_amount(item_code, account_head, doctype, parent): if key == item_code: tax_amount = value[1] break - + return tax_amount \ No newline at end of file diff --git a/erpnext/regional/saudi_arabia/utils.py b/erpnext/regional/saudi_arabia/utils.py index 4431ba065e..e83d8c72ad 100644 --- a/erpnext/regional/saudi_arabia/utils.py +++ b/erpnext/regional/saudi_arabia/utils.py @@ -1,10 +1,11 @@ -import frappe -from frappe import _ -from erpnext import get_region -from pyqrcode import create as qr_create import io import os +import frappe +from pyqrcode import create as qr_create + +from erpnext import get_region + def create_qr_code(doc, method): """Create QR Code after inserting Sales Inv @@ -24,21 +25,21 @@ def create_qr_code(doc, method): return fields = frappe.get_meta('Sales Invoice').fields - + for field in fields: if field.fieldname == 'qr_code' and field.fieldtype == 'Attach Image': # Creating public url to print format default_print_format = frappe.db.get_value('Property Setter', dict(property='default_print_format', doc_type=doc.doctype), "value") - + # System Language language = frappe.get_system_settings('language') - + # creating qr code for the url url = f"{ frappe.utils.get_url() }/{ doc.doctype }/{ doc.name }?format={ default_print_format or 'Standard' }&_lang={ language }&key={ doc.get_signature() }" qr_image = io.BytesIO() url = qr_create(url, error='L') url.png(qr_image, scale=2, quiet_zone=1) - + # making file filename = f"QR-CODE-{doc.name}.png".replace(os.path.sep, "__") _file = frappe.get_doc({ @@ -59,7 +60,7 @@ def create_qr_code(doc, method): def delete_qr_code_file(doc, method): """Delete QR Code on deleted sales invoice""" - + region = get_region(doc.company) if region not in ['Saudi Arabia']: return From 95b3b9c8f5f3d2c53d82b6f7a9b9a85bae722d15 Mon Sep 17 00:00:00 2001 From: Ahmad <7881486+ahmadpak@users.noreply.github.com> Date: Fri, 17 Sep 2021 01:27:37 +0500 Subject: [PATCH 10/16] Update erpnext/regional/saudi_arabia/utils.py Co-authored-by: Saqib --- erpnext/regional/saudi_arabia/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/regional/saudi_arabia/utils.py b/erpnext/regional/saudi_arabia/utils.py index e83d8c72ad..5b8b7c1383 100644 --- a/erpnext/regional/saudi_arabia/utils.py +++ b/erpnext/regional/saudi_arabia/utils.py @@ -68,7 +68,7 @@ def delete_qr_code_file(doc, method): if hasattr(doc, 'qr_code'): if doc.get('qr_code'): file_doc = frappe.get_list('File', { - 'file_url': doc.qr_code + 'file_url': doc.get('qr_code') }) if len(file_doc): frappe.delete_doc('File', file_doc[0].name) \ No newline at end of file From 05321d7f4e1b72f59a93039ba6b2774bda7dc0fb Mon Sep 17 00:00:00 2001 From: Ahmad <7881486+ahmadpak@users.noreply.github.com> Date: Fri, 17 Sep 2021 01:28:52 +0500 Subject: [PATCH 11/16] Update erpnext/regional/saudi_arabia/utils.py Co-authored-by: Saqib --- erpnext/regional/saudi_arabia/utils.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/erpnext/regional/saudi_arabia/utils.py b/erpnext/regional/saudi_arabia/utils.py index 5b8b7c1383..79a29de9ac 100644 --- a/erpnext/regional/saudi_arabia/utils.py +++ b/erpnext/regional/saudi_arabia/utils.py @@ -46,7 +46,10 @@ def create_qr_code(doc, method): "doctype": "File", "file_name": filename, "is_private": 0, - "content": qr_image.getvalue() + "content": qr_image.getvalue(), + "attached_to_doctype": doc.get("doctype"), + "attached_to_name": doc.get("name"), + "attached_to_field": "qr_code" }) _file.save() From f1e5a64c61b8bea35e9fff813e290e8f05a32b7a Mon Sep 17 00:00:00 2001 From: Ahmad Date: Fri, 17 Sep 2021 01:33:32 +0500 Subject: [PATCH 12/16] refactor (regional): KSA utils --- erpnext/regional/saudi_arabia/utils.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/erpnext/regional/saudi_arabia/utils.py b/erpnext/regional/saudi_arabia/utils.py index 79a29de9ac..cc6c0af7a5 100644 --- a/erpnext/regional/saudi_arabia/utils.py +++ b/erpnext/regional/saudi_arabia/utils.py @@ -24,10 +24,10 @@ def create_qr_code(doc, method): if qr_code and frappe.db.exists({"doctype": "File", "file_url": qr_code}): return - fields = frappe.get_meta('Sales Invoice').fields + meta = frappe.get_meta('Sales Invoice') - for field in fields: - if field.fieldname == 'qr_code' and field.fieldtype == 'Attach Image': + for field in meta.get_image_fields(): + if field.fieldname == 'qr_code': # Creating public url to print format default_print_format = frappe.db.get_value('Property Setter', dict(property='default_print_format', doc_type=doc.doctype), "value") From 4ec733fcc0d2f1bae8c016edac5d6dbc5598e764 Mon Sep 17 00:00:00 2001 From: Ahmad Date: Fri, 17 Sep 2021 01:46:45 +0500 Subject: [PATCH 13/16] fix: pre-commit hooks --- .../wizard/operations/setup_ksa_vat_setting.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/erpnext/regional/saudi_arabia/wizard/operations/setup_ksa_vat_setting.py b/erpnext/regional/saudi_arabia/wizard/operations/setup_ksa_vat_setting.py index 4bccdc35bf..c30fcffc37 100644 --- a/erpnext/regional/saudi_arabia/wizard/operations/setup_ksa_vat_setting.py +++ b/erpnext/regional/saudi_arabia/wizard/operations/setup_ksa_vat_setting.py @@ -1,11 +1,13 @@ -import frappe -import os import json +import os + +import frappe + from erpnext.setup.setup_wizard.operations.taxes_setup import setup_taxes_and_charges + def create_ksa_vat_setting(company): - """ - On creation of first company. Creates KSA VAT Setting""" + """On creation of first company. Creates KSA VAT Setting""" company = frappe.get_doc('Company', company) setup_taxes_and_charges(company.name, company.country) @@ -13,14 +15,14 @@ def create_ksa_vat_setting(company): file_path = os.path.join(os.path.dirname(__file__), '..', 'data', 'ksa_vat_settings.json') with open(file_path, 'r') as json_file: account_data = json.load(json_file) - + # Creating KSA VAT Setting ksa_vat_setting = frappe.get_doc({ 'doctype': 'KSA VAT Setting', 'company': company.name }) - + for data in account_data: if data['type'] == 'Sales Account': for row in data['accounts']: @@ -31,7 +33,7 @@ def create_ksa_vat_setting(company): 'item_tax_template': f'{item_tax_template} - {company.abbr}', 'account': f'{account} - {company.abbr}' }) - + elif data['type'] == 'Purchase Account': for row in data['accounts']: item_tax_template = row['item_tax_template'] From 9dae36b81d88359da72efcc1d1020af83188799b Mon Sep 17 00:00:00 2001 From: Ahmad Date: Fri, 17 Sep 2021 01:51:32 +0500 Subject: [PATCH 14/16] fix: pre-commit hooks --- erpnext/regional/saudi_arabia/setup.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/erpnext/regional/saudi_arabia/setup.py b/erpnext/regional/saudi_arabia/setup.py index 82f2f4fab0..6113f48d3f 100644 --- a/erpnext/regional/saudi_arabia/setup.py +++ b/erpnext/regional/saudi_arabia/setup.py @@ -14,7 +14,6 @@ def setup(company=None, patch=True): add_permissions() create_ksa_vat_setting(company) make_qrcode_field() - def add_permissions(): """Add Permissions for KSA VAT Setting.""" @@ -28,10 +27,11 @@ def add_permissions(): frappe.db.set_value('Report', 'KSA VAT', 'disabled', 0) def make_qrcode_field(): + """Created QR code Image file""" qr_code_field = dict( - fieldname='qr_code', - label='QR Code', - fieldtype='Attach Image', + fieldname='qr_code', + label='QR Code', + fieldtype='Attach Image', read_only=1, no_copy=1, hidden=1) - + create_custom_field('Sales Invoice', qr_code_field) From 0ab57d49c1e2da11b3a2f12d394515e5e2991bca Mon Sep 17 00:00:00 2001 From: Ahmad Date: Fri, 17 Sep 2021 01:54:59 +0500 Subject: [PATCH 15/16] fix: pre-commit hooks --- .../ksa_vat_purchase_account/ksa_vat_purchase_account.py | 1 + .../doctype/ksa_vat_sales_account/ksa_vat_sales_account.py | 1 + .../doctype/ksa_vat_sales_account/test_ksa_vat_sales_account.py | 1 + erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.py | 1 + .../regional/doctype/ksa_vat_setting/test_ksa_vat_setting.py | 1 + erpnext/regional/report/ksa_vat/ksa_vat.js | 2 +- 6 files changed, 6 insertions(+), 1 deletion(-) diff --git a/erpnext/regional/doctype/ksa_vat_purchase_account/ksa_vat_purchase_account.py b/erpnext/regional/doctype/ksa_vat_purchase_account/ksa_vat_purchase_account.py index 1302e314c3..3920bc546c 100644 --- a/erpnext/regional/doctype/ksa_vat_purchase_account/ksa_vat_purchase_account.py +++ b/erpnext/regional/doctype/ksa_vat_purchase_account/ksa_vat_purchase_account.py @@ -4,5 +4,6 @@ # import frappe from frappe.model.document import Document + class KSAVATPurchaseAccount(Document): pass diff --git a/erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.py b/erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.py index 8e437f832b..7c2689f530 100644 --- a/erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.py +++ b/erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.py @@ -4,5 +4,6 @@ # import frappe from frappe.model.document import Document + class KSAVATSalesAccount(Document): pass diff --git a/erpnext/regional/doctype/ksa_vat_sales_account/test_ksa_vat_sales_account.py b/erpnext/regional/doctype/ksa_vat_sales_account/test_ksa_vat_sales_account.py index d7f911343b..1d6a6a793d 100644 --- a/erpnext/regional/doctype/ksa_vat_sales_account/test_ksa_vat_sales_account.py +++ b/erpnext/regional/doctype/ksa_vat_sales_account/test_ksa_vat_sales_account.py @@ -4,5 +4,6 @@ # import frappe import unittest + class TestKSAVATSalesAccount(unittest.TestCase): pass diff --git a/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.py b/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.py index 6db6f9cc59..bdae1161fd 100644 --- a/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.py +++ b/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.py @@ -4,5 +4,6 @@ # import frappe from frappe.model.document import Document + class KSAVATSetting(Document): pass diff --git a/erpnext/regional/doctype/ksa_vat_setting/test_ksa_vat_setting.py b/erpnext/regional/doctype/ksa_vat_setting/test_ksa_vat_setting.py index ae2defc61d..7207901fd4 100644 --- a/erpnext/regional/doctype/ksa_vat_setting/test_ksa_vat_setting.py +++ b/erpnext/regional/doctype/ksa_vat_setting/test_ksa_vat_setting.py @@ -4,5 +4,6 @@ # import frappe import unittest + class TestKSAVATSetting(unittest.TestCase): pass diff --git a/erpnext/regional/report/ksa_vat/ksa_vat.js b/erpnext/regional/report/ksa_vat/ksa_vat.js index 5dd9c92bf7..d46d260ac1 100644 --- a/erpnext/regional/report/ksa_vat/ksa_vat.js +++ b/erpnext/regional/report/ksa_vat/ksa_vat.js @@ -4,7 +4,7 @@ frappe.query_reports["KSA VAT"] = { onload() { - frappe.breadcrumbs.add('Accounts'); + frappe.breadcrumbs.add('Accounts'); }, "filters": [ { From cb2213ef0cc066eb2ba40d6cb1d8ecf3d377d842 Mon Sep 17 00:00:00 2001 From: Ahmad Date: Sun, 10 Oct 2021 21:17:59 +0200 Subject: [PATCH 16/16] refactor: make strings translate --- erpnext/regional/report/ksa_vat/ksa_vat.py | 4 ++-- .../saudi_arabia/wizard/operations/setup_ksa_vat_setting.py | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/erpnext/regional/report/ksa_vat/ksa_vat.py b/erpnext/regional/report/ksa_vat/ksa_vat.py index 1697bbbd4d..a42ebc9f7e 100644 --- a/erpnext/regional/report/ksa_vat/ksa_vat.py +++ b/erpnext/regional/report/ksa_vat/ksa_vat.py @@ -150,7 +150,7 @@ def get_tax_data_for_each_vat_setting(vat_setting, filters, doctype): def append_data(data, title, amount, adjustment_amount, vat_amount): """Returns data with appended value.""" - data.append({"title":title, "amount": amount, "adjustment_amount": adjustment_amount, "vat_amount": vat_amount}) + data.append({"title": _(title), "amount": amount, "adjustment_amount": adjustment_amount, "vat_amount": vat_amount}) def get_tax_amount(item_code, account_head, doctype, parent): if doctype == 'Sales Invoice': @@ -173,4 +173,4 @@ def get_tax_amount(item_code, account_head, doctype, parent): tax_amount = value[1] break - return tax_amount \ No newline at end of file + return tax_amount diff --git a/erpnext/regional/saudi_arabia/wizard/operations/setup_ksa_vat_setting.py b/erpnext/regional/saudi_arabia/wizard/operations/setup_ksa_vat_setting.py index c30fcffc37..3c89edd37e 100644 --- a/erpnext/regional/saudi_arabia/wizard/operations/setup_ksa_vat_setting.py +++ b/erpnext/regional/saudi_arabia/wizard/operations/setup_ksa_vat_setting.py @@ -16,7 +16,6 @@ def create_ksa_vat_setting(company): with open(file_path, 'r') as json_file: account_data = json.load(json_file) - # Creating KSA VAT Setting ksa_vat_setting = frappe.get_doc({ 'doctype': 'KSA VAT Setting', @@ -44,4 +43,4 @@ def create_ksa_vat_setting(company): 'account': f'{account} - {company.abbr}' }) - ksa_vat_setting.save() \ No newline at end of file + ksa_vat_setting.save()