diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000000..24f122a8d43 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,14 @@ +# Root editor config file +root = true + +# Common settings +[*] +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +charset = utf-8 + +# python, js indentation settings +[{*.py,*.js}] +indent_style = tab +indent_size = 4 diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000000..26bb7ab280c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: + - name: Community Forum + url: https://discuss.erpnext.com/ + about: For general QnA, discussions and community help. diff --git a/.github/helper/documentation.py b/.github/helper/documentation.py index b603ed5e53d..9cc4663c394 100644 --- a/.github/helper/documentation.py +++ b/.github/helper/documentation.py @@ -21,8 +21,8 @@ def docs_link_exists(body): if word.startswith('http') and uri_validator(word): parsed_url = urlparse(word) if parsed_url.netloc == "github.com": - _, org, repo, _type, ref = parsed_url.path.split('/') - if org == "frappe" and repo in docs_repos: + parts = parsed_url.path.split('/') + if len(parts) == 5 and parts[1] == "frappe" and parts[2] in docs_repos: return True diff --git a/.travis/site_config.json b/.travis/site_config.json index dae80095d45..572bbd08532 100644 --- a/.travis/site_config.json +++ b/.travis/site_config.json @@ -9,5 +9,6 @@ "root_login": "root", "root_password": "travis", "host_name": "http://test_site:8000", - "install_apps": ["erpnext"] + "install_apps": ["erpnext"], + "throttle_user_limit": 100 } \ No newline at end of file diff --git a/README.md b/README.md index 0f6a52142bf..15782a2e0c4 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@
ERP made simple
-[](https://travis-ci.com/frappe/erpnext) +[](https://travis-ci.com/frappe/erpnext) [](https://www.codetriage.com/frappe/erpnext) [](https://coveralls.io/github/frappe/erpnext?branch=develop) diff --git a/erpnext/accounts/dashboard_chart_source/account_balance_timeline/account_balance_timeline.py b/erpnext/accounts/dashboard_chart_source/account_balance_timeline/account_balance_timeline.py index 39bf4b053a7..85f54f98ba8 100644 --- a/erpnext/accounts/dashboard_chart_source/account_balance_timeline/account_balance_timeline.py +++ b/erpnext/accounts/dashboard_chart_source/account_balance_timeline/account_balance_timeline.py @@ -6,9 +6,8 @@ import frappe, json from frappe import _ from frappe.utils import add_to_date, date_diff, getdate, nowdate, get_last_day, formatdate, get_link_to_form from erpnext.accounts.report.general_ledger.general_ledger import execute -from frappe.utils.dashboard import cache_source, get_from_date_from_timespan -from frappe.desk.doctype.dashboard_chart.dashboard_chart import get_period_ending - +from frappe.utils.dashboard import cache_source +from frappe.utils.dateutils import get_from_date_from_timespan, get_period_ending from frappe.utils.nestedset import get_descendants_of @frappe.whitelist() diff --git a/erpnext/accounts/desk_page/accounting/accounting.json b/erpnext/accounts/desk_page/accounting/accounting.json index b2a3f83e5fd..a18dbffd9ab 100644 --- a/erpnext/accounts/desk_page/accounting/accounting.json +++ b/erpnext/accounts/desk_page/accounting/accounting.json @@ -43,7 +43,7 @@ { "hidden": 0, "label": "Bank Statement", - "links": "[\n {\n \"label\": \"Bank\",\n \"name\": \"Bank\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Bank Account\",\n \"name\": \"Bank Account\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Bank Clearance\",\n \"name\": \"Bank Clearance\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Bank Reconciliation\",\n \"name\": \"bank-reconciliation\",\n \"type\": \"page\"\n },\n {\n \"dependencies\": [\n \"GL Entry\"\n ],\n \"doctype\": \"GL Entry\",\n \"is_query_report\": true,\n \"label\": \"Bank Reconciliation Statement\",\n \"name\": \"Bank Reconciliation Statement\",\n \"type\": \"report\"\n },\n {\n \"label\": \"Bank Statement Transaction Entry\",\n \"name\": \"Bank Statement Transaction Entry\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Bank Statement Settings\",\n \"name\": \"Bank Statement Settings\",\n \"type\": \"doctype\"\n }\n]" + "links": "[\n {\n \"label\": \"Bank\",\n \"name\": \"Bank\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Bank Account\",\n \"name\": \"Bank Account\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Bank Clearance\",\n \"name\": \"Bank Clearance\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Bank Reconciliation\",\n \"name\": \"bank-reconciliation\",\n \"type\": \"page\"\n },\n {\n \"dependencies\": [\n \"GL Entry\"\n ],\n \"doctype\": \"GL Entry\",\n \"is_query_report\": true,\n \"label\": \"Bank Reconciliation Statement\",\n \"name\": \"Bank Reconciliation Statement\",\n \"type\": \"report\"\n }\n]" }, { "hidden": 0, diff --git a/erpnext/accounts/doctype/account/chart_of_accounts/verified/de_kontenplan_SKR04_with_account_number.json b/erpnext/accounts/doctype/account/chart_of_accounts/verified/de_kontenplan_SKR04_with_account_number.json index 3fc109bfd67..849df18c6f9 100644 --- a/erpnext/accounts/doctype/account/chart_of_accounts/verified/de_kontenplan_SKR04_with_account_number.json +++ b/erpnext/accounts/doctype/account/chart_of_accounts/verified/de_kontenplan_SKR04_with_account_number.json @@ -910,98 +910,8 @@ }, "is_group": 1 }, - "Passiva": { + "Passiva - Verbindlichkeiten": { "root_type": "Liability", - "A - Eigenkapital": { - "account_type": "Equity", - "is_group": 1, - "I - Gezeichnetes Kapital": { - "account_type": "Equity", - "is_group": 1, - "Gezeichnetes Kapital": { - "account_type": "Equity", - "account_number": "2900" - }, - "Ausstehende Einlagen auf das gezeichnete Kapital": { - "account_number": "2910", - "is_group": 1 - } - }, - "II - Kapitalr\u00fccklage": { - "account_type": "Equity", - "is_group": 1, - "Kapitalr\u00fccklage": { - "account_number": "2920" - } - }, - "III - Gewinnr\u00fccklagen": { - "account_type": "Equity", - "1 - gesetzliche R\u00fccklage": { - "account_type": "Equity", - "is_group": 1, - "Gesetzliche R\u00fccklage": { - "account_number": "2930" - } - }, - "2 - R\u00fccklage f. Anteile an einem herrschenden oder mehrheitlich beteiligten Unternehmen": { - "account_type": "Equity", - "is_group": 1 - }, - "3 - satzungsm\u00e4\u00dfige R\u00fccklagen": { - "account_type": "Equity", - "is_group": 1, - "Satzungsm\u00e4\u00dfige R\u00fccklagen": { - "account_number": "2950" - } - }, - "4 - andere Gewinnr\u00fccklagen": { - "account_type": "Equity", - "is_group": 1, - "Gewinnr\u00fccklagen aus den \u00dcbergangsvorschriften BilMoG": { - "is_group": 1, - "Gewinnr\u00fccklagen (BilMoG)": { - "account_number": "2963" - }, - "Gewinnr\u00fccklagen aus Zuschreibung Sachanlageverm\u00f6gen (BilMoG)": { - "account_number": "2964" - }, - "Gewinnr\u00fccklagen aus Zuschreibung Finanzanlageverm\u00f6gen (BilMoG)": { - "account_number": "2965" - }, - "Gewinnr\u00fccklagen aus Aufl\u00f6sung der Sonderposten mit R\u00fccklageanteil (BilMoG)": { - "account_number": "2966" - } - }, - "Latente Steuern (Gewinnr\u00fccklage Haben) aus erfolgsneutralen Verrechnungen": { - "account_number": "2967" - }, - "Latente Steuern (Gewinnr\u00fccklage Soll) aus erfolgsneutralen Verrechnungen": { - "account_number": "2968" - }, - "Rechnungsabgrenzungsposten (Gewinnr\u00fccklage Soll) aus erfolgsneutralen Verrechnungen": { - "account_number": "2969" - } - }, - "is_group": 1 - }, - "IV - Gewinnvortrag/Verlustvortrag": { - "account_type": "Equity", - "is_group": 1, - "Gewinnvortrag vor Verwendung": { - "account_number": "2970" - }, - "Verlustvortrag vor Verwendung": { - "account_number": "2978" - } - }, - "V - Jahres\u00fcberschu\u00df/Jahresfehlbetrag": { - "account_type": "Equity", - "is_group": 1 - }, - "Einlagen stiller Gesellschafter": { - "account_number": "9295" - } - }, "B - R\u00fcckstellungen": { "is_group": 1, "1 - R\u00fcckstellungen f. Pensionen und \u00e4hnliche Verplicht.": { @@ -1618,6 +1528,143 @@ }, "is_group": 1 }, + "Passiva - Eigenkapital": { + "root_type": "Equity", + "A - Eigenkapital": { + "account_type": "Equity", + "is_group": 1, + "I - Gezeichnetes Kapital": { + "account_type": "Equity", + "is_group": 1, + "Gezeichnetes Kapital": { + "account_number": "2900", + "account_type": "Equity" + }, + "Gesch\u00e4ftsguthaben der verbleibenden Mitglieder": { + "account_number": "2901" + }, + "Gesch\u00e4ftsguthaben der ausscheidenden Mitglieder": { + "account_number": "2902" + }, + "Gesch\u00e4ftsguthaben aus gek\u00fcndigten Gesch\u00e4ftsanteilen": { + "account_number": "2903" + }, + "R\u00fcckst\u00e4ndige f\u00e4llige Einzahlungen auf Gesch\u00e4ftsanteile, vermerkt": { + "account_number": "2906" + }, + "Gegenkonto R\u00fcckst\u00e4ndige f\u00e4llige Einzahlungen auf Gesch\u00e4ftsanteile, vermerkt": { + "account_number": "2907" + }, + "Kapitalerh\u00f6hung aus Gesellschaftsmitteln": { + "account_number": "2908" + }, + "Ausstehende Einlagen auf das gezeichnete Kapital, nicht eingefordert": { + "account_number": "2910" + } + }, + "II - Kapitalr\u00fccklage": { + "account_type": "Equity", + "is_group": 1, + "Kapitalr\u00fccklage": { + "account_number": "2920" + }, + "Kapitalr\u00fccklage durch Ausgabe von Anteilen \u00fcber Nennbetrag": { + "account_number": "2925" + }, + "Kapitalr\u00fccklage durch Ausgabe von Schuldverschreibungen": { + "account_number": "2926" + }, + "Kapitalr\u00fccklage durch Zuzahlungen gegen Gew\u00e4hrung eines Vorzugs": { + "account_number": "2927" + }, + "Kapitalr\u00fccklage durch Zuzahlungen in das Eigenkapital": { + "account_number": "2928" + }, + "Nachschusskapital (Gegenkonto 1299)": { + "account_number": "2929" + } + }, + "III - Gewinnr\u00fccklagen": { + "account_type": "Equity", + "1 - gesetzliche R\u00fccklage": { + "account_type": "Equity", + "is_group": 1, + "Gesetzliche R\u00fccklage": { + "account_number": "2930" + } + }, + "2 - R\u00fccklage f. Anteile an einem herrschenden oder mehrheitlich beteiligten Unternehmen": { + "account_type": "Equity", + "is_group": 1, + "R\u00fccklage f. Anteile an einem herrschenden oder mehrheitlich beteiligten Unternehmen": { + "account_number": "2935" + } + }, + "3 - satzungsm\u00e4\u00dfige R\u00fccklagen": { + "account_type": "Equity", + "is_group": 1, + "Satzungsm\u00e4\u00dfige R\u00fccklagen": { + "account_number": "2950" + } + }, + "4 - andere Gewinnr\u00fccklagen": { + "account_type": "Equity", + "is_group": 1, + "Andere Gewinnr\u00fccklagen": { + "account_number": "2960" + }, + "Andere Gewinnr\u00fccklagen aus dem Erwerb eigener Anteile": { + "account_number": "2961" + }, + "Eigenkapitalanteil von Wertaufholungen": { + "account_number": "2962" + }, + "Gewinnr\u00fccklagen aus den \u00dcbergangsvorschriften BilMoG": { + "is_group": 1, + "Gewinnr\u00fccklagen (BilMoG)": { + "account_number": "2963" + }, + "Gewinnr\u00fccklagen aus Zuschreibung Sachanlageverm\u00f6gen (BilMoG)": { + "account_number": "2964" + }, + "Gewinnr\u00fccklagen aus Zuschreibung Finanzanlageverm\u00f6gen (BilMoG)": { + "account_number": "2965" + }, + "Gewinnr\u00fccklagen aus Aufl\u00f6sung der Sonderposten mit R\u00fccklageanteil (BilMoG)": { + "account_number": "2966" + } + }, + "Latente Steuern (Gewinnr\u00fccklage Haben) aus erfolgsneutralen Verrechnungen": { + "account_number": "2967" + }, + "Latente Steuern (Gewinnr\u00fccklage Soll) aus erfolgsneutralen Verrechnungen": { + "account_number": "2968" + }, + "Rechnungsabgrenzungsposten (Gewinnr\u00fccklage Soll) aus erfolgsneutralen Verrechnungen": { + "account_number": "2969" + } + }, + "is_group": 1 + }, + "IV - Gewinnvortrag/Verlustvortrag": { + "account_type": "Equity", + "is_group": 1, + "Gewinnvortrag vor Verwendung": { + "account_number": "2970" + }, + "Verlustvortrag vor Verwendung": { + "account_number": "2978" + } + }, + "V - Jahres\u00fcberschu\u00df/Jahresfehlbetrag": { + "account_type": "Equity", + "is_group": 1 + }, + "Einlagen stiller Gesellschafter": { + "account_number": "9295" + } + } + }, "1 - Umsatzerl\u00f6se": { "root_type": "Income", "is_group": 1, diff --git a/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts_with_account_number.py b/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts_with_account_number.py index 6c83e3bd670..acb11e557a5 100644 --- a/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts_with_account_number.py +++ b/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts_with_account_number.py @@ -245,6 +245,9 @@ def get(): "account_number": "2200" }, _("Duties and Taxes"): { + _("TDS Payable"): { + "account_number": "2310" + }, "account_type": "Tax", "is_group": 1, "account_number": "2300" diff --git a/erpnext/accounts/doctype/account/test_account.py b/erpnext/accounts/doctype/account/test_account.py index 0605d89a7e2..113bea00645 100644 --- a/erpnext/accounts/doctype/account/test_account.py +++ b/erpnext/accounts/doctype/account/test_account.py @@ -172,7 +172,7 @@ class TestAccount(unittest.TestCase): frappe.delete_doc("Account", doc) -def _make_test_records(verbose): +def _make_test_records(verbose=None): from frappe.test_runner import make_test_objects accounts = [ diff --git a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.js b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.js index 9a6c3893393..65c5ff1ceaf 100644 --- a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.js +++ b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.js @@ -2,7 +2,6 @@ // For license information, please see license.txt frappe.ui.form.on('Accounting Dimension', { - refresh: function(frm) { frm.set_query('document_type', () => { let invalid_doctypes = frappe.model.core_doctypes_list; diff --git a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py index f888d9e038a..52e9ff8b764 100644 --- a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py +++ b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py @@ -203,7 +203,7 @@ def get_dimension_with_children(doctype, dimension): return all_dimensions @frappe.whitelist() -def get_dimension_filters(): +def get_dimensions(with_cost_center_and_project=False): dimension_filters = frappe.db.sql(""" SELECT label, fieldname, document_type FROM `tabAccounting Dimension` @@ -214,6 +214,18 @@ def get_dimension_filters(): FROM `tabAccounting Dimension Detail` c, `tabAccounting Dimension` p WHERE c.parent = p.name""", as_dict=1) + if with_cost_center_and_project: + dimension_filters.extend([ + { + 'fieldname': 'cost_center', + 'document_type': 'Cost Center' + }, + { + 'fieldname': 'project', + 'document_type': 'Project' + } + ]) + default_dimensions_map = {} for dimension in default_dimensions: default_dimensions_map.setdefault(dimension.company, {}) diff --git a/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py b/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py index 104880f6f34..fc1d7e344af 100644 --- a/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py +++ b/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py @@ -11,37 +11,7 @@ from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import d class TestAccountingDimension(unittest.TestCase): def setUp(self): - frappe.set_user("Administrator") - - if not frappe.db.exists("Accounting Dimension", {"document_type": "Department"}): - dimension = frappe.get_doc({ - "doctype": "Accounting Dimension", - "document_type": "Department", - }).insert() - else: - dimension1 = frappe.get_doc("Accounting Dimension", "Department") - dimension1.disabled = 0 - dimension1.save() - - if not frappe.db.exists("Accounting Dimension", {"document_type": "Location"}): - dimension1 = frappe.get_doc({ - "doctype": "Accounting Dimension", - "document_type": "Location", - }) - - dimension1.append("dimension_defaults", { - "company": "_Test Company", - "reference_document": "Location", - "default_dimension": "Block 1", - "mandatory_for_bs": 1 - }) - - dimension1.insert() - dimension1.save() - else: - dimension1 = frappe.get_doc("Accounting Dimension", "Location") - dimension1.disabled = 0 - dimension1.save() + create_dimension() def test_dimension_against_sales_invoice(self): si = create_sales_invoice(do_not_save=1) @@ -101,6 +71,38 @@ class TestAccountingDimension(unittest.TestCase): def tearDown(self): disable_dimension() +def create_dimension(): + frappe.set_user("Administrator") + + if not frappe.db.exists("Accounting Dimension", {"document_type": "Department"}): + frappe.get_doc({ + "doctype": "Accounting Dimension", + "document_type": "Department", + }).insert() + else: + dimension = frappe.get_doc("Accounting Dimension", "Department") + dimension.disabled = 0 + dimension.save() + + if not frappe.db.exists("Accounting Dimension", {"document_type": "Location"}): + dimension1 = frappe.get_doc({ + "doctype": "Accounting Dimension", + "document_type": "Location", + }) + + dimension1.append("dimension_defaults", { + "company": "_Test Company", + "reference_document": "Location", + "default_dimension": "Block 1", + "mandatory_for_bs": 1 + }) + + dimension1.insert() + dimension1.save() + else: + dimension1 = frappe.get_doc("Accounting Dimension", "Location") + dimension1.disabled = 0 + dimension1.save() def disable_dimension(): dimension1 = frappe.get_doc("Accounting Dimension", "Department") diff --git a/erpnext/communication/doctype/call_log/__init__.py b/erpnext/accounts/doctype/accounting_dimension_filter/__init__.py similarity index 100% rename from erpnext/communication/doctype/call_log/__init__.py rename to erpnext/accounts/doctype/accounting_dimension_filter/__init__.py diff --git a/erpnext/accounts/doctype/accounting_dimension_filter/accounting_dimension_filter.js b/erpnext/accounts/doctype/accounting_dimension_filter/accounting_dimension_filter.js new file mode 100644 index 00000000000..74b7b516763 --- /dev/null +++ b/erpnext/accounts/doctype/accounting_dimension_filter/accounting_dimension_filter.js @@ -0,0 +1,82 @@ +// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt + +frappe.ui.form.on('Accounting Dimension Filter', { + refresh: function(frm, cdt, cdn) { + if (frm.doc.accounting_dimension) { + frm.set_df_property('dimensions', 'label', frm.doc.accounting_dimension, cdn, 'dimension_value'); + } + + let help_content = + `|
+ + + {{__('Note: On checking Is Mandatory the accounting dimension will become mandatory against that specific account for all accounting transactions')}} + + |
{{ seller.Gstin }}
+{{ seller.LglNm }}
+{{ seller.Addr1 }}
+ {%- if seller.Addr2 -%}{{ seller.Addr2 }}
{% endif %} +{{ seller.Loc }}
+{{ frappe.db.get_value("Address", doc.company_address, "gst_state") }} - {{ seller.Pin }}
+ + {%- if einvoice.ShipDtls -%} + {%- set shipping = einvoice.ShipDtls -%} +{{ shipping.Gstin }}
+{{ shipping.LglNm }}
+{{ shipping.Addr1 }}
+ {%- if shipping.Addr2 -%}{{ shipping.Addr2 }}
{% endif %} +{{ shipping.Loc }}
+{{ frappe.db.get_value("Address", doc.shipping_address_name, "gst_state") }} - {{ shipping.Pin }}
+ {% endif %} +{{ buyer.Gstin }}
+{{ buyer.LglNm }}
+{{ buyer.Addr1 }}
+ {%- if buyer.Addr2 -%}{{ buyer.Addr2 }}
{% endif %} +{{ buyer.Loc }}
+{{ frappe.db.get_value("Address", doc.customer_address, "gst_state") }} - {{ buyer.Pin }}
+| Sr. No. | +Item | +HSN Code | +Qty | +UOM | +Rate | +Discount | +Taxable Amount | +Tax Rate | +Other Charges | +Total | +
|---|---|---|---|---|---|---|---|---|---|---|
| {{ item.SlNo }} | +{{ item.PrdDesc }} | +{{ item.HsnCd }} | +{{ item.Qty }} | +{{ item.Unit }} | +{{ frappe.utils.fmt_money(item.UnitPrice, None, "INR") }} | +{{ frappe.utils.fmt_money(item.Discount, None, "INR") }} | +{{ frappe.utils.fmt_money(item.AssAmt, None, "INR") }} | +{{ item.GstRt + item.CesRt }} % | +{{ frappe.utils.fmt_money(0, None, "INR") }} | +{{ frappe.utils.fmt_money(item.TotItemVal, None, "INR") }} | +
| Taxable Amount | +CGST | +SGST | +IGST | +CESS | +State CESS | +Discount | +Other Charges | +Round Off | +Total Value | +
|---|---|---|---|---|---|---|---|---|---|
| {{ frappe.utils.fmt_money(value_details.AssVal, None, "INR") }} | +{{ frappe.utils.fmt_money(value_details.CgstVal, None, "INR") }} | +{{ frappe.utils.fmt_money(value_details.SgstVal, None, "INR") }} | +{{ frappe.utils.fmt_money(value_details.IgstVal, None, "INR") }} | +{{ frappe.utils.fmt_money(value_details.CesVal, None, "INR") }} | +{{ frappe.utils.fmt_money(0, None, "INR") }} | +{{ frappe.utils.fmt_money(value_details.Discount, None, "INR") }} | +{{ frappe.utils.fmt_money(0, None, "INR") }} | +{{ frappe.utils.fmt_money(value_details.RndOffAmt, None, "INR") }} | +{{ frappe.utils.fmt_money(value_details.TotInvVal, None, "INR") }} | +
| {%= __(range3) %} | {%= __(range4) %} | {%= __(range5) %} | +{%= __(range6) %} | {%= __("Total") %} | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| {%= __("Total Outstanding") %} | -{%= format_number(balance_row["range1"], null, 2) %} | -{%= format_currency(balance_row["range2"]) %} | -{%= format_currency(balance_row["range3"]) %} | -{%= format_currency(balance_row["range4"]) %} | -{%= format_currency(balance_row["range5"]) %} | ++ {%= format_number(balance_row["age"], null, 2) %} + | ++ {%= format_currency(balance_row["range1"], data[data.length-1]["currency"]) %} + | ++ {%= format_currency(balance_row["range2"], data[data.length-1]["currency"]) %} + | ++ {%= format_currency(balance_row["range3"], data[data.length-1]["currency"]) %} + | ++ {%= format_currency(balance_row["range4"], data[data.length-1]["currency"]) %} + | ++ {%= format_currency(balance_row["range5"], data[data.length-1]["currency"]) %} + | {%= format_currency(flt(balance_row["outstanding"]), data[data.length-1]["currency"]) %} - | +{%= __("Future Payments") %} | @@ -91,6 +107,7 @@ | + | {%= format_currency(flt(balance_row[("future_amount")]), data[data.length-1]["currency"]) %} | @@ -101,6 +118,7 @@+ | {%= format_currency(flt(balance_row["outstanding"] - balance_row[("future_amount")]), data[data.length-1]["currency"]) %} | @@ -218,15 +236,15 @@{%= __("Total") %} | - {%= format_currency(data[i]["invoiced"], data[0]["currency"] ) %} | + {%= format_currency(data[i]["invoiced"], data[i]["currency"] ) %} {% if(!filters.show_future_payments) { %}- {%= format_currency(data[i]["paid"], data[0]["currency"]) %} | -{%= format_currency(data[i]["credit_note"], data[0]["currency"]) %} | + {%= format_currency(data[i]["paid"], data[i]["currency"]) %} +{%= format_currency(data[i]["credit_note"], data[i]["currency"]) %} | {% } %}- {%= format_currency(data[i]["outstanding"], data[0]["currency"]) %} | + {%= format_currency(data[i]["outstanding"], data[i]["currency"]) %} {% if(filters.show_future_payments) { %} {% if(report.report_name === "Accounts Receivable") { %} @@ -234,8 +252,8 @@ {%= data[i]["po_no"] %} {% } %}{%= data[i]["future_ref"] %} | -{%= format_currency(data[i]["future_amount"], data[0]["currency"]) %} | -{%= format_currency(data[i]["remaining_balance"], data[0]["currency"]) %} | +{%= format_currency(data[i]["future_amount"], data[i]["currency"]) %} | +{%= format_currency(data[i]["remaining_balance"], data[i]["currency"]) %} | {% } %} {% } %} {% } else { %} @@ -256,10 +274,10 @@ {% } else { %}{%= __("Total") %} | {% } %} -{%= format_currency(data[i]["invoiced"], data[0]["currency"]) %} | -{%= format_currency(data[i]["paid"], data[0]["currency"]) %} | -{%= format_currency(data[i]["credit_note"], data[0]["currency"]) %} | -{%= format_currency(data[i]["outstanding"], data[0]["currency"]) %} | +{%= format_currency(data[i]["invoiced"], data[i]["currency"]) %} | +{%= format_currency(data[i]["paid"], data[i]["currency"]) %} | +{%= format_currency(data[i]["credit_note"], data[i]["currency"]) %} | +{%= format_currency(data[i]["outstanding"], data[i]["currency"]) %} | {% } %} {% } %} diff --git a/erpnext/accounts/report/asset_depreciation_ledger/asset_depreciation_ledger.py b/erpnext/accounts/report/asset_depreciation_ledger/asset_depreciation_ledger.py index 16bef565252..2162a02eff9 100644 --- a/erpnext/accounts/report/asset_depreciation_ledger/asset_depreciation_ledger.py +++ b/erpnext/accounts/report/asset_depreciation_ledger/asset_depreciation_ledger.py @@ -47,21 +47,22 @@ def get_data(filters): for d in gl_entries: asset_data = assets_details.get(d.against_voucher) - if not asset_data.get("accumulated_depreciation_amount"): - asset_data.accumulated_depreciation_amount = d.debit - else: - asset_data.accumulated_depreciation_amount += d.debit + if asset_data: + if not asset_data.get("accumulated_depreciation_amount"): + asset_data.accumulated_depreciation_amount = d.debit + else: + asset_data.accumulated_depreciation_amount += d.debit - row = frappe._dict(asset_data) - row.update({ - "depreciation_amount": d.debit, - "depreciation_date": d.posting_date, - "amount_after_depreciation": (flt(row.gross_purchase_amount) - - flt(row.accumulated_depreciation_amount)), - "depreciation_entry": d.voucher_no - }) + row = frappe._dict(asset_data) + row.update({ + "depreciation_amount": d.debit, + "depreciation_date": d.posting_date, + "amount_after_depreciation": (flt(row.gross_purchase_amount) - + flt(row.accumulated_depreciation_amount)), + "depreciation_entry": d.voucher_no + }) - data.append(row) + data.append(row) return data diff --git a/erpnext/accounts/report/delivered_items_to_be_billed/delivered_items_to_be_billed.py b/erpnext/accounts/report/delivered_items_to_be_billed/delivered_items_to_be_billed.py index 3ffb3ac1df4..515fd995e66 100644 --- a/erpnext/accounts/report/delivered_items_to_be_billed/delivered_items_to_be_billed.py +++ b/erpnext/accounts/report/delivered_items_to_be_billed/delivered_items_to_be_billed.py @@ -14,11 +14,93 @@ def execute(filters=None): def get_column(): return [ - _("Delivery Note") + ":Link/Delivery Note:120", _("Status") + "::120", _("Date") + ":Date:100", - _("Suplier") + ":Link/Customer:120", _("Customer Name") + "::120", - _("Project") + ":Link/Project:120", _("Item Code") + ":Link/Item:120", - _("Amount") + ":Currency:100", _("Billed Amount") + ":Currency:100", _("Pending Amount") + ":Currency:100", - _("Item Name") + "::120", _("Description") + "::120", _("Company") + ":Link/Company:120", + { + "label": _("Delivery Note"), + "fieldname": "name", + "fieldtype": "Link", + "options": "Delivery Note", + "width": 160 + }, + { + "label": _("Date"), + "fieldname": "date", + "fieldtype": "Date", + "width": 100 + }, + { + "label": _("Customer"), + "fieldname": "customer", + "fieldtype": "Link", + "options": "Customer", + "width": 120 + }, + { + "label": _("Customer Name"), + "fieldname": "customer_name", + "fieldtype": "Data", + "width": 120 + }, + { + "label": _("Item Code"), + "fieldname": "item_code", + "fieldtype": "Link", + "options": "Item", + "width": 120 + }, + { + "label": _("Amount"), + "fieldname": "amount", + "fieldtype": "Currency", + "width": 100, + "options": "Company:company:default_currency" + }, + { + "label": _("Billed Amount"), + "fieldname": "billed_amount", + "fieldtype": "Currency", + "width": 100, + "options": "Company:company:default_currency" + }, + { + "label": _("Returned Amount"), + "fieldname": "returned_amount", + "fieldtype": "Currency", + "width": 120, + "options": "Company:company:default_currency" + }, + { + "label": _("Pending Amount"), + "fieldname": "pending_amount", + "fieldtype": "Currency", + "width": 120, + "options": "Company:company:default_currency" + }, + { + "label": _("Item Name"), + "fieldname": "item_name", + "fieldtype": "Data", + "width": 120 + }, + { + "label": _("Description"), + "fieldname": "description", + "fieldtype": "Data", + "width": 120 + }, + { + "label": _("Project"), + "fieldname": "project", + "fieldtype": "Link", + "options": "Project", + "width": 120 + }, + { + "label": _("Company"), + "fieldname": "company", + "fieldtype": "Link", + "options": "Company", + "width": 120 + } ] def get_args(): diff --git a/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py b/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py index 3445df7206f..a36e7f8581f 100644 --- a/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py +++ b/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py @@ -8,6 +8,7 @@ from frappe.utils import flt from erpnext.accounts.report.item_wise_sales_register.item_wise_sales_register import (get_tax_accounts, get_grand_total, add_total_row, get_display_value, get_group_by_and_display_fields, add_sub_total_row, get_group_by_conditions) +from erpnext.selling.report.item_wise_sales_history.item_wise_sales_history import get_item_details def execute(filters=None): return _execute(filters) @@ -22,7 +23,7 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum aii_account_map = get_aii_accounts() if item_list: itemised_tax, tax_columns = get_tax_accounts(item_list, columns, company_currency, - doctype="Purchase Invoice", tax_doctype="Purchase Taxes and Charges") + doctype='Purchase Invoice', tax_doctype='Purchase Taxes and Charges') po_pr_map = get_purchase_receipts_against_purchase_order(item_list) @@ -34,10 +35,14 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum if filters.get('group_by'): grand_total = get_grand_total(filters, 'Purchase Invoice') + item_details = get_item_details() + for d in item_list: if not d.stock_qty: continue + item_record = item_details.get(d.item_code) + purchase_receipt = None if d.purchase_receipt: purchase_receipt = d.purchase_receipt @@ -48,8 +53,8 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum row = { 'item_code': d.item_code, - 'item_name': d.item_name, - 'item_group': d.item_group, + 'item_name': item_record.item_name, + 'item_group': item_record.item_group, 'description': d.description, 'invoice': d.parent, 'posting_date': d.posting_date, @@ -81,10 +86,10 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum for tax in tax_columns: item_tax = itemised_tax.get(d.name, {}).get(tax, {}) row.update({ - frappe.scrub(tax + ' Rate'): item_tax.get("tax_rate", 0), - frappe.scrub(tax + ' Amount'): item_tax.get("tax_amount", 0), + frappe.scrub(tax + ' Rate'): item_tax.get('tax_rate', 0), + frappe.scrub(tax + ' Amount'): item_tax.get('tax_amount', 0), }) - total_tax += flt(item_tax.get("tax_amount")) + total_tax += flt(item_tax.get('tax_amount')) row.update({ 'total_tax': total_tax, @@ -309,8 +314,8 @@ def get_items(filters, additional_query_columns): select `tabPurchase Invoice Item`.`name`, `tabPurchase Invoice Item`.`parent`, `tabPurchase Invoice`.posting_date, `tabPurchase Invoice`.credit_to, `tabPurchase Invoice`.company, - `tabPurchase Invoice`.supplier, `tabPurchase Invoice`.remarks, `tabPurchase Invoice`.base_net_total, `tabPurchase Invoice Item`.`item_code`, - `tabPurchase Invoice Item`.`item_name`, `tabPurchase Invoice Item`.`item_group`, `tabPurchase Invoice Item`.description, + `tabPurchase Invoice`.supplier, `tabPurchase Invoice`.remarks, `tabPurchase Invoice`.base_net_total, + `tabPurchase Invoice Item`.`item_code`, `tabPurchase Invoice Item`.description, `tabPurchase Invoice Item`.`project`, `tabPurchase Invoice Item`.`purchase_order`, `tabPurchase Invoice Item`.`purchase_receipt`, `tabPurchase Invoice Item`.`po_detail`, `tabPurchase Invoice Item`.`expense_account`, `tabPurchase Invoice Item`.`stock_qty`, diff --git a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py index a05dcd75ce5..f54ceb0d2f5 100644 --- a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py +++ b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py @@ -8,6 +8,7 @@ from frappe.utils import flt, cstr from frappe.model.meta import get_field_precision from frappe.utils.xlsxutils import handle_html from erpnext.accounts.report.sales_register.sales_register import get_mode_of_payments +from erpnext.selling.report.item_wise_sales_history.item_wise_sales_history import get_item_details, get_customer_details def execute(filters=None): return _execute(filters) @@ -16,7 +17,7 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum if not filters: filters = {} columns = get_columns(additional_table_columns, filters) - company_currency = frappe.get_cached_value('Company', filters.get("company"), "default_currency") + company_currency = frappe.get_cached_value('Company', filters.get('company'), 'default_currency') item_list = get_items(filters, additional_query_columns) if item_list: @@ -33,7 +34,13 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum if filters.get('group_by'): grand_total = get_grand_total(filters, 'Sales Invoice') + customer_details = get_customer_details() + item_details = get_item_details() + for d in item_list: + customer_record = customer_details.get(d.customer) + item_record = item_details.get(d.item_code) + delivery_note = None if d.delivery_note: delivery_note = d.delivery_note @@ -45,14 +52,14 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum row = { 'item_code': d.item_code, - 'item_name': d.item_name, - 'item_group': d.item_group, + 'item_name': item_record.item_name, + 'item_group': item_record.item_group, 'description': d.description, 'invoice': d.parent, 'posting_date': d.posting_date, 'customer': d.customer, - 'customer_name': d.customer_name, - 'customer_group': d.customer_group, + 'customer_name': customer_record.customer_name, + 'customer_group': customer_record.customer_group, } if additional_query_columns: @@ -90,10 +97,10 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum for tax in tax_columns: item_tax = itemised_tax.get(d.name, {}).get(tax, {}) row.update({ - frappe.scrub(tax + ' Rate'): item_tax.get("tax_rate", 0), - frappe.scrub(tax + ' Amount'): item_tax.get("tax_amount", 0), + frappe.scrub(tax + ' Rate'): item_tax.get('tax_rate', 0), + frappe.scrub(tax + ' Amount'): item_tax.get('tax_amount', 0), }) - total_tax += flt(item_tax.get("tax_amount")) + total_tax += flt(item_tax.get('tax_amount')) row.update({ 'total_tax': total_tax, @@ -226,7 +233,7 @@ def get_columns(additional_table_columns, filters): if filters.get('group_by') != 'Territory': columns.extend([ { - 'label': _("Territory"), + 'label': _('Territory'), 'fieldname': 'territory', 'fieldtype': 'Link', 'options': 'Territory', @@ -374,13 +381,12 @@ def get_items(filters, additional_query_columns): `tabSales Invoice`.posting_date, `tabSales Invoice`.debit_to, `tabSales Invoice`.project, `tabSales Invoice`.customer, `tabSales Invoice`.remarks, `tabSales Invoice`.territory, `tabSales Invoice`.company, `tabSales Invoice`.base_net_total, - `tabSales Invoice Item`.item_code, `tabSales Invoice Item`.item_name, - `tabSales Invoice Item`.item_group, `tabSales Invoice Item`.description, `tabSales Invoice Item`.sales_order, - `tabSales Invoice Item`.delivery_note, `tabSales Invoice Item`.income_account, - `tabSales Invoice Item`.cost_center, `tabSales Invoice Item`.stock_qty, - `tabSales Invoice Item`.stock_uom, `tabSales Invoice Item`.base_net_rate, - `tabSales Invoice Item`.base_net_amount, `tabSales Invoice`.customer_name, - `tabSales Invoice`.customer_group, `tabSales Invoice Item`.so_detail, + `tabSales Invoice Item`.item_code, `tabSales Invoice Item`.description, + `tabSales Invoice Item`.sales_order, `tabSales Invoice Item`.delivery_note, + `tabSales Invoice Item`.income_account, `tabSales Invoice Item`.cost_center, + `tabSales Invoice Item`.stock_qty, `tabSales Invoice Item`.stock_uom, + `tabSales Invoice Item`.base_net_rate, `tabSales Invoice Item`.base_net_amount, + `tabSales Invoice`.customer_name, `tabSales Invoice`.customer_group, `tabSales Invoice Item`.so_detail, `tabSales Invoice`.update_stock, `tabSales Invoice Item`.uom, `tabSales Invoice Item`.qty {0} from `tabSales Invoice`, `tabSales Invoice Item` where `tabSales Invoice`.name = `tabSales Invoice Item`.parent @@ -417,14 +423,14 @@ def get_deducted_taxes(): return frappe.db.sql_list("select name from `tabPurchase Taxes and Charges` where add_deduct_tax = 'Deduct'") def get_tax_accounts(item_list, columns, company_currency, - doctype="Sales Invoice", tax_doctype="Sales Taxes and Charges"): + doctype='Sales Invoice', tax_doctype='Sales Taxes and Charges'): import json item_row_map = {} tax_columns = [] invoice_item_row = {} itemised_tax = {} - tax_amount_precision = get_field_precision(frappe.get_meta(tax_doctype).get_field("tax_amount"), + tax_amount_precision = get_field_precision(frappe.get_meta(tax_doctype).get_field('tax_amount'), currency=company_currency) or 2 for d in item_list: @@ -469,8 +475,8 @@ def get_tax_accounts(item_list, columns, company_currency, tax_rate = tax_data tax_amount = 0 - if charge_type == "Actual" and not tax_rate: - tax_rate = "NA" + if charge_type == 'Actual' and not tax_rate: + tax_rate = 'NA' item_net_amount = sum([flt(d.base_net_amount) for d in item_row_map.get(parent, {}).get(item_code, [])]) @@ -484,17 +490,17 @@ def get_tax_accounts(item_list, columns, company_currency, if (doctype == 'Purchase Invoice' and name in deducted_tax) else tax_value) itemised_tax.setdefault(d.name, {})[description] = frappe._dict({ - "tax_rate": tax_rate, - "tax_amount": tax_value + 'tax_rate': tax_rate, + 'tax_amount': tax_value }) except ValueError: continue - elif charge_type == "Actual" and tax_amount: + elif charge_type == 'Actual' and tax_amount: for d in invoice_item_row.get(parent, []): itemised_tax.setdefault(d.name, {})[description] = frappe._dict({ - "tax_rate": "NA", - "tax_amount": flt((tax_amount * d.base_net_amount) / d.base_net_total, + 'tax_rate': 'NA', + 'tax_amount': flt((tax_amount * d.base_net_amount) / d.base_net_total, tax_amount_precision) }) @@ -563,7 +569,7 @@ def add_total_row(data, filters, prev_group_by_value, item, total_row_map, }) total_row_map.setdefault('total_row', { - subtotal_display_field: "Total", + subtotal_display_field: 'Total', 'stock_qty': 0.0, 'amount': 0.0, 'bold': 1, diff --git a/erpnext/accounts/report/non_billed_report.py b/erpnext/accounts/report/non_billed_report.py index a9e25bc25bf..2e18ce11ddc 100644 --- a/erpnext/accounts/report/non_billed_report.py +++ b/erpnext/accounts/report/non_billed_report.py @@ -17,18 +17,26 @@ def get_ordered_to_be_billed_data(args): return frappe.db.sql(""" Select - `{parent_tab}`.name, `{parent_tab}`.status, `{parent_tab}`.{date_field}, `{parent_tab}`.{party}, `{parent_tab}`.{party}_name, - {project_field}, `{child_tab}`.item_code, `{child_tab}`.base_amount, + `{parent_tab}`.name, `{parent_tab}`.{date_field}, + `{parent_tab}`.{party}, `{parent_tab}`.{party}_name, + `{child_tab}`.item_code, + `{child_tab}`.base_amount, (`{child_tab}`.billed_amt * ifnull(`{parent_tab}`.conversion_rate, 1)), - (`{child_tab}`.base_amount - (`{child_tab}`.billed_amt * ifnull(`{parent_tab}`.conversion_rate, 1))), - `{child_tab}`.item_name, `{child_tab}`.description, `{parent_tab}`.company + (`{child_tab}`.base_rate * ifnull(`{child_tab}`.returned_qty, 0)), + (`{child_tab}`.base_amount - + (`{child_tab}`.billed_amt * ifnull(`{parent_tab}`.conversion_rate, 1)) - + (`{child_tab}`.base_rate * ifnull(`{child_tab}`.returned_qty, 0))), + `{child_tab}`.item_name, `{child_tab}`.description, + {project_field}, `{parent_tab}`.company from `{parent_tab}`, `{child_tab}` where `{parent_tab}`.name = `{child_tab}`.parent and `{parent_tab}`.docstatus = 1 and `{parent_tab}`.status not in ('Closed', 'Completed') - and `{child_tab}`.amount > 0 and round(`{child_tab}`.billed_amt * - ifnull(`{parent_tab}`.conversion_rate, 1), {precision}) < `{child_tab}`.base_amount + and `{child_tab}`.amount > 0 + and (`{child_tab}`.base_amount - + round(`{child_tab}`.billed_amt * ifnull(`{parent_tab}`.conversion_rate, 1), {precision}) - + (`{child_tab}`.base_rate * ifnull(`{child_tab}`.returned_qty, 0))) > 0 order by `{parent_tab}`.{order} {order_by} """.format(parent_tab = 'tab' + doctype, child_tab = 'tab' + child_tab, precision= precision, party = party, diff --git a/erpnext/accounts/report/payment_period_based_on_invoice_date/payment_period_based_on_invoice_date.py b/erpnext/accounts/report/payment_period_based_on_invoice_date/payment_period_based_on_invoice_date.py index 57a1231f5a9..7195c7e0b8b 100644 --- a/erpnext/accounts/report/payment_period_based_on_invoice_date/payment_period_based_on_invoice_date.py +++ b/erpnext/accounts/report/payment_period_based_on_invoice_date/payment_period_based_on_invoice_date.py @@ -59,23 +59,111 @@ def validate_filters(filters): def get_columns(filters): return [ - _("Payment Document") + ":: 100", - _("Payment Entry") + ":Dynamic Link/"+_("Payment Document")+":140", - _("Party Type") + "::100", - _("Party") + ":Dynamic Link/Party Type:140", - _("Posting Date") + ":Date:100", - _("Invoice") + (":Link/Purchase Invoice:130" if filters.get("payment_type") == _("Outgoing") else ":Link/Sales Invoice:130"), - _("Invoice Posting Date") + ":Date:130", - _("Payment Due Date") + ":Date:130", - _("Debit") + ":Currency:120", - _("Credit") + ":Currency:120", - _("Remarks") + "::150", - _("Age") +":Int:40", - "0-30:Currency:100", - "30-60:Currency:100", - "60-90:Currency:100", - _("90-Above") + ":Currency:100", - _("Delay in payment (Days)") + "::150" + { + "fieldname": "payment_document", + "label": _("Payment Document Type"), + "fieldtype": "Data", + "width": 100 + }, + { + "fieldname": "payment_entry", + "label": _("Payment Document"), + "fieldtype": "Dynamic Link", + "options": "payment_document", + "width": 160 + }, + { + "fieldname": "party_type", + "label": _("Party Type"), + "fieldtype": "Data", + "width": 100 + }, + { + "fieldname": "party", + "label": _("Party"), + "fieldtype": "Dynamic Link", + "options": "party_type", + "width": 160 + }, + { + "fieldname": "posting_date", + "label": _("Posting Date"), + "fieldtype": "Date", + "width": 100 + }, + { + "fieldname": "invoice", + "label": _("Invoice"), + "fieldtype": "Link", + "options": "Purchase Invoice" if filters.get("payment_type") == _("Outgoing") else "Sales Invoice", + "width": 160 + }, + { + "fieldname": "invoice_posting_date", + "label": _("Invoice Posting Date"), + "fieldtype": "Date", + "width": 100 + }, + { + "fieldname": "due_date", + "label": _("Payment Due Date"), + "fieldtype": "Date", + "width": 100 + }, + { + "fieldname": "debit", + "label": _("Debit"), + "fieldtype": "Currency", + "width": 140 + }, + { + "fieldname": "credit", + "label": _("Credit"), + "fieldtype": "Currency", + "width": 140 + }, + { + "fieldname": "remarks", + "label": _("Remarks"), + "fieldtype": "Data", + "width": 200 + }, + { + "fieldname": "age", + "label": _("Age"), + "fieldtype": "Int", + "width": 50 + }, + { + "fieldname": "range1", + "label": "0-30", + "fieldtype": "Currency", + "width": 140 + }, + { + "fieldname": "range2", + "label": "30-60", + "fieldtype": "Currency", + "width": 140 + }, + { + "fieldname": "range3", + "label": "60-90", + "fieldtype": "Currency", + "width": 140 + }, + { + "fieldname": "range4", + "label": _("90 Above"), + "fieldtype": "Currency", + "width": 140 + }, + { + "fieldname": "delay_in_payment", + "label": _("Delay in payment (Days)"), + "fieldtype": "Int", + "width": 100 + } ] def get_conditions(filters): diff --git a/erpnext/accounts/report/received_items_to_be_billed/received_items_to_be_billed.py b/erpnext/accounts/report/received_items_to_be_billed/received_items_to_be_billed.py index 5e8d7730b76..e9e9c9c4e69 100644 --- a/erpnext/accounts/report/received_items_to_be_billed/received_items_to_be_billed.py +++ b/erpnext/accounts/report/received_items_to_be_billed/received_items_to_be_billed.py @@ -14,11 +14,93 @@ def execute(filters=None): def get_column(): return [ - _("Purchase Receipt") + ":Link/Purchase Receipt:120", _("Status") + "::120", _("Date") + ":Date:100", - _("Supplier") + ":Link/Supplier:120", _("Supplier Name") + "::120", - _("Project") + ":Link/Project:120", _("Item Code") + ":Link/Item:120", - _("Amount") + ":Currency:100", _("Billed Amount") + ":Currency:100", _("Amount to Bill") + ":Currency:100", - _("Item Name") + "::120", _("Description") + "::120", _("Company") + ":Link/Company:120", + { + "label": _("Purchase Receipt"), + "fieldname": "name", + "fieldtype": "Link", + "options": "Purchase Receipt", + "width": 160 + }, + { + "label": _("Date"), + "fieldname": "date", + "fieldtype": "Date", + "width": 100 + }, + { + "label": _("Supplier"), + "fieldname": "supplier", + "fieldtype": "Link", + "options": "Supplier", + "width": 120 + }, + { + "label": _("Supplier Name"), + "fieldname": "supplier_name", + "fieldtype": "Data", + "width": 120 + }, + { + "label": _("Item Code"), + "fieldname": "item_code", + "fieldtype": "Link", + "options": "Item", + "width": 120 + }, + { + "label": _("Amount"), + "fieldname": "amount", + "fieldtype": "Currency", + "width": 100, + "options": "Company:company:default_currency" + }, + { + "label": _("Billed Amount"), + "fieldname": "billed_amount", + "fieldtype": "Currency", + "width": 100, + "options": "Company:company:default_currency" + }, + { + "label": _("Returned Amount"), + "fieldname": "returned_amount", + "fieldtype": "Currency", + "width": 120, + "options": "Company:company:default_currency" + }, + { + "label": _("Pending Amount"), + "fieldname": "pending_amount", + "fieldtype": "Currency", + "width": 120, + "options": "Company:company:default_currency" + }, + { + "label": _("Item Name"), + "fieldname": "item_name", + "fieldtype": "Data", + "width": 120 + }, + { + "label": _("Description"), + "fieldname": "description", + "fieldtype": "Data", + "width": 120 + }, + { + "label": _("Project"), + "fieldname": "project", + "fieldtype": "Link", + "options": "Project", + "width": 120 + }, + { + "label": _("Company"), + "fieldname": "company", + "fieldtype": "Link", + "options": "Company", + "width": 120 + } ] def get_args(): diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py index 53677cde8aa..67c7fd2d22a 100644 --- a/erpnext/accounts/utils.py +++ b/erpnext/accounts/utils.py @@ -12,11 +12,12 @@ from frappe.utils import formatdate, get_number_format_info from six import iteritems # imported to enable erpnext.accounts.utils.get_account_currency from erpnext.accounts.doctype.account.account import get_account_currency +from frappe.model.meta import get_field_precision from erpnext.stock.utils import get_stock_value_on from erpnext.stock import get_warehouse_account_map - +class StockValueAndAccountBalanceOutOfSync(frappe.ValidationError): pass class FiscalYearError(frappe.ValidationError): pass @frappe.whitelist() @@ -78,7 +79,10 @@ def get_fiscal_years(transaction_date=None, fiscal_year=None, label="Date", verb else: return ((fy.name, fy.year_start_date, fy.year_end_date),) - error_msg = _("""{0} {1} not in any active Fiscal Year.""").format(label, formatdate(transaction_date)) + error_msg = _("""{0} {1} is not in any active Fiscal Year""").format(label, formatdate(transaction_date)) + if company: + error_msg = _("""{0} for {1}""").format(error_msg, frappe.bold(company)) + if verbose==1: frappe.msgprint(error_msg) raise FiscalYearError(error_msg) @@ -582,24 +586,6 @@ def fix_total_debit_credit(): (dr_or_cr, dr_or_cr, '%s', '%s', '%s', dr_or_cr), (d.diff, d.voucher_type, d.voucher_no)) -def get_stock_and_account_balance(account=None, posting_date=None, company=None): - if not posting_date: posting_date = nowdate() - - warehouse_account = get_warehouse_account_map(company) - - account_balance = get_balance_on(account, posting_date, in_account_currency=False, ignore_account_permission=True) - - related_warehouses = [wh for wh, wh_details in warehouse_account.items() - if wh_details.account == account and not wh_details.is_group] - - total_stock_value = 0.0 - for warehouse in related_warehouses: - value = get_stock_value_on(warehouse, posting_date) - total_stock_value += value - - precision = frappe.get_precision("Journal Entry Account", "debit_in_account_currency") - return flt(account_balance, precision), flt(total_stock_value, precision), related_warehouses - def get_currency_precision(): precision = cint(frappe.db.get_default("currency_precision")) if not precision: @@ -900,12 +886,6 @@ def get_coa(doctype, parent, is_root, chart=None): return accounts -def get_stock_accounts(company): - return frappe.get_all("Account", filters = { - "account_type": "Stock", - "company": company - }) - def update_gl_entries_after(posting_date, posting_time, for_warehouses=None, for_items=None, warehouse_account=None, company=None): def _delete_gl_entries(voucher_type, voucher_no): @@ -925,7 +905,7 @@ def update_gl_entries_after(posting_date, posting_time, for_warehouses=None, for if expected_gle: if not existing_gle or not compare_existing_and_expected_gle(existing_gle, expected_gle): _delete_gl_entries(voucher_type, voucher_no) - voucher_obj.make_gl_entries(gl_entries=expected_gle, repost_future_gle=False, from_repost=True) + voucher_obj.make_gl_entries(gl_entries=expected_gle, from_repost=True) else: _delete_gl_entries(voucher_type, voucher_no) @@ -944,7 +924,10 @@ def get_future_stock_vouchers(posting_date, posting_time, for_warehouses=None, f for d in frappe.db.sql("""select distinct sle.voucher_type, sle.voucher_no from `tabStock Ledger Entry` sle - where timestamp(sle.posting_date, sle.posting_time) >= timestamp(%s, %s) {condition} + where + timestamp(sle.posting_date, sle.posting_time) >= timestamp(%s, %s) + and is_cancelled = 0 + {condition} order by timestamp(sle.posting_date, sle.posting_time) asc, creation asc for update""".format(condition=condition), tuple([posting_date, posting_time] + values), as_dict=True): future_stock_vouchers.append([d.voucher_type, d.voucher_no]) @@ -961,3 +944,106 @@ def get_voucherwise_gl_entries(future_stock_vouchers, posting_date): gl_entries.setdefault((d.voucher_type, d.voucher_no), []).append(d) return gl_entries + +def compare_existing_and_expected_gle(existing_gle, expected_gle): + matched = True + for entry in expected_gle: + account_existed = False + for e in existing_gle: + if entry.account == e.account: + account_existed = True + if entry.account == e.account and entry.against_account == e.against_account \ + and (not entry.cost_center or not e.cost_center or entry.cost_center == e.cost_center) \ + and (entry.debit != e.debit or entry.credit != e.credit): + matched = False + break + if not account_existed: + matched = False + break + return matched + +def check_if_stock_and_account_balance_synced(posting_date, company, voucher_type=None, voucher_no=None): + if not cint(erpnext.is_perpetual_inventory_enabled(company)): + return + + accounts = get_stock_accounts(company, voucher_type, voucher_no) + stock_adjustment_account = frappe.db.get_value("Company", company, "stock_adjustment_account") + + for account in accounts: + account_bal, stock_bal, warehouse_list = get_stock_and_account_balance(account, + posting_date, company) + + if abs(account_bal - stock_bal) > 0.1: + precision = get_field_precision(frappe.get_meta("GL Entry").get_field("debit"), + currency=frappe.get_cached_value('Company', company, "default_currency")) + + diff = flt(stock_bal - account_bal, precision) + + error_reason = _("Stock Value ({0}) and Account Balance ({1}) are out of sync for account {2} and it's linked warehouses as on {3}.").format( + stock_bal, account_bal, frappe.bold(account), posting_date) + error_resolution = _("Please create an adjustment Journal Entry for amount {0} on {1}")\ + .format(frappe.bold(diff), frappe.bold(posting_date)) + + frappe.msgprint( + msg="""{0}{0} | +{1} | + """.format(item_link, frappe.bold(shortage_qty)) + + message += """ +
| {0} | +{1} | + + {2} +
|---|
| {0} | +{1} | + + {2} +
|---|
{{ doc.description }}
+ {%- if doc.publish_salary_range -%} +{{_("Salary range per month")}}: {{ frappe.format_value(frappe.utils.flt(doc.lower_range), currency=doc.currency) }} - {{ frappe.format_value(frappe.utils.flt(doc.upper_range), currency=doc.currency) }}
+ {% endif %}| "+__('Leave Type')+" | "+__("Leave Allocation")+" | "+__("Leaves Granted")+" |
|---|---|---|
| "+key+" | "+leave_allocations[key]["name"]+" | "+leave_allocations[key]["leaves"]+" |
- + {{ _("Apply Now") }} + {% else %} + {{ _("Apply Now") }} + {% endif %}
{% endblock %} diff --git a/erpnext/templates/print_formats/includes/taxes.html b/erpnext/templates/print_formats/includes/taxes.html index 6e984f39016..304e845287c 100644 --- a/erpnext/templates/print_formats/includes/taxes.html +++ b/erpnext/templates/print_formats/includes/taxes.html @@ -20,10 +20,10 @@ {%- if (charge.tax_amount or doc.flags.print_taxes_with_zero_amount) and (not charge.included_in_print_rate or doc.flags.show_inclusive_tax_in_print) -%}