From 1babc5f367e5f114741dd29f063d68b4c308b113 Mon Sep 17 00:00:00 2001 From: rahib-hassan Date: Fri, 8 Apr 2022 08:05:10 +0530 Subject: [PATCH 01/46] feat: separated discount accounting settings for sales and purchase --- .../buying_settings/buying_settings.json | 10 ++- .../buying_settings/buying_settings.py | 62 +++++++++++++++++++ .../selling_settings/selling_settings.json | 12 +++- .../selling_settings/selling_settings.py | 58 +++++++++++++++++ 4 files changed, 139 insertions(+), 3 deletions(-) diff --git a/erpnext/buying/doctype/buying_settings/buying_settings.json b/erpnext/buying/doctype/buying_settings/buying_settings.json index 50321baa2e..90e6975f64 100644 --- a/erpnext/buying/doctype/buying_settings/buying_settings.json +++ b/erpnext/buying/doctype/buying_settings/buying_settings.json @@ -20,6 +20,7 @@ "maintain_same_rate", "allow_multiple_items", "bill_for_rejected_quantity_in_purchase_invoice", + "enable_discount_accounting", "subcontract", "backflush_raw_materials_of_subcontract_based_on", "column_break_11", @@ -133,6 +134,13 @@ { "fieldname": "column_break_12", "fieldtype": "Column Break" + }, + { + "default": "0", + "description": "If enabled, additional ledger entries will be made for discounts in a separate Discount Account", + "fieldname": "enable_discount_accounting", + "fieldtype": "Check", + "label": "Enable Discount Accounting" } ], "icon": "fa fa-cog", @@ -140,7 +148,7 @@ "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2022-01-27 17:57:58.367048", + "modified": "2022-04-08 07:48:12.632498", "modified_by": "Administrator", "module": "Buying", "name": "Buying Settings", diff --git a/erpnext/buying/doctype/buying_settings/buying_settings.py b/erpnext/buying/doctype/buying_settings/buying_settings.py index 5507254bbc..4d266e1264 100644 --- a/erpnext/buying/doctype/buying_settings/buying_settings.py +++ b/erpnext/buying/doctype/buying_settings/buying_settings.py @@ -6,9 +6,14 @@ import frappe from frappe.model.document import Document +from frappe.custom.doctype.property_setter.property_setter import make_property_setter +from frappe.utils import cint class BuyingSettings(Document): + def on_update(self): + self.toggle_discount_accounting_fields() + def validate(self): for key in ["supplier_group", "supp_master_name", "maintain_same_rate", "buying_price_list"]: frappe.db.set_default(key, self.get(key, "")) @@ -21,3 +26,60 @@ class BuyingSettings(Document): self.get("supp_master_name") == "Naming Series", hide_name_field=False, ) + + def toggle_discount_accounting_fields(self): + enable_discount_accounting = cint(self.enable_discount_accounting) + + make_property_setter( + "Purchase Invoice Item", + "discount_account", + "hidden", + not (enable_discount_accounting), + "Check", + validate_fields_for_doctype=False, + ) + if enable_discount_accounting: + make_property_setter( + "Purchase Invoice Item", + "discount_account", + "mandatory_depends_on", + "eval: doc.discount_amount", + "Code", + validate_fields_for_doctype=False, + ) + else: + make_property_setter( + "Purchase Invoice Item", + "discount_account", + "mandatory_depends_on", + "", + "Code", + validate_fields_for_doctype=False, + ) + + make_property_setter( + "Purchase Invoice", + "additional_discount_account", + "hidden", + not (enable_discount_accounting), + "Check", + validate_fields_for_doctype=False, + ) + if enable_discount_accounting: + make_property_setter( + "Purchase Invoice", + "additional_discount_account", + "mandatory_depends_on", + "eval: doc.discount_amount", + "Code", + validate_fields_for_doctype=False, + ) + else: + make_property_setter( + "Purchase Invoice", + "additional_discount_account", + "mandatory_depends_on", + "", + "Code", + validate_fields_for_doctype=False, + ) \ No newline at end of file diff --git a/erpnext/selling/doctype/selling_settings/selling_settings.json b/erpnext/selling/doctype/selling_settings/selling_settings.json index 7c4a3f63dc..2c880ee029 100644 --- a/erpnext/selling/doctype/selling_settings/selling_settings.json +++ b/erpnext/selling/doctype/selling_settings/selling_settings.json @@ -27,7 +27,8 @@ "column_break_5", "allow_multiple_items", "allow_against_multiple_purchase_orders", - "hide_tax_id" + "hide_tax_id", + "enable_discount_accounting" ], "fields": [ { @@ -164,6 +165,13 @@ "fieldname": "editable_bundle_item_rates", "fieldtype": "Check", "label": "Calculate Product Bundle Price based on Child Items' Rates" + }, + { + "default": "0", + "description": "If enabled, additional ledger entries will be made for discounts in a separate Discount Account", + "fieldname": "enable_discount_accounting", + "fieldtype": "Check", + "label": "Enable Discount Accounting" } ], "icon": "fa fa-cog", @@ -171,7 +179,7 @@ "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2022-02-04 15:41:59.939261", + "modified": "2022-04-08 07:48:48.074220", "modified_by": "Administrator", "module": "Selling", "name": "Selling Settings", diff --git a/erpnext/selling/doctype/selling_settings/selling_settings.py b/erpnext/selling/doctype/selling_settings/selling_settings.py index 29e4712be3..c656c52c17 100644 --- a/erpnext/selling/doctype/selling_settings/selling_settings.py +++ b/erpnext/selling/doctype/selling_settings/selling_settings.py @@ -14,6 +14,7 @@ class SellingSettings(Document): def on_update(self): self.toggle_hide_tax_id() self.toggle_editable_rate_for_bundle_items() + self.toggle_discount_accounting_fields() def validate(self): for key in [ @@ -58,3 +59,60 @@ class SellingSettings(Document): "Check", validate_fields_for_doctype=False, ) + + def toggle_discount_accounting_fields(self): + enable_discount_accounting = cint(self.enable_discount_accounting) + + make_property_setter( + "Sales Invoice Item", + "discount_account", + "hidden", + not (enable_discount_accounting), + "Check", + validate_fields_for_doctype=False, + ) + if enable_discount_accounting: + make_property_setter( + "Sales Invoice Item", + "discount_account", + "mandatory_depends_on", + "eval: doc.discount_amount", + "Code", + validate_fields_for_doctype=False, + ) + else: + make_property_setter( + "Sales Invoice Item", + "discount_account", + "mandatory_depends_on", + "", + "Code", + validate_fields_for_doctype=False, + ) + + make_property_setter( + "Sales Invoice", + "additional_discount_account", + "hidden", + not (enable_discount_accounting), + "Check", + validate_fields_for_doctype=False, + ) + if enable_discount_accounting: + make_property_setter( + "Sales Invoice", + "additional_discount_account", + "mandatory_depends_on", + "eval: doc.discount_amount", + "Code", + validate_fields_for_doctype=False, + ) + else: + make_property_setter( + "Sales Invoice", + "additional_discount_account", + "mandatory_depends_on", + "", + "Code", + validate_fields_for_doctype=False, + ) \ No newline at end of file From 0fcdf1b6137306dfadab0dc5f3389416d3898121 Mon Sep 17 00:00:00 2001 From: rahib-hassan Date: Fri, 8 Apr 2022 08:10:27 +0530 Subject: [PATCH 02/46] removed discount-accounting from account settings --- .../accounts_settings/accounts_settings.py | 69 ------------------- 1 file changed, 69 deletions(-) diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.py b/erpnext/accounts/doctype/accounts_settings/accounts_settings.py index 835498176c..3b125a2986 100644 --- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.py +++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.py @@ -28,7 +28,6 @@ class AccountsSettings(Document): self.validate_stale_days() self.enable_payment_schedule_in_print() - self.toggle_discount_accounting_fields() self.validate_pending_reposts() def validate_stale_days(self): @@ -52,74 +51,6 @@ class AccountsSettings(Document): validate_fields_for_doctype=False, ) - def toggle_discount_accounting_fields(self): - enable_discount_accounting = cint(self.enable_discount_accounting) - - for doctype in ["Sales Invoice Item", "Purchase Invoice Item"]: - make_property_setter( - doctype, - "discount_account", - "hidden", - not (enable_discount_accounting), - "Check", - validate_fields_for_doctype=False, - ) - if enable_discount_accounting: - make_property_setter( - doctype, - "discount_account", - "mandatory_depends_on", - "eval: doc.discount_amount", - "Code", - validate_fields_for_doctype=False, - ) - else: - make_property_setter( - doctype, - "discount_account", - "mandatory_depends_on", - "", - "Code", - validate_fields_for_doctype=False, - ) - - for doctype in ["Sales Invoice", "Purchase Invoice"]: - make_property_setter( - doctype, - "additional_discount_account", - "hidden", - not (enable_discount_accounting), - "Check", - validate_fields_for_doctype=False, - ) - if enable_discount_accounting: - make_property_setter( - doctype, - "additional_discount_account", - "mandatory_depends_on", - "eval: doc.discount_amount", - "Code", - validate_fields_for_doctype=False, - ) - else: - make_property_setter( - doctype, - "additional_discount_account", - "mandatory_depends_on", - "", - "Code", - validate_fields_for_doctype=False, - ) - - make_property_setter( - "Item", - "default_discount_account", - "hidden", - not (enable_discount_accounting), - "Check", - validate_fields_for_doctype=False, - ) - def validate_pending_reposts(self): if self.acc_frozen_upto: check_pending_reposting(self.acc_frozen_upto) From b6ce49760132dac9b61d20fd05a68590004050ac Mon Sep 17 00:00:00 2001 From: rahib-hassan Date: Fri, 8 Apr 2022 15:08:21 +0530 Subject: [PATCH 03/46] fix: removed discount account field from account settings --- .../doctype/accounts_settings/accounts_settings.json | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json index 9a35a247dd..417611fecd 100644 --- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json +++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json @@ -18,7 +18,6 @@ "automatically_fetch_payment_terms", "column_break_17", "enable_common_party_accounting", - "enable_discount_accounting", "report_setting_section", "use_custom_cash_flow", "deferred_accounting_settings_section", @@ -272,13 +271,6 @@ "fieldtype": "Check", "label": "Create Ledger Entries for Change Amount" }, - { - "default": "0", - "description": "If enabled, additional ledger entries will be made for discounts in a separate Discount Account", - "fieldname": "enable_discount_accounting", - "fieldtype": "Check", - "label": "Enable Discount Accounting" - }, { "default": "0", "description": "Learn about Common Party", @@ -354,7 +346,7 @@ "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2022-02-04 12:32:36.805652", + "modified": "2022-04-08 14:45:06.796418", "modified_by": "Administrator", "module": "Accounts", "name": "Accounts Settings", From 786887768ee5d7063915cdd30e3e222df22fa5de Mon Sep 17 00:00:00 2001 From: rahib-hassan Date: Fri, 8 Apr 2022 08:10:27 +0530 Subject: [PATCH 04/46] fix: removed discount-accounting code from account settings --- .../accounts_settings/accounts_settings.py | 69 ------------------- 1 file changed, 69 deletions(-) diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.py b/erpnext/accounts/doctype/accounts_settings/accounts_settings.py index 835498176c..3b125a2986 100644 --- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.py +++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.py @@ -28,7 +28,6 @@ class AccountsSettings(Document): self.validate_stale_days() self.enable_payment_schedule_in_print() - self.toggle_discount_accounting_fields() self.validate_pending_reposts() def validate_stale_days(self): @@ -52,74 +51,6 @@ class AccountsSettings(Document): validate_fields_for_doctype=False, ) - def toggle_discount_accounting_fields(self): - enable_discount_accounting = cint(self.enable_discount_accounting) - - for doctype in ["Sales Invoice Item", "Purchase Invoice Item"]: - make_property_setter( - doctype, - "discount_account", - "hidden", - not (enable_discount_accounting), - "Check", - validate_fields_for_doctype=False, - ) - if enable_discount_accounting: - make_property_setter( - doctype, - "discount_account", - "mandatory_depends_on", - "eval: doc.discount_amount", - "Code", - validate_fields_for_doctype=False, - ) - else: - make_property_setter( - doctype, - "discount_account", - "mandatory_depends_on", - "", - "Code", - validate_fields_for_doctype=False, - ) - - for doctype in ["Sales Invoice", "Purchase Invoice"]: - make_property_setter( - doctype, - "additional_discount_account", - "hidden", - not (enable_discount_accounting), - "Check", - validate_fields_for_doctype=False, - ) - if enable_discount_accounting: - make_property_setter( - doctype, - "additional_discount_account", - "mandatory_depends_on", - "eval: doc.discount_amount", - "Code", - validate_fields_for_doctype=False, - ) - else: - make_property_setter( - doctype, - "additional_discount_account", - "mandatory_depends_on", - "", - "Code", - validate_fields_for_doctype=False, - ) - - make_property_setter( - "Item", - "default_discount_account", - "hidden", - not (enable_discount_accounting), - "Check", - validate_fields_for_doctype=False, - ) - def validate_pending_reposts(self): if self.acc_frozen_upto: check_pending_reposting(self.acc_frozen_upto) From 171c60ff37d6e1f95378a049f0fec66189aeac90 Mon Sep 17 00:00:00 2001 From: rahib-hassan Date: Fri, 8 Apr 2022 15:08:21 +0530 Subject: [PATCH 05/46] fix: removed discount account field from account settings --- .../doctype/accounts_settings/accounts_settings.json | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json index 9a35a247dd..417611fecd 100644 --- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json +++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json @@ -18,7 +18,6 @@ "automatically_fetch_payment_terms", "column_break_17", "enable_common_party_accounting", - "enable_discount_accounting", "report_setting_section", "use_custom_cash_flow", "deferred_accounting_settings_section", @@ -272,13 +271,6 @@ "fieldtype": "Check", "label": "Create Ledger Entries for Change Amount" }, - { - "default": "0", - "description": "If enabled, additional ledger entries will be made for discounts in a separate Discount Account", - "fieldname": "enable_discount_accounting", - "fieldtype": "Check", - "label": "Enable Discount Accounting" - }, { "default": "0", "description": "Learn about Common Party", @@ -354,7 +346,7 @@ "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2022-02-04 12:32:36.805652", + "modified": "2022-04-08 14:45:06.796418", "modified_by": "Administrator", "module": "Accounts", "name": "Accounts Settings", From 35e875c11131465fe41be6a215c74cf81d47e67e Mon Sep 17 00:00:00 2001 From: rahib-hassan Date: Fri, 8 Apr 2022 17:27:53 +0530 Subject: [PATCH 06/46] fix(patch): enable discount account in buying and selling if exist in accounts settings --- .../v14_0/discount_accounting_separation.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 erpnext/patches/v14_0/discount_accounting_separation.py diff --git a/erpnext/patches/v14_0/discount_accounting_separation.py b/erpnext/patches/v14_0/discount_accounting_separation.py new file mode 100644 index 0000000000..bb236f783a --- /dev/null +++ b/erpnext/patches/v14_0/discount_accounting_separation.py @@ -0,0 +1,14 @@ +import frappe + +def execute(): + doc = frappe.get_doc("Accounts Settings") + discount_account = doc.enable_discount_accounting + if discount_account: + buying_settings = frappe.get_doc("Buying Settings") + selling_settings = frappe.get_doc("Selling Settings") + + buying_settings.enable_discount_accounting = 1 + selling_settings.enable_discount_accounting = 1 + + buying_settings.save() + selling_settings.save() \ No newline at end of file From 2173c8b11478e76f32807a6253b28456ba016239 Mon Sep 17 00:00:00 2001 From: rahib-hassan Date: Fri, 8 Apr 2022 17:29:08 +0530 Subject: [PATCH 07/46] fix(pathces): added to patches.txt --- erpnext/patches.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/erpnext/patches.txt b/erpnext/patches.txt index a3bf78b532..24354c3842 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -364,3 +364,4 @@ erpnext.patches.v13_0.add_cost_center_in_loans erpnext.patches.v13_0.set_return_against_in_pos_invoice_references erpnext.patches.v13_0.remove_unknown_links_to_prod_plan_items # 24-03-2022 erpnext.patches.v13_0.update_expense_claim_status_for_paid_advances +erpnext.patches.v14_0.discount_accounting_separation \ No newline at end of file From ac7f1cbd87efe933f785a3476a478bb773bb7601 Mon Sep 17 00:00:00 2001 From: rahib-hassan Date: Fri, 8 Apr 2022 17:46:49 +0530 Subject: [PATCH 08/46] fix: minor fix --- erpnext/patches/v14_0/discount_accounting_separation.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/patches/v14_0/discount_accounting_separation.py b/erpnext/patches/v14_0/discount_accounting_separation.py index bb236f783a..e7e4a2ebcf 100644 --- a/erpnext/patches/v14_0/discount_accounting_separation.py +++ b/erpnext/patches/v14_0/discount_accounting_separation.py @@ -4,8 +4,8 @@ def execute(): doc = frappe.get_doc("Accounts Settings") discount_account = doc.enable_discount_accounting if discount_account: - buying_settings = frappe.get_doc("Buying Settings") - selling_settings = frappe.get_doc("Selling Settings") + buying_settings = frappe.get_doc("Buying Settings", "Buying Settings") + selling_settings = frappe.get_doc("Selling Settings", "Selling Settings") buying_settings.enable_discount_accounting = 1 selling_settings.enable_discount_accounting = 1 From ac16f3b71fc403d2ad1f37f7ca54dc6236aa909c Mon Sep 17 00:00:00 2001 From: rahib-hassan Date: Fri, 8 Apr 2022 18:20:41 +0530 Subject: [PATCH 09/46] fix: lock timeout exceeded --- .../patches/v14_0/discount_accounting_separation.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/erpnext/patches/v14_0/discount_accounting_separation.py b/erpnext/patches/v14_0/discount_accounting_separation.py index e7e4a2ebcf..3d4907cca3 100644 --- a/erpnext/patches/v14_0/discount_accounting_separation.py +++ b/erpnext/patches/v14_0/discount_accounting_separation.py @@ -4,11 +4,5 @@ def execute(): doc = frappe.get_doc("Accounts Settings") discount_account = doc.enable_discount_accounting if discount_account: - buying_settings = frappe.get_doc("Buying Settings", "Buying Settings") - selling_settings = frappe.get_doc("Selling Settings", "Selling Settings") - - buying_settings.enable_discount_accounting = 1 - selling_settings.enable_discount_accounting = 1 - - buying_settings.save() - selling_settings.save() \ No newline at end of file + for doctype in ["Buying Settings", "Selling Settings"]: + doc = frappe.db.set_value(doctype, doctype, 'enable_discount_accounting', 1, update_modified=False) \ No newline at end of file From dc2944a0410811ce800107fbb3a531b5eb440498 Mon Sep 17 00:00:00 2001 From: rahib-hassan Date: Sat, 9 Apr 2022 03:55:25 +0530 Subject: [PATCH 10/46] fix[minor]: removed doc assignment --- erpnext/patches/v14_0/discount_accounting_separation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/patches/v14_0/discount_accounting_separation.py b/erpnext/patches/v14_0/discount_accounting_separation.py index 3d4907cca3..a814522a38 100644 --- a/erpnext/patches/v14_0/discount_accounting_separation.py +++ b/erpnext/patches/v14_0/discount_accounting_separation.py @@ -5,4 +5,4 @@ def execute(): discount_account = doc.enable_discount_accounting if discount_account: for doctype in ["Buying Settings", "Selling Settings"]: - doc = frappe.db.set_value(doctype, doctype, 'enable_discount_accounting', 1, update_modified=False) \ No newline at end of file + frappe.db.set_value(doctype, doctype, 'enable_discount_accounting', 1, update_modified=False) \ No newline at end of file From a7a574237502446885e3a2e2c255920e4045dcd7 Mon Sep 17 00:00:00 2001 From: rahib-hassan Date: Mon, 11 Apr 2022 14:28:36 +0530 Subject: [PATCH 11/46] fix: merge conflict(patch) --- erpnext/patches.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 24354c3842..46d6e93db5 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -364,4 +364,5 @@ erpnext.patches.v13_0.add_cost_center_in_loans erpnext.patches.v13_0.set_return_against_in_pos_invoice_references erpnext.patches.v13_0.remove_unknown_links_to_prod_plan_items # 24-03-2022 erpnext.patches.v13_0.update_expense_claim_status_for_paid_advances +erpnext.patches.v13_0.create_gst_custom_fields_in_quotation erpnext.patches.v14_0.discount_accounting_separation \ No newline at end of file From 0eff74c6500a229c5ff80f15a45fdf889add52e7 Mon Sep 17 00:00:00 2001 From: rahib-hassan Date: Thu, 14 Apr 2022 15:42:16 +0530 Subject: [PATCH 12/46] fix: tabspacing --- .../patches/v14_0/discount_accounting_separation.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/erpnext/patches/v14_0/discount_accounting_separation.py b/erpnext/patches/v14_0/discount_accounting_separation.py index a814522a38..fd498052d8 100644 --- a/erpnext/patches/v14_0/discount_accounting_separation.py +++ b/erpnext/patches/v14_0/discount_accounting_separation.py @@ -1,8 +1,9 @@ import frappe + def execute(): - doc = frappe.get_doc("Accounts Settings") - discount_account = doc.enable_discount_accounting - if discount_account: - for doctype in ["Buying Settings", "Selling Settings"]: - frappe.db.set_value(doctype, doctype, 'enable_discount_accounting', 1, update_modified=False) \ No newline at end of file + doc = frappe.get_doc("Accounts Settings") + discount_account = doc.enable_discount_accounting + if discount_account: + for doctype in ["Buying Settings", "Selling Settings"]: + frappe.db.set_value(doctype, doctype, "enable_discount_accounting", 1, update_modified=False) From 01fde15bd5a0c111eadd567323b15f04d10731cc Mon Sep 17 00:00:00 2001 From: rahib-hassan Date: Thu, 14 Apr 2022 15:48:55 +0530 Subject: [PATCH 13/46] fix: dependent codes updated --- .../accounts/doctype/purchase_invoice/purchase_invoice.py | 6 +++--- erpnext/accounts/doctype/sales_invoice/sales_invoice.py | 6 +++--- erpnext/controllers/accounts_controller.py | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index e6a46d0676..a222dd98e9 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -669,7 +669,7 @@ class PurchaseInvoice(BuyingController): exchange_rate_map, net_rate_map = get_purchase_document_details(self) enable_discount_accounting = cint( - frappe.db.get_single_value("Accounts Settings", "enable_discount_accounting") + frappe.db.get_single_value("Buying Settings", "enable_discount_accounting") ) provisional_accounting_for_non_stock_items = cint( frappe.db.get_value( @@ -1157,7 +1157,7 @@ class PurchaseInvoice(BuyingController): # tax table gl entries valuation_tax = {} enable_discount_accounting = cint( - frappe.db.get_single_value("Accounts Settings", "enable_discount_accounting") + frappe.db.get_single_value("Buying Settings", "enable_discount_accounting") ) for tax in self.get("taxes"): @@ -1250,7 +1250,7 @@ class PurchaseInvoice(BuyingController): def enable_discount_accounting(self): if not hasattr(self, "_enable_discount_accounting"): self._enable_discount_accounting = cint( - frappe.db.get_single_value("Accounts Settings", "enable_discount_accounting") + frappe.db.get_single_value("Buying Settings", "enable_discount_accounting") ) return self._enable_discount_accounting diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 1efd3dca0d..dd85d99a8c 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -1051,7 +1051,7 @@ class SalesInvoice(SellingController): def make_tax_gl_entries(self, gl_entries): enable_discount_accounting = cint( - frappe.db.get_single_value("Accounts Settings", "enable_discount_accounting") + frappe.db.get_single_value("Selling Settings", "enable_discount_accounting") ) for tax in self.get("taxes"): @@ -1097,7 +1097,7 @@ class SalesInvoice(SellingController): def make_item_gl_entries(self, gl_entries): # income account gl entries enable_discount_accounting = cint( - frappe.db.get_single_value("Accounts Settings", "enable_discount_accounting") + frappe.db.get_single_value("Selling Settings", "enable_discount_accounting") ) for item in self.get("items"): @@ -1276,7 +1276,7 @@ class SalesInvoice(SellingController): def enable_discount_accounting(self): if not hasattr(self, "_enable_discount_accounting"): self._enable_discount_accounting = cint( - frappe.db.get_single_value("Accounts Settings", "enable_discount_accounting") + frappe.db.get_single_value("Selling Settings", "enable_discount_accounting") ) return self._enable_discount_accounting diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index 7cbd2bd6c7..5ebbb7a3f0 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -1080,7 +1080,7 @@ class AccountsController(TransactionBase): def make_discount_gl_entries(self, gl_entries): enable_discount_accounting = cint( - frappe.db.get_single_value("Accounts Settings", "enable_discount_accounting") + frappe.db.get_single_value("Selling Settings", "enable_discount_accounting") ) if enable_discount_accounting: From 4130493b589cea2e4bfb0fe98cc7fcca2e64f45f Mon Sep 17 00:00:00 2001 From: rahib-hassan Date: Thu, 14 Apr 2022 16:03:08 +0530 Subject: [PATCH 14/46] fix: Label typo --- erpnext/buying/doctype/buying_settings/buying_settings.json | 4 ++-- .../selling/doctype/selling_settings/selling_settings.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/erpnext/buying/doctype/buying_settings/buying_settings.json b/erpnext/buying/doctype/buying_settings/buying_settings.json index 90e6975f64..89a9448716 100644 --- a/erpnext/buying/doctype/buying_settings/buying_settings.json +++ b/erpnext/buying/doctype/buying_settings/buying_settings.json @@ -140,7 +140,7 @@ "description": "If enabled, additional ledger entries will be made for discounts in a separate Discount Account", "fieldname": "enable_discount_accounting", "fieldtype": "Check", - "label": "Enable Discount Accounting" + "label": "Enable Discount Accounting for Buying" } ], "icon": "fa fa-cog", @@ -148,7 +148,7 @@ "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2022-04-08 07:48:12.632498", + "modified": "2022-04-14 15:56:42.340223", "modified_by": "Administrator", "module": "Buying", "name": "Buying Settings", diff --git a/erpnext/selling/doctype/selling_settings/selling_settings.json b/erpnext/selling/doctype/selling_settings/selling_settings.json index 2c880ee029..005e24cfbe 100644 --- a/erpnext/selling/doctype/selling_settings/selling_settings.json +++ b/erpnext/selling/doctype/selling_settings/selling_settings.json @@ -171,7 +171,7 @@ "description": "If enabled, additional ledger entries will be made for discounts in a separate Discount Account", "fieldname": "enable_discount_accounting", "fieldtype": "Check", - "label": "Enable Discount Accounting" + "label": "Enable Discount Accounting for Selling" } ], "icon": "fa fa-cog", @@ -179,7 +179,7 @@ "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2022-04-08 07:48:48.074220", + "modified": "2022-04-14 16:01:29.405642", "modified_by": "Administrator", "module": "Selling", "name": "Selling Settings", From ebb7bc201b900df0f335b898494cc68b5a93366f Mon Sep 17 00:00:00 2001 From: rahib-hassan Date: Mon, 18 Apr 2022 14:53:45 +0530 Subject: [PATCH 15/46] fix: library import formatting --- erpnext/buying/doctype/buying_settings/buying_settings.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/erpnext/buying/doctype/buying_settings/buying_settings.py b/erpnext/buying/doctype/buying_settings/buying_settings.py index 4d266e1264..c52b59e4c0 100644 --- a/erpnext/buying/doctype/buying_settings/buying_settings.py +++ b/erpnext/buying/doctype/buying_settings/buying_settings.py @@ -5,8 +5,8 @@ import frappe -from frappe.model.document import Document from frappe.custom.doctype.property_setter.property_setter import make_property_setter +from frappe.model.document import Document from frappe.utils import cint @@ -26,7 +26,7 @@ class BuyingSettings(Document): self.get("supp_master_name") == "Naming Series", hide_name_field=False, ) - + def toggle_discount_accounting_fields(self): enable_discount_accounting = cint(self.enable_discount_accounting) @@ -82,4 +82,4 @@ class BuyingSettings(Document): "", "Code", validate_fields_for_doctype=False, - ) \ No newline at end of file + ) From bcfbb3e9c8d3cfc6818d21032bcf619eb33668aa Mon Sep 17 00:00:00 2001 From: rahib-hassan Date: Mon, 18 Apr 2022 15:04:47 +0530 Subject: [PATCH 16/46] fix: code formatting --- erpnext/selling/doctype/selling_settings/selling_settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/selling/doctype/selling_settings/selling_settings.py b/erpnext/selling/doctype/selling_settings/selling_settings.py index c656c52c17..6c09894251 100644 --- a/erpnext/selling/doctype/selling_settings/selling_settings.py +++ b/erpnext/selling/doctype/selling_settings/selling_settings.py @@ -115,4 +115,4 @@ class SellingSettings(Document): "", "Code", validate_fields_for_doctype=False, - ) \ No newline at end of file + ) From 0ac11a5b305ecd6002bef94cefe04eba65c13f87 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Wed, 20 Apr 2022 12:18:11 +0530 Subject: [PATCH 17/46] fix: First preference to parent cost center rather than round off cost center --- erpnext/accounts/general_ledger.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/general_ledger.py b/erpnext/accounts/general_ledger.py index f52e517f73..4dbc4d6a72 100644 --- a/erpnext/accounts/general_ledger.py +++ b/erpnext/accounts/general_ledger.py @@ -355,7 +355,7 @@ def raise_debit_credit_not_equal_error(debit_credit_diff, voucher_type, voucher_ def make_round_off_gle(gl_map, debit_credit_diff, precision): round_off_account, round_off_cost_center = get_round_off_account_and_cost_center( - gl_map[0].company + gl_map[0].company, gl_map[0].voucher_type, gl_map[0].voucher_no ) round_off_account_exists = False round_off_gle = frappe._dict() @@ -396,10 +396,17 @@ def make_round_off_gle(gl_map, debit_credit_diff, precision): gl_map.append(round_off_gle) -def get_round_off_account_and_cost_center(company): +def get_round_off_account_and_cost_center(company, voucher_type, voucher_no): round_off_account, round_off_cost_center = frappe.get_cached_value( "Company", company, ["round_off_account", "round_off_cost_center"] ) or [None, None] + + # Give first preference to parent cost center for round off GLE + if frappe.db.has_column(voucher_type, "cost_center"): + parent_cost_center = frappe.db.get_value(voucher_type, voucher_no, "cost_center") + if parent_cost_center: + round_off_cost_center = parent_cost_center + if not round_off_account: frappe.throw(_("Please mention Round Off Account in Company")) From f058755ad362d55d45906c4db4a7bbe440adf6e4 Mon Sep 17 00:00:00 2001 From: rahib-hassan Date: Wed, 20 Apr 2022 13:24:15 +0530 Subject: [PATCH 18/46] fix: test cases updated --- .../purchase_invoice/test_purchase_invoice.py | 6 +++--- .../doctype/sales_invoice/test_sales_invoice.py | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py index 59bd637e41..a12f06bc96 100644 --- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py @@ -1589,9 +1589,9 @@ def unlink_payment_on_cancel_of_invoice(enable=1): def enable_discount_accounting(enable=1): - accounts_settings = frappe.get_doc("Accounts Settings") - accounts_settings.enable_discount_accounting = enable - accounts_settings.save() + buying_settings = frappe.get_doc("Buying Settings") + buying_settings.enable_discount_accounting = enable + buying_settings.save() def make_purchase_invoice(**args): diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index caa70d00ef..eaab94108d 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -2685,9 +2685,6 @@ class TestSalesInvoice(unittest.TestCase): ) def test_sales_invoice_with_discount_accounting_enabled(self): - from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import ( - enable_discount_accounting, - ) enable_discount_accounting() @@ -2708,9 +2705,6 @@ class TestSalesInvoice(unittest.TestCase): enable_discount_accounting(enable=0) def test_additional_discount_for_sales_invoice_with_discount_accounting_enabled(self): - from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import ( - enable_discount_accounting, - ) enable_discount_accounting() additional_discount_account = create_account( @@ -3181,6 +3175,12 @@ class TestSalesInvoice(unittest.TestCase): ) +def enable_discount_accounting(enable=1): + selling_settings = frappe.get_doc("Selling Settings") + selling_settings.enable_discount_accounting = enable + selling_settings.save() + + def get_sales_invoice_for_e_invoice(): si = make_sales_invoice_for_ewaybill() si.naming_series = "INV-2020-.#####" From f3fa6ac4c20a87ed55c54ca738b9bedcbc777da3 Mon Sep 17 00:00:00 2001 From: rahib-hassan Date: Wed, 20 Apr 2022 16:01:12 +0530 Subject: [PATCH 19/46] fix: account setting seperation gl discount account creation --- erpnext/controllers/accounts_controller.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index 8558cea0f0..78645e0d4f 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -1079,9 +1079,14 @@ class AccountsController(TransactionBase): return amount, base_amount def make_discount_gl_entries(self, gl_entries): - enable_discount_accounting = cint( - frappe.db.get_single_value("Selling Settings", "enable_discount_accounting") - ) + if self.doctype == "Purchase Invoice": + enable_discount_accounting = cint( + frappe.db.get_single_value("Buying Settings", "enable_discount_accounting") + ) + elif self.doctype == "Sales Invoice": + enable_discount_accounting = cint( + frappe.db.get_single_value("Selling Settings", "enable_discount_accounting") + ) if enable_discount_accounting: if self.doctype == "Purchase Invoice": From 1e143e7479d78a6dd53eeef8a161a1cb6c4e50f1 Mon Sep 17 00:00:00 2001 From: rahib-hassan Date: Wed, 20 Apr 2022 16:06:55 +0530 Subject: [PATCH 20/46] fix: use @change_settings to enable_discount_account --- .../purchase_invoice/test_purchase_invoice.py | 13 ++++--------- .../doctype/sales_invoice/test_sales_invoice.py | 14 +++----------- 2 files changed, 7 insertions(+), 20 deletions(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py index a12f06bc96..30d26acf3a 100644 --- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py @@ -5,6 +5,7 @@ import unittest import frappe +from frappe.tests.utils import change_settings from frappe.utils import add_days, cint, flt, getdate, nowdate, today import erpnext @@ -336,8 +337,8 @@ class TestPurchaseInvoice(unittest.TestCase): self.assertEqual(discrepancy_caused_by_exchange_rate_diff, amount) + @change_settings("Buying Settings", {"enable_discount_accounting": 1}) def test_purchase_invoice_with_discount_accounting_enabled(self): - enable_discount_accounting() discount_account = create_account( account_name="Discount Account", @@ -353,10 +354,10 @@ class TestPurchaseInvoice(unittest.TestCase): ] check_gl_entries(self, pi.name, expected_gle, nowdate()) - enable_discount_accounting(enable=0) + @change_settings("Buying Settings", {"enable_discount_accounting": 1}) def test_additional_discount_for_purchase_invoice_with_discount_accounting_enabled(self): - enable_discount_accounting() + additional_discount_account = create_account( account_name="Discount Account", parent_account="Indirect Expenses - _TC", @@ -1588,12 +1589,6 @@ def unlink_payment_on_cancel_of_invoice(enable=1): accounts_settings.save() -def enable_discount_accounting(enable=1): - buying_settings = frappe.get_doc("Buying Settings") - buying_settings.enable_discount_accounting = enable - buying_settings.save() - - def make_purchase_invoice(**args): pi = frappe.new_doc("Purchase Invoice") args = frappe._dict(args) diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index eaab94108d..98a5755f71 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -7,6 +7,7 @@ import unittest import frappe from frappe.model.dynamic_links import get_dynamic_link_map from frappe.model.naming import make_autoname +from frappe.tests.utils import change_settings from frappe.utils import add_days, flt, getdate, nowdate import erpnext @@ -2684,10 +2685,9 @@ class TestSalesInvoice(unittest.TestCase): sales_invoice.items[0].item_tax_template, "_Test Account Excise Duty @ 10 - _TC" ) + @change_settings("Selling Settings", {"enable_discount_accounting": 1}) def test_sales_invoice_with_discount_accounting_enabled(self): - enable_discount_accounting() - discount_account = create_account( account_name="Discount Account", parent_account="Indirect Expenses - _TC", @@ -2702,11 +2702,10 @@ class TestSalesInvoice(unittest.TestCase): ] check_gl_entries(self, si.name, expected_gle, add_days(nowdate(), -1)) - enable_discount_accounting(enable=0) + @change_settings("Selling Settings", {"enable_discount_accounting": 1}) def test_additional_discount_for_sales_invoice_with_discount_accounting_enabled(self): - enable_discount_accounting() additional_discount_account = create_account( account_name="Discount Account", parent_account="Indirect Expenses - _TC", @@ -2737,7 +2736,6 @@ class TestSalesInvoice(unittest.TestCase): ] check_gl_entries(self, si.name, expected_gle, add_days(nowdate(), -1)) - enable_discount_accounting(enable=0) def test_asset_depreciation_on_sale_with_pro_rata(self): """ @@ -3175,12 +3173,6 @@ class TestSalesInvoice(unittest.TestCase): ) -def enable_discount_accounting(enable=1): - selling_settings = frappe.get_doc("Selling Settings") - selling_settings.enable_discount_accounting = enable - selling_settings.save() - - def get_sales_invoice_for_e_invoice(): si = make_sales_invoice_for_ewaybill() si.naming_series = "INV-2020-.#####" From 13092bcc2dbb312ef5367ca74f6bfe90e72950b2 Mon Sep 17 00:00:00 2001 From: rahib-hassan Date: Wed, 20 Apr 2022 16:46:29 +0530 Subject: [PATCH 21/46] fix: enable discount roll_back --- .../doctype/purchase_invoice/test_purchase_invoice.py | 8 ++++++++ .../accounts/doctype/sales_invoice/test_sales_invoice.py | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py index 30d26acf3a..e894252f5d 100644 --- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py @@ -354,6 +354,7 @@ class TestPurchaseInvoice(unittest.TestCase): ] check_gl_entries(self, pi.name, expected_gle, nowdate()) + enable_discount_accounting(enable=0) @change_settings("Buying Settings", {"enable_discount_accounting": 1}) def test_additional_discount_for_purchase_invoice_with_discount_accounting_enabled(self): @@ -389,6 +390,7 @@ class TestPurchaseInvoice(unittest.TestCase): ] check_gl_entries(self, pi.name, expected_gle, nowdate()) + enable_discount_accounting(enable=0) def test_purchase_invoice_change_naming_series(self): pi = frappe.copy_doc(test_records[1]) @@ -1530,6 +1532,12 @@ class TestPurchaseInvoice(unittest.TestCase): company.save() +def enable_discount_accounting(enable=1): + buying_settings = frappe.get_doc("Buying Settings") + buying_settings.enable_discount_accounting = enable + buying_settings.save() + + def check_gl_entries(doc, voucher_no, expected_gle, posting_date): gl_entries = frappe.db.sql( """select account, debit, credit, posting_date diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index 98a5755f71..e4df20f6b7 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -2702,6 +2702,7 @@ class TestSalesInvoice(unittest.TestCase): ] check_gl_entries(self, si.name, expected_gle, add_days(nowdate(), -1)) + enable_discount_accounting(enable=0) @change_settings("Selling Settings", {"enable_discount_accounting": 1}) def test_additional_discount_for_sales_invoice_with_discount_accounting_enabled(self): @@ -2736,6 +2737,7 @@ class TestSalesInvoice(unittest.TestCase): ] check_gl_entries(self, si.name, expected_gle, add_days(nowdate(), -1)) + enable_discount_accounting(enable=0) def test_asset_depreciation_on_sale_with_pro_rata(self): """ @@ -3173,6 +3175,12 @@ class TestSalesInvoice(unittest.TestCase): ) +def enable_discount_accounting(enable=1): + selling_settings = frappe.get_doc("Selling Settings") + selling_settings.enable_discount_accounting = enable + selling_settings.save() + + def get_sales_invoice_for_e_invoice(): si = make_sales_invoice_for_ewaybill() si.naming_series = "INV-2020-.#####" From c3e27b5556bc2ffe1c4bd6ab0b3731b8017af04c Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Wed, 20 Apr 2022 19:07:53 +0530 Subject: [PATCH 22/46] fix: Loan doctypes in bank reconciliation --- .../doctype/bank_clearance/bank_clearance.py | 63 ++++++++++++++++++- 1 file changed, 60 insertions(+), 3 deletions(-) diff --git a/erpnext/accounts/doctype/bank_clearance/bank_clearance.py b/erpnext/accounts/doctype/bank_clearance/bank_clearance.py index 96779d75be..ed5a699463 100644 --- a/erpnext/accounts/doctype/bank_clearance/bank_clearance.py +++ b/erpnext/accounts/doctype/bank_clearance/bank_clearance.py @@ -5,7 +5,10 @@ import frappe from frappe import _, msgprint from frappe.model.document import Document -from frappe.utils import flt, fmt_money, getdate, nowdate +from frappe.query_builder.custom import ConstantColumn +from frappe.utils import flt, fmt_money, getdate + +import erpnext form_grid_templates = {"journal_entries": "templates/form_grid/bank_reconciliation_grid.html"} @@ -76,6 +79,52 @@ class BankClearance(Document): as_dict=1, ) + loan_disbursement = frappe.qb.DocType("Loan Disbursement") + + loan_disbursements = ( + frappe.qb.from_(loan_disbursement) + .select( + ConstantColumn("Loan Disbursement").as_("payment_document"), + loan_disbursement.name.as_("payment_entry"), + loan_disbursement.disbursed_amount.as_("credit"), + ConstantColumn(0).as_("debit"), + loan_disbursement.reference_number.as_("cheque_number"), + loan_disbursement.reference_date.as_("cheque_date"), + loan_disbursement.disbursement_date.as_("posting_date"), + loan_disbursement.applicant.as_("against_account"), + ) + .where(loan_disbursement.docstatus == 1) + .where(loan_disbursement.disbursement_date >= self.from_date) + .where(loan_disbursement.disbursement_date <= self.to_date) + .where(loan_disbursement.clearance_date.isnull()) + .where(loan_disbursement.disbursement_account.isin([self.bank_account, self.account])) + .orderby(loan_disbursement.disbursement_date) + .orderby(loan_disbursement.name, frappe.qb.desc) + ).run(as_dict=1) + + loan_repayment = frappe.qb.DocType("Loan Repayment") + + loan_repayments = ( + frappe.qb.from_(loan_repayment) + .select( + ConstantColumn("Loan Repayment").as_("doctype"), + loan_repayment.name.as_("payment_entry"), + loan_repayment.amount_paid.as_("debit"), + ConstantColumn(0).as_("credit"), + loan_repayment.reference_number.as_("cheque_number"), + loan_repayment.reference_date.as_("cheque_date"), + loan_repayment.applicant.as_("against_account"), + loan_repayment.posting_date, + ) + .where(loan_repayment.docstatus == 1) + .where(loan_repayment.clearance_date.isnull()) + .where(loan_repayment.posting_date >= self.from_date) + .where(loan_repayment.posting_date <= self.to_date) + .where(loan_repayment.payment_account.isin([self.bank_account, self.account])) + .orderby(loan_repayment.posting_date) + .orderby(loan_repayment.name, frappe.qb.desc) + ).run(as_dict=1) + pos_sales_invoices, pos_purchase_invoices = [], [] if self.include_pos_transactions: pos_sales_invoices = frappe.db.sql( @@ -114,18 +163,26 @@ class BankClearance(Document): entries = sorted( list(payment_entries) - + list(journal_entries + list(pos_sales_invoices) + list(pos_purchase_invoices)), - key=lambda k: k["posting_date"] or getdate(nowdate()), + + list(journal_entries) + + list(pos_sales_invoices) + + list(pos_purchase_invoices) + + list(loan_disbursements) + + list(loan_repayments), + key=lambda k: getdate(k["posting_date"]), ) self.set("payment_entries", []) self.total_amount = 0.0 + default_currency = erpnext.get_default_currency() for d in entries: row = self.append("payment_entries", {}) amount = flt(d.get("debit", 0)) - flt(d.get("credit", 0)) + if not d.get("account_currency"): + d.account_currency = default_currency + formatted_amount = fmt_money(abs(amount), 2, d.account_currency) d.amount = formatted_amount + " " + (_("Dr") if amount > 0 else _("Cr")) From 3d0e68acaa82aa0e1a6ab50e835f192297bd7bd2 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Wed, 20 Apr 2022 19:49:53 +0530 Subject: [PATCH 23/46] fix: select doctype as payment_document --- erpnext/accounts/doctype/bank_clearance/bank_clearance.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/bank_clearance/bank_clearance.py b/erpnext/accounts/doctype/bank_clearance/bank_clearance.py index ed5a699463..0f617b5dda 100644 --- a/erpnext/accounts/doctype/bank_clearance/bank_clearance.py +++ b/erpnext/accounts/doctype/bank_clearance/bank_clearance.py @@ -107,7 +107,7 @@ class BankClearance(Document): loan_repayments = ( frappe.qb.from_(loan_repayment) .select( - ConstantColumn("Loan Repayment").as_("doctype"), + ConstantColumn("Loan Repayment").as_("payment_document"), loan_repayment.name.as_("payment_entry"), loan_repayment.amount_paid.as_("debit"), ConstantColumn(0).as_("credit"), @@ -185,6 +185,7 @@ class BankClearance(Document): formatted_amount = fmt_money(abs(amount), 2, d.account_currency) d.amount = formatted_amount + " " + (_("Dr") if amount > 0 else _("Cr")) + d.posting_date = getdate(d.posting_date) d.pop("credit") d.pop("debit") From 2c78cc2014496ed7f1b358d19b66cacecf8967ec Mon Sep 17 00:00:00 2001 From: rahib-hassan Date: Thu, 21 Apr 2022 02:40:59 +0530 Subject: [PATCH 24/46] fix: removed manual rollback - enable discount account --- .../accounts/doctype/purchase_invoice/test_purchase_invoice.py | 2 -- erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py | 2 -- 2 files changed, 4 deletions(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py index e894252f5d..42455bf431 100644 --- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py @@ -354,7 +354,6 @@ class TestPurchaseInvoice(unittest.TestCase): ] check_gl_entries(self, pi.name, expected_gle, nowdate()) - enable_discount_accounting(enable=0) @change_settings("Buying Settings", {"enable_discount_accounting": 1}) def test_additional_discount_for_purchase_invoice_with_discount_accounting_enabled(self): @@ -390,7 +389,6 @@ class TestPurchaseInvoice(unittest.TestCase): ] check_gl_entries(self, pi.name, expected_gle, nowdate()) - enable_discount_accounting(enable=0) def test_purchase_invoice_change_naming_series(self): pi = frappe.copy_doc(test_records[1]) diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index e4df20f6b7..3c52c6ed9a 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -2702,7 +2702,6 @@ class TestSalesInvoice(unittest.TestCase): ] check_gl_entries(self, si.name, expected_gle, add_days(nowdate(), -1)) - enable_discount_accounting(enable=0) @change_settings("Selling Settings", {"enable_discount_accounting": 1}) def test_additional_discount_for_sales_invoice_with_discount_accounting_enabled(self): @@ -2737,7 +2736,6 @@ class TestSalesInvoice(unittest.TestCase): ] check_gl_entries(self, si.name, expected_gle, add_days(nowdate(), -1)) - enable_discount_accounting(enable=0) def test_asset_depreciation_on_sale_with_pro_rata(self): """ From 02e17dbded5cd954563090e659bebd409a808559 Mon Sep 17 00:00:00 2001 From: rahib-hassan Date: Thu, 21 Apr 2022 02:42:42 +0530 Subject: [PATCH 25/46] fix: removed manual enable-discount-account method --- .../accounts/doctype/sales_invoice/test_sales_invoice.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index 3c52c6ed9a..98a5755f71 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -3173,12 +3173,6 @@ class TestSalesInvoice(unittest.TestCase): ) -def enable_discount_accounting(enable=1): - selling_settings = frappe.get_doc("Selling Settings") - selling_settings.enable_discount_accounting = enable - selling_settings.save() - - def get_sales_invoice_for_e_invoice(): si = make_sales_invoice_for_ewaybill() si.naming_series = "INV-2020-.#####" From c42547d40f5b23dd0c0a045005c49677863215fd Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Thu, 21 Apr 2022 13:26:44 +0530 Subject: [PATCH 26/46] fix: Use parent cost center for Sales and Purchase Invoice --- erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py | 4 +++- erpnext/accounts/doctype/sales_invoice/sales_invoice.py | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index a5f9e24e15..e37900b02e 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -1369,7 +1369,9 @@ class PurchaseInvoice(BuyingController): if ( not self.is_internal_transfer() and self.rounding_adjustment and self.base_rounding_adjustment ): - round_off_account, round_off_cost_center = get_round_off_account_and_cost_center(self.company) + round_off_account, round_off_cost_center = get_round_off_account_and_cost_center( + self.company, "Purchase Invoice", self.name + ) gl_entries.append( self.get_gl_dict( diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 1efd3dca0d..5b7f1ce8fd 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -1466,7 +1466,9 @@ class SalesInvoice(SellingController): and self.base_rounding_adjustment and not self.is_internal_transfer() ): - round_off_account, round_off_cost_center = get_round_off_account_and_cost_center(self.company) + round_off_account, round_off_cost_center = get_round_off_account_and_cost_center( + self.company, "Sales Invoice", self.name + ) gl_entries.append( self.get_gl_dict( From 8a8476bb5c9e487a80d0631b685a4a596caa297e Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Thu, 21 Apr 2022 18:53:18 +0530 Subject: [PATCH 27/46] test: Add test coverage for bank clearance --- .../bank_clearance/test_bank_clearance.py | 121 +++++++++++++++++- 1 file changed, 119 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/bank_clearance/test_bank_clearance.py b/erpnext/accounts/doctype/bank_clearance/test_bank_clearance.py index 706fbbe245..fbc44ee312 100644 --- a/erpnext/accounts/doctype/bank_clearance/test_bank_clearance.py +++ b/erpnext/accounts/doctype/bank_clearance/test_bank_clearance.py @@ -1,9 +1,126 @@ # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -# import frappe import unittest +import frappe +from frappe.utils import add_months, getdate + +from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_payment_entry +from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice +from erpnext.loan_management.doctype.loan.test_loan import ( + create_loan, + create_loan_accounts, + create_loan_type, + create_repayment_entry, + make_loan_disbursement_entry, +) + class TestBankClearance(unittest.TestCase): - pass + @classmethod + def setUpClass(cls): + make_bank_account() + create_loan_accounts() + create_loan_masters() + add_transactions() + + @classmethod + def tearDownClass(cls): + payment_entry = frappe.get_doc( + "Payment Entry", {"party_name": "_Test Supplier", "paid_from": "_Test Bank Clearance - _TC"} + ) + payment_entry.cancel() + payment_entry.delete() + + loan = frappe.get_doc("Loan", {"applicant": "_Test Customer"}) + + ld_doc = frappe.get_doc("Loan Disbursement", {"against_loan": loan.name}) + ld_doc.cancel() + ld_doc.delete() + + lr_doc = frappe.get_doc("Loan Repayment", {"against_loan": loan.name}) + lr_doc.cancel() + lr_doc.delete() + + lia = frappe.get_doc("Loan Interest Accrual", {"loan": loan.name}) + lia.delete() + + plia = frappe.get_doc("Process Loan Interest Accrual", {"loan": loan.name}) + plia.cancel() + plia.delete() + + loan.load_from_db() + loan.cancel() + loan.flags.ignore_links = True + loan.delete() + + # Basic test case to test if bank clearance tool doesn't break + # Detailed test can be added later + def test_bank_clearance(self): + bank_clearance = frappe.get_doc("Bank Clearance") + bank_clearance.account = "_Test Bank Clearance - _TC" + bank_clearance.from_date = add_months(getdate(), -1) + bank_clearance.to_date = getdate() + bank_clearance.get_payment_entries() + self.assertEqual(len(bank_clearance.payment_entries), 3) + + +def make_bank_account(): + if not frappe.db.get_value("Account", "_Test Bank Clearance - _TC"): + frappe.get_doc( + { + "doctype": "Account", + "account_type": "Bank", + "account_name": "_Test Bank Clearance", + "company": "_Test Company", + "parent_account": "Bank Accounts - _TC", + } + ).insert() + + +def create_loan_masters(): + create_loan_type( + "Clearance Loan", + 2000000, + 13.5, + 25, + 0, + 5, + "Cash", + "_Test Bank Clearance - _TC", + "_Test Bank Clearance - _TC", + "Loan Account - _TC", + "Interest Income Account - _TC", + "Penalty Income Account - _TC", + ) + + +def add_transactions(): + make_payment_entry() + make_loan() + + +def make_loan(): + loan = create_loan( + "_Test Customer", + "Clearance Loan", + 280000, + "Repay Over Number of Periods", + 20, + applicant_type="Customer", + ) + loan.submit() + make_loan_disbursement_entry(loan.name, loan.loan_amount, disbursement_date=getdate()) + repayment_entry = create_repayment_entry(loan.name, "_Test Customer", getdate(), loan.loan_amount) + repayment_entry.save() + repayment_entry.submit() + + +def make_payment_entry(): + pi = make_purchase_invoice(supplier="_Test Supplier", qty=1, rate=690) + pe = get_payment_entry("Purchase Invoice", pi.name, bank_account="_Test Bank Clearance - _TC") + pe.reference_no = "Conrad Oct 18" + pe.reference_date = "2018-10-24" + pe.insert() + pe.submit() From 9bb132fdd3d98a149427be3341e268d818e3bfa1 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Fri, 22 Apr 2022 13:39:43 +0530 Subject: [PATCH 28/46] fix: Do not validate while creating accounting dimension --- .../doctype/accounting_dimension/accounting_dimension.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py index 445378300b..3f1998a3b3 100644 --- a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py +++ b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py @@ -99,7 +99,7 @@ def make_dimension_in_accounting_doctypes(doc, doclist=None): if doctype == "Budget": add_dimension_to_budget_doctype(df.copy(), doc) else: - create_custom_field(doctype, df) + create_custom_field(doctype, df, ignore_validate=True) count += 1 @@ -115,7 +115,7 @@ def add_dimension_to_budget_doctype(df, doc): } ) - create_custom_field("Budget", df) + create_custom_field("Budget", df, ignore_validate=True) property_setter = frappe.db.exists("Property Setter", "Budget-budget_against-options") From 0eacc99ab705af446a0464f09ac92af760f5d9cf Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Sat, 23 Apr 2022 12:08:30 +0530 Subject: [PATCH 29/46] test: Fixes in test case --- .../bank_clearance/test_bank_clearance.py | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/erpnext/accounts/doctype/bank_clearance/test_bank_clearance.py b/erpnext/accounts/doctype/bank_clearance/test_bank_clearance.py index fbc44ee312..c09aa1c013 100644 --- a/erpnext/accounts/doctype/bank_clearance/test_bank_clearance.py +++ b/erpnext/accounts/doctype/bank_clearance/test_bank_clearance.py @@ -30,25 +30,33 @@ class TestBankClearance(unittest.TestCase): payment_entry = frappe.get_doc( "Payment Entry", {"party_name": "_Test Supplier", "paid_from": "_Test Bank Clearance - _TC"} ) - payment_entry.cancel() - payment_entry.delete() + + if payment_entry.docstatus == 1: + payment_entry.cancel() + payment_entry.delete() loan = frappe.get_doc("Loan", {"applicant": "_Test Customer"}) ld_doc = frappe.get_doc("Loan Disbursement", {"against_loan": loan.name}) - ld_doc.cancel() - ld_doc.delete() + + if ld_doc.docstatus == 1: + ld_doc.cancel() + ld_doc.delete() lr_doc = frappe.get_doc("Loan Repayment", {"against_loan": loan.name}) - lr_doc.cancel() - lr_doc.delete() + + if lr_doc.docstatus == 1: + lr_doc.cancel() + lr_doc.delete() lia = frappe.get_doc("Loan Interest Accrual", {"loan": loan.name}) lia.delete() plia = frappe.get_doc("Process Loan Interest Accrual", {"loan": loan.name}) - plia.cancel() - plia.delete() + + if plia.docstatus == 1: + plia.cancel() + plia.delete() loan.load_from_db() loan.cancel() From d4d83f4bb6f34353347f4b613bfe7c9554343425 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Sat, 23 Apr 2022 12:33:35 +0530 Subject: [PATCH 30/46] test: Fixes in test case --- .../accounts/doctype/bank_clearance/test_bank_clearance.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/erpnext/accounts/doctype/bank_clearance/test_bank_clearance.py b/erpnext/accounts/doctype/bank_clearance/test_bank_clearance.py index c09aa1c013..18645c7517 100644 --- a/erpnext/accounts/doctype/bank_clearance/test_bank_clearance.py +++ b/erpnext/accounts/doctype/bank_clearance/test_bank_clearance.py @@ -27,6 +27,8 @@ class TestBankClearance(unittest.TestCase): @classmethod def tearDownClass(cls): + frappe.db.set_single_value("Accounts Settings", "delete_linked_ledger_entries", 1) + payment_entry = frappe.get_doc( "Payment Entry", {"party_name": "_Test Supplier", "paid_from": "_Test Bank Clearance - _TC"} ) @@ -63,6 +65,8 @@ class TestBankClearance(unittest.TestCase): loan.flags.ignore_links = True loan.delete() + frappe.db.set_single_value("Accounts Settings", "delete_linked_ledger_entries", 0) + # Basic test case to test if bank clearance tool doesn't break # Detailed test can be added later def test_bank_clearance(self): From 015812b0b8216d0d66e005700691dfa1ace74bf7 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Sat, 23 Apr 2022 21:40:08 +0530 Subject: [PATCH 31/46] fix: Add accounting dimensions for round off GL Entry --- erpnext/accounts/general_ledger.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/erpnext/accounts/general_ledger.py b/erpnext/accounts/general_ledger.py index 4dbc4d6a72..2d36835869 100644 --- a/erpnext/accounts/general_ledger.py +++ b/erpnext/accounts/general_ledger.py @@ -392,10 +392,22 @@ def make_round_off_gle(gl_map, debit_credit_diff, precision): } ) + update_accounting_dimensions(round_off_gle) + if not round_off_account_exists: gl_map.append(round_off_gle) +def update_accounting_dimensions(round_off_gle): + dimensions = get_accounting_dimensions() + dimension_values = frappe.db.get_value( + round_off_gle["voucher_type"], round_off_gle["voucher_no"], dimensions + ) + + for dimension in dimensions: + round_off_gle[dimension] = dimension_values.get(dimension) + + def get_round_off_account_and_cost_center(company, voucher_type, voucher_no): round_off_account, round_off_cost_center = frappe.get_cached_value( "Company", company, ["round_off_account", "round_off_cost_center"] From c312cd3725680cff91aa9e41da5a40fa91af7784 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Sun, 24 Apr 2022 18:11:32 +0530 Subject: [PATCH 32/46] fix: Check if accounting dimension exists --- erpnext/accounts/general_ledger.py | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/erpnext/accounts/general_ledger.py b/erpnext/accounts/general_ledger.py index 2d36835869..56f84c2392 100644 --- a/erpnext/accounts/general_ledger.py +++ b/erpnext/accounts/general_ledger.py @@ -400,12 +400,20 @@ def make_round_off_gle(gl_map, debit_credit_diff, precision): def update_accounting_dimensions(round_off_gle): dimensions = get_accounting_dimensions() - dimension_values = frappe.db.get_value( - round_off_gle["voucher_type"], round_off_gle["voucher_no"], dimensions - ) + meta = frappe.get_meta(round_off_gle["voucher_type"]) + has_all_dimensions = True for dimension in dimensions: - round_off_gle[dimension] = dimension_values.get(dimension) + if not meta.has_field(dimension): + has_all_dimensions = False + + if dimensions and has_all_dimensions: + dimension_values = frappe.db.get_value( + round_off_gle["voucher_type"], round_off_gle["voucher_no"], dimensions + ) + + for dimension in dimensions: + round_off_gle[dimension] = dimension_values.get(dimension) def get_round_off_account_and_cost_center(company, voucher_type, voucher_no): @@ -413,8 +421,10 @@ def get_round_off_account_and_cost_center(company, voucher_type, voucher_no): "Company", company, ["round_off_account", "round_off_cost_center"] ) or [None, None] + meta = frappe.get_meta(voucher_type) + # Give first preference to parent cost center for round off GLE - if frappe.db.has_column(voucher_type, "cost_center"): + if meta.has_field("cost_center"): parent_cost_center = frappe.db.get_value(voucher_type, voucher_no, "cost_center") if parent_cost_center: round_off_cost_center = parent_cost_center From c515abc392a8ae6b230ff39e32aae6a8ca4a6dfe Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Sun, 24 Apr 2022 19:20:29 +0530 Subject: [PATCH 33/46] test: Remove teardown method --- .../bank_clearance/test_bank_clearance.py | 42 ------------------- 1 file changed, 42 deletions(-) diff --git a/erpnext/accounts/doctype/bank_clearance/test_bank_clearance.py b/erpnext/accounts/doctype/bank_clearance/test_bank_clearance.py index 18645c7517..c1e55f6f72 100644 --- a/erpnext/accounts/doctype/bank_clearance/test_bank_clearance.py +++ b/erpnext/accounts/doctype/bank_clearance/test_bank_clearance.py @@ -25,48 +25,6 @@ class TestBankClearance(unittest.TestCase): create_loan_masters() add_transactions() - @classmethod - def tearDownClass(cls): - frappe.db.set_single_value("Accounts Settings", "delete_linked_ledger_entries", 1) - - payment_entry = frappe.get_doc( - "Payment Entry", {"party_name": "_Test Supplier", "paid_from": "_Test Bank Clearance - _TC"} - ) - - if payment_entry.docstatus == 1: - payment_entry.cancel() - payment_entry.delete() - - loan = frappe.get_doc("Loan", {"applicant": "_Test Customer"}) - - ld_doc = frappe.get_doc("Loan Disbursement", {"against_loan": loan.name}) - - if ld_doc.docstatus == 1: - ld_doc.cancel() - ld_doc.delete() - - lr_doc = frappe.get_doc("Loan Repayment", {"against_loan": loan.name}) - - if lr_doc.docstatus == 1: - lr_doc.cancel() - lr_doc.delete() - - lia = frappe.get_doc("Loan Interest Accrual", {"loan": loan.name}) - lia.delete() - - plia = frappe.get_doc("Process Loan Interest Accrual", {"loan": loan.name}) - - if plia.docstatus == 1: - plia.cancel() - plia.delete() - - loan.load_from_db() - loan.cancel() - loan.flags.ignore_links = True - loan.delete() - - frappe.db.set_single_value("Accounts Settings", "delete_linked_ledger_entries", 0) - # Basic test case to test if bank clearance tool doesn't break # Detailed test can be added later def test_bank_clearance(self): From d6a43a39aef6915276e9d433f0d2d085c045ab27 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Mon, 25 Apr 2022 11:46:01 +0530 Subject: [PATCH 34/46] test: tie breaking in SLEs (#30796) [skip ci] --- .../test_stock_ledger_entry.py | 59 ++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py b/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py index b4fac82935..5850ec7be6 100644 --- a/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py +++ b/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py @@ -2,12 +2,12 @@ # See license.txt import json -from datetime import timedelta from uuid import uuid4 import frappe from frappe.core.page.permission_manager.permission_manager import reset from frappe.custom.doctype.property_setter.property_setter import make_property_setter +from frappe.query_builder.functions import CombineDatetime from frappe.tests.utils import FrappeTestCase from frappe.utils import add_days, today from frappe.utils.data import add_to_date @@ -1126,6 +1126,63 @@ class TestStockLedgerEntry(FrappeTestCase): # original amount self.assertEqual(50, _get_stock_credit(final_consumption)) + def test_tie_breaking(self): + frappe.flags.dont_execute_stock_reposts = True + self.addCleanup(frappe.flags.pop, "dont_execute_stock_reposts") + + item = make_item().name + warehouse = "_Test Warehouse - _TC" + + posting_date = "2022-01-01" + posting_time = "00:00:01" + sle = frappe.qb.DocType("Stock Ledger Entry") + + def ordered_qty_after_transaction(): + return ( + frappe.qb.from_(sle) + .select("qty_after_transaction") + .where((sle.item_code == item) & (sle.warehouse == warehouse) & (sle.is_cancelled == 0)) + .orderby(CombineDatetime(sle.posting_date, sle.posting_time)) + .orderby(sle.creation) + ).run(pluck=True) + + first = make_stock_entry( + item_code=item, + to_warehouse=warehouse, + qty=10, + posting_time=posting_time, + posting_date=posting_date, + do_not_submit=True, + ) + second = make_stock_entry( + item_code=item, + to_warehouse=warehouse, + qty=1, + posting_date=posting_date, + posting_time=posting_time, + do_not_submit=True, + ) + + first.submit() + second.submit() + + self.assertEqual([10, 11], ordered_qty_after_transaction()) + + first.cancel() + self.assertEqual([1], ordered_qty_after_transaction()) + + backdated = make_stock_entry( + item_code=item, + to_warehouse=warehouse, + qty=1, + posting_date="2021-01-01", + posting_time=posting_time, + ) + self.assertEqual([1, 2], ordered_qty_after_transaction()) + + backdated.cancel() + self.assertEqual([1], ordered_qty_after_transaction()) + def create_repack_entry(**args): args = frappe._dict(args) From 02aaa6546ce4766aed84908bca79747cd77b0250 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Mon, 25 Apr 2022 12:42:06 +0530 Subject: [PATCH 35/46] chore: Remove dead code --- .../doctype/purchase_invoice/test_purchase_invoice.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py index 42455bf431..30d26acf3a 100644 --- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py @@ -1530,12 +1530,6 @@ class TestPurchaseInvoice(unittest.TestCase): company.save() -def enable_discount_accounting(enable=1): - buying_settings = frappe.get_doc("Buying Settings") - buying_settings.enable_discount_accounting = enable - buying_settings.save() - - def check_gl_entries(doc, voucher_no, expected_gle, posting_date): gl_entries = frappe.db.sql( """select account, debit, credit, posting_date From 8e6c7a6bf7b1b934ae239a77e8767c8d8e9c375b Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Mon, 25 Apr 2022 14:02:46 +0530 Subject: [PATCH 36/46] fix(india): cess value not considered while validating e-invoice totals --- erpnext/regional/india/e_invoice/utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/erpnext/regional/india/e_invoice/utils.py b/erpnext/regional/india/e_invoice/utils.py index f317569312..5518e1cb35 100644 --- a/erpnext/regional/india/e_invoice/utils.py +++ b/erpnext/regional/india/e_invoice/utils.py @@ -552,6 +552,7 @@ def validate_totals(einvoice): + flt(value_details["CgstVal"]) + flt(value_details["SgstVal"]) + flt(value_details["IgstVal"]) + + flt(value_details["CesVal"]) + flt(value_details["OthChrg"]) + flt(value_details["RndOffAmt"]) - flt(value_details["Discount"]) From 3fa1c634790095bf7eabc135ed717e124efa4ff0 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Mon, 25 Apr 2022 16:29:26 +0530 Subject: [PATCH 37/46] test: Unit test for round off entry dimensions --- .../sales_invoice/test_sales_invoice.py | 23 +++++++++++++++++++ erpnext/accounts/general_ledger.py | 2 +- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index caa70d00ef..b22ec44f8a 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -1977,6 +1977,13 @@ class TestSalesInvoice(unittest.TestCase): self.assertEqual(expected_values[gle.account][2], gle.credit) def test_rounding_adjustment_3(self): + from erpnext.accounts.doctype.accounting_dimension.test_accounting_dimension import ( + create_dimension, + disable_dimension, + ) + + create_dimension() + si = create_sales_invoice(do_not_save=True) si.items = [] for d in [(1122, 2), (1122.01, 1), (1122.01, 1)]: @@ -2004,6 +2011,10 @@ class TestSalesInvoice(unittest.TestCase): "included_in_print_rate": 1, }, ) + + si.cost_center = "_Test Cost Center 2 - _TC" + si.location = "Block 1" + si.save() si.submit() self.assertEqual(si.net_total, 4007.16) @@ -2039,6 +2050,18 @@ class TestSalesInvoice(unittest.TestCase): self.assertEqual(debit_credit_diff, 0) + round_off_gle = frappe.db.get_value( + "GL Entry", + {"voucher_type": "Sales Invoice", "voucher_no": si.name, "account": "Round Off - _TC"}, + ["cost_center", "location"], + as_dict=1, + ) + + self.assertEqual(round_off_gle.cost_center, "_Test Cost Center 2 - _TC") + self.assertEqual(round_off_gle.location, "Block 1") + + disable_dimension() + def test_sales_invoice_with_shipping_rule(self): from erpnext.accounts.doctype.shipping_rule.test_shipping_rule import create_shipping_rule diff --git a/erpnext/accounts/general_ledger.py b/erpnext/accounts/general_ledger.py index 56f84c2392..89034ebb8c 100644 --- a/erpnext/accounts/general_ledger.py +++ b/erpnext/accounts/general_ledger.py @@ -409,7 +409,7 @@ def update_accounting_dimensions(round_off_gle): if dimensions and has_all_dimensions: dimension_values = frappe.db.get_value( - round_off_gle["voucher_type"], round_off_gle["voucher_no"], dimensions + round_off_gle["voucher_type"], round_off_gle["voucher_no"], dimensions, as_dict=1 ) for dimension in dimensions: From e1c168766198d44dc7e28746bcad9f4c266c3a39 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Thu, 21 Apr 2022 20:01:48 +0530 Subject: [PATCH 38/46] refactor: use db agnostic `CombineDatetime` --- erpnext/stock/stock_ledger.py | 10 ++++------ erpnext/stock/utils.py | 6 +++--- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py index a781479cf6..7e5c231d9c 100644 --- a/erpnext/stock/stock_ledger.py +++ b/erpnext/stock/stock_ledger.py @@ -8,9 +8,8 @@ from typing import Optional, Set, Tuple import frappe from frappe import _ from frappe.model.meta import get_field_precision -from frappe.query_builder.functions import Sum +from frappe.query_builder.functions import CombineDatetime, Sum from frappe.utils import cint, cstr, flt, get_link_to_form, getdate, now, nowdate -from pypika import CustomFunction import erpnext from erpnext.stock.doctype.bin.bin import update_qty as update_bin_qty @@ -1158,16 +1157,15 @@ def get_batch_incoming_rate( item_code, warehouse, batch_no, posting_date, posting_time, creation=None ): - Timestamp = CustomFunction("timestamp", ["date", "time"]) - sle = frappe.qb.DocType("Stock Ledger Entry") - timestamp_condition = Timestamp(sle.posting_date, sle.posting_time) < Timestamp( + timestamp_condition = CombineDatetime(sle.posting_date, sle.posting_time) < CombineDatetime( posting_date, posting_time ) if creation: timestamp_condition |= ( - Timestamp(sle.posting_date, sle.posting_time) == Timestamp(posting_date, posting_time) + CombineDatetime(sle.posting_date, sle.posting_time) + == CombineDatetime(posting_date, posting_time) ) & (sle.creation < creation) batch_details = ( diff --git a/erpnext/stock/utils.py b/erpnext/stock/utils.py index d40218e143..2120304097 100644 --- a/erpnext/stock/utils.py +++ b/erpnext/stock/utils.py @@ -7,6 +7,7 @@ from typing import Dict, Optional import frappe from frappe import _ +from frappe.query_builder.functions import CombineDatetime from frappe.utils import cstr, flt, get_link_to_form, nowdate, nowtime import erpnext @@ -143,12 +144,10 @@ def get_stock_balance( def get_serial_nos_data_after_transactions(args): - from pypika import CustomFunction serial_nos = set() args = frappe._dict(args) sle = frappe.qb.DocType("Stock Ledger Entry") - Timestamp = CustomFunction("timestamp", ["date", "time"]) stock_ledger_entries = ( frappe.qb.from_(sle) @@ -157,7 +156,8 @@ def get_serial_nos_data_after_transactions(args): (sle.item_code == args.item_code) & (sle.warehouse == args.warehouse) & ( - Timestamp(sle.posting_date, sle.posting_time) < Timestamp(args.posting_date, args.posting_time) + CombineDatetime(sle.posting_date, sle.posting_time) + < CombineDatetime(args.posting_date, args.posting_time) ) & (sle.is_cancelled == 0) ) From cdac2b8c63e5856498e5c4cbcc871a1178f7cb80 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Thu, 21 Apr 2022 20:43:07 +0530 Subject: [PATCH 39/46] fix: ignore duplicate fixtures --- erpnext/regional/india/setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py index 446faaa708..062c2ef5c5 100644 --- a/erpnext/regional/india/setup.py +++ b/erpnext/regional/india/setup.py @@ -1219,7 +1219,7 @@ def make_fixtures(company=None): try: doc = frappe.get_doc(d) doc.flags.ignore_permissions = True - doc.insert() + doc.insert(ignore_if_duplicate=True) except frappe.NameError: frappe.clear_messages() except frappe.DuplicateEntryError: From ce75fe0ec405c68f1c5dd7b4a5d1bbde1af70705 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Fri, 22 Apr 2022 11:44:30 +0530 Subject: [PATCH 40/46] fix: out of range date value --- erpnext/stock/doctype/stock_entry/stock_entry.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index c4aa8a4711..27a6eaf08b 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -1167,7 +1167,7 @@ class StockEntry(StockController): from `tabItem` i LEFT JOIN `tabItem Default` id ON i.name=id.parent and id.company=%s where i.name=%s and i.disabled=0 - and (i.end_of_life is null or i.end_of_life='0000-00-00' or i.end_of_life > %s)""", + and (i.end_of_life is null or i.end_of_life<'1900-01-01' or i.end_of_life > %s)""", (self.company, args.get("item_code"), nowdate()), as_dict=1, ) From 0fdfc1e76e7aa89268e89a67c968b7acb6d980ec Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Sun, 24 Apr 2022 19:19:22 +0530 Subject: [PATCH 41/46] fix: only query fields that exist --- erpnext/crm/doctype/opportunity/opportunity.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/erpnext/crm/doctype/opportunity/opportunity.py b/erpnext/crm/doctype/opportunity/opportunity.py index 96c730c668..19b4d68e1c 100644 --- a/erpnext/crm/doctype/opportunity/opportunity.py +++ b/erpnext/crm/doctype/opportunity/opportunity.py @@ -54,11 +54,11 @@ class Opportunity(TransactionBase): self.calculate_totals() def map_fields(self): - for field in self.meta.fields: - if not self.get(field.fieldname): + for field in self.meta.get_valid_columns(): + if not self.get(field) and frappe.db.field_exists(self.opportunity_from, field): try: - value = frappe.db.get_value(self.opportunity_from, self.party_name, field.fieldname) - frappe.db.set(self, field.fieldname, value) + value = frappe.db.get_value(self.opportunity_from, self.party_name, field) + frappe.db.set(self, field, value) except Exception: continue From 7d2587c0a9b2ab30ab45bbc9c2af40b1f2ade1fb Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Sun, 24 Apr 2022 19:26:15 +0530 Subject: [PATCH 42/46] fix: nullish check and table name --- erpnext/manufacturing/doctype/bom/bom.py | 2 +- erpnext/stock/doctype/item_price/item_price.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py index fefb2e59f0..220ce1dbd8 100644 --- a/erpnext/manufacturing/doctype/bom/bom.py +++ b/erpnext/manufacturing/doctype/bom/bom.py @@ -753,7 +753,7 @@ class BOM(WebsiteGenerator): bom_item.include_item_in_manufacturing, bom_item.sourced_by_supplier, bom_item.stock_qty / ifnull(bom.quantity, 1) AS qty_consumed_per_unit - FROM `tabBOM Explosion Item` bom_item, tabBOM bom + FROM `tabBOM Explosion Item` bom_item, `tabBOM` bom WHERE bom_item.parent = bom.name AND bom.name = %s diff --git a/erpnext/stock/doctype/item_price/item_price.py b/erpnext/stock/doctype/item_price/item_price.py index 562f7b9e12..ab797cd039 100644 --- a/erpnext/stock/doctype/item_price/item_price.py +++ b/erpnext/stock/doctype/item_price/item_price.py @@ -64,7 +64,7 @@ class ItemPrice(Document): if self.get(field): conditions += " and {0} = %({0})s ".format(field) else: - conditions += "and (isnull({0}) or {0} = '')".format(field) + conditions += "and ({0} is null or {0} = '')".format(field) price_list_rate = frappe.db.sql( """ From 7e555d3d8c47bc7f304905a3d52b02e9da6b0283 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Sun, 24 Apr 2022 19:47:07 +0530 Subject: [PATCH 43/46] fix: item price query for postgres postgres doesn't like bad type comparisons and doesn't have `isnull` funciton --- .../stock/doctype/item_price/item_price.py | 64 +++++++++++++------ 1 file changed, 44 insertions(+), 20 deletions(-) diff --git a/erpnext/stock/doctype/item_price/item_price.py b/erpnext/stock/doctype/item_price/item_price.py index ab797cd039..bcd31ada83 100644 --- a/erpnext/stock/doctype/item_price/item_price.py +++ b/erpnext/stock/doctype/item_price/item_price.py @@ -5,6 +5,8 @@ import frappe from frappe import _ from frappe.model.document import Document +from frappe.query_builder import Criterion +from frappe.query_builder.functions import Cast_ from frappe.utils import getdate @@ -48,35 +50,57 @@ class ItemPrice(Document): ) def check_duplicates(self): - conditions = ( - """where item_code = %(item_code)s and price_list = %(price_list)s and name != %(name)s""" - ) - for field in [ + item_price = frappe.qb.DocType("Item Price") + + query = ( + frappe.qb.from_(item_price) + .select(item_price.price_list_rate) + .where( + (item_price.item_code == self.item_code) + & (item_price.price_list == self.price_list) + & (item_price.name != self.name) + ) + ) + data_fields = ( "uom", "valid_from", "valid_upto", - "packing_unit", "customer", "supplier", "batch_no", - ]: - if self.get(field): - conditions += " and {0} = %({0})s ".format(field) - else: - conditions += "and ({0} is null or {0} = '')".format(field) - - price_list_rate = frappe.db.sql( - """ - select price_list_rate - from `tabItem Price` - {conditions} - """.format( - conditions=conditions - ), - self.as_dict(), ) + number_fields = ["packing_unit"] + + for field in data_fields: + if self.get(field): + query = query.where(item_price[field] == self.get(field)) + else: + query = query.where( + Criterion.any( + [ + item_price[field].isnull(), + Cast_(item_price[field], "varchar") == "", + ] + ) + ) + + for field in number_fields: + if self.get(field): + query = query.where(item_price[field] == self.get(field)) + else: + query = query.where( + Criterion.any( + [ + item_price[field].isnull(), + item_price[field] == 0, + ] + ) + ) + + price_list_rate = query.run(as_dict=True) + if price_list_rate: frappe.throw( _( From a90e7e32a42362f5a03ad1467c7a1e5757fe95fe Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Sun, 24 Apr 2022 20:05:36 +0530 Subject: [PATCH 44/46] fix: proper quoting in sql queries --- erpnext/accounts/party.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py index b0b3049d48..ac1dfec7a5 100644 --- a/erpnext/accounts/party.py +++ b/erpnext/accounts/party.py @@ -881,11 +881,11 @@ def get_default_contact(doctype, name): """ SELECT dl.parent, c.is_primary_contact, c.is_billing_contact FROM `tabDynamic Link` dl - INNER JOIN tabContact c ON c.name = dl.parent + INNER JOIN `tabContact` c ON c.name = dl.parent WHERE dl.link_doctype=%s AND dl.link_name=%s AND - dl.parenttype = "Contact" + dl.parenttype = 'Contact' ORDER BY is_primary_contact DESC, is_billing_contact DESC """, (doctype, name), From 052171f51c17c77459c05423a87ca935dd0ab555 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Sun, 24 Apr 2022 20:14:01 +0530 Subject: [PATCH 45/46] fix: date condition in tax rule --- erpnext/accounts/doctype/tax_rule/tax_rule.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/tax_rule/tax_rule.py b/erpnext/accounts/doctype/tax_rule/tax_rule.py index 27b78e9fab..5bfca96bb1 100644 --- a/erpnext/accounts/doctype/tax_rule/tax_rule.py +++ b/erpnext/accounts/doctype/tax_rule/tax_rule.py @@ -163,10 +163,15 @@ def get_party_details(party, party_type, args=None): def get_tax_template(posting_date, args): """Get matching tax rule""" args = frappe._dict(args) + from_date = to_date = posting_date + if not posting_date: + from_date = "1900-01-01" + to_date = "4000-01-01" + conditions = [ """(from_date is null or from_date <= '{0}') - and (to_date is null or to_date >= '{0}')""".format( - posting_date + and (to_date is null or to_date >= '{1}')""".format( + from_date, to_date ) ] From 88e257ff6d89ba03e3b273be33fec62714751b69 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Sun, 24 Apr 2022 20:17:17 +0530 Subject: [PATCH 46/46] fix: column name in party query --- erpnext/accounts/party.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py index ac1dfec7a5..db741d97e1 100644 --- a/erpnext/accounts/party.py +++ b/erpnext/accounts/party.py @@ -831,9 +831,9 @@ def get_party_shipping_address(doctype, name): "where " "dl.link_doctype=%s " "and dl.link_name=%s " - 'and dl.parenttype="Address" ' + "and dl.parenttype='Address' " "and ifnull(ta.disabled, 0) = 0 and" - '(ta.address_type="Shipping" or ta.is_shipping_address=1) ' + "(ta.address_type='Shipping' or ta.is_shipping_address=1) " "order by ta.is_shipping_address desc, ta.address_type desc limit 1", (doctype, name), )