From fb4a75c5aa39f4a0b5725a5f14e87f42b9291c1b Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Thu, 18 Apr 2024 12:24:45 +0530 Subject: [PATCH 01/34] fix: validation to prevent foreign currency advance accounts in PE (cherry picked from commit e3fc5990ee1015ad055a70be3279e4adfe81f1cc) --- .../doctype/payment_entry/payment_entry.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py index 0d1206b0cc7..6674e0ce17a 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py @@ -76,6 +76,7 @@ class PaymentEntry(AccountsController): self.setup_party_account_field() self.set_missing_values() self.set_liability_account() + self.validate_advance_account_currency() self.set_missing_ref_details(force=True) self.validate_payment_type() self.validate_party_details() @@ -157,6 +158,22 @@ class PaymentEntry(AccountsController): alert=True, ) + def validate_advance_account_currency(self): + if self.book_advance_payments_in_separate_party_account is True: + company_currency = frappe.get_cached_value("Company", self.company, "default_currency") + if self.payment_type == "Receive" and self.paid_from_account_currency != company_currency: + frappe.throw( + _("Booking advances in foreign currency account: {0} ({1}) is not yet supported.").format( + frappe.bold(self.paid_from), frappe.bold(self.paid_from_account_currency) + ) + ) + if self.payment_type == "Pay" and self.paid_to_account_currency != company_currency: + frappe.throw( + _("Booking advances in foreign currency account: {0} ({1}) is not yet supported.").format( + frappe.bold(self.paid_to), frappe.bold(self.paid_to_account_currency) + ) + ) + def on_cancel(self): self.ignore_linked_doctypes = ( "GL Entry", From dd67b0ee612a9dd0f0956a6d79b992a55311cdb4 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Thu, 18 Apr 2024 17:15:52 +0530 Subject: [PATCH 02/34] fix: advance account validation in company master (cherry picked from commit 1ad065fc5467291743e97806eb0f5ab76c543000) --- erpnext/setup/doctype/company/company.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py index 7181e90139e..553c0f5fc95 100644 --- a/erpnext/setup/doctype/company/company.py +++ b/erpnext/setup/doctype/company/company.py @@ -139,6 +139,7 @@ class Company(NestedSet): self.validate_abbr() self.validate_default_accounts() self.validate_currency() + self.validate_advance_account_currency() self.validate_coa_input() self.validate_perpetual_inventory() self.validate_provisional_account_for_non_stock_items() @@ -192,6 +193,29 @@ class Company(NestedSet): ).format(frappe.bold(account[0])) frappe.throw(error_message) + def validate_advance_account_currency(self): + if ( + self.default_advance_received_account + and frappe.get_cached_value("Account", self.default_advance_received_account, "account_currency") + != self.default_currency + ): + frappe.throw( + _("'{0}' should be in company currency {1}.").format( + frappe.bold("Default Advance Received Account"), frappe.bold(self.default_currency) + ) + ) + + if ( + self.default_advance_paid_account + and frappe.get_cached_value("Account", self.default_advance_paid_account, "account_currency") + != self.default_currency + ): + frappe.throw( + _("'{0}' should be in company currency {1}.").format( + frappe.bold("Default Advance Paid Account"), frappe.bold(self.default_currency) + ) + ) + def validate_currency(self): if self.is_new(): return From c6145a1101d56603047282b92b8be98a8305ed16 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Tue, 23 Apr 2024 10:38:37 +0530 Subject: [PATCH 03/34] fix: mode of payment has precedance Mode of Payment is given precedence over company/party bank account (cherry picked from commit 4aef96987988c66ef2f1c41392661711f9b6e98b) --- erpnext/accounts/doctype/payment_entry/payment_entry.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.js b/erpnext/accounts/doctype/payment_entry/payment_entry.js index c4ef4017fd1..77426ef9740 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.js +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.js @@ -1334,7 +1334,9 @@ frappe.ui.form.on("Payment Entry", { }, callback: function (r) { if (r.message) { - frm.set_value(field, r.message.account); + if (!frm.doc.mode_of_payment) { + frm.set_value(field, r.message.account); + } frm.set_value("bank", r.message.bank); frm.set_value("bank_account_no", r.message.bank_account_no); } From b34582e6baed79bd479fe44ec84801b3fbd90b21 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Thu, 25 Apr 2024 17:26:26 +0530 Subject: [PATCH 04/34] fix: handle stock balance unbuffered_cursor error (backport #41186) (#41188) fix: handle stock balance unbuffered_cursor error (#41186) (cherry picked from commit 341fb6d8f3b507700638c59548093784b12dde04) Co-authored-by: Ankush Menat --- erpnext/stock/report/stock_balance/stock_balance.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/erpnext/stock/report/stock_balance/stock_balance.py b/erpnext/stock/report/stock_balance/stock_balance.py index af07dd7f73c..64ad36ff5b1 100644 --- a/erpnext/stock/report/stock_balance/stock_balance.py +++ b/erpnext/stock/report/stock_balance/stock_balance.py @@ -146,6 +146,8 @@ class StockBalanceReport: if self.filters.get("show_stock_ageing_data"): self.sle_entries = self.sle_query.run(as_dict=True) + # HACK: This is required to avoid causing db query in flt + _system_settings = frappe.get_cached_doc("System Settings") with frappe.db.unbuffered_cursor(): if not self.filters.get("show_stock_ageing_data"): self.sle_entries = self.sle_query.run(as_dict=True, as_iterator=True) From c3073d6e74a7e03eb205ad6365474393e02c4a44 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Thu, 25 Apr 2024 12:18:11 +0530 Subject: [PATCH 05/34] fix: enable advance in separate acc only for customer and Supplier (cherry picked from commit 3c1af2acf015d7b4ce6aa8e19c333d87f2ea292a) --- erpnext/accounts/doctype/payment_entry/payment_entry.py | 1 + 1 file changed, 1 insertion(+) diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py index 8a8f7cb55e9..2fb62b79ab1 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py @@ -114,6 +114,7 @@ class PaymentEntry(AccountsController): if self.docstatus > 0 or self.payment_type == "Internal Transfer": return + self.book_advance_payments_in_separate_party_account = False if self.party_type not in ("Customer", "Supplier"): return From a62298a635315f294128b0888387cedf9711a10d Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Fri, 26 Apr 2024 10:43:30 +0530 Subject: [PATCH 06/34] fix: duplicate column in the stock ledger report (cherry picked from commit be7fd6bfb42081e3e3fbb24e82dd5b3dbdc681d8) --- erpnext/stock/report/stock_ledger/stock_ledger.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/erpnext/stock/report/stock_ledger/stock_ledger.py b/erpnext/stock/report/stock_ledger/stock_ledger.py index 04cd1b846b3..b57333f9f35 100644 --- a/erpnext/stock/report/stock_ledger/stock_ledger.py +++ b/erpnext/stock/report/stock_ledger/stock_ledger.py @@ -231,13 +231,6 @@ def get_columns(filters): "width": 100, "convertible": "qty", }, - { - "label": _("Voucher #"), - "fieldname": "voucher_no", - "fieldtype": "Dynamic Link", - "options": "voucher_type", - "width": 150, - }, { "label": _("Warehouse"), "fieldname": "warehouse", From 7b7987363f6e28ac2e5421ee1939a841fd38e6da Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Fri, 26 Apr 2024 12:20:08 +0530 Subject: [PATCH 07/34] fix: basic rate for SABB (cherry picked from commit 7fa94843aadbd546a4d73d11491161f5b88955c8) --- erpnext/public/js/utils/sales_common.js | 1 + erpnext/stock/doctype/stock_entry/stock_entry.js | 1 + 2 files changed, 2 insertions(+) diff --git a/erpnext/public/js/utils/sales_common.js b/erpnext/public/js/utils/sales_common.js index 5bc4ffe1bff..0b482c3292f 100644 --- a/erpnext/public/js/utils/sales_common.js +++ b/erpnext/public/js/utils/sales_common.js @@ -373,6 +373,7 @@ erpnext.sales_common = { frappe.model.set_value(item.doctype, item.name, { serial_and_batch_bundle: r.name, use_serial_batch_fields: 0, + incoming_rate: r.avg_rate, qty: qty / flt( diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js index 9b929f9f1b8..fb63f1c23c6 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.js +++ b/erpnext/stock/doctype/stock_entry/stock_entry.js @@ -1340,6 +1340,7 @@ erpnext.stock.select_batch_and_serial_no = (frm, item) => { frappe.model.set_value(item.doctype, item.name, { serial_and_batch_bundle: r.name, use_serial_batch_fields: 0, + basic_rate: r.avg_rate, qty: Math.abs(r.total_qty) / flt(item.conversion_factor || 1, precision("conversion_factor", item)), From e9acacdd5d7f1afe08318fc5dd5487febcaa13ca Mon Sep 17 00:00:00 2001 From: Nihantra Patel Date: Thu, 25 Apr 2024 16:42:38 +0530 Subject: [PATCH 08/34] fix: args when get the delivery note in delivery trip (cherry picked from commit 2f359e201d9cbc7e06ccec13ef87280eb6314880) # Conflicts: # erpnext/stock/doctype/delivery_note/delivery_note.py --- erpnext/stock/doctype/delivery_note/delivery_note.py | 6 ++++++ erpnext/stock/doctype/delivery_trip/delivery_trip.js | 1 + 2 files changed, 7 insertions(+) diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py index bce87b80c51..f8be3f1b54f 100644 --- a/erpnext/stock/doctype/delivery_note/delivery_note.py +++ b/erpnext/stock/doctype/delivery_note/delivery_note.py @@ -1066,6 +1066,7 @@ def make_sales_invoice(source_name, target_doc=None, args=None): @frappe.whitelist() +<<<<<<< HEAD def make_delivery_trip(source_name, target_doc=None): def update_stop_details(source_doc, target_doc, source_parent): target_doc.customer = source_parent.customer @@ -1080,6 +1081,11 @@ def make_delivery_trip(source_name, target_doc=None): delivery_notes = [] +======= +def make_delivery_trip(source_name, target_doc=None, kwargs=None): + if not target_doc: + target_doc = frappe.new_doc("Delivery Trip") +>>>>>>> 2f359e201d (fix: args when get the delivery note in delivery trip) doclist = get_mapped_doc( "Delivery Note", source_name, diff --git a/erpnext/stock/doctype/delivery_trip/delivery_trip.js b/erpnext/stock/doctype/delivery_trip/delivery_trip.js index 4f8649c0bfa..ba4a3b3486c 100755 --- a/erpnext/stock/doctype/delivery_trip/delivery_trip.js +++ b/erpnext/stock/doctype/delivery_trip/delivery_trip.js @@ -51,6 +51,7 @@ frappe.ui.form.on("Delivery Trip", { frm.add_custom_button( __("Delivery Note"), () => { + frm.clear_table('delivery_stops'); erpnext.utils.map_current_doc({ method: "erpnext.stock.doctype.delivery_note.delivery_note.make_delivery_trip", source_doctype: "Delivery Note", From 61d6838b2c16f6e06bc89758dafcf6ff447a8aa5 Mon Sep 17 00:00:00 2001 From: Nihantra Patel Date: Thu, 25 Apr 2024 16:46:29 +0530 Subject: [PATCH 09/34] fix: args when get the delivery note in delivery trip (cherry picked from commit ca577f7aaa595ec05754d54ac3a672ad4187c8af) --- erpnext/stock/doctype/delivery_trip/delivery_trip.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/stock/doctype/delivery_trip/delivery_trip.js b/erpnext/stock/doctype/delivery_trip/delivery_trip.js index ba4a3b3486c..77eae534d17 100755 --- a/erpnext/stock/doctype/delivery_trip/delivery_trip.js +++ b/erpnext/stock/doctype/delivery_trip/delivery_trip.js @@ -51,7 +51,7 @@ frappe.ui.form.on("Delivery Trip", { frm.add_custom_button( __("Delivery Note"), () => { - frm.clear_table('delivery_stops'); + frm.clear_table("delivery_stops"); erpnext.utils.map_current_doc({ method: "erpnext.stock.doctype.delivery_note.delivery_note.make_delivery_trip", source_doctype: "Delivery Note", From 3068dad4108de2a8dfd9ce7fe24e7fc743115924 Mon Sep 17 00:00:00 2001 From: "Nihantra C. Patel" <141945075+Nihantra-Patel@users.noreply.github.com> Date: Thu, 25 Apr 2024 12:01:28 +0530 Subject: [PATCH 10/34] fix: rendering the email template when user HTML (cherry picked from commit 7cb66f7fd3e20e8881fc2a4406a9aaef7c3c723c) --- erpnext/crm/doctype/email_campaign/email_campaign.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/crm/doctype/email_campaign/email_campaign.py b/erpnext/crm/doctype/email_campaign/email_campaign.py index 17cf0e461d0..f8fce7ab697 100644 --- a/erpnext/crm/doctype/email_campaign/email_campaign.py +++ b/erpnext/crm/doctype/email_campaign/email_campaign.py @@ -121,7 +121,7 @@ def send_mail(entry, email_campaign): doctype="Email Campaign", name=email_campaign.name, subject=frappe.render_template(email_template.get("subject"), context), - content=frappe.render_template(email_template.get("response"), context), + content=frappe.render_template(email_template.response_, context), sender=sender, recipients=recipient_list, communication_medium="Email", From 48351d6da82916297149a620074e8cc981a43295 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Wed, 24 Apr 2024 14:41:10 +0530 Subject: [PATCH 11/34] fix: warehouse type filter for stock reports (cherry picked from commit 4250ac821fb068ffb0073cd3d71ad60f86a1d3ab) --- .../batch_wise_balance_history.js | 11 +++++++++- .../batch_wise_balance_history.py | 20 +++++++++++++++++++ .../stock/report/stock_ageing/stock_ageing.js | 11 +++++++++- .../stock/report/stock_ageing/stock_ageing.py | 9 +++++++++ 4 files changed, 49 insertions(+), 2 deletions(-) diff --git a/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.js b/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.js index 352fb19dd93..942b35e1afb 100644 --- a/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.js +++ b/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.js @@ -40,16 +40,25 @@ frappe.query_reports["Batch-Wise Balance History"] = { }; }, }, + { + fieldname: "warehouse_type", + label: __("Warehouse Type"), + fieldtype: "Link", + width: "80", + options: "Warehouse Type", + }, { fieldname: "warehouse", label: __("Warehouse"), fieldtype: "Link", options: "Warehouse", get_query: function () { + let warehouse_type = frappe.query_report.get_filter_value("warehouse_type"); let company = frappe.query_report.get_filter_value("company"); return { filters: { - company: company, + ...(warehouse_type && { warehouse_type }), + ...(company && { company }), }, }; }, diff --git a/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.py b/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.py index fe0cefda644..2cce803481c 100644 --- a/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.py +++ b/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.py @@ -121,6 +121,16 @@ def get_stock_ledger_entries_for_batch_no(filters): ) query = apply_warehouse_filter(query, sle, filters) + if filters.warehouse_type and not filters.warehouse: + warehouses = frappe.get_all( + "Warehouse", + filters={"warehouse_type": filters.warehouse_type, "is_group": 0}, + pluck="name", + ) + + if warehouses: + query = query.where(sle.warehouse.isin(warehouses)) + for field in ["item_code", "batch_no", "company"]: if filters.get(field): query = query.where(sle[field] == filters.get(field)) @@ -154,6 +164,16 @@ def get_stock_ledger_entries_for_batch_bundle(filters): ) query = apply_warehouse_filter(query, sle, filters) + if filters.warehouse_type and not filters.warehouse: + warehouses = frappe.get_all( + "Warehouse", + filters={"warehouse_type": filters.warehouse_type, "is_group": 0}, + pluck="name", + ) + + if warehouses: + query = query.where(sle.warehouse.isin(warehouses)) + for field in ["item_code", "batch_no", "company"]: if filters.get(field): if field == "batch_no": diff --git a/erpnext/stock/report/stock_ageing/stock_ageing.js b/erpnext/stock/report/stock_ageing/stock_ageing.js index 641084149ab..578869b6e93 100644 --- a/erpnext/stock/report/stock_ageing/stock_ageing.js +++ b/erpnext/stock/report/stock_ageing/stock_ageing.js @@ -18,15 +18,24 @@ frappe.query_reports["Stock Ageing"] = { default: frappe.datetime.get_today(), reqd: 1, }, + { + fieldname: "warehouse_type", + label: __("Warehouse Type"), + fieldtype: "Link", + width: "80", + options: "Warehouse Type", + }, { fieldname: "warehouse", label: __("Warehouse"), fieldtype: "Link", options: "Warehouse", get_query: () => { - const company = frappe.query_report.get_filter_value("company"); + let warehouse_type = frappe.query_report.get_filter_value("warehouse_type"); + let company = frappe.query_report.get_filter_value("company"); return { filters: { + ...(warehouse_type && { warehouse_type }), ...(company && { company }), }, }; diff --git a/erpnext/stock/report/stock_ageing/stock_ageing.py b/erpnext/stock/report/stock_ageing/stock_ageing.py index c4156e7e64e..8738b65f50d 100644 --- a/erpnext/stock/report/stock_ageing/stock_ageing.py +++ b/erpnext/stock/report/stock_ageing/stock_ageing.py @@ -434,6 +434,15 @@ class FIFOSlots: if self.filters.get("warehouse"): sle_query = self.__get_warehouse_conditions(sle, sle_query) + elif self.filters.get("warehouse_type"): + warehouses = frappe.get_all( + "Warehouse", + filters={"warehouse_type": self.filters.get("warehouse_type"), "is_group": 0}, + pluck="name", + ) + + if warehouses: + sle_query = sle_query.where(sle.warehouse.isin(warehouses)) sle_query = sle_query.orderby(sle.posting_date, sle.posting_time, sle.creation, sle.actual_qty) From 6fd356b6548fa5108f0d0236b1a7f38db364cc5b Mon Sep 17 00:00:00 2001 From: rohitwaghchaure Date: Fri, 26 Apr 2024 13:13:55 +0530 Subject: [PATCH 12/34] chore: fix conflicts --- erpnext/stock/doctype/delivery_note/delivery_note.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py index f8be3f1b54f..ec05738c68a 100644 --- a/erpnext/stock/doctype/delivery_note/delivery_note.py +++ b/erpnext/stock/doctype/delivery_note/delivery_note.py @@ -1066,8 +1066,7 @@ def make_sales_invoice(source_name, target_doc=None, args=None): @frappe.whitelist() -<<<<<<< HEAD -def make_delivery_trip(source_name, target_doc=None): +def make_delivery_trip(source_name, target_doc=None, kwargs=None): def update_stop_details(source_doc, target_doc, source_parent): target_doc.customer = source_parent.customer target_doc.address = source_parent.shipping_address_name @@ -1081,11 +1080,6 @@ def make_delivery_trip(source_name, target_doc=None): delivery_notes = [] -======= -def make_delivery_trip(source_name, target_doc=None, kwargs=None): - if not target_doc: - target_doc = frappe.new_doc("Delivery Trip") ->>>>>>> 2f359e201d (fix: args when get the delivery note in delivery trip) doclist = get_mapped_doc( "Delivery Note", source_name, From 4555f8a9a67f2f79c012e86e960dc2dc5df93906 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Wed, 24 Apr 2024 12:32:01 +0530 Subject: [PATCH 13/34] feat: allow to do reposting for all transactions (audit) (cherry picked from commit aefbe21b464d7895b412562fb04d91ae6feed373) # Conflicts: # erpnext/stock/doctype/stock_reposting_settings/stock_reposting_settings.json --- erpnext/controllers/stock_controller.py | 7 ++- erpnext/stock/doctype/bin/bin.py | 2 +- .../stock_reposting_settings.json | 11 +++++ .../stock_reposting_settings.py | 5 ++ .../test_stock_reposting_settings.py | 48 +++++++++++++++++++ 5 files changed, 71 insertions(+), 2 deletions(-) diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index 219a1d68c52..f4988895b37 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -1404,7 +1404,12 @@ def is_reposting_pending(): ) -def future_sle_exists(args, sl_entries=None): +def future_sle_exists(args, sl_entries=None, allow_force_reposting=True): + if allow_force_reposting and frappe.db.get_single_value( + "Stock Reposting Settings", "do_reposting_for_each_stock_transaction" + ): + return True + key = (args.voucher_type, args.voucher_no) if not hasattr(frappe.local, "future_sle"): frappe.local.future_sle = {} diff --git a/erpnext/stock/doctype/bin/bin.py b/erpnext/stock/doctype/bin/bin.py index e3a155bbad2..db5d1e58a84 100644 --- a/erpnext/stock/doctype/bin/bin.py +++ b/erpnext/stock/doctype/bin/bin.py @@ -238,7 +238,7 @@ def update_qty(bin_name, args): sle = frappe.qb.DocType("Stock Ledger Entry") # actual qty is not up to date in case of backdated transaction - if future_sle_exists(args): + if future_sle_exists(args, allow_force_reposting=False): last_sle_qty = ( frappe.qb.from_(sle) .select(sle.qty_after_transaction) diff --git a/erpnext/stock/doctype/stock_reposting_settings/stock_reposting_settings.json b/erpnext/stock/doctype/stock_reposting_settings/stock_reposting_settings.json index 68afd996b49..6da3b4d5c8e 100644 --- a/erpnext/stock/doctype/stock_reposting_settings/stock_reposting_settings.json +++ b/erpnext/stock/doctype/stock_reposting_settings/stock_reposting_settings.json @@ -13,6 +13,7 @@ "end_time", "limits_dont_apply_on", "item_based_reposting", + "do_reposting_for_each_stock_transaction", "errors_notification_section", "notify_reposting_error_to_role" ], @@ -65,12 +66,22 @@ "fieldname": "errors_notification_section", "fieldtype": "Section Break", "label": "Errors Notification" + }, + { + "default": "0", + "fieldname": "do_reposting_for_each_stock_transaction", + "fieldtype": "Check", + "label": "Do reposting for each Stock Transaction" } ], "index_web_pages_for_search": 1, "issingle": 1, "links": [], +<<<<<<< HEAD "modified": "2023-11-01 16:14:29.080697", +======= + "modified": "2024-04-24 12:19:40.204888", +>>>>>>> aefbe21b46 (feat: allow to do reposting for all transactions (audit)) "modified_by": "Administrator", "module": "Stock", "name": "Stock Reposting Settings", diff --git a/erpnext/stock/doctype/stock_reposting_settings/stock_reposting_settings.py b/erpnext/stock/doctype/stock_reposting_settings/stock_reposting_settings.py index 50f39817fff..eb3d38bfbfc 100644 --- a/erpnext/stock/doctype/stock_reposting_settings/stock_reposting_settings.py +++ b/erpnext/stock/doctype/stock_reposting_settings/stock_reposting_settings.py @@ -16,6 +16,7 @@ class StockRepostingSettings(Document): if TYPE_CHECKING: from frappe.types import DF + do_reposting_for_each_stock_transaction: DF.Check end_time: DF.Time | None item_based_reposting: DF.Check limit_reposting_timeslot: DF.Check @@ -29,6 +30,10 @@ class StockRepostingSettings(Document): def validate(self): self.set_minimum_reposting_time_slot() + def before_save(self): + if self.do_reposting_for_each_stock_transaction: + self.item_based_reposting = 1 + def set_minimum_reposting_time_slot(self): """Ensure that timeslot for reposting is at least 12 hours.""" if not self.limit_reposting_timeslot: diff --git a/erpnext/stock/doctype/stock_reposting_settings/test_stock_reposting_settings.py b/erpnext/stock/doctype/stock_reposting_settings/test_stock_reposting_settings.py index a6dc72d7a42..e53659c1735 100644 --- a/erpnext/stock/doctype/stock_reposting_settings/test_stock_reposting_settings.py +++ b/erpnext/stock/doctype/stock_reposting_settings/test_stock_reposting_settings.py @@ -38,3 +38,51 @@ class TestStockRepostingSettings(unittest.TestCase): users = get_recipients() self.assertTrue(user in users) + + def test_do_reposting_for_each_stock_transaction(self): + from erpnext.stock.doctype.item.test_item import make_item + from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry + + frappe.db.set_single_value("Stock Reposting Settings", "do_reposting_for_each_stock_transaction", 1) + if frappe.db.get_single_value("Stock Reposting Settings", "item_based_reposting"): + frappe.db.set_single_value("Stock Reposting Settings", "item_based_reposting", 0) + + item = make_item( + "_Test item for reposting check for each transaction", properties={"is_stock_item": 1} + ).name + + stock_entry = make_stock_entry( + item_code=item, + qty=1, + rate=100, + stock_entry_type="Material Receipt", + target="_Test Warehouse - _TC", + ) + + riv = frappe.get_all("Repost Item Valuation", filters={"voucher_no": stock_entry.name}, pluck="name") + self.assertTrue(riv) + + frappe.db.set_single_value("Stock Reposting Settings", "do_reposting_for_each_stock_transaction", 0) + + def test_do_not_reposting_for_each_stock_transaction(self): + from erpnext.stock.doctype.item.test_item import make_item + from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry + + frappe.db.set_single_value("Stock Reposting Settings", "do_reposting_for_each_stock_transaction", 0) + if frappe.db.get_single_value("Stock Reposting Settings", "item_based_reposting"): + frappe.db.set_single_value("Stock Reposting Settings", "item_based_reposting", 0) + + item = make_item( + "_Test item for do not reposting check for each transaction", properties={"is_stock_item": 1} + ).name + + stock_entry = make_stock_entry( + item_code=item, + qty=1, + rate=100, + stock_entry_type="Material Receipt", + target="_Test Warehouse - _TC", + ) + + riv = frappe.get_all("Repost Item Valuation", filters={"voucher_no": stock_entry.name}, pluck="name") + self.assertFalse(riv) From a292e52b34aa24ef0ad055d91bd720a410720c95 Mon Sep 17 00:00:00 2001 From: rohitwaghchaure Date: Fri, 26 Apr 2024 13:47:03 +0530 Subject: [PATCH 14/34] chore: fix conflicts --- .../stock_reposting_settings/stock_reposting_settings.json | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/erpnext/stock/doctype/stock_reposting_settings/stock_reposting_settings.json b/erpnext/stock/doctype/stock_reposting_settings/stock_reposting_settings.json index 6da3b4d5c8e..cbbb0ce0990 100644 --- a/erpnext/stock/doctype/stock_reposting_settings/stock_reposting_settings.json +++ b/erpnext/stock/doctype/stock_reposting_settings/stock_reposting_settings.json @@ -77,11 +77,7 @@ "index_web_pages_for_search": 1, "issingle": 1, "links": [], -<<<<<<< HEAD - "modified": "2023-11-01 16:14:29.080697", -======= "modified": "2024-04-24 12:19:40.204888", ->>>>>>> aefbe21b46 (feat: allow to do reposting for all transactions (audit)) "modified_by": "Administrator", "module": "Stock", "name": "Stock Reposting Settings", @@ -102,4 +98,4 @@ "sort_order": "DESC", "states": [], "track_changes": 1 -} \ No newline at end of file +} From f65b28a18979a41dbfd053237bc144af4104fc66 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Fri, 26 Apr 2024 13:59:22 +0530 Subject: [PATCH 15/34] fix: handle and receivable accounts based on response type (cherry picked from commit 066859cca0a91ce350a7c69efd2dda04716a7277) --- .../payment_reconciliation/payment_reconciliation.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js index cc99fe7b583..c5b815b5e61 100644 --- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js +++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js @@ -176,8 +176,12 @@ erpnext.accounts.PaymentReconciliationController = class PaymentReconciliationCo }, callback: (r) => { if (!r.exc && r.message) { - this.frm.set_value("receivable_payable_account", r.message[0]); - this.frm.set_value("default_advance_account", r.message[1]); + if (typeof r.message === "string") { + this.frm.set_value("receivable_payable_account", r.message); + } else if (Array.isArray(r.message)) { + this.frm.set_value("receivable_payable_account", r.message[0]); + this.frm.set_value("default_advance_account", r.message[1]); + } } this.frm.refresh(); }, From 0a65a37eed00341d9b9d117b3ebe1a86a7e1f0fc Mon Sep 17 00:00:00 2001 From: Dany Robert Date: Thu, 4 Apr 2024 16:18:20 +0000 Subject: [PATCH 16/34] fix: missing def expense if no exp in first month (cherry picked from commit 5c9ce575f65eb0d0282f38e23e7c5eebd628518b) --- erpnext/accounts/deferred_revenue.py | 74 ++++++++++++++-------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/erpnext/accounts/deferred_revenue.py b/erpnext/accounts/deferred_revenue.py index 9ffdf186f02..a48ce9b4c63 100644 --- a/erpnext/accounts/deferred_revenue.py +++ b/erpnext/accounts/deferred_revenue.py @@ -360,45 +360,45 @@ def book_deferred_income_or_expense(doc, deferred_process, posting_date=None): ) if not amount: - return - - gl_posting_date = end_date - prev_posting_date = None - # check if books nor frozen till endate: - if accounts_frozen_upto and getdate(end_date) <= getdate(accounts_frozen_upto): - gl_posting_date = get_last_day(add_days(accounts_frozen_upto, 1)) prev_posting_date = end_date - - if via_journal_entry: - book_revenue_via_journal_entry( - doc, - credit_account, - debit_account, - amount, - base_amount, - gl_posting_date, - project, - account_currency, - item.cost_center, - item, - deferred_process, - submit_journal_entry, - ) else: - make_gl_entries( - doc, - credit_account, - debit_account, - against, - amount, - base_amount, - gl_posting_date, - project, - account_currency, - item.cost_center, - item, - deferred_process, - ) + gl_posting_date = end_date + prev_posting_date = None + # check if books nor frozen till endate: + if accounts_frozen_upto and getdate(end_date) <= getdate(accounts_frozen_upto): + gl_posting_date = get_last_day(add_days(accounts_frozen_upto, 1)) + prev_posting_date = end_date + + if via_journal_entry: + book_revenue_via_journal_entry( + doc, + credit_account, + debit_account, + amount, + base_amount, + gl_posting_date, + project, + account_currency, + item.cost_center, + item, + deferred_process, + submit_journal_entry, + ) + else: + make_gl_entries( + doc, + credit_account, + debit_account, + against, + amount, + base_amount, + gl_posting_date, + project, + account_currency, + item.cost_center, + item, + deferred_process, + ) # Returned in case of any errors because it tries to submit the same record again and again in case of errors if frappe.flags.deferred_accounting_error: From 23c3c3cc0c0eb60077a4787f5767a901ed79c0ab Mon Sep 17 00:00:00 2001 From: Dany Robert Date: Fri, 5 Apr 2024 17:59:48 +0000 Subject: [PATCH 17/34] fix: test case for zero deferred expense (cherry picked from commit 7ef4dbcaf66e213bfd06c9e75cf7c0828f89dd63) --- .../test_deferred_revenue_and_expense.py | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/erpnext/accounts/report/deferred_revenue_and_expense/test_deferred_revenue_and_expense.py b/erpnext/accounts/report/deferred_revenue_and_expense/test_deferred_revenue_and_expense.py index f8a965b699c..983eb0ee6af 100644 --- a/erpnext/accounts/report/deferred_revenue_and_expense/test_deferred_revenue_and_expense.py +++ b/erpnext/accounts/report/deferred_revenue_and_expense/test_deferred_revenue_and_expense.py @@ -279,3 +279,78 @@ class TestDeferredRevenueAndExpense(FrappeTestCase, AccountsTestMixin): {"key": "aug_2021", "total": 0, "actual": 0}, ] self.assertEqual(report.period_total, expected) + + @change_settings("Accounts Settings", {"book_deferred_entries_based_on": "Months"}) + def test_zero_amount(self): + self.create_item("_Test Office Desk", 0, self.warehouse, self.company) + item = frappe.get_doc("Item", self.item) + item.enable_deferred_expense = 1 + item.item_defaults[0].deferred_expense_account = self.deferred_expense_account + item.no_of_months_exp = 12 + item.save() + + pi = make_purchase_invoice( + item=self.item, + company=self.company, + supplier=self.supplier, + is_return=False, + update_stock=False, + posting_date=frappe.utils.datetime.date(2023, 12, 30), + parent_cost_center=self.cost_center, + cost_center=self.cost_center, + do_not_save=True, + rate=3910, + price_list_rate=3910, + warehouse=self.warehouse, + qty=1, + ) + pi.set_posting_time = True + pi.items[0].enable_deferred_expense = 1 + pi.items[0].service_start_date = "2023-12-30" + pi.items[0].service_end_date = "2024-12-30" + pi.items[0].deferred_expense_account = self.deferred_expense_account + pi.items[0].expense_account = self.expense_account + pi.save() + pi.submit() + + pda = frappe.get_doc( + dict( + doctype="Process Deferred Accounting", + posting_date=nowdate(), + start_date="2024-01-01", + end_date="2024-01-31", + type="Expense", + company=self.company, + ) + ) + pda.insert() + pda.submit() + + # execute report + fiscal_year = frappe.get_doc("Fiscal Year", get_fiscal_year(date="2024-01-31")) + self.filters = frappe._dict( + { + "company": self.company, + "filter_based_on": "Date Range", + "period_start_date": "2024-01-01", + "period_end_date": "2024-01-31", + "from_fiscal_year": fiscal_year.year, + "to_fiscal_year": fiscal_year.year, + "periodicity": "Monthly", + "type": "Expense", + "with_upcoming_postings": False, + } + ) + + report = Deferred_Revenue_and_Expense_Report(filters=self.filters) + report.run() + + # fetch the invoice from deferred invoices list + inv = [d for d in report.deferred_invoices if d.name == pi.name] + # make sure the list isn't empty + self.assertTrue(inv) + # calculate the total deferred expense for the period + inv = inv[0].calculate_invoice_revenue_expense_for_period() + deferred_exp = sum([inv[idx].actual for idx in range(len(report.period_total))]) + # make sure the total deferred expense is greater than 0 + self.assertGreater(deferred_exp, 0) From 62966ac55099dea85cf3b08548a7df5258c5385c Mon Sep 17 00:00:00 2001 From: Dany Robert Date: Fri, 5 Apr 2024 18:16:26 +0000 Subject: [PATCH 18/34] chore: semgrep (cherry picked from commit 581af4ecedc3a8e134a8a1d545a789329d26fccc) --- .../test_deferred_revenue_and_expense.py | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/erpnext/accounts/report/deferred_revenue_and_expense/test_deferred_revenue_and_expense.py b/erpnext/accounts/report/deferred_revenue_and_expense/test_deferred_revenue_and_expense.py index 983eb0ee6af..5b848ac2955 100644 --- a/erpnext/accounts/report/deferred_revenue_and_expense/test_deferred_revenue_and_expense.py +++ b/erpnext/accounts/report/deferred_revenue_and_expense/test_deferred_revenue_and_expense.py @@ -314,14 +314,12 @@ class TestDeferredRevenueAndExpense(FrappeTestCase, AccountsTestMixin): pi.submit() pda = frappe.get_doc( - dict( - doctype="Process Deferred Accounting", - posting_date=nowdate(), - start_date="2024-01-01", - end_date="2024-01-31", - type="Expense", - company=self.company, - ) + doctype="Process Deferred Accounting", + posting_date=nowdate(), + start_date="2024-01-01", + end_date="2024-01-31", + type="Expense", + company=self.company, ) pda.insert() pda.submit() @@ -351,6 +349,6 @@ class TestDeferredRevenueAndExpense(FrappeTestCase, AccountsTestMixin): self.assertTrue(inv) # calculate the total deferred expense for the period inv = inv[0].calculate_invoice_revenue_expense_for_period() - deferred_exp = sum([inv[idx].actual for idx in range(len(report.period_total))]) + deferred_exp = sum([inv[idx].actual for idx in range(len(report.period_list))]) # make sure the total deferred expense is greater than 0 - self.assertGreater(deferred_exp, 0) + self.assertLess(deferred_exp, 0) From acfee4273533d6e095098b7fd22087f5e9f8331d Mon Sep 17 00:00:00 2001 From: Dany Robert Date: Sat, 6 Apr 2024 06:13:42 +0000 Subject: [PATCH 19/34] fix: expense causing p&l test case to fail (cherry picked from commit 01888c98bc8a9aaca42840381ce26bab7351510a) --- .../test_deferred_revenue_and_expense.py | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/erpnext/accounts/report/deferred_revenue_and_expense/test_deferred_revenue_and_expense.py b/erpnext/accounts/report/deferred_revenue_and_expense/test_deferred_revenue_and_expense.py index 5b848ac2955..4ca65dc04e5 100644 --- a/erpnext/accounts/report/deferred_revenue_and_expense/test_deferred_revenue_and_expense.py +++ b/erpnext/accounts/report/deferred_revenue_and_expense/test_deferred_revenue_and_expense.py @@ -280,7 +280,10 @@ class TestDeferredRevenueAndExpense(FrappeTestCase, AccountsTestMixin): ] self.assertEqual(report.period_total, expected) - @change_settings("Accounts Settings", {"book_deferred_entries_based_on": "Months"}) + @change_settings( + "Accounts Settings", + {"book_deferred_entries_based_on": "Months", "book_deferred_entries_via_journal_entry": 0}, + ) def test_zero_amount(self): self.create_item("_Test Office Desk", 0, self.warehouse, self.company) item = frappe.get_doc("Item", self.item) @@ -295,7 +298,7 @@ class TestDeferredRevenueAndExpense(FrappeTestCase, AccountsTestMixin): supplier=self.supplier, is_return=False, update_stock=False, - posting_date=frappe.utils.datetime.date(2023, 12, 30), + posting_date=frappe.utils.datetime.date(2021, 12, 30), parent_cost_center=self.cost_center, cost_center=self.cost_center, do_not_save=True, @@ -306,8 +309,8 @@ class TestDeferredRevenueAndExpense(FrappeTestCase, AccountsTestMixin): ) pi.set_posting_time = True pi.items[0].enable_deferred_expense = 1 - pi.items[0].service_start_date = "2023-12-30" - pi.items[0].service_end_date = "2024-12-30" + pi.items[0].service_start_date = "2021-12-30" + pi.items[0].service_end_date = "2022-12-30" pi.items[0].deferred_expense_account = self.deferred_expense_account pi.items[0].expense_account = self.expense_account pi.save() @@ -316,8 +319,8 @@ class TestDeferredRevenueAndExpense(FrappeTestCase, AccountsTestMixin): pda = frappe.get_doc( doctype="Process Deferred Accounting", posting_date=nowdate(), - start_date="2024-01-01", - end_date="2024-01-31", + start_date="2022-01-01", + end_date="2022-01-31", type="Expense", company=self.company, ) @@ -325,13 +328,13 @@ class TestDeferredRevenueAndExpense(FrappeTestCase, AccountsTestMixin): pda.submit() # execute report - fiscal_year = frappe.get_doc("Fiscal Year", get_fiscal_year(date="2024-01-31")) + fiscal_year = frappe.get_doc("Fiscal Year", get_fiscal_year(date="2022-01-31")) self.filters = frappe._dict( { "company": self.company, "filter_based_on": "Date Range", - "period_start_date": "2024-01-01", - "period_end_date": "2024-01-31", + "period_start_date": "2022-01-01", + "period_end_date": "2022-01-31", "from_fiscal_year": fiscal_year.year, "to_fiscal_year": fiscal_year.year, "periodicity": "Monthly", From 067419b7cdbe43d4845e1a98c0889ba3c8de6ce2 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Mon, 29 Apr 2024 10:31:22 +0530 Subject: [PATCH 20/34] chore: delete invalid translations (#41227) --- erpnext/translations/en.csv | 1 - 1 file changed, 1 deletion(-) delete mode 100644 erpnext/translations/en.csv diff --git a/erpnext/translations/en.csv b/erpnext/translations/en.csv deleted file mode 100644 index 7fac9e1785b..00000000000 --- a/erpnext/translations/en.csv +++ /dev/null @@ -1 +0,0 @@ -Married,既婚, From ee9822fd420a20fc7d0d75304b21ff26a31ccf74 Mon Sep 17 00:00:00 2001 From: Nikhil Kothari Date: Mon, 29 Apr 2024 17:31:39 +0530 Subject: [PATCH 21/34] fix: party and party type label on accounting preview (cherry picked from commit f7f3b2278610d94ec7823f5ea722a8fecb94656f) --- erpnext/controllers/stock_controller.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index f4988895b37..49252bd5b54 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -1227,8 +1227,8 @@ def get_accounting_ledger_preview(doc, filters): "debit", "credit", "against", - "party", "party_type", + "party", "cost_center", "against_voucher_type", "against_voucher", From 08f888a326d4d787bb5a878843a8215d914cace2 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Fri, 26 Apr 2024 10:50:51 +0530 Subject: [PATCH 22/34] fix: incorrectly applying TDS when Advance is in previous FY (cherry picked from commit b195f519e2266a63d4a38ec7c39c5d23392dad36) --- .../tax_withholding_category.py | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py index 2a2428a6c1b..a9a4090a02c 100644 --- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py +++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py @@ -282,6 +282,14 @@ def get_tax_amount(party_type, parties, inv, tax_details, posting_date, pan_no=N if taxable_vouchers: tax_deducted = get_deducted_tax(taxable_vouchers, tax_details) + # If advance is outside the current tax withholding period (usually a fiscal year), `get_deducted_tax` won't fetch it. + # updating `tax_deducted` with correct advance tax value (from current and previous previous withholding periods), will allow the + # rest of the below logic to function properly + # ---FY 2023-------------||---------------------FY 2024-----------------------||-- + # ---Advance-------------||---------Inv_1--------Inv_2------------------------||-- + if tax_deducted_on_advances: + tax_deducted += get_advance_tax_across_fiscal_year(tax_deducted_on_advances, tax_details) + tax_amount = 0 if party_type == "Supplier": @@ -418,7 +426,7 @@ def get_taxes_deducted_on_advances_allocated(inv, tax_details): frappe.qb.from_(at) .inner_join(pe) .on(pe.name == at.parent) - .select(at.parent, at.name, at.tax_amount, at.allocated_amount) + .select(pe.posting_date, at.parent, at.name, at.tax_amount, at.allocated_amount) .where(pe.tax_withholding_category == tax_details.get("tax_withholding_category")) .where(at.parent.isin(advances)) .where(at.account_head == tax_details.account_head) @@ -443,6 +451,16 @@ def get_deducted_tax(taxable_vouchers, tax_details): return sum(entries) +def get_advance_tax_across_fiscal_year(tax_deducted_on_advances, tax_details): + """ + Only applies for Taxes deducted on Advance Payments + """ + advance_tax_from_across_fiscal_year = sum( + [adv.tax_amount for adv in tax_deducted_on_advances if adv.posting_date < tax_details.from_date] + ) + return advance_tax_from_across_fiscal_year + + def get_tds_amount(ldc, parties, inv, tax_details, vouchers): tds_amount = 0 invoice_filters = {"name": ("in", vouchers), "docstatus": 1, "apply_tds": 1} From 15ac3d8b0ba2f1e123bfae671b21ac3294411dd4 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Mon, 29 Apr 2024 10:25:07 +0530 Subject: [PATCH 23/34] test: TDS deduction across fiscal year (cherry picked from commit 2f9a144023433e8b2a0d5f4be4c98c97ab6e2cab) --- .../test_tax_withholding_category.py | 139 +++++++++++++++++- 1 file changed, 134 insertions(+), 5 deletions(-) diff --git a/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py index 087e0d0ff6f..1e3939d98a4 100644 --- a/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py +++ b/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py @@ -1,18 +1,22 @@ # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt +import datetime import unittest import frappe from frappe.custom.doctype.custom_field.custom_field import create_custom_fields -from frappe.utils import today +from frappe.tests.utils import FrappeTestCase, change_settings +from frappe.utils import add_days, today +from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry from erpnext.accounts.utils import get_fiscal_year +from erpnext.buying.doctype.purchase_order.purchase_order import make_purchase_invoice test_dependencies = ["Supplier Group", "Customer Group"] -class TestTaxWithholdingCategory(unittest.TestCase): +class TestTaxWithholdingCategory(FrappeTestCase): @classmethod def setUpClass(self): # create relevant supplier, etc @@ -21,7 +25,7 @@ class TestTaxWithholdingCategory(unittest.TestCase): make_pan_no_field() def tearDown(self): - cancel_invoices() + frappe.db.rollback() def test_cumulative_threshold_tds(self): frappe.db.set_value( @@ -317,8 +321,6 @@ class TestTaxWithholdingCategory(unittest.TestCase): d.cancel() def test_tds_deduction_for_po_via_payment_entry(self): - from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry - frappe.db.set_value( "Supplier", "Test TDS Supplier8", "tax_withholding_category", "Cumulative Threshold TDS" ) @@ -485,6 +487,133 @@ class TestTaxWithholdingCategory(unittest.TestCase): pi2.cancel() pi3.cancel() + def set_previous_fy_and_tax_category(self): + test_company = "_Test Company" + category = "Cumulative Threshold TDS" + + def add_company_to_fy(fy, company): + if not [x.company for x in fy.companies if x.company == company]: + fy.append("companies", {"company": company}) + fy.save() + + # setup previous fiscal year + fiscal_year = get_fiscal_year(today(), company=test_company) + if prev_fiscal_year := get_fiscal_year(add_days(fiscal_year[1], -10)): + self.prev_fy = frappe.get_doc("Fiscal Year", prev_fiscal_year[0]) + add_company_to_fy(self.prev_fy, test_company) + else: + # make previous fiscal year + start = datetime.date(fiscal_year[1].year - 1, fiscal_year[1].month, fiscal_year[1].day) + end = datetime.date(fiscal_year[2].year - 1, fiscal_year[2].month, fiscal_year[2].day) + self.prev_fy = frappe.get_doc( + { + "doctype": "Fiscal Year", + "year_start_date": start, + "year_end_date": end, + "companies": [{"company": test_company}], + } + ) + self.prev_fy.save() + + # setup tax withholding category for previous fiscal year + cat = frappe.get_doc("Tax Withholding Category", category) + cat.append( + "rates", + { + "from_date": self.prev_fy.year_start_date, + "to_date": self.prev_fy.year_end_date, + "tax_withholding_rate": 10, + "single_threshold": 0, + "cumulative_threshold": 30000, + }, + ) + cat.save() + + def test_tds_across_fiscal_year(self): + """ + Advance TDS on previous fiscal year should be properly allocated on Invoices in upcoming fiscal year + --||-----FY 2023-----||-----FY 2024-----||-- + --||-----Advance-----||---Inv1---Inv2---||-- + """ + self.set_previous_fy_and_tax_category() + supplier = "Test TDS Supplier" + # Cumulative threshold 30000 and tax rate 10% + category = "Cumulative Threshold TDS" + frappe.db.set_value( + "Supplier", + supplier, + { + "tax_withholding_category": category, + "pan": "ABCTY1234D", + }, + ) + po_and_advance_posting_date = add_days(self.prev_fy.year_end_date, -10) + po = create_purchase_order(supplier=supplier, qty=10, rate=10000) + po.transaction_date = po_and_advance_posting_date + po.taxes = [] + po.apply_tds = False + po.tax_withholding_category = None + po.save().submit() + + # Partial advance + payment = get_payment_entry(po.doctype, po.name) + payment.posting_date = po_and_advance_posting_date + payment.paid_amount = 60000 + payment.apply_tax_withholding_amount = 1 + payment.tax_withholding_category = category + payment.references = [] + payment.taxes = [] + payment.save().submit() + + self.assertEqual(len(payment.taxes), 1) + self.assertEqual(payment.taxes[0].tax_amount, 6000) + + # Multiple partial invoices + payment.reload() + pi1 = make_purchase_invoice(source_name=po.name) + pi1.apply_tds = True + pi1.tax_withholding_category = category + pi1.items[0].qty = 3 + pi1.items[0].rate = 10000 + advances = pi1.get_advance_entries() + pi1.append( + "advances", + { + "reference_type": advances[0].reference_type, + "reference_name": advances[0].reference_name, + "advance_amount": advances[0].amount, + "allocated_amount": 30000, + }, + ) + pi1.save().submit() + pi1.reload() + payment.reload() + self.assertEqual(pi1.taxes, []) + self.assertEqual(payment.taxes[0].tax_amount, 6000) + self.assertEqual(payment.taxes[0].allocated_amount, 3000) + + pi2 = make_purchase_invoice(source_name=po.name) + pi2.apply_tds = True + pi2.tax_withholding_category = category + pi2.items[0].qty = 3 + pi2.items[0].rate = 10000 + advances = pi2.get_advance_entries() + pi2.append( + "advances", + { + "reference_type": advances[0].reference_type, + "reference_name": advances[0].reference_name, + "advance_amount": advances[0].amount, + "allocated_amount": 30000, + }, + ) + pi2.save().submit() + pi2.reload() + payment.reload() + self.assertEqual(pi2.taxes, []) + self.assertEqual(payment.taxes[0].tax_amount, 6000) + self.assertEqual(payment.taxes[0].allocated_amount, 6000) + def cancel_invoices(): purchase_invoices = frappe.get_all( From a7d1a8851928c17f69df24928c610841ce924ac5 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Mon, 29 Apr 2024 19:31:21 +0530 Subject: [PATCH 24/34] fix: display term name for single term invoices (cherry picked from commit 5fa4cfee041b333bf112f9a435d9f3298399f693) --- .../report/accounts_receivable/accounts_receivable.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py index af1e1c79eb2..2bd493cd4d0 100644 --- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py +++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py @@ -501,8 +501,9 @@ class ReceivablePayableReport: # Deduct that from paid amount pre allocation row.paid -= flt(payment_terms_details[0].total_advance) - # If no or single payment terms, no need to split the row - if len(payment_terms_details) <= 1: + # If single payment terms, no need to split the row + if len(payment_terms_details) == 1 and payment_terms_details[0].payment_term: + self.append_payment_term(row, payment_terms_details[0], original_row) return for d in payment_terms_details: From 737c4809e3e768a935e914d669c9bacc0094ef79 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Sun, 28 Apr 2024 14:41:34 +0530 Subject: [PATCH 25/34] fix: Ignore user perm in Bank Reco Tool for company (cherry picked from commit 9f346e7ba00707bc1b3cb324a2dcbd1e2e25397b) # Conflicts: # erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.json --- .../bank_reconciliation_tool/bank_reconciliation_tool.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.json b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.json index 93fc4439d35..23d2fc8d413 100644 --- a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.json +++ b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.json @@ -26,6 +26,7 @@ { "fieldname": "company", "fieldtype": "Link", + "ignore_user_permissions": 1, "label": "Company", "options": "Company" }, @@ -118,7 +119,11 @@ "index_web_pages_for_search": 1, "issingle": 1, "links": [], +<<<<<<< HEAD "modified": "2023-03-07 11:02:24.535714", +======= + "modified": "2024-04-28 14:40:50.910884", +>>>>>>> 9f346e7ba0 (fix: Ignore user perm in Bank Reco Tool for company) "modified_by": "Administrator", "module": "Accounts", "name": "Bank Reconciliation Tool", From 03b4a8582521c9aac7a4f791a0d9c97093ea0848 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Tue, 30 Apr 2024 10:25:51 +0530 Subject: [PATCH 26/34] chore: resolve conflicts --- .../bank_reconciliation_tool/bank_reconciliation_tool.json | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.json b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.json index 23d2fc8d413..2969161949f 100644 --- a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.json +++ b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.json @@ -119,11 +119,7 @@ "index_web_pages_for_search": 1, "issingle": 1, "links": [], -<<<<<<< HEAD - "modified": "2023-03-07 11:02:24.535714", -======= "modified": "2024-04-28 14:40:50.910884", ->>>>>>> 9f346e7ba0 (fix: Ignore user perm in Bank Reco Tool for company) "modified_by": "Administrator", "module": "Accounts", "name": "Bank Reconciliation Tool", @@ -144,4 +140,4 @@ "sort_field": "modified", "sort_order": "DESC", "states": [] -} \ No newline at end of file +} From 759c7f5490d179bb94369a7168be2cf19e5a0c73 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Wed, 24 Apr 2024 21:49:07 +0530 Subject: [PATCH 27/34] fix: paid amount in bank reconciliation tool (cherry picked from commit a48966f08cc8262b9ae5866e7f6f641c99d4fc52) --- .../bank_reconciliation_tool/bank_reconciliation_tool.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py index 77cb3201dbc..05787665a76 100644 --- a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py +++ b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py @@ -719,7 +719,7 @@ def get_pe_matching_query( (ref_rank + amount_rank + party_rank + 1).as_("rank"), ConstantColumn("Payment Entry").as_("doctype"), pe.name, - pe.paid_amount, + pe.paid_amount_after_tax.as_("paid_amount"), pe.reference_no, pe.reference_date, pe.party, From 44c3ad6810df2c9a2205f8e6f1f3bd372782dfbc Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Wed, 24 Apr 2024 19:40:05 +0530 Subject: [PATCH 28/34] fix: Invoice with no GLEs in deferred report (cherry picked from commit 1c613ada6fafa2566b8750c1ed9fc11608b493c9) --- .../deferred_revenue_and_expense.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/erpnext/accounts/report/deferred_revenue_and_expense/deferred_revenue_and_expense.py b/erpnext/accounts/report/deferred_revenue_and_expense/deferred_revenue_and_expense.py index 8999ef710f0..96eb739d247 100644 --- a/erpnext/accounts/report/deferred_revenue_and_expense/deferred_revenue_and_expense.py +++ b/erpnext/accounts/report/deferred_revenue_and_expense/deferred_revenue_and_expense.py @@ -58,9 +58,9 @@ class Deferred_Item: For a given GL/Journal posting, get balance based on item type """ if self.type == "Deferred Sale Item": - return entry.debit - entry.credit + return flt(entry.debit) - flt(entry.credit) elif self.type == "Deferred Purchase Item": - return -(entry.credit - entry.debit) + return -(flt(entry.credit) - flt(entry.debit)) return 0 def get_item_total(self): @@ -147,7 +147,7 @@ class Deferred_Item: actual = 0 for posting in self.gle_entries: # if period.from_date <= posting.posting_date <= period.to_date: - if period.from_date <= posting.gle_posting_date <= period.to_date: + if period.from_date <= getdate(posting.gle_posting_date) <= period.to_date: period_sum += self.get_amount(posting) if posting.posted == "posted": actual += self.get_amount(posting) @@ -285,7 +285,7 @@ class Deferred_Revenue_and_Expense_Report: qb.from_(inv_item) .join(inv) .on(inv.name == inv_item.parent) - .join(gle) + .left_join(gle) .on((inv_item.name == gle.voucher_detail_no) & (deferred_account_field == gle.account)) .select( inv.name.as_("doc"), @@ -318,7 +318,7 @@ class Deferred_Revenue_and_Expense_Report: .groupby(inv.name, inv_item.name, gle.posting_date) .orderby(gle.posting_date) ) - self.invoices = query.run(as_dict=True) + self.invoices = query.run(as_dict=True, debug=1) uniq_invoice = set([x.doc for x in self.invoices]) for inv in uniq_invoice: From b67e9e4aa8138569974ad14eaf5bbc6b501bee40 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Wed, 24 Apr 2024 19:44:47 +0530 Subject: [PATCH 29/34] chore: remove debug flag (cherry picked from commit ecf07bd128415bfb52682324c34a663ef7544013) --- .../deferred_revenue_and_expense.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/report/deferred_revenue_and_expense/deferred_revenue_and_expense.py b/erpnext/accounts/report/deferred_revenue_and_expense/deferred_revenue_and_expense.py index 96eb739d247..c6d9eac5966 100644 --- a/erpnext/accounts/report/deferred_revenue_and_expense/deferred_revenue_and_expense.py +++ b/erpnext/accounts/report/deferred_revenue_and_expense/deferred_revenue_and_expense.py @@ -318,7 +318,7 @@ class Deferred_Revenue_and_Expense_Report: .groupby(inv.name, inv_item.name, gle.posting_date) .orderby(gle.posting_date) ) - self.invoices = query.run(as_dict=True, debug=1) + self.invoices = query.run(as_dict=True) uniq_invoice = set([x.doc for x in self.invoices]) for inv in uniq_invoice: From 8d70a0e0bc0776005cfe4b9083202dea3ffd8d5d Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Tue, 30 Apr 2024 12:19:18 +0530 Subject: [PATCH 30/34] fix: permission issue when user permission restricts on company --- .../tax_withholding_account/tax_withholding_account.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/erpnext/accounts/doctype/tax_withholding_account/tax_withholding_account.json b/erpnext/accounts/doctype/tax_withholding_account/tax_withholding_account.json index 06d6b088e5b..8603584b7a8 100644 --- a/erpnext/accounts/doctype/tax_withholding_account/tax_withholding_account.json +++ b/erpnext/accounts/doctype/tax_withholding_account/tax_withholding_account.json @@ -21,7 +21,7 @@ "fieldname": "company", "fieldtype": "Link", "hidden": 0, - "ignore_user_permissions": 0, + "ignore_user_permissions": 1, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, @@ -53,7 +53,7 @@ "fieldname": "account", "fieldtype": "Link", "hidden": 0, - "ignore_user_permissions": 0, + "ignore_user_permissions": 1, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, @@ -87,7 +87,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2018-04-13 18:44:25.055382", + "modified": "2024-04-30 10:26:48.21829", "modified_by": "Administrator", "module": "Accounts", "name": "Tax Withholding Account", From ea596eb4a2ab28a66ab6466dcf152a4c31b4ab18 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Tue, 30 Apr 2024 17:06:48 +0530 Subject: [PATCH 31/34] fix: validation to prevent overallocation (cherry picked from commit bf755fab550134fccc344dd220143bf0a4fb4a8c) --- erpnext/accounts/utils.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py index 04ea2cb8530..30c34a05329 100644 --- a/erpnext/accounts/utils.py +++ b/erpnext/accounts/utils.py @@ -516,6 +516,10 @@ def reconcile_against_document( doc.make_advance_gl_entries() else: gl_map = doc.build_gl_map() + # Make sure there is no overallocation + from erpnext.accounts.general_ledger import process_debit_credit_difference + + process_debit_credit_difference(gl_map) create_payment_ledger_entry(gl_map, update_outstanding="No", cancel=0, adv_adj=1) # Only update outstanding for newly linked vouchers From c3077ee067c09b14462a4b599b7de6ad9ed64e59 Mon Sep 17 00:00:00 2001 From: Fritz Date: Tue, 30 Apr 2024 14:27:58 +0200 Subject: [PATCH 32/34] fix: compute tree-view parent field name (#41234) fix: Fixing treeView lookup incompatibility, see : See https://github.com/frappe/frappe/pull/26199 --- erpnext/accounts/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py index 04ea2cb8530..b3bfabe4187 100644 --- a/erpnext/accounts/utils.py +++ b/erpnext/accounts/utils.py @@ -1094,7 +1094,7 @@ def get_companies(): def get_children(doctype, parent, company, is_root=False): from erpnext.accounts.report.financial_statements import sort_accounts - parent_fieldname = "parent_" + doctype.lower().replace(" ", "_") + parent_fieldname = "parent_" + frappe.scrub(doctype) fields = ["name as value", "is_group as expandable"] filters = [["docstatus", "<", 2]] From de77894e59f963b2edb4676d0b7b7cd90028917c Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Wed, 1 May 2024 15:46:52 +0530 Subject: [PATCH 33/34] fix: multiple pricing rules with discount amount and discount percentage not working (backport #41211) (backport #41241) (#41275) fix: multiple pricing rules with discount amount and discount percentage not working (backport #41211) (#41241) fix: multiple pricing rules with discount amount and discount percentage not working (#41211) (cherry picked from commit 54313b5db902c108458392b6d389d16e9213b55a) Co-authored-by: rohitwaghchaure (cherry picked from commit da3010a41f897eb9e818c56a755d3ad329f15941) Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> --- .../doctype/pricing_rule/pricing_rule.py | 16 ++++++ .../doctype/pricing_rule/test_pricing_rule.py | 53 +++++++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py index 1848bafe800..ee9a2137d55 100644 --- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py +++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py @@ -573,6 +573,22 @@ def apply_price_discount_rule(pricing_rule, item_details, args): if pricing_rule.apply_discount_on_rate and item_details.get("discount_percentage"): # Apply discount on discounted rate item_details[field] += (100 - item_details[field]) * (pricing_rule.get(field, 0) / 100) + elif args.price_list_rate: + value = pricing_rule.get(field, 0) + calculate_discount_percentage = False + if field == "discount_percentage": + field = "discount_amount" + value = args.price_list_rate * (value / 100) + calculate_discount_percentage = True + + if field not in item_details: + item_details.setdefault(field, 0) + + item_details[field] += value if pricing_rule else args.get(field, 0) + if calculate_discount_percentage and args.price_list_rate and item_details.discount_amount: + item_details.discount_percentage = flt( + (flt(item_details.discount_amount) / flt(args.price_list_rate)) * 100 + ) else: if field not in item_details: item_details.setdefault(field, 0) diff --git a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py index 046a5995d9a..676ed4c2ad5 100644 --- a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py +++ b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py @@ -1104,6 +1104,59 @@ class TestPricingRule(unittest.TestCase): self.assertEqual(so.items[1].item_code, "_Test Item") self.assertEqual(so.items[1].qty, 4) + def test_apply_multiple_pricing_rules_for_discount_percentage_and_amount(self): + frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule 1") + frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule 2") + test_record = { + "doctype": "Pricing Rule", + "title": "_Test Pricing Rule 1", + "name": "_Test Pricing Rule 1", + "apply_on": "Item Code", + "currency": "USD", + "items": [ + { + "item_code": "_Test Item", + } + ], + "selling": 1, + "price_or_product_discount": "Price", + "rate_or_discount": "Discount Percentage", + "discount_percentage": 10, + "apply_multiple_pricing_rules": 1, + "company": "_Test Company", + } + + frappe.get_doc(test_record.copy()).insert() + + test_record = { + "doctype": "Pricing Rule", + "title": "_Test Pricing Rule 2", + "name": "_Test Pricing Rule 2", + "apply_on": "Item Code", + "currency": "USD", + "items": [ + { + "item_code": "_Test Item", + } + ], + "selling": 1, + "price_or_product_discount": "Price", + "rate_or_discount": "Discount Amount", + "discount_amount": 100, + "apply_multiple_pricing_rules": 1, + "company": "_Test Company", + } + + frappe.get_doc(test_record.copy()).insert() + + so = make_sales_order(item_code="_Test Item", qty=1, price_list_rate=1000, do_not_submit=True) + self.assertEqual(so.items[0].discount_amount, 200) + self.assertEqual(so.items[0].rate, 800) + + frappe.delete_doc_if_exists("Sales Order", so.name) + frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule 1") + frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule 2") + test_dependencies = ["Campaign"] From 4bbf0a46b515334df2cd39bd7124188276c83ae0 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Wed, 1 May 2024 16:03:37 +0530 Subject: [PATCH 34/34] =?UTF-8?q?fix:=20added=20brand=20column=20in=20Ware?= =?UTF-8?q?house=20wise=20Item=20Balance=20Age=20and=20Value=20=E2=80=A6?= =?UTF-8?q?=20(backport=20#41280)=20(#41282)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix: added brand column in Warehouse wise Item Balance Age and Value … (#41280) fix: added brand coulmn in Warehouse wise Item Balance Age and Value report (cherry picked from commit 1cbc200770d2955f9d638c0047e0e58a514a5d23) Co-authored-by: rohitwaghchaure --- .../warehouse_wise_item_balance_age_and_value.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/erpnext/stock/report/warehouse_wise_item_balance_age_and_value/warehouse_wise_item_balance_age_and_value.py b/erpnext/stock/report/warehouse_wise_item_balance_age_and_value/warehouse_wise_item_balance_age_and_value.py index e1cce31329e..f5a059a7f61 100644 --- a/erpnext/stock/report/warehouse_wise_item_balance_age_and_value/warehouse_wise_item_balance_age_and_value.py +++ b/erpnext/stock/report/warehouse_wise_item_balance_age_and_value/warehouse_wise_item_balance_age_and_value.py @@ -56,13 +56,14 @@ def execute(filters=None): item_value.setdefault((item, item_map[item]["item_group"]), []) item_value[(item, item_map[item]["item_group"])].append(total_stock_value) + itemwise_brand = frappe._dict(get_itemwise_brand(items)) # sum bal_qty by item for (item, item_group), wh_balance in item_balance.items(): if not item_ageing.get(item): continue total_stock_value = sum(item_value[(item, item_group)]) - row = [item, item_map[item]["item_name"], item_group, total_stock_value] + row = [item, item_map[item]["item_name"], item_group, itemwise_brand.get(item), total_stock_value] fifo_queue = item_ageing[item]["fifo_queue"] average_age = 0.00 @@ -85,6 +86,10 @@ def execute(filters=None): return columns, data +def get_itemwise_brand(items): + return frappe.get_all("Item", filters={"name": ("in", items)}, fields=["name", "brand"], as_list=1) + + def get_columns(filters): """return columns""" @@ -92,6 +97,7 @@ def get_columns(filters): _("Item") + ":Link/Item:150", _("Item Name") + ":Link/Item:150", _("Item Group") + "::120", + _("Brand") + ":Link/Brand:120", _("Value") + ":Currency:120", _("Age") + ":Float:120", ]