From c957a5cd2eda6d2ab589919c20dd56245589e140 Mon Sep 17 00:00:00 2001 From: Anand Baburajan Date: Tue, 11 Apr 2023 12:16:07 +0530 Subject: [PATCH 01/15] fix: provide filter by depreciable assets in fixed asset register (#34803) --- .../fixed_asset_register.js | 24 +++++++++----- .../fixed_asset_register.py | 33 ++++++++++--------- 2 files changed, 32 insertions(+), 25 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 06989a95da..65a4226ebd 100644 --- a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.js +++ b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.js @@ -24,7 +24,7 @@ frappe.query_reports["Fixed Asset Register"] = { "label": __("Period Based On"), "fieldtype": "Select", "options": ["Fiscal Year", "Date Range"], - "default": ["Fiscal Year"], + "default": "Fiscal Year", "reqd": 1 }, { @@ -75,12 +75,6 @@ frappe.query_reports["Fixed Asset Register"] = { fieldtype: "Link", options: "Asset Category" }, - { - fieldname:"finance_book", - label: __("Finance Book"), - fieldtype: "Link", - options: "Finance Book" - }, { fieldname:"cost_center", label: __("Cost Center"), @@ -96,8 +90,20 @@ frappe.query_reports["Fixed Asset Register"] = { reqd: 1 }, { - fieldname:"is_existing_asset", - label: __("Is Existing Asset"), + fieldname:"finance_book", + label: __("Finance Book"), + fieldtype: "Link", + options: "Finance Book", + depends_on: "eval: doc.only_depreciable_assets == 1", + }, + { + fieldname:"only_depreciable_assets", + label: __("Only depreciable assets"), + fieldtype: "Check" + }, + { + fieldname:"only_existing_assets", + label: __("Only existing assets"), 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 59d43b1ea6..5fbcbe2f7f 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,10 @@ 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("is_existing_asset"): - conditions["is_existing_asset"] = filters.get("is_existing_asset") + 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"): conditions["asset_category"] = filters.get("asset_category") if filters.get("cost_center"): @@ -102,19 +104,18 @@ def get_data(filters): ] assets_record = frappe.db.get_all("Asset", filters=conditions, fields=fields) - assets_linked_to_fb = frappe.db.get_all( - doctype="Asset Finance Book", - filters={"finance_book": filters.finance_book or ("is", "not set")}, - pluck="parent", - ) + assets_linked_to_fb = None + + if filters.only_depreciable_assets: + assets_linked_to_fb = frappe.db.get_all( + doctype="Asset Finance Book", + filters={"finance_book": filters.finance_book or ("is", "not set")}, + pluck="parent", + ) for asset in assets_record: - if filters.finance_book: - if asset.asset_id not in assets_linked_to_fb: - continue - else: - if asset.calculate_depreciation and asset.asset_id not in assets_linked_to_fb: - continue + if assets_linked_to_fb and asset.asset_id not in assets_linked_to_fb: + continue asset_value = get_asset_value_after_depreciation(asset.asset_id, filters.finance_book) row = { @@ -172,11 +173,11 @@ def prepare_chart_data(data, filters): "datasets": [ { "name": _("Asset Value"), - "values": [d.get("asset_value") for d in labels_values_map.values()], + "values": [flt(d.get("asset_value"), 2) for d in labels_values_map.values()], }, { "name": _("Depreciatied Amount"), - "values": [d.get("depreciated_amount") for d in labels_values_map.values()], + "values": [flt(d.get("depreciated_amount"), 2) for d in labels_values_map.values()], }, ], }, @@ -312,7 +313,7 @@ def get_columns(filters): return [ { - "label": _("Asset Id"), + "label": _("Asset ID"), "fieldtype": "Link", "fieldname": "asset_id", "options": "Asset", From 6851b5ba974a3460fca7af2e66440f64f6361223 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Tue, 11 Apr 2023 13:24:43 +0530 Subject: [PATCH 02/15] fix: reposting record not created for backdated stock reco --- .../stock_reconciliation.py | 16 +++- .../test_stock_reconciliation.py | 73 +++++++++++++++++++ erpnext/stock/stock_ledger.py | 1 + 3 files changed, 87 insertions(+), 3 deletions(-) diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py index 482b103d1e..e304bd1819 100644 --- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py +++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py @@ -5,7 +5,7 @@ from typing import Optional import frappe from frappe import _, bold, msgprint -from frappe.query_builder.functions import Sum +from frappe.query_builder.functions import CombineDatetime, Sum from frappe.utils import cint, cstr, flt import erpnext @@ -575,7 +575,9 @@ class StockReconciliation(StockController): if not (row.item_code == item_code and row.batch_no == batch_no): continue - row.current_qty = get_batch_qty_for_stock_reco(item_code, row.warehouse, batch_no) + row.current_qty = get_batch_qty_for_stock_reco( + item_code, row.warehouse, batch_no, self.posting_date, self.posting_time, self.name + ) qty, val_rate = get_stock_balance( item_code, @@ -596,7 +598,9 @@ class StockReconciliation(StockController): ) -def get_batch_qty_for_stock_reco(item_code, warehouse, batch_no): +def get_batch_qty_for_stock_reco( + item_code, warehouse, batch_no, posting_date, posting_time, voucher_no +): ledger = frappe.qb.DocType("Stock Ledger Entry") query = ( @@ -610,6 +614,12 @@ def get_batch_qty_for_stock_reco(item_code, warehouse, batch_no): & (ledger.docstatus == 1) & (ledger.is_cancelled == 0) & (ledger.batch_no == batch_no) + & (ledger.posting_date <= posting_date) + & ( + CombineDatetime(ledger.posting_date, ledger.posting_time) + <= CombineDatetime(posting_date, posting_time) + ) + & (ledger.voucher_no != voucher_no) ) .groupby(ledger.batch_no) ) diff --git a/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py index eaea301432..7d59441d8b 100644 --- a/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py +++ b/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py @@ -676,6 +676,79 @@ class TestStockReconciliation(FrappeTestCase, StockTestMixin): self.assertEqual(flt(sl_entry.actual_qty), 1.0) self.assertEqual(flt(sl_entry.qty_after_transaction), 1.0) + def test_backdated_stock_reco_entry(self): + from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry + + item_code = self.make_item( + "Test New Batch Item ABCV", + { + "is_stock_item": 1, + "has_batch_no": 1, + "batch_number_series": "BNS9.####", + "create_new_batch": 1, + }, + ).name + + warehouse = "_Test Warehouse - _TC" + + # Added 100 Qty, Balace Qty 100 + se1 = make_stock_entry( + item_code=item_code, posting_time="09:00:00", target=warehouse, qty=100, basic_rate=700 + ) + + # Removed 50 Qty, Balace Qty 50 + se2 = make_stock_entry( + item_code=item_code, + batch_no=se1.items[0].batch_no, + posting_time="10:00:00", + source=warehouse, + qty=50, + basic_rate=700, + ) + + # Stock Reco for 100, Balace Qty 100 + stock_reco = create_stock_reconciliation( + item_code=item_code, + posting_time="11:00:00", + warehouse=warehouse, + batch_no=se1.items[0].batch_no, + qty=100, + rate=100, + ) + + # Removed 50 Qty, Balace Qty 50 + make_stock_entry( + item_code=item_code, + batch_no=se1.items[0].batch_no, + posting_time="12:00:00", + source=warehouse, + qty=50, + basic_rate=700, + ) + + self.assertFalse(frappe.db.exists("Repost Item Valuation", {"voucher_no": stock_reco.name})) + + # Cancel the backdated Stock Entry se2, + # Since Stock Reco entry in the future the Balace Qty should remain as it's (50) + + se2.cancel() + + self.assertTrue(frappe.db.exists("Repost Item Valuation", {"voucher_no": stock_reco.name})) + + self.assertEqual( + frappe.db.get_value("Repost Item Valuation", {"voucher_no": stock_reco.name}, "status"), + "Completed", + ) + + sle = frappe.get_all( + "Stock Ledger Entry", + filters={"item_code": item_code, "warehouse": warehouse, "is_cancelled": 0}, + fields=["qty_after_transaction"], + order_by="posting_time desc, creation desc", + ) + + self.assertEqual(flt(sle[0].qty_after_transaction), flt(50.0)) + def create_batch_item_with_batch(item_name, batch_id): batch_item_doc = create_item(item_name, is_stock_item=1) diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py index c954befdc2..b0a093def4 100644 --- a/erpnext/stock/stock_ledger.py +++ b/erpnext/stock/stock_ledger.py @@ -1375,6 +1375,7 @@ def regenerate_sle_for_batch_stock_reco(detail): doc.recalculate_current_qty(detail.item_code, detail.batch_no) doc.docstatus = 1 doc.update_stock_ledger() + doc.repost_future_sle_and_gle() def get_stock_reco_qty_shift(args): From aa8b241d5a7767911c585bd244c60b6fafbf0f30 Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Tue, 11 Apr 2023 15:46:47 +0530 Subject: [PATCH 03/15] chore: update CODEOWNERS [skip ci] --- CODEOWNERS | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index c4ea16328e..7f8c4d1ac8 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -3,13 +3,13 @@ # These owners will be the default owners for everything in # the repo. Unless a later match takes precedence, -erpnext/accounts/ @nextchamp-saqib @deepeshgarg007 @ruthra-kumar +erpnext/accounts/ @deepeshgarg007 @ruthra-kumar erpnext/assets/ @anandbaburajan @deepeshgarg007 -erpnext/loan_management/ @nextchamp-saqib @deepeshgarg007 -erpnext/regional @nextchamp-saqib @deepeshgarg007 @ruthra-kumar -erpnext/selling @nextchamp-saqib @deepeshgarg007 @ruthra-kumar -erpnext/support/ @nextchamp-saqib @deepeshgarg007 -pos* @nextchamp-saqib +erpnext/loan_management/ @deepeshgarg007 +erpnext/regional @deepeshgarg007 @ruthra-kumar +erpnext/selling @deepeshgarg007 @ruthra-kumar +erpnext/support/ @deepeshgarg007 +pos* erpnext/buying/ @rohitwaghchaure @s-aga-r erpnext/maintenance/ @rohitwaghchaure @s-aga-r @@ -18,12 +18,8 @@ erpnext/quality_management/ @rohitwaghchaure @s-aga-r erpnext/stock/ @rohitwaghchaure @s-aga-r erpnext/subcontracting @rohitwaghchaure @s-aga-r -erpnext/crm/ @NagariaHussain -erpnext/education/ @rutwikhdev -erpnext/projects/ @ruchamahabal +erpnext/controllers/ @deepeshgarg007 @rohitwaghchaure +erpnext/patches/ @deepeshgarg007 -erpnext/controllers/ @deepeshgarg007 @nextchamp-saqib @rohitwaghchaure -erpnext/patches/ @deepeshgarg007 @nextchamp-saqib - -.github/ @ankush +.github/ @deepeshgarg007 pyproject.toml @ankush From 66130493ebb7bc5d4fa69f5fd96cd3cebcbacb21 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Fri, 14 Apr 2023 09:47:15 +0530 Subject: [PATCH 04/15] fix: Remove unnecessary checkbox from Accounts doctype (#34821) --- erpnext/accounts/doctype/account/account.json | 88 +++++-------------- .../journal_entry/test_journal_entry.py | 4 - .../general_ledger/test_general_ledger.py | 1 - 3 files changed, 20 insertions(+), 73 deletions(-) diff --git a/erpnext/accounts/doctype/account/account.json b/erpnext/accounts/doctype/account/account.json index d2659d429b..e79fb66062 100644 --- a/erpnext/accounts/doctype/account/account.json +++ b/erpnext/accounts/doctype/account/account.json @@ -18,7 +18,6 @@ "root_type", "report_type", "account_currency", - "inter_company_account", "column_break1", "parent_account", "account_type", @@ -34,15 +33,11 @@ { "fieldname": "properties", "fieldtype": "Section Break", - "oldfieldtype": "Section Break", - "show_days": 1, - "show_seconds": 1 + "oldfieldtype": "Section Break" }, { "fieldname": "column_break0", "fieldtype": "Column Break", - "show_days": 1, - "show_seconds": 1, "width": "50%" }, { @@ -53,9 +48,7 @@ "no_copy": 1, "oldfieldname": "account_name", "oldfieldtype": "Data", - "reqd": 1, - "show_days": 1, - "show_seconds": 1 + "reqd": 1 }, { "fieldname": "account_number", @@ -63,17 +56,13 @@ "in_list_view": 1, "in_standard_filter": 1, "label": "Account Number", - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "default": "0", "fieldname": "is_group", "fieldtype": "Check", - "label": "Is Group", - "show_days": 1, - "show_seconds": 1 + "label": "Is Group" }, { "fieldname": "company", @@ -85,9 +74,7 @@ "options": "Company", "read_only": 1, "remember_last_selected_value": 1, - "reqd": 1, - "show_days": 1, - "show_seconds": 1 + "reqd": 1 }, { "fieldname": "root_type", @@ -95,9 +82,7 @@ "in_standard_filter": 1, "label": "Root Type", "options": "\nAsset\nLiability\nIncome\nExpense\nEquity", - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "report_type", @@ -105,32 +90,18 @@ "in_standard_filter": 1, "label": "Report Type", "options": "\nBalance Sheet\nProfit and Loss", - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "depends_on": "eval:doc.is_group==0", "fieldname": "account_currency", "fieldtype": "Link", "label": "Currency", - "options": "Currency", - "show_days": 1, - "show_seconds": 1 - }, - { - "default": "0", - "fieldname": "inter_company_account", - "fieldtype": "Check", - "label": "Inter Company Account", - "show_days": 1, - "show_seconds": 1 + "options": "Currency" }, { "fieldname": "column_break1", "fieldtype": "Column Break", - "show_days": 1, - "show_seconds": 1, "width": "50%" }, { @@ -142,9 +113,7 @@ "oldfieldtype": "Link", "options": "Account", "reqd": 1, - "search_index": 1, - "show_days": 1, - "show_seconds": 1 + "search_index": 1 }, { "description": "Setting Account Type helps in selecting this Account in transactions.", @@ -154,9 +123,7 @@ "label": "Account Type", "oldfieldname": "account_type", "oldfieldtype": "Select", - "options": "\nAccumulated Depreciation\nAsset Received But Not Billed\nBank\nCash\nChargeable\nCapital Work in Progress\nCost of Goods Sold\nDepreciation\nEquity\nExpense Account\nExpenses Included In Asset Valuation\nExpenses Included In Valuation\nFixed Asset\nIncome Account\nPayable\nReceivable\nRound Off\nStock\nStock Adjustment\nStock Received But Not Billed\nService Received But Not Billed\nTax\nTemporary", - "show_days": 1, - "show_seconds": 1 + "options": "\nAccumulated Depreciation\nAsset Received But Not Billed\nBank\nCash\nChargeable\nCapital Work in Progress\nCost of Goods Sold\nDepreciation\nEquity\nExpense Account\nExpenses Included In Asset Valuation\nExpenses Included In Valuation\nFixed Asset\nIncome Account\nPayable\nReceivable\nRound Off\nStock\nStock Adjustment\nStock Received But Not Billed\nService Received But Not Billed\nTax\nTemporary" }, { "description": "Rate at which this tax is applied", @@ -164,9 +131,7 @@ "fieldtype": "Float", "label": "Rate", "oldfieldname": "tax_rate", - "oldfieldtype": "Currency", - "show_days": 1, - "show_seconds": 1 + "oldfieldtype": "Currency" }, { "description": "If the account is frozen, entries are allowed to restricted users.", @@ -175,17 +140,13 @@ "label": "Frozen", "oldfieldname": "freeze_account", "oldfieldtype": "Select", - "options": "No\nYes", - "show_days": 1, - "show_seconds": 1 + "options": "No\nYes" }, { "fieldname": "balance_must_be", "fieldtype": "Select", "label": "Balance must be", - "options": "\nDebit\nCredit", - "show_days": 1, - "show_seconds": 1 + "options": "\nDebit\nCredit" }, { "fieldname": "lft", @@ -194,9 +155,7 @@ "label": "Lft", "print_hide": 1, "read_only": 1, - "search_index": 1, - "show_days": 1, - "show_seconds": 1 + "search_index": 1 }, { "fieldname": "rgt", @@ -205,9 +164,7 @@ "label": "Rgt", "print_hide": 1, "read_only": 1, - "search_index": 1, - "show_days": 1, - "show_seconds": 1 + "search_index": 1 }, { "fieldname": "old_parent", @@ -215,33 +172,27 @@ "hidden": 1, "label": "Old Parent", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "default": "0", "depends_on": "eval:(doc.report_type == 'Profit and Loss' && !doc.is_group)", "fieldname": "include_in_gross", "fieldtype": "Check", - "label": "Include in gross", - "show_days": 1, - "show_seconds": 1 + "label": "Include in gross" }, { "default": "0", "fieldname": "disabled", "fieldtype": "Check", - "label": "Disable", - "show_days": 1, - "show_seconds": 1 + "label": "Disable" } ], "icon": "fa fa-money", "idx": 1, "is_tree": 1, "links": [], - "modified": "2020-06-11 15:15:54.338622", + "modified": "2023-04-11 16:08:46.983677", "modified_by": "Administrator", "module": "Accounts", "name": "Account", @@ -301,5 +252,6 @@ "show_name_in_global_search": 1, "sort_field": "modified", "sort_order": "ASC", + "states": [], "track_changes": 1 } \ No newline at end of file diff --git a/erpnext/accounts/doctype/journal_entry/test_journal_entry.py b/erpnext/accounts/doctype/journal_entry/test_journal_entry.py index 2cc5378e92..f7297d19e0 100644 --- a/erpnext/accounts/doctype/journal_entry/test_journal_entry.py +++ b/erpnext/accounts/doctype/journal_entry/test_journal_entry.py @@ -287,10 +287,6 @@ class TestJournalEntry(unittest.TestCase): jv.submit() def test_inter_company_jv(self): - frappe.db.set_value("Account", "Sales Expenses - _TC", "inter_company_account", 1) - frappe.db.set_value("Account", "Buildings - _TC", "inter_company_account", 1) - frappe.db.set_value("Account", "Sales Expenses - _TC1", "inter_company_account", 1) - frappe.db.set_value("Account", "Buildings - _TC1", "inter_company_account", 1) jv = make_journal_entry( "Sales Expenses - _TC", "Buildings - _TC", diff --git a/erpnext/accounts/report/general_ledger/test_general_ledger.py b/erpnext/accounts/report/general_ledger/test_general_ledger.py index c563785763..a8c362e78c 100644 --- a/erpnext/accounts/report/general_ledger/test_general_ledger.py +++ b/erpnext/accounts/report/general_ledger/test_general_ledger.py @@ -24,7 +24,6 @@ class TestGeneralLedger(FrappeTestCase): "root_type": "Asset", "report_type": "Balance Sheet", "account_currency": "USD", - "inter_company_account": 0, "parent_account": "Bank Accounts - _TC", "account_type": "Bank", "doctype": "Account", From a7051cb9b59d3f86670a2cb5968af9585a083ab9 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Fri, 14 Apr 2023 09:59:42 +0530 Subject: [PATCH 05/15] fix: Don't use stale item details (#34847) --- erpnext/controllers/accounts_controller.py | 13 +------------ erpnext/stock/get_item_details.py | 22 +++------------------- 2 files changed, 4 insertions(+), 31 deletions(-) diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index a347323e35..7fcc28bac3 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -515,7 +515,6 @@ class AccountsController(TransactionBase): parent_dict.update({"customer": parent_dict.get("party_name")}) self.pricing_rules = [] - basic_item_details_map = {} for item in self.get("items"): if item.get("item_code"): @@ -535,17 +534,7 @@ class AccountsController(TransactionBase): if self.get("is_subcontracted"): args["is_subcontracted"] = self.is_subcontracted - basic_details = basic_item_details_map.get(item.item_code) - ret, basic_item_details = get_item_details( - args, - self, - for_validate=True, - overwrite_warehouse=False, - return_basic_details=True, - basic_details=basic_details, - ) - - basic_item_details_map.setdefault(item.item_code, basic_item_details) + ret = get_item_details(args, self, for_validate=True, overwrite_warehouse=False) for fieldname, value in ret.items(): if item.meta.get_field(fieldname) and value is not None: diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index 2cf3797a36..ce85702f48 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -35,14 +35,7 @@ purchase_doctypes = [ @frappe.whitelist() -def get_item_details( - args, - doc=None, - for_validate=False, - overwrite_warehouse=True, - return_basic_details=False, - basic_details=None, -): +def get_item_details(args, doc=None, for_validate=False, overwrite_warehouse=True): """ args = { "item_code": "", @@ -80,12 +73,7 @@ def get_item_details( if doc.get("doctype") == "Purchase Invoice": args["bill_date"] = doc.get("bill_date") - if not basic_details: - out = get_basic_details(args, item, overwrite_warehouse) - else: - out = basic_details - - basic_details = out.copy() + out = get_basic_details(args, item, overwrite_warehouse) get_item_tax_template(args, item, out) out["item_tax_rate"] = get_item_tax_map( @@ -154,11 +142,7 @@ def get_item_details( out.amount = flt(args.qty) * flt(out.rate) out = remove_standard_fields(out) - - if return_basic_details: - return out, basic_details - else: - return out + return out def remove_standard_fields(details): From 9d1cae01bd7b9e33835d2d56b81b73d1ebfb45ef Mon Sep 17 00:00:00 2001 From: Wolfram Schmidt Date: Fri, 14 Apr 2023 09:05:09 +0200 Subject: [PATCH 06/15] fix allowing rename of Lead This is needed to consolidate data like merging leads together when duplicated appear. --- erpnext/crm/doctype/lead/lead.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/erpnext/crm/doctype/lead/lead.json b/erpnext/crm/doctype/lead/lead.json index 077e7fa4af..0cb8824577 100644 --- a/erpnext/crm/doctype/lead/lead.json +++ b/erpnext/crm/doctype/lead/lead.json @@ -2,6 +2,7 @@ "actions": [], "allow_events_in_timeline": 1, "allow_import": 1, + "allow_rename": 1, "autoname": "naming_series:", "creation": "2022-02-08 13:14:41.083327", "doctype": "DocType", @@ -515,7 +516,7 @@ "idx": 5, "image_field": "image", "links": [], - "modified": "2023-01-24 18:20:05.044791", + "modified": "2023-04-14 18:20:05.044791", "modified_by": "Administrator", "module": "CRM", "name": "Lead", @@ -582,4 +583,4 @@ "states": [], "subject_field": "title", "title_field": "title" -} \ No newline at end of file +} From 59f6b773cdb0eb0964c7b27123bb2e03cf447d93 Mon Sep 17 00:00:00 2001 From: Raffael Meyer <14891507+barredterra@users.noreply.github.com> Date: Fri, 14 Apr 2023 09:44:00 +0200 Subject: [PATCH 07/15] feat: add german sales tax template (#34823) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Nullsteuersatz nach § 12 Abs. 3 UStG --- .../setup_wizard/data/country_wise_tax.json | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/erpnext/setup/setup_wizard/data/country_wise_tax.json b/erpnext/setup/setup_wizard/data/country_wise_tax.json index 5750914b9a..3532d6b456 100644 --- a/erpnext/setup/setup_wizard/data/country_wise_tax.json +++ b/erpnext/setup/setup_wizard/data/country_wise_tax.json @@ -581,6 +581,11 @@ "title": "Bauleistungen nach § 13b UStG", "is_default": 0, "taxes": [] + }, + { + "title": "Nullsteuersatz nach § 12 Abs. 3 UStG", + "is_default": 0, + "taxes": [] } ], "purchase_tax_templates": [ @@ -1339,6 +1344,11 @@ "title": "Bauleistungen nach § 13b UStG", "is_default": 0, "taxes": [] + }, + { + "title": "Nullsteuersatz nach § 12 Abs. 3 UStG", + "is_default": 0, + "taxes": [] } ], "purchase_tax_templates": [ @@ -2097,6 +2107,11 @@ "title": "Bauleistungen nach § 13b UStG", "is_default": 0, "taxes": [] + }, + { + "title": "Nullsteuersatz nach § 12 Abs. 3 UStG", + "is_default": 0, + "taxes": [] } ], "purchase_tax_templates": [ @@ -2849,6 +2864,11 @@ "title": "Bauleistungen nach § 13b UStG", "is_default": 0, "taxes": [] + }, + { + "title": "Nullsteuersatz nach § 12 Abs. 3 UStG", + "is_default": 0, + "taxes": [] } ], "purchase_tax_templates": [ From 7bfc8f12367c14245682b32bb0853bbf044114c4 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Fri, 14 Apr 2023 12:22:19 +0530 Subject: [PATCH 08/15] fix: too many writes error while making backdated stock reconciliation --- .../stock_reconciliation.py | 26 ++++++++++++++----- erpnext/stock/stock_ledger.py | 24 +++++++++++++---- 2 files changed, 38 insertions(+), 12 deletions(-) diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py index e304bd1819..3fd4cec5d8 100644 --- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py +++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py @@ -571,24 +571,33 @@ class StockReconciliation(StockController): self._cancel() def recalculate_current_qty(self, item_code, batch_no): + from erpnext.stock.stock_ledger import get_valuation_rate + + sl_entries = [] for row in self.items: if not (row.item_code == item_code and row.batch_no == batch_no): continue - row.current_qty = get_batch_qty_for_stock_reco( + current_qty = get_batch_qty_for_stock_reco( item_code, row.warehouse, batch_no, self.posting_date, self.posting_time, self.name ) - qty, val_rate = get_stock_balance( - item_code, - row.warehouse, - self.posting_date, - self.posting_time, - with_valuation_rate=True, + precesion = row.precision("current_qty") + if flt(current_qty, precesion) == flt(row.current_qty, precesion): + continue + + val_rate = get_valuation_rate( + item_code, row.warehouse, self.doctype, self.name, company=self.company, batch_no=batch_no ) row.current_valuation_rate = val_rate + if not row.current_qty and current_qty: + sle = self.get_sle_for_items(row) + sle.actual_qty = current_qty * -1 + sle.valuation_rate = val_rate + sl_entries.append(sle) + row.current_qty = current_qty row.db_set( { "current_qty": row.current_qty, @@ -597,6 +606,9 @@ class StockReconciliation(StockController): } ) + if sl_entries: + self.make_sl_entries(sl_entries) + def get_batch_qty_for_stock_reco( item_code, warehouse, batch_no, posting_date, posting_time, voucher_no diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py index b0a093def4..a605b0c24a 100644 --- a/erpnext/stock/stock_ledger.py +++ b/erpnext/stock/stock_ledger.py @@ -544,6 +544,14 @@ class update_entries_after(object): if not self.args.get("sle_id"): self.get_dynamic_incoming_outgoing_rate(sle) + if ( + sle.voucher_type == "Stock Reconciliation" + and sle.batch_no + and sle.voucher_detail_no + and sle.actual_qty < 0 + ): + self.reset_actual_qty_for_stock_reco(sle) + if ( sle.voucher_type in ["Purchase Receipt", "Purchase Invoice"] and sle.voucher_detail_no @@ -605,6 +613,16 @@ class update_entries_after(object): if not self.args.get("sle_id"): self.update_outgoing_rate_on_transaction(sle) + def reset_actual_qty_for_stock_reco(self, sle): + current_qty = frappe.get_cached_value( + "Stock Reconciliation Item", sle.voucher_detail_no, "current_qty" + ) + + if current_qty: + sle.actual_qty = current_qty * -1 + elif current_qty == 0: + sle.is_cancelled = 1 + def validate_negative_stock(self, sle): """ validate negative stock for entries current datetime onwards @@ -1369,12 +1387,7 @@ def update_qty_in_future_sle(args, allow_negative_stock=False): def regenerate_sle_for_batch_stock_reco(detail): doc = frappe.get_cached_doc("Stock Reconciliation", detail.voucher_no) - doc.docstatus = 2 - doc.update_stock_ledger() - doc.recalculate_current_qty(detail.item_code, detail.batch_no) - doc.docstatus = 1 - doc.update_stock_ledger() doc.repost_future_sle_and_gle() @@ -1416,6 +1429,7 @@ def get_next_stock_reco(args): and voucher_type = 'Stock Reconciliation' and voucher_no != %(voucher_no)s and is_cancelled = 0 + and batch_no = %(batch_no)s and (timestamp(posting_date, posting_time) > timestamp(%(posting_date)s, %(posting_time)s) or ( timestamp(posting_date, posting_time) = timestamp(%(posting_date)s, %(posting_time)s) From 51c4338661817267e383b094ad802da4cfa87940 Mon Sep 17 00:00:00 2001 From: Devin Slauenwhite Date: Fri, 14 Apr 2023 05:50:51 -0400 Subject: [PATCH 09/15] fix(ux): don't throw error when company defaults aren't set (#34825) * fix(ux): don't throw error when company defaults aren't set; instead prompt account input. * fix: translate label and title --- .../doctype/payment_entry/payment_entry.js | 52 +++++++++++++------ .../doctype/payment_entry/payment_entry.py | 12 +---- 2 files changed, 36 insertions(+), 28 deletions(-) diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.js b/erpnext/accounts/doctype/payment_entry/payment_entry.js index f8969b8b46..ed6d0a710a 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.js +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.js @@ -970,29 +970,47 @@ frappe.ui.form.on('Payment Entry', { }, callback: function(r, rt) { if(r.message) { - var write_off_row = $.map(frm.doc["deductions"] || [], function(t) { + const write_off_row = $.map(frm.doc["deductions"] || [], function(t) { return t.account==r.message[account] ? t : null; }); - var row = []; - - var difference_amount = flt(frm.doc.difference_amount, + const difference_amount = flt(frm.doc.difference_amount, precision("difference_amount")); - if (!write_off_row.length && difference_amount) { - row = frm.add_child("deductions"); - row.account = r.message[account]; - row.cost_center = r.message["cost_center"]; - } else { - row = write_off_row[0]; - } + const add_deductions = (details) => { + if (!write_off_row.length && difference_amount) { + row = frm.add_child("deductions"); + row.account = details[account]; + row.cost_center = details["cost_center"]; + } else { + row = write_off_row[0]; + } - if (row) { - row.amount = flt(row.amount) + difference_amount; - } else { - frappe.msgprint(__("No gain or loss in the exchange rate")) - } + if (row) { + row.amount = flt(row.amount) + difference_amount; + } else { + frappe.msgprint(__("No gain or loss in the exchange rate")) + } + refresh_field("deductions"); + }; - refresh_field("deductions"); + if (!r.message[account]) { + frappe.prompt({ + label: __("Please Specify Account"), + fieldname: account, + fieldtype: "Link", + options: "Account", + get_query: () => ({ + filters: { + company: frm.doc.company, + } + }) + }, (values) => { + const details = Object.assign({}, r.message, values); + add_deductions(details); + }, __(frappe.unscrub(account))); + } else { + add_deductions(r.message); + } frm.events.set_unallocated_amount(frm); } diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py index c34bddd77e..f8a2653759 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py @@ -1594,17 +1594,7 @@ def get_account_details(account, date, cost_center=None): @frappe.whitelist() def get_company_defaults(company): fields = ["write_off_account", "exchange_gain_loss_account", "cost_center"] - ret = frappe.get_cached_value("Company", company, fields, as_dict=1) - - for fieldname in fields: - if not ret[fieldname]: - frappe.throw( - _("Please set default {0} in Company {1}").format( - frappe.get_meta("Company").get_label(fieldname), company - ) - ) - - return ret + return frappe.get_cached_value("Company", company, fields, as_dict=1) def get_outstanding_on_journal_entry(name): From fb3271c6249d647c2add2a83c06cbbb879762b81 Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Fri, 14 Apr 2023 15:59:35 +0530 Subject: [PATCH 10/15] fix: unable to change `company` for manual `Serial No` entry --- erpnext/stock/doctype/serial_no/serial_no.json | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/erpnext/stock/doctype/serial_no/serial_no.json b/erpnext/stock/doctype/serial_no/serial_no.json index 6e1e0d461a..7989b1ac75 100644 --- a/erpnext/stock/doctype/serial_no/serial_no.json +++ b/erpnext/stock/doctype/serial_no/serial_no.json @@ -410,10 +410,10 @@ "fieldtype": "Link", "label": "Company", "options": "Company", - "read_only": 1, "remember_last_selected_value": 1, "reqd": 1, - "search_index": 1 + "search_index": 1, + "set_only_once": 1 }, { "fieldname": "status", @@ -433,7 +433,7 @@ "icon": "fa fa-barcode", "idx": 1, "links": [], - "modified": "2021-12-23 10:44:30.299450", + "modified": "2023-04-14 15:58:46.139887", "modified_by": "Administrator", "module": "Stock", "name": "Serial No", @@ -461,7 +461,6 @@ "read": 1, "report": 1, "role": "Stock Manager", - "set_user_permissions": 1, "write": 1 }, { From 5a4dd354c1662db7a7c2ed7312a04833a4822223 Mon Sep 17 00:00:00 2001 From: Shariq Ansari Date: Sun, 16 Apr 2023 13:10:42 +0530 Subject: [PATCH 11/15] fix: selling workspace is not migrating properly --- erpnext/selling/workspace/selling/selling.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/selling/workspace/selling/selling.json b/erpnext/selling/workspace/selling/selling.json index 45e160d143..180a3d783e 100644 --- a/erpnext/selling/workspace/selling/selling.json +++ b/erpnext/selling/workspace/selling/selling.json @@ -704,7 +704,7 @@ "type": "Link" } ], - "modified": "2022-04-26 13:29:55.087240", + "modified": "2023-04-16 13:29:55.087240", "modified_by": "Administrator", "module": "Selling", "name": "Selling", From 5c75894065cd0d20be33eeed43a8f0d6e9ed3656 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Sun, 16 Apr 2023 17:11:24 +0530 Subject: [PATCH 12/15] fix: Advance payment against payment terms (#34872) --- .../accounts_settings/accounts_settings.json | 3 +- .../doctype/payment_entry/payment_entry.py | 7 +++- erpnext/controllers/accounts_controller.py | 34 +++++++++++-------- erpnext/public/js/controllers/transaction.js | 4 +-- 4 files changed, 30 insertions(+), 18 deletions(-) diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json index c0eed18ad1..5cecddd2a9 100644 --- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json +++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json @@ -184,6 +184,7 @@ }, { "default": "0", + "description": "Payment Terms from orders will be fetched into the invoices as is", "fieldname": "automatically_fetch_payment_terms", "fieldtype": "Check", "label": "Automatically Fetch Payment Terms from Order" @@ -375,7 +376,7 @@ "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2023-03-28 09:50:20.375233", + "modified": "2023-04-14 17:22:03.680886", "modified_by": "Administrator", "module": "Accounts", "name": "Accounts Settings", diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py index f8a2653759..3583dc7a90 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py @@ -1754,7 +1754,12 @@ def get_payment_entry( if doc.doctype == "Purchase Invoice" and doc.invoice_is_blocked(): frappe.msgprint(_("{0} is on hold till {1}").format(doc.name, doc.release_date)) else: - if doc.doctype in ("Sales Invoice", "Purchase Invoice") and frappe.get_cached_value( + if doc.doctype in ( + "Sales Invoice", + "Purchase Invoice", + "Purchase Order", + "Sales Order", + ) and frappe.get_cached_value( "Payment Terms Template", doc.payment_terms_template, "allocate_payment_based_on_payment_terms", diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index 7fcc28bac3..c7416228ee 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -273,8 +273,8 @@ class AccountsController(TransactionBase): self.validate_payment_schedule_dates() self.set_due_date() self.set_payment_schedule() - self.validate_payment_schedule_amount() if not self.get("ignore_default_payment_terms_template"): + self.validate_payment_schedule_amount() self.validate_due_date() self.validate_advance_entries() @@ -1607,6 +1607,7 @@ class AccountsController(TransactionBase): base_grand_total = self.get("base_rounded_total") or self.base_grand_total grand_total = self.get("rounded_total") or self.grand_total + automatically_fetch_payment_terms = 0 if self.doctype in ("Sales Invoice", "Purchase Invoice"): base_grand_total = base_grand_total - flt(self.base_write_off_amount) @@ -1652,19 +1653,20 @@ class AccountsController(TransactionBase): ) self.append("payment_schedule", data) - for d in self.get("payment_schedule"): - if d.invoice_portion: - d.payment_amount = flt( - grand_total * flt(d.invoice_portion / 100), d.precision("payment_amount") - ) - d.base_payment_amount = flt( - base_grand_total * flt(d.invoice_portion / 100), d.precision("base_payment_amount") - ) - d.outstanding = d.payment_amount - elif not d.invoice_portion: - d.base_payment_amount = flt( - d.payment_amount * self.get("conversion_rate"), d.precision("base_payment_amount") - ) + if not automatically_fetch_payment_terms: + for d in self.get("payment_schedule"): + if d.invoice_portion: + d.payment_amount = flt( + grand_total * flt(d.invoice_portion / 100), d.precision("payment_amount") + ) + d.base_payment_amount = flt( + base_grand_total * flt(d.invoice_portion / 100), d.precision("base_payment_amount") + ) + d.outstanding = d.payment_amount + elif not d.invoice_portion: + d.base_payment_amount = flt( + d.payment_amount * self.get("conversion_rate"), d.precision("base_payment_amount") + ) def get_order_details(self): if self.doctype == "Sales Invoice": @@ -1717,6 +1719,10 @@ class AccountsController(TransactionBase): "invoice_portion": schedule.invoice_portion, "mode_of_payment": schedule.mode_of_payment, "description": schedule.description, + "payment_amount": schedule.payment_amount, + "base_payment_amount": schedule.base_payment_amount, + "outstanding": schedule.outstanding, + "paid_amount": schedule.paid_amount, } if schedule.discount_type == "Percentage": diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index 0bd4d91c6f..1675e2c963 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -1920,7 +1920,7 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe } prompt_user_for_reference_date(){ - var me = this; + let me = this; frappe.prompt({ label: __("Cheque/Reference Date"), fieldname: "reference_date", @@ -1947,7 +1947,7 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe let has_payment_schedule = this.frm.doc.payment_schedule && this.frm.doc.payment_schedule.length; if(!is_eligible || !has_payment_schedule) return false; - let has_discount = this.frm.doc.payment_schedule.some(row => row.discount_date); + let has_discount = this.frm.doc.payment_schedule.some(row => row.discount); return has_discount; } From d9dd64b4d2fcce9ffb6d2f21b5a9f56c39580b02 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Fri, 14 Apr 2023 13:00:12 +0530 Subject: [PATCH 13/15] fix: linters issues --- erpnext/controllers/stock_controller.py | 13 ++++-- erpnext/stock/stock_ledger.py | 61 +++++++++++++++---------- 2 files changed, 47 insertions(+), 27 deletions(-) diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index 1e4fabe0d2..479fef72c6 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -859,6 +859,8 @@ def is_reposting_pending(): def future_sle_exists(args, sl_entries=None): key = (args.voucher_type, args.voucher_no) + if not hasattr(frappe.local, "future_sle"): + frappe.local.future_sle = {} if validate_future_sle_not_exists(args, key, sl_entries): return False @@ -892,6 +894,9 @@ def future_sle_exists(args, sl_entries=None): ) for d in data: + if key not in frappe.local.future_sle: + frappe.local.future_sle[key] = frappe._dict({}) + frappe.local.future_sle[key][(d.item_code, d.warehouse)] = d.total_row return len(data) @@ -903,6 +908,9 @@ def validate_future_sle_not_exists(args, key, sl_entries=None): item_key = (args.get("item_code"), args.get("warehouse")) if not sl_entries and hasattr(frappe.local, "future_sle"): + if key not in frappe.local.future_sle: + return False + if not frappe.local.future_sle.get(key) or ( item_key and item_key not in frappe.local.future_sle.get(key) ): @@ -910,11 +918,8 @@ def validate_future_sle_not_exists(args, key, sl_entries=None): def get_cached_data(args, key): - if not hasattr(frappe.local, "future_sle"): - frappe.local.future_sle = {} - if key not in frappe.local.future_sle: - frappe.local.future_sle[key] = frappe._dict({}) + return False if args.get("item_code"): item_key = (args.get("item_code"), args.get("warehouse")) diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py index a605b0c24a..03c04a54ad 100644 --- a/erpnext/stock/stock_ledger.py +++ b/erpnext/stock/stock_ledger.py @@ -1414,35 +1414,50 @@ def get_stock_reco_qty_shift(args): return stock_reco_qty_shift -def get_next_stock_reco(args): +def get_next_stock_reco(kwargs): """Returns next nearest stock reconciliaton's details.""" - return frappe.db.sql( - """ - select - name, posting_date, posting_time, creation, voucher_no, item_code, batch_no, actual_qty - from - `tabStock Ledger Entry` - where - item_code = %(item_code)s - and warehouse = %(warehouse)s - and voucher_type = 'Stock Reconciliation' - and voucher_no != %(voucher_no)s - and is_cancelled = 0 - and batch_no = %(batch_no)s - and (timestamp(posting_date, posting_time) > timestamp(%(posting_date)s, %(posting_time)s) - or ( - timestamp(posting_date, posting_time) = timestamp(%(posting_date)s, %(posting_time)s) - and creation > %(creation)s + sle = frappe.qb.DocType("Stock Ledger Entry") + + query = ( + frappe.qb.from_(sle) + .select( + sle.name, + sle.posting_date, + sle.posting_time, + sle.creation, + sle.voucher_no, + sle.item_code, + sle.batch_no, + sle.actual_qty, + ) + .where( + (sle.item_code == kwargs.get("item_code")) + & (sle.warehouse == kwargs.get("warehouse")) + & (sle.voucher_type == "Stock Reconciliation") + & (sle.voucher_no != kwargs.get("voucher_no")) + & (sle.is_cancelled == 0) + & ( + ( + CombineDatetime(sle.posting_date, sle.posting_time) + > CombineDatetime(kwargs.get("posting_date"), kwargs.get("posting_time")) + | ( + ( + CombineDatetime(sle.posting_date, sle.posting_time) + == CombineDatetime(kwargs.get("posting_date"), kwargs.get("posting_time")) + ) + & (sle.creation > kwargs.get("creation")) + ) ) ) - order by timestamp(posting_date, posting_time) asc, creation asc - limit 1 - """, - args, - as_dict=1, + ) ) + if kwargs.get("batch_no"): + query.where(sle.batch_no == kwargs.get("batch_no")) + + return query.run(as_dict=True) + def get_datetime_limit_condition(detail): return f""" From 9ceb1f6bda093061c7f8d70d6ab169258d4815a9 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Mon, 17 Apr 2023 11:05:32 +0530 Subject: [PATCH 14/15] fix: don't show disabled warehouses in the Warehouse Wise Stock Balance report --- .../warehouse_wise_stock_balance.js | 7 +++++ .../warehouse_wise_stock_balance.py | 27 +++++++++++++++---- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/erpnext/stock/report/warehouse_wise_stock_balance/warehouse_wise_stock_balance.js b/erpnext/stock/report/warehouse_wise_stock_balance/warehouse_wise_stock_balance.js index 58a043ec20..752e464e27 100644 --- a/erpnext/stock/report/warehouse_wise_stock_balance/warehouse_wise_stock_balance.js +++ b/erpnext/stock/report/warehouse_wise_stock_balance/warehouse_wise_stock_balance.js @@ -11,6 +11,13 @@ frappe.query_reports["Warehouse Wise Stock Balance"] = { "options": "Company", "reqd": 1, "default": frappe.defaults.get_user_default("Company") + }, + { + "fieldname":"show_disabled_warehouses", + "label": __("Show Disabled Warehouses"), + "fieldtype": "Check", + "default": 0 + } ], "initial_depth": 3, diff --git a/erpnext/stock/report/warehouse_wise_stock_balance/warehouse_wise_stock_balance.py b/erpnext/stock/report/warehouse_wise_stock_balance/warehouse_wise_stock_balance.py index d364b577a2..a0e994482f 100644 --- a/erpnext/stock/report/warehouse_wise_stock_balance/warehouse_wise_stock_balance.py +++ b/erpnext/stock/report/warehouse_wise_stock_balance/warehouse_wise_stock_balance.py @@ -11,6 +11,7 @@ from frappe.query_builder.functions import Sum class StockBalanceFilter(TypedDict): company: Optional[str] warehouse: Optional[str] + show_disabled_warehouses: Optional[int] SLEntry = Dict[str, Any] @@ -18,7 +19,7 @@ SLEntry = Dict[str, Any] def execute(filters=None): columns, data = [], [] - columns = get_columns() + columns = get_columns(filters) data = get_data(filters) return columns, data @@ -42,10 +43,14 @@ def get_warehouse_wise_balance(filters: StockBalanceFilter) -> List[SLEntry]: def get_warehouses(report_filters: StockBalanceFilter): + filters = {"company": report_filters.company, "disabled": 0} + if report_filters.get("show_disabled_warehouses"): + filters["disabled"] = ("in", [0, report_filters.show_disabled_warehouses]) + return frappe.get_all( "Warehouse", - fields=["name", "parent_warehouse", "is_group"], - filters={"company": report_filters.company}, + fields=["name", "parent_warehouse", "is_group", "disabled"], + filters=filters, order_by="lft", ) @@ -90,8 +95,8 @@ def set_balance_in_parent(warehouses): update_balance(warehouse, warehouse.stock_balance) -def get_columns(): - return [ +def get_columns(filters: StockBalanceFilter) -> List[Dict]: + columns = [ { "label": _("Warehouse"), "fieldname": "name", @@ -101,3 +106,15 @@ def get_columns(): }, {"label": _("Stock Balance"), "fieldname": "stock_balance", "fieldtype": "Float", "width": 150}, ] + + if filters.get("show_disabled_warehouses"): + columns.append( + { + "label": _("Warehouse Disabled?"), + "fieldname": "disabled", + "fieldtype": "Check", + "width": 200, + } + ) + + return columns From 6bccd8644e99b3750d643a7d98ee75e2f79cef9a Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Mon, 17 Apr 2023 14:22:27 +0530 Subject: [PATCH 15/15] fix: stock reco test case --- erpnext/stock/stock_ledger.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py index 03c04a54ad..b638f08ed9 100644 --- a/erpnext/stock/stock_ledger.py +++ b/erpnext/stock/stock_ledger.py @@ -1451,6 +1451,8 @@ def get_next_stock_reco(kwargs): ) ) ) + .orderby(CombineDatetime(sle.posting_date, sle.posting_time)) + .orderby(sle.creation) ) if kwargs.get("batch_no"):