From e43bc38e05349a780e0a4a97812cebea4a90a109 Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Wed, 19 Apr 2023 12:05:17 +0530 Subject: [PATCH 01/22] refactor: rewrite `get_stock_value_on()` queries in `QB` --- erpnext/stock/utils.py | 49 +++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/erpnext/stock/utils.py b/erpnext/stock/utils.py index b8c5187b2c..d928dca723 100644 --- a/erpnext/stock/utils.py +++ b/erpnext/stock/utils.py @@ -9,6 +9,7 @@ import frappe from frappe import _ from frappe.query_builder.functions import CombineDatetime from frappe.utils import cstr, flt, get_link_to_form, nowdate, nowtime +from pypika.terms import ExistsCriterion import erpnext from erpnext.stock.valuation import FIFOValuation, LIFOValuation @@ -57,39 +58,39 @@ def get_stock_value_on(warehouse=None, posting_date=None, item_code=None): if not posting_date: posting_date = nowdate() - values, condition = [posting_date], "" + sle = frappe.qb.DocType("Stock Ledger Entry") + query = ( + frappe.qb.from_(sle) + .select( + sle.item_code, + sle.stock_value, + sle.name, + sle.warehouse, + ) + .where((sle.posting_date <= posting_date) & (sle.is_cancelled == 0)) + .orderby(CombineDatetime(sle.posting_date, sle.posting_time), order=frappe.qb.desc) + .orderby(sle.creation, order=frappe.qb.desc) + ) if warehouse: - lft, rgt, is_group = frappe.db.get_value("Warehouse", warehouse, ["lft", "rgt", "is_group"]) if is_group: - values.extend([lft, rgt]) - condition += "and exists (\ - select name from `tabWarehouse` wh where wh.name = sle.warehouse\ - and wh.lft >= %s and wh.rgt <= %s)" - + wh = frappe.qb.DocType("Warehouse") + query = query.where( + ExistsCriterion( + frappe.qb.from_(wh) + .select(wh.name) + .where((wh.name == sle.warehouse) & (wh.lft >= lft) & (wh.rgt <= rgt)) + ) + ) else: - values.append(warehouse) - condition += " AND warehouse = %s" + query = query.where(sle.warehouse == warehouse) if item_code: - values.append(item_code) - condition += " AND item_code = %s" + query = query.where(sle.item_code == item_code) - stock_ledger_entries = frappe.db.sql( - """ - SELECT item_code, stock_value, name, warehouse - FROM `tabStock Ledger Entry` sle - WHERE posting_date <= %s {0} - and is_cancelled = 0 - ORDER BY timestamp(posting_date, posting_time) DESC, creation DESC - """.format( - condition - ), - values, - as_dict=1, - ) + stock_ledger_entries = query.run(as_dict=True) sle_map = {} for sle in stock_ledger_entries: From 9a37ac6c2563f8f6459c5c47a95ef349a9fc10bf Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Fri, 21 Apr 2023 13:28:14 +0530 Subject: [PATCH 02/22] refactor: sum up SLE value in query --- erpnext/stock/utils.py | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/erpnext/stock/utils.py b/erpnext/stock/utils.py index d928dca723..9c2e2c805b 100644 --- a/erpnext/stock/utils.py +++ b/erpnext/stock/utils.py @@ -7,7 +7,7 @@ from typing import Dict, Optional import frappe from frappe import _ -from frappe.query_builder.functions import CombineDatetime +from frappe.query_builder.functions import CombineDatetime, IfNull, Sum from frappe.utils import cstr, flt, get_link_to_form, nowdate, nowtime from pypika.terms import ExistsCriterion @@ -61,12 +61,7 @@ def get_stock_value_on(warehouse=None, posting_date=None, item_code=None): sle = frappe.qb.DocType("Stock Ledger Entry") query = ( frappe.qb.from_(sle) - .select( - sle.item_code, - sle.stock_value, - sle.name, - sle.warehouse, - ) + .select(IfNull(Sum(sle.stock_value_difference), 0)) .where((sle.posting_date <= posting_date) & (sle.is_cancelled == 0)) .orderby(CombineDatetime(sle.posting_date, sle.posting_time), order=frappe.qb.desc) .orderby(sle.creation, order=frappe.qb.desc) @@ -90,14 +85,7 @@ def get_stock_value_on(warehouse=None, posting_date=None, item_code=None): if item_code: query = query.where(sle.item_code == item_code) - stock_ledger_entries = query.run(as_dict=True) - - sle_map = {} - for sle in stock_ledger_entries: - if not (sle.item_code, sle.warehouse) in sle_map: - sle_map[(sle.item_code, sle.warehouse)] = flt(sle.stock_value) - - return sum(sle_map.values()) + return query.run(as_list=True)[0][0] @frappe.whitelist() From cb7a99cbaa2caa9746a49dd09c2c2bdea5ba1540 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Fri, 21 Apr 2023 12:59:52 +0530 Subject: [PATCH 03/22] Revert "fix: Rate from LDC in TDS reports (#33699)" This reverts commit db9beb3cddc78376ccd30b57efafa35381b482d6. --- .../report/tds_payable_monthly/tds_payable_monthly.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.py b/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.py index bfe2a0fd2b..98838907be 100644 --- a/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.py +++ b/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.py @@ -4,7 +4,6 @@ import frappe from frappe import _ -from frappe.utils import flt def execute(filters=None): @@ -66,12 +65,6 @@ def get_result( else: total_amount_credited += entry.credit - ## Check if ldc is applied and show rate as per ldc - actual_rate = (tds_deducted / total_amount_credited) * 100 - - if flt(actual_rate) < flt(rate): - rate = actual_rate - if tds_deducted: row = { "pan" From 7a63fbef4fcb0f57e5ec38f7900c6905cfe3954b Mon Sep 17 00:00:00 2001 From: rohitwaghchaure Date: Tue, 25 Apr 2023 12:01:26 +0530 Subject: [PATCH 04/22] =?UTF-8?q?Revert=20"fix:=20Incorrect=20difference?= =?UTF-8?q?=20value=20in=20Stock=20and=20Account=20Value=20Comparison?= =?UTF-8?q?=E2=80=A6"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../stock_and_account_value_comparison.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/stock/report/stock_and_account_value_comparison/stock_and_account_value_comparison.py b/erpnext/stock/report/stock_and_account_value_comparison/stock_and_account_value_comparison.py index 5fb456502e..106e877c4c 100644 --- a/erpnext/stock/report/stock_and_account_value_comparison/stock_and_account_value_comparison.py +++ b/erpnext/stock/report/stock_and_account_value_comparison/stock_and_account_value_comparison.py @@ -41,7 +41,7 @@ def get_data(report_filters): key = (d.voucher_type, d.voucher_no) gl_data = voucher_wise_gl_data.get(key) or {} d.account_value = gl_data.get("account_value", 0) - d.difference_value = abs(d.stock_value) - abs(d.account_value) + d.difference_value = d.stock_value - d.account_value if abs(d.difference_value) > 0.1: data.append(d) From ca388ed9cdc05a8797b9812989e88d5cdaf1a811 Mon Sep 17 00:00:00 2001 From: Anand Baburajan Date: Tue, 25 Apr 2023 12:45:05 +0530 Subject: [PATCH 05/22] fix: value of depreciable assets not updating after manual depr entry [develop] (#35020) * fix: value of depreciable assets not updating after manual depr entry * chore: add asset depr schedule to jv's ignore_doctypes_on_cancel_all --- .../accounts/doctype/account/test_account.py | 2 +- .../doctype/journal_entry/journal_entry.js | 2 +- .../doctype/journal_entry/journal_entry.py | 72 ++++++++++++------- .../asset_depreciations_and_balances.py | 24 +------ erpnext/assets/doctype/asset/depreciation.py | 1 + erpnext/assets/doctype/asset/test_asset.py | 62 +++++++++++++++- 6 files changed, 108 insertions(+), 55 deletions(-) diff --git a/erpnext/accounts/doctype/account/test_account.py b/erpnext/accounts/doctype/account/test_account.py index f9c9173af0..3a360c48c4 100644 --- a/erpnext/accounts/doctype/account/test_account.py +++ b/erpnext/accounts/doctype/account/test_account.py @@ -297,7 +297,7 @@ def _make_test_records(verbose=None): # fixed asset depreciation ["_Test Fixed Asset", "Current Assets", 0, "Fixed Asset", None], ["_Test Accumulated Depreciations", "Current Assets", 0, "Accumulated Depreciation", None], - ["_Test Depreciations", "Expenses", 0, None, None], + ["_Test Depreciations", "Expenses", 0, "Depreciation", None], ["_Test Gain/Loss on Asset Disposal", "Expenses", 0, None, None], # Receivable / Payable Account ["_Test Receivable", "Current Assets", 0, "Receivable", None], diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.js b/erpnext/accounts/doctype/journal_entry/journal_entry.js index 089f20b467..b31cc3212e 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.js +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.js @@ -8,7 +8,7 @@ frappe.provide("erpnext.journal_entry"); frappe.ui.form.on("Journal Entry", { setup: function(frm) { frm.add_fetch("bank_account", "account", "account"); - frm.ignore_doctypes_on_cancel_all = ['Sales Invoice', 'Purchase Invoice', 'Journal Entry', "Repost Payment Ledger"]; + frm.ignore_doctypes_on_cancel_all = ['Sales Invoice', 'Purchase Invoice', 'Journal Entry', "Repost Payment Ledger", 'Asset Depreciation Schedule']; }, refresh: function(frm) { diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py index 0f8ae4f37d..34a753f267 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.py +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py @@ -69,6 +69,7 @@ class JournalEntry(AccountsController): self.validate_empty_accounts_table() self.set_account_and_party_balance() self.validate_inter_company_accounts() + self.validate_depr_entry_voucher_type() if self.docstatus == 0: self.apply_tax_withholding() @@ -130,6 +131,13 @@ class JournalEntry(AccountsController): if self.total_credit != doc.total_debit or self.total_debit != doc.total_credit: frappe.throw(_("Total Credit/ Debit Amount should be same as linked Journal Entry")) + def validate_depr_entry_voucher_type(self): + if ( + any(d.account_type == "Depreciation" for d in self.get("accounts")) + and self.voucher_type != "Depreciation Entry" + ): + frappe.throw(_("Journal Entry type should be set as Depreciation Entry for asset depreciation")) + def validate_stock_accounts(self): stock_accounts = get_stock_accounts(self.company, self.doctype, self.name) for account in stock_accounts: @@ -233,25 +241,30 @@ class JournalEntry(AccountsController): self.remove(d) def update_asset_value(self): - if self.voucher_type != "Depreciation Entry": + if self.flags.planned_depr_entry or self.voucher_type != "Depreciation Entry": return - processed_assets = [] - for d in self.get("accounts"): if ( - d.reference_type == "Asset" and d.reference_name and d.reference_name not in processed_assets + d.reference_type == "Asset" + and d.reference_name + and d.account_type == "Depreciation" + and d.debit ): - processed_assets.append(d.reference_name) - asset = frappe.get_doc("Asset", d.reference_name) if asset.calculate_depreciation: - continue - - depr_value = d.debit or d.credit - - asset.db_set("value_after_depreciation", asset.value_after_depreciation - depr_value) + fb_idx = 1 + if self.finance_book: + for fb_row in asset.get("finance_books"): + if fb_row.finance_book == self.finance_book: + fb_idx = fb_row.idx + break + fb_row = asset.get("finance_books")[fb_idx - 1] + fb_row.value_after_depreciation -= d.debit + fb_row.db_update() + else: + asset.db_set("value_after_depreciation", asset.value_after_depreciation - d.debit) asset.set_status() @@ -316,42 +329,47 @@ class JournalEntry(AccountsController): if self.voucher_type != "Depreciation Entry": return - processed_assets = [] - for d in self.get("accounts"): if ( - d.reference_type == "Asset" and d.reference_name and d.reference_name not in processed_assets + d.reference_type == "Asset" + and d.reference_name + and d.account_type == "Depreciation" + and d.debit ): - processed_assets.append(d.reference_name) - asset = frappe.get_doc("Asset", d.reference_name) if asset.calculate_depreciation: je_found = False - for row in asset.get("finance_books"): + for fb_row in asset.get("finance_books"): if je_found: break - depr_schedule = get_depr_schedule(asset.name, "Active", row.finance_book) + depr_schedule = get_depr_schedule(asset.name, "Active", fb_row.finance_book) for s in depr_schedule or []: if s.journal_entry == self.name: s.db_set("journal_entry", None) - row.value_after_depreciation += s.depreciation_amount - row.db_update() - - asset.set_status() + fb_row.value_after_depreciation += d.debit + fb_row.db_update() je_found = True break + if not je_found: + fb_idx = 1 + if self.finance_book: + for fb_row in asset.get("finance_books"): + if fb_row.finance_book == self.finance_book: + fb_idx = fb_row.idx + break + + fb_row = asset.get("finance_books")[fb_idx - 1] + fb_row.value_after_depreciation += d.debit + fb_row.db_update() else: - depr_value = d.debit or d.credit - - asset.db_set("value_after_depreciation", asset.value_after_depreciation + depr_value) - - asset.set_status() + asset.db_set("value_after_depreciation", asset.value_after_depreciation + d.debit) + asset.set_status() def unlink_inter_company_jv(self): if ( diff --git a/erpnext/accounts/report/asset_depreciations_and_balances/asset_depreciations_and_balances.py b/erpnext/accounts/report/asset_depreciations_and_balances/asset_depreciations_and_balances.py index 5827697023..d67eee3552 100644 --- a/erpnext/accounts/report/asset_depreciations_and_balances/asset_depreciations_and_balances.py +++ b/erpnext/accounts/report/asset_depreciations_and_balances/asset_depreciations_and_balances.py @@ -114,28 +114,6 @@ def get_assets(filters): sum(results.depreciation_eliminated_during_the_period) as depreciation_eliminated_during_the_period, sum(results.depreciation_amount_during_the_period) as depreciation_amount_during_the_period from (SELECT a.asset_category, - ifnull(sum(case when ds.schedule_date < %(from_date)s and (ifnull(a.disposal_date, 0) = 0 or a.disposal_date >= %(from_date)s) then - ds.depreciation_amount - else - 0 - end), 0) as accumulated_depreciation_as_on_from_date, - ifnull(sum(case when ifnull(a.disposal_date, 0) != 0 and a.disposal_date >= %(from_date)s - and a.disposal_date <= %(to_date)s and ds.schedule_date <= a.disposal_date then - ds.depreciation_amount - else - 0 - end), 0) as depreciation_eliminated_during_the_period, - ifnull(sum(case when ds.schedule_date >= %(from_date)s and ds.schedule_date <= %(to_date)s - and (ifnull(a.disposal_date, 0) = 0 or ds.schedule_date <= a.disposal_date) then - ds.depreciation_amount - else - 0 - end), 0) as depreciation_amount_during_the_period - from `tabAsset` a, `tabAsset Depreciation Schedule` ads, `tabDepreciation Schedule` ds - where a.docstatus=1 and a.company=%(company)s and a.purchase_date <= %(to_date)s and ads.asset = a.name and ads.docstatus=1 and ads.name = ds.parent and ifnull(ds.journal_entry, '') != '' - group by a.asset_category - union - SELECT a.asset_category, ifnull(sum(case when gle.posting_date < %(from_date)s and (ifnull(a.disposal_date, 0) = 0 or a.disposal_date >= %(from_date)s) then gle.debit else @@ -160,7 +138,7 @@ def get_assets(filters): aca.parent = a.asset_category and aca.company_name = %(company)s join `tabCompany` company on company.name = %(company)s - where a.docstatus=1 and a.company=%(company)s and a.calculate_depreciation=0 and a.purchase_date <= %(to_date)s and gle.debit != 0 and gle.is_cancelled = 0 and gle.account = ifnull(aca.depreciation_expense_account, company.depreciation_expense_account) + where a.docstatus=1 and a.company=%(company)s and a.purchase_date <= %(to_date)s and gle.debit != 0 and gle.is_cancelled = 0 and gle.account = ifnull(aca.depreciation_expense_account, company.depreciation_expense_account) group by a.asset_category union SELECT a.asset_category, diff --git a/erpnext/assets/doctype/asset/depreciation.py b/erpnext/assets/doctype/asset/depreciation.py index 028e3d6268..f23ae2f165 100644 --- a/erpnext/assets/doctype/asset/depreciation.py +++ b/erpnext/assets/doctype/asset/depreciation.py @@ -157,6 +157,7 @@ def make_depreciation_entry(asset_depr_schedule_name, date=None): je.append("accounts", debit_entry) je.flags.ignore_permissions = True + je.flags.planned_depr_entry = True je.save() if not je.meta.get_workflow(): je.submit() diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py index cde02809f1..203612ff1b 100644 --- a/erpnext/assets/doctype/asset/test_asset.py +++ b/erpnext/assets/doctype/asset/test_asset.py @@ -1511,7 +1511,7 @@ class TestDepreciationBasics(AssetSetup): ) self.assertEqual(asset.status, "Submitted") - self.assertEqual(asset.get("value_after_depreciation"), 100000) + self.assertEqual(asset.get_value_after_depreciation(), 100000) jv = make_journal_entry( "_Test Depreciations - _TC", "_Test Accumulated Depreciations - _TC", 100, save=False @@ -1524,12 +1524,68 @@ class TestDepreciationBasics(AssetSetup): jv.submit() asset.reload() - self.assertEqual(asset.get("value_after_depreciation"), 99900) + self.assertEqual(asset.get_value_after_depreciation(), 99900) jv.cancel() asset.reload() - self.assertEqual(asset.get("value_after_depreciation"), 100000) + self.assertEqual(asset.get_value_after_depreciation(), 100000) + + def test_manual_depreciation_for_depreciable_asset(self): + asset = create_asset( + item_code="Macbook Pro", + calculate_depreciation=1, + purchase_date="2020-01-30", + available_for_use_date="2020-01-30", + expected_value_after_useful_life=10000, + total_number_of_depreciations=10, + frequency_of_depreciation=1, + submit=1, + ) + + self.assertEqual(asset.status, "Submitted") + self.assertEqual(asset.get_value_after_depreciation(), 100000) + + jv = make_journal_entry( + "_Test Depreciations - _TC", "_Test Accumulated Depreciations - _TC", 100, save=False + ) + for d in jv.accounts: + d.reference_type = "Asset" + d.reference_name = asset.name + jv.voucher_type = "Depreciation Entry" + jv.insert() + jv.submit() + + asset.reload() + self.assertEqual(asset.get_value_after_depreciation(), 99900) + + jv.cancel() + + asset.reload() + self.assertEqual(asset.get_value_after_depreciation(), 100000) + + def test_manual_depreciation_with_incorrect_jv_voucher_type(self): + asset = create_asset( + item_code="Macbook Pro", + calculate_depreciation=1, + purchase_date="2020-01-30", + available_for_use_date="2020-01-30", + expected_value_after_useful_life=10000, + total_number_of_depreciations=10, + frequency_of_depreciation=1, + submit=1, + ) + + jv = make_journal_entry( + "_Test Depreciations - _TC", "_Test Accumulated Depreciations - _TC", 100, save=False + ) + for d in jv.accounts: + d.reference_type = "Asset" + d.reference_name = asset.name + d.account_type = "Depreciation" + jv.voucher_type = "Journal Entry" + + self.assertRaises(frappe.ValidationError, jv.insert) def create_asset_data(): From e782a054c80656f378da6108bdd91fae99de685e Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Tue, 25 Apr 2023 13:54:36 +0530 Subject: [PATCH 06/22] refactor: `get_stock_value_on()` to get stock value of multiple warehouses at once --- erpnext/accounts/utils.py | 5 +--- .../incorrect_stock_value_report.py | 2 +- erpnext/stock/utils.py | 28 +++++++++---------- 3 files changed, 15 insertions(+), 20 deletions(-) diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py index 2ab9ef64b3..015bce5547 100644 --- a/erpnext/accounts/utils.py +++ b/erpnext/accounts/utils.py @@ -1368,10 +1368,7 @@ def get_stock_and_account_balance(account=None, posting_date=None, company=None) if wh_details.account == account and not wh_details.is_group ] - total_stock_value = 0.0 - for warehouse in related_warehouses: - value = get_stock_value_on(warehouse, posting_date) - total_stock_value += value + total_stock_value = get_stock_value_on(related_warehouses, posting_date) precision = frappe.get_precision("Journal Entry Account", "debit_in_account_currency") return flt(account_balance, precision), flt(total_stock_value, precision), related_warehouses diff --git a/erpnext/stock/report/incorrect_stock_value_report/incorrect_stock_value_report.py b/erpnext/stock/report/incorrect_stock_value_report/incorrect_stock_value_report.py index df01b14d11..16ff5278e7 100644 --- a/erpnext/stock/report/incorrect_stock_value_report/incorrect_stock_value_report.py +++ b/erpnext/stock/report/incorrect_stock_value_report/incorrect_stock_value_report.py @@ -84,7 +84,7 @@ def get_data(report_filters): closing_date = add_days(from_date, -1) for key, stock_data in voucher_wise_dict.items(): prev_stock_value = get_stock_value_on( - posting_date=closing_date, item_code=key[0], warehouse=key[1] + posting_date=closing_date, item_code=key[0], warehouses=key[1] ) for data in stock_data: expected_stock_value = prev_stock_value + data.stock_value_difference diff --git a/erpnext/stock/utils.py b/erpnext/stock/utils.py index 9c2e2c805b..fb526971ed 100644 --- a/erpnext/stock/utils.py +++ b/erpnext/stock/utils.py @@ -9,9 +9,9 @@ import frappe from frappe import _ from frappe.query_builder.functions import CombineDatetime, IfNull, Sum from frappe.utils import cstr, flt, get_link_to_form, nowdate, nowtime -from pypika.terms import ExistsCriterion import erpnext +from erpnext.stock.doctype.warehouse.warehouse import get_child_warehouses from erpnext.stock.valuation import FIFOValuation, LIFOValuation BarcodeScanResult = Dict[str, Optional[str]] @@ -54,7 +54,9 @@ def get_stock_value_from_bin(warehouse=None, item_code=None): return stock_value -def get_stock_value_on(warehouse=None, posting_date=None, item_code=None): +def get_stock_value_on( + warehouses: list | str = None, posting_date: str = None, item_code: str = None +) -> float: if not posting_date: posting_date = nowdate() @@ -67,20 +69,16 @@ def get_stock_value_on(warehouse=None, posting_date=None, item_code=None): .orderby(sle.creation, order=frappe.qb.desc) ) - if warehouse: - lft, rgt, is_group = frappe.db.get_value("Warehouse", warehouse, ["lft", "rgt", "is_group"]) + if warehouses: + if isinstance(warehouses, str): + warehouses = [warehouses] - if is_group: - wh = frappe.qb.DocType("Warehouse") - query = query.where( - ExistsCriterion( - frappe.qb.from_(wh) - .select(wh.name) - .where((wh.name == sle.warehouse) & (wh.lft >= lft) & (wh.rgt <= rgt)) - ) - ) - else: - query = query.where(sle.warehouse == warehouse) + warehouses = set(warehouses) + for wh in list(warehouses): + if frappe.db.get_value("Warehouse", wh, "is_group"): + warehouses.update(get_child_warehouses(wh)) + + query = query.where(sle.warehouse.isin(warehouses)) if item_code: query = query.where(sle.item_code == item_code) From e08d636bf7979356f60301260177e57213e84fd7 Mon Sep 17 00:00:00 2001 From: Anand Baburajan Date: Tue, 25 Apr 2023 15:16:50 +0530 Subject: [PATCH 07/22] fix: use filter_by_finance_book instead of only_depreciable_assets in fixed asset register (#35031) fix: use filter_by_finance_book instead of only_depreciable_assets --- .../report/fixed_asset_register/fixed_asset_register.js | 6 +++--- .../report/fixed_asset_register/fixed_asset_register.py | 4 +--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.js b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.js index 65a4226ebd..4f7b836107 100644 --- a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.js +++ b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.js @@ -94,11 +94,11 @@ frappe.query_reports["Fixed Asset Register"] = { label: __("Finance Book"), fieldtype: "Link", options: "Finance Book", - depends_on: "eval: doc.only_depreciable_assets == 1", + depends_on: "eval: doc.filter_by_finance_book == 1", }, { - fieldname:"only_depreciable_assets", - label: __("Only depreciable assets"), + fieldname:"filter_by_finance_book", + label: __("Filter by Finance Book"), fieldtype: "Check" }, { diff --git a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py index 5fbcbe2f7f..984b3fd982 100644 --- a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py +++ b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py @@ -45,8 +45,6 @@ def get_conditions(filters): filters.year_end_date = getdate(fiscal_year.year_end_date) conditions[date_field] = ["between", [filters.year_start_date, filters.year_end_date]] - if filters.get("only_depreciable_assets"): - conditions["calculate_depreciation"] = filters.get("only_depreciable_assets") if filters.get("only_existing_assets"): conditions["is_existing_asset"] = filters.get("only_existing_assets") if filters.get("asset_category"): @@ -106,7 +104,7 @@ def get_data(filters): assets_linked_to_fb = None - if filters.only_depreciable_assets: + if filters.filter_by_finance_book: assets_linked_to_fb = frappe.db.get_all( doctype="Asset Finance Book", filters={"finance_book": filters.finance_book or ("is", "not set")}, From 6de71eb15857291295921df984c59d4d871eb9f0 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Tue, 25 Apr 2023 18:33:31 +0530 Subject: [PATCH 08/22] fix: pass reference_doctype in link queries (#35038) --- erpnext/controllers/queries.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/erpnext/controllers/queries.py b/erpnext/controllers/queries.py index b0cf724166..799fed99cc 100644 --- a/erpnext/controllers/queries.py +++ b/erpnext/controllers/queries.py @@ -576,7 +576,9 @@ def get_income_account(doctype, txt, searchfield, start, page_len, filters): @frappe.whitelist() @frappe.validate_and_sanitize_search_inputs -def get_filtered_dimensions(doctype, txt, searchfield, start, page_len, filters): +def get_filtered_dimensions( + doctype, txt, searchfield, start, page_len, filters, reference_doctype=None +): from erpnext.accounts.doctype.accounting_dimension_filter.accounting_dimension_filter import ( get_dimension_filter_map, ) @@ -617,7 +619,12 @@ def get_filtered_dimensions(doctype, txt, searchfield, start, page_len, filters) query_filters.append(["name", query_selector, dimensions]) output = frappe.get_list( - doctype, fields=fields, filters=query_filters, or_filters=or_filters, as_list=1 + doctype, + fields=fields, + filters=query_filters, + or_filters=or_filters, + as_list=1, + reference_doctype=reference_doctype, ) return [tuple(d) for d in set(output)] From b545e3def01fb9b9dd6b964478efcb7d764ce386 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Tue, 25 Apr 2023 19:07:45 +0530 Subject: [PATCH 09/22] fix: Add company field to lower deduction certificate (#34914) --- .../tax_withholding_category.py | 5 +++-- erpnext/patches.txt | 1 + erpnext/patches/v14_0/update_company_in_ldc.py | 14 ++++++++++++++ .../lower_deduction_certificate.json | 11 ++++++++++- 4 files changed, 28 insertions(+), 3 deletions(-) create mode 100644 erpnext/patches/v14_0/update_company_in_ldc.py 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 f0146ea70e..ad3477ef3d 100644 --- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py +++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py @@ -215,7 +215,7 @@ def get_tax_row_for_tds(tax_details, tax_amount): } -def get_lower_deduction_certificate(tax_details, pan_no): +def get_lower_deduction_certificate(company, tax_details, pan_no): ldc_name = frappe.db.get_value( "Lower Deduction Certificate", { @@ -223,6 +223,7 @@ def get_lower_deduction_certificate(tax_details, pan_no): "tax_withholding_category": tax_details.tax_withholding_category, "valid_from": (">=", tax_details.from_date), "valid_upto": ("<=", tax_details.to_date), + "company": company, }, "name", ) @@ -255,7 +256,7 @@ def get_tax_amount(party_type, parties, inv, tax_details, posting_date, pan_no=N tax_amount = 0 if party_type == "Supplier": - ldc = get_lower_deduction_certificate(tax_details, pan_no) + ldc = get_lower_deduction_certificate(inv.company, tax_details, pan_no) if tax_deducted: net_total = inv.tax_withholding_net_total if ldc: diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 74c8af1f0c..03c7b01856 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -332,3 +332,4 @@ execute:frappe.db.set_single_value("Accounts Settings", "merge_similar_account_h erpnext.patches.v14_0.migrate_gl_to_payment_ledger execute:frappe.delete_doc_if_exists("Report", "Tax Detail") erpnext.patches.v15_0.enable_all_leads +erpnext.patches.v14_0.update_company_in_ldc diff --git a/erpnext/patches/v14_0/update_company_in_ldc.py b/erpnext/patches/v14_0/update_company_in_ldc.py new file mode 100644 index 0000000000..ca95cf2fd7 --- /dev/null +++ b/erpnext/patches/v14_0/update_company_in_ldc.py @@ -0,0 +1,14 @@ +# Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and Contributors +# License: MIT. See LICENSE + + +import frappe + +from erpnext import get_default_company + + +def execute(): + company = get_default_company() + if company: + for d in frappe.get_all("Lower Deduction Certificate", pluck="name"): + frappe.db.set_value("Lower Deduction Certificate", d, "company", company, update_modified=False) diff --git a/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.json b/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.json index c32ab6bec2..d332b4e76b 100644 --- a/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.json +++ b/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.json @@ -10,6 +10,7 @@ "tax_withholding_category", "fiscal_year", "column_break_3", + "company", "certificate_no", "section_break_3", "supplier", @@ -123,11 +124,18 @@ "label": "Tax Withholding Category", "options": "Tax Withholding Category", "reqd": 1 + }, + { + "fieldname": "company", + "fieldtype": "Link", + "label": "Company", + "options": "Company", + "reqd": 1 } ], "index_web_pages_for_search": 1, "links": [], - "modified": "2021-10-23 18:33:38.962622", + "modified": "2023-04-18 08:25:35.302081", "modified_by": "Administrator", "module": "Regional", "name": "Lower Deduction Certificate", @@ -136,5 +144,6 @@ "permissions": [], "sort_field": "modified", "sort_order": "DESC", + "states": [], "track_changes": 1 } \ No newline at end of file From 22290c2694e626132de692a04e0fce2dba4c29df Mon Sep 17 00:00:00 2001 From: HarryPaulo Date: Tue, 25 Apr 2023 10:43:53 -0300 Subject: [PATCH 10/22] fix: respect title_field from doctype to bulk transactions (#34928) --- erpnext/utilities/bulk_transaction.py | 1 + 1 file changed, 1 insertion(+) diff --git a/erpnext/utilities/bulk_transaction.py b/erpnext/utilities/bulk_transaction.py index c1579b3cbc..7fc1d9734c 100644 --- a/erpnext/utilities/bulk_transaction.py +++ b/erpnext/utilities/bulk_transaction.py @@ -104,6 +104,7 @@ def task(doc_name, from_doctype, to_doctype): obj = mapper[from_doctype][to_doctype](doc_name) obj.flags.ignore_validate = True + obj.set_title_field() obj.insert(ignore_mandatory=True) From f1acc5fabb27999dbae2f56885c8922a4b683139 Mon Sep 17 00:00:00 2001 From: Solufy Solution <34390782+Solufyin@users.noreply.github.com> Date: Tue, 25 Apr 2023 19:16:30 +0530 Subject: [PATCH 11/22] fix: Bulk Payment Entry from PO/SO (#34942) Co-authored-by: Nihantra Patel --- .../buying/doctype/purchase_order/purchase_order_list.js | 2 +- erpnext/selling/doctype/sales_order/sales_order_list.js | 2 +- erpnext/utilities/bulk_transaction.py | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/erpnext/buying/doctype/purchase_order/purchase_order_list.js b/erpnext/buying/doctype/purchase_order/purchase_order_list.js index d7907e4274..6594746cfc 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order_list.js +++ b/erpnext/buying/doctype/purchase_order/purchase_order_list.js @@ -43,7 +43,7 @@ frappe.listview_settings['Purchase Order'] = { }); listview.page.add_action_item(__("Advance Payment"), ()=>{ - erpnext.bulk_transaction_processing.create(listview, "Purchase Order", "Advance Payment"); + erpnext.bulk_transaction_processing.create(listview, "Purchase Order", "Payment Entry"); }); } diff --git a/erpnext/selling/doctype/sales_order/sales_order_list.js b/erpnext/selling/doctype/sales_order/sales_order_list.js index 4691190d2a..64c58ef5d7 100644 --- a/erpnext/selling/doctype/sales_order/sales_order_list.js +++ b/erpnext/selling/doctype/sales_order/sales_order_list.js @@ -57,7 +57,7 @@ frappe.listview_settings['Sales Order'] = { }); listview.page.add_action_item(__("Advance Payment"), ()=>{ - erpnext.bulk_transaction_processing.create(listview, "Sales Order", "Advance Payment"); + erpnext.bulk_transaction_processing.create(listview, "Sales Order", "Payment Entry"); }); } diff --git a/erpnext/utilities/bulk_transaction.py b/erpnext/utilities/bulk_transaction.py index 7fc1d9734c..5e57b31793 100644 --- a/erpnext/utilities/bulk_transaction.py +++ b/erpnext/utilities/bulk_transaction.py @@ -69,7 +69,7 @@ def task(doc_name, from_doctype, to_doctype): "Sales Order": { "Sales Invoice": sales_order.make_sales_invoice, "Delivery Note": sales_order.make_delivery_note, - "Advance Payment": payment_entry.get_payment_entry, + "Payment Entry": payment_entry.get_payment_entry, }, "Sales Invoice": { "Delivery Note": sales_invoice.make_delivery_note, @@ -86,11 +86,11 @@ def task(doc_name, from_doctype, to_doctype): "Supplier Quotation": { "Purchase Order": supplier_quotation.make_purchase_order, "Purchase Invoice": supplier_quotation.make_purchase_invoice, - "Advance Payment": payment_entry.get_payment_entry, }, "Purchase Order": { "Purchase Invoice": purchase_order.make_purchase_invoice, "Purchase Receipt": purchase_order.make_purchase_receipt, + "Payment Entry": payment_entry.get_payment_entry, }, "Purchase Invoice": { "Purchase Receipt": purchase_invoice.make_purchase_receipt, @@ -98,7 +98,7 @@ def task(doc_name, from_doctype, to_doctype): }, "Purchase Receipt": {"Purchase Invoice": purchase_receipt.make_purchase_invoice}, } - if to_doctype in ["Advance Payment", "Payment Entry"]: + if to_doctype in ["Payment Entry"]: obj = mapper[from_doctype][to_doctype](from_doctype, doc_name) else: obj = mapper[from_doctype][to_doctype](doc_name) From ecea9b44a339fcfb261696118add5873a4d625fb Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Tue, 25 Apr 2023 19:17:13 +0530 Subject: [PATCH 12/22] fix: Payment entry with TDS in bank reco statement (#34961) --- erpnext/accounts/doctype/bank_clearance/bank_clearance.py | 2 +- .../report/bank_clearance_summary/bank_clearance_summary.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/bank_clearance/bank_clearance.py b/erpnext/accounts/doctype/bank_clearance/bank_clearance.py index 081718726b..8ad0bd17b4 100644 --- a/erpnext/accounts/doctype/bank_clearance/bank_clearance.py +++ b/erpnext/accounts/doctype/bank_clearance/bank_clearance.py @@ -56,7 +56,7 @@ class BankClearance(Document): select "Payment Entry" as payment_document, name as payment_entry, reference_no as cheque_number, reference_date as cheque_date, - if(paid_from=%(account)s, paid_amount, 0) as credit, + if(paid_from=%(account)s, paid_amount + total_taxes_and_charges, 0) as credit, if(paid_from=%(account)s, 0, received_amount) as debit, posting_date, ifnull(party,if(paid_from=%(account)s,paid_to,paid_from)) as against_account, clearance_date, if(paid_to=%(account)s, paid_to_account_currency, paid_from_account_currency) as account_currency diff --git a/erpnext/accounts/report/bank_clearance_summary/bank_clearance_summary.py b/erpnext/accounts/report/bank_clearance_summary/bank_clearance_summary.py index 306af722ba..2d68bb70b8 100644 --- a/erpnext/accounts/report/bank_clearance_summary/bank_clearance_summary.py +++ b/erpnext/accounts/report/bank_clearance_summary/bank_clearance_summary.py @@ -80,7 +80,7 @@ def get_entries(filters): payment_entries = frappe.db.sql( """SELECT "Payment Entry", name, posting_date, reference_no, clearance_date, party, - if(paid_from=%(account)s, paid_amount * -1, received_amount) + if(paid_from=%(account)s, ((paid_amount * -1) - total_taxes_and_charges) , received_amount) FROM `tabPayment Entry` WHERE From 72b5c1f70a51f18cda48c8e71602ee2d620e582b Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 25 Apr 2023 19:18:08 +0530 Subject: [PATCH 13/22] fix: Use set instead of db_set as it is called from validate (#34967) --- erpnext/crm/doctype/opportunity/opportunity.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/crm/doctype/opportunity/opportunity.py b/erpnext/crm/doctype/opportunity/opportunity.py index 6a5fead0f8..2a8d65f486 100644 --- a/erpnext/crm/doctype/opportunity/opportunity.py +++ b/erpnext/crm/doctype/opportunity/opportunity.py @@ -59,7 +59,7 @@ class Opportunity(TransactionBase, CRMNote): 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) - self.db_set(field, value) + self.set(field, value) except Exception: continue From f7b50f2adef11b9f2bd843d6bca3f2b6cf7be19b Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Tue, 25 Apr 2023 19:18:45 +0530 Subject: [PATCH 14/22] fix: Unable to allocate advance against invoice (#35007) --- erpnext/controllers/accounts_controller.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index 642d51c325..6982f716bf 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -1662,7 +1662,10 @@ class AccountsController(TransactionBase): ) self.append("payment_schedule", data) - if not automatically_fetch_payment_terms: + if not ( + automatically_fetch_payment_terms + and self.linked_order_has_payment_terms(po_or_so, fieldname, doctype) + ): for d in self.get("payment_schedule"): if d.invoice_portion: d.payment_amount = flt( From 74fb2bec3a5055d6bb76be0d5e3fd80899c642d1 Mon Sep 17 00:00:00 2001 From: Nandhinidevi123 Date: Tue, 25 Apr 2023 20:08:35 +0530 Subject: [PATCH 15/22] add if condition for workstation filter --- erpnext/manufacturing/doctype/bom/bom.js | 2 +- erpnext/manufacturing/doctype/routing/routing.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/manufacturing/doctype/bom/bom.js b/erpnext/manufacturing/doctype/bom/bom.js index 7cdcef9c7a..ad9aafe066 100644 --- a/erpnext/manufacturing/doctype/bom/bom.js +++ b/erpnext/manufacturing/doctype/bom/bom.js @@ -652,7 +652,7 @@ frappe.ui.form.on("BOM Operation", "operation", function(frm, cdt, cdn) { frappe.ui.form.on("BOM Operation", "workstation", function(frm, cdt, cdn) { var d = locals[cdt][cdn]; - + if(!d.workstation) return; frappe.call({ "method": "frappe.client.get", args: { diff --git a/erpnext/manufacturing/doctype/routing/routing.js b/erpnext/manufacturing/doctype/routing/routing.js index b480c70ad5..784e83a4c0 100644 --- a/erpnext/manufacturing/doctype/routing/routing.js +++ b/erpnext/manufacturing/doctype/routing/routing.js @@ -50,7 +50,7 @@ frappe.ui.form.on('BOM Operation', { workstation: function(frm, cdt, cdn) { const d = locals[cdt][cdn]; - + if(!d.workstation) return; frappe.call({ "method": "frappe.client.get", args: { From d6bc8bba8b7ed748483bf61b03c8c87eb54f8ab0 Mon Sep 17 00:00:00 2001 From: Raffael Meyer <14891507+barredterra@users.noreply.github.com> Date: Tue, 25 Apr 2023 17:21:11 +0200 Subject: [PATCH 16/22] fix: per_billed condition for Payment Entry (#34969) --- erpnext/accounts/doctype/payment_entry/payment_entry.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py index ee4d4d29e2..082128ac1e 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py @@ -1693,7 +1693,10 @@ def get_payment_entry( ): reference_doc = None doc = frappe.get_doc(dt, dn) - if dt in ("Sales Order", "Purchase Order") and flt(doc.per_billed, 2) >= 99.99: + over_billing_allowance = frappe.db.get_single_value("Accounts Settings", "over_billing_allowance") + if dt in ("Sales Order", "Purchase Order") and flt(doc.per_billed, 2) >= ( + 100.0 + over_billing_allowance + ): frappe.throw(_("Can only make payment against unbilled {0}").format(dt)) if not party_type: From f88431a79a6bda662352ec38b8fe650c7f07fdd3 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Tue, 25 Apr 2023 20:54:22 +0530 Subject: [PATCH 17/22] fix: Common party JV cost center (#35008) --- erpnext/controllers/accounts_controller.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index 6982f716bf..d0ec654162 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -1904,12 +1904,14 @@ class AccountsController(TransactionBase): reconcilation_entry.party = secondary_party reconcilation_entry.reference_type = self.doctype reconcilation_entry.reference_name = self.name - reconcilation_entry.cost_center = self.cost_center + reconcilation_entry.cost_center = self.cost_center or erpnext.get_default_cost_center( + self.company + ) advance_entry.account = primary_account advance_entry.party_type = primary_party_type advance_entry.party = primary_party - advance_entry.cost_center = self.cost_center + advance_entry.cost_center = self.cost_center or erpnext.get_default_cost_center(self.company) advance_entry.is_advance = "Yes" if self.doctype == "Sales Invoice": From c4512d552e3262276df907148fafa57319bdebb1 Mon Sep 17 00:00:00 2001 From: Ernesto Ruiz Date: Tue, 25 Apr 2023 09:26:53 -0600 Subject: [PATCH 18/22] chore: Add translate function to Depreciation Journal Entry Remark (#35022) chore: Add translate function to Depreciation Journal Entry Remark --- erpnext/assets/doctype/asset/asset.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py index 6001254762..42f531189a 100644 --- a/erpnext/assets/doctype/asset/asset.py +++ b/erpnext/assets/doctype/asset/asset.py @@ -783,7 +783,7 @@ def make_journal_entry(asset_name): je.voucher_type = "Depreciation Entry" je.naming_series = depreciation_series je.company = asset.company - je.remark = "Depreciation Entry against asset {0}".format(asset_name) + je.remark = _("Depreciation Entry against asset {0}").format(asset_name) je.append( "accounts", From 3d90b970d19ee0f41582dada6dbcdc4999fde10a Mon Sep 17 00:00:00 2001 From: tundebabzy Date: Tue, 25 Apr 2023 16:27:59 +0100 Subject: [PATCH 19/22] fix: click handler should not attempt indexed access of empty array (#35013) fix: click handler should not attempt indexed access of empty array --- erpnext/public/js/projects/timer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/public/js/projects/timer.js b/erpnext/public/js/projects/timer.js index 9dae7118d9..0209f4c232 100644 --- a/erpnext/public/js/projects/timer.js +++ b/erpnext/public/js/projects/timer.js @@ -68,7 +68,7 @@ erpnext.timesheet.control_timer = function(frm, dialog, row, timestamp=0) { // New activity if no activities found var args = dialog.get_values(); if(!args) return; - if (frm.doc.time_logs.length <= 1 && !frm.doc.time_logs[0].activity_type && !frm.doc.time_logs[0].from_time) { + if (frm.doc.time_logs.length == 1 && !frm.doc.time_logs[0].activity_type && !frm.doc.time_logs[0].from_time) { frm.doc.time_logs = []; } row = frappe.model.add_child(frm.doc, "Timesheet Detail", "time_logs"); From ab0f7794b77a1cc6ff312331fd84e1541cfe2ac8 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Tue, 25 Apr 2023 21:08:50 +0530 Subject: [PATCH 20/22] fix: wrong qty of remaining work orders to be created when using "Create" > "Work Order" (#34726) fix: wrong qty of remaining work orders to be created when using "Create" > "Work Order" (#34726) * fix: convert asynchronous field update to synchronous * fix: wrong qty of remaining work orders to be created when using "Create" > "Work Order" (cherry picked from commit 189b020d228bdb1c0c589697162cf91718b2fa27) Co-authored-by: danjeremynavarro <46537526+danjeremynavarro@users.noreply.github.com> --- erpnext/selling/doctype/sales_order/sales_order.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index ee9161bee4..d995517af8 100755 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -1340,8 +1340,9 @@ def get_work_order_items(sales_order, for_raw_material_request=0): .select(Sum(wo.qty)) .where( (wo.production_item == i.item_code) - & (wo.sales_order == so.name) * (wo.sales_order_item == i.name) - & (wo.docstatus.lte(2)) + & (wo.sales_order == so.name) + & (wo.sales_order_item == i.name) + & (wo.docstatus.lt(2)) ) .run()[0][0] ) From c36dc3dc57629c4f77e492508beb09b705a2f25b Mon Sep 17 00:00:00 2001 From: "Kitti U. @ Ecosoft" Date: Tue, 25 Apr 2023 23:04:28 +0700 Subject: [PATCH 21/22] fix: v14, Bank Reconcile Tools not cover case JV debit bank (#35000) --- .../doctype/bank_transaction/bank_transaction.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/erpnext/accounts/doctype/bank_transaction/bank_transaction.py b/erpnext/accounts/doctype/bank_transaction/bank_transaction.py index fcbaf329f5..b441af9660 100644 --- a/erpnext/accounts/doctype/bank_transaction/bank_transaction.py +++ b/erpnext/accounts/doctype/bank_transaction/bank_transaction.py @@ -281,10 +281,13 @@ def get_paid_amount(payment_entry, currency, gl_bank_account): ) elif payment_entry.payment_document == "Journal Entry": - return frappe.db.get_value( - "Journal Entry Account", - {"parent": payment_entry.payment_entry, "account": gl_bank_account}, - "sum(credit_in_account_currency)", + return abs( + frappe.db.get_value( + "Journal Entry Account", + {"parent": payment_entry.payment_entry, "account": gl_bank_account}, + "sum(debit_in_account_currency-credit_in_account_currency)", + ) + or 0 ) elif payment_entry.payment_document == "Expense Claim": From 3be1ab9b8dbf339e23138e5e518c950b2e7a1b97 Mon Sep 17 00:00:00 2001 From: HarryPaulo Date: Tue, 25 Apr 2023 13:24:41 -0300 Subject: [PATCH 22/22] fix: allow submit delivery note when the sales order was billed... (#34910) --- erpnext/stock/doctype/delivery_note/delivery_note.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py index 9f9f5cbe2a..9f6dd24fa6 100644 --- a/erpnext/stock/doctype/delivery_note/delivery_note.py +++ b/erpnext/stock/doctype/delivery_note/delivery_note.py @@ -271,6 +271,9 @@ class DeliveryNote(SellingController): def check_credit_limit(self): from erpnext.selling.doctype.customer.customer import check_credit_limit + if self.per_billed == 100: + return + extra_amount = 0 validate_against_credit_limit = False bypass_credit_limit_check_at_sales_order = cint(