From 7b878ea3d8f2a1da6c8bd9d4994e638c630e59ba Mon Sep 17 00:00:00 2001 From: Sagar Sharma Date: Tue, 13 Sep 2022 21:52:58 +0530 Subject: [PATCH 01/11] fix: unknown column error while updating value of maintain-stock in item master --- erpnext/stock/doctype/item/item.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py index 87fa72d74f..143fe408c3 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -945,7 +945,12 @@ class Item(Document): if doctype == "Product Bundle": filters = {"new_item_code": self.name} - if doctype in ( + if linked_doc := frappe.db.get_value( + doctype, filters, ["new_item_code as docname"], as_dict=True + ): + return linked_doc.update({"doctype": doctype}) + + elif doctype in ( "Purchase Invoice Item", "Sales Invoice Item", ): From bf1fa014f472e4b614c0b18fab9a72277fa147a2 Mon Sep 17 00:00:00 2001 From: Sagar Sharma Date: Tue, 13 Sep 2022 22:12:56 +0530 Subject: [PATCH 02/11] test: add test case for item master maintain-stock --- erpnext/stock/doctype/item/test_item.py | 30 +++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/erpnext/stock/doctype/item/test_item.py b/erpnext/stock/doctype/item/test_item.py index 89da72195f..1cee553be5 100644 --- a/erpnext/stock/doctype/item/test_item.py +++ b/erpnext/stock/doctype/item/test_item.py @@ -786,6 +786,36 @@ class TestItem(FrappeTestCase): item.save() self.assertTrue(len(item.customer_code) > 140) + def test_update_is_stock_item(self): + # Step - 1: Create an Item with Maintain Stock enabled + item = make_item(properties={"is_stock_item": 1}) + + # Step - 2: Disable Maintain Stock + item.is_stock_item = 0 + item.save() + item.reload() + self.assertEqual(item.is_stock_item, 0) + + # Step - 3: Create Product Bundle + pb = frappe.new_doc("Product Bundle") + pb.new_item_code = item.name + pb.flags.ignore_mandatory = True + pb.save() + + # Step - 4: Try to enable Maintain Stock, should throw a validation error + item.is_stock_item = 1 + self.assertRaises(frappe.ValidationError, item.save) + item.reload() + + # Step - 5: Delete Product Bundle + pb.delete() + + # Step - 6: Again try to enable Maintain Stock + item.is_stock_item = 1 + item.save() + item.reload() + self.assertEqual(item.is_stock_item, 1) + def set_item_variant_settings(fields): doc = frappe.get_doc("Item Variant Settings") From f2209045f8e0deceaa4e743c40ac2fe037d85e3a Mon Sep 17 00:00:00 2001 From: Abhinav Raut Date: Wed, 14 Sep 2022 11:55:03 +0530 Subject: [PATCH 03/11] fix: pending accrual entries --- .../doctype/loan_repayment/loan_repayment.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py index 018832c7d7..e9fa2adfdd 100644 --- a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py +++ b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py @@ -519,6 +519,8 @@ def get_accrued_interest_entries(against_loan, posting_date=None): if not posting_date: posting_date = getdate() + precision = cint(frappe.db.get_default("currency_precision")) or 2 + unpaid_accrued_entries = frappe.db.sql( """ SELECT name, posting_date, interest_amount - paid_interest_amount as interest_amount, @@ -539,6 +541,13 @@ def get_accrued_interest_entries(against_loan, posting_date=None): as_dict=1, ) + # Skip entries with zero interest amount & payable principal amount + unpaid_accrued_entries = [ + d + for d in unpaid_accrued_entries + if flt(d.interest_amount, precision) > 0 or flt(d.payable_principal_amount, precision) > 0 + ] + return unpaid_accrued_entries From 97977cdb4ba42a1a20a6e747cc5586ae92e8954b Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Wed, 14 Sep 2022 19:19:05 +0530 Subject: [PATCH 04/11] fix: correct sql output format in CRM patch (#32213) --- .../v14_0/migrate_existing_lead_notes_as_per_the_new_format.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/patches/v14_0/migrate_existing_lead_notes_as_per_the_new_format.py b/erpnext/patches/v14_0/migrate_existing_lead_notes_as_per_the_new_format.py index 032aeccc23..ec72527552 100644 --- a/erpnext/patches/v14_0/migrate_existing_lead_notes_as_per_the_new_format.py +++ b/erpnext/patches/v14_0/migrate_existing_lead_notes_as_per_the_new_format.py @@ -12,7 +12,7 @@ def execute(): frappe.qb.from_(dt) .select(dt.name, dt.notes, dt.modified_by, dt.modified) .where(dt.notes.isnotnull() & dt.notes != "") - ).run() + ).run(as_dict=True) for d in records: if strip_html(cstr(d.notes)).strip(): From cbf973d90ff877f67087f5e87b83318a32c9bf71 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 14 Sep 2022 12:55:49 +0530 Subject: [PATCH 05/11] fix: always set default expense account in company --- erpnext/setup/doctype/company/company.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py index dc698886a0..490504a7c9 100644 --- a/erpnext/setup/doctype/company/company.py +++ b/erpnext/setup/doctype/company/company.py @@ -389,6 +389,7 @@ class Company(NestedSet): "capital_work_in_progress_account": "Capital Work in Progress", "asset_received_but_not_billed": "Asset Received But Not Billed", "expenses_included_in_asset_valuation": "Expenses Included In Asset Valuation", + "default_expense_account": "Cost of Goods Sold", } if self.enable_perpetual_inventory: @@ -398,7 +399,6 @@ class Company(NestedSet): "default_inventory_account": "Stock", "stock_adjustment_account": "Stock Adjustment", "expenses_included_in_valuation": "Expenses Included In Valuation", - "default_expense_account": "Cost of Goods Sold", } ) From a5b58859334218dde1876a42fbceda870152f046 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 14 Sep 2022 17:20:19 +0530 Subject: [PATCH 06/11] fix: test cases --- .../stock_reconciliation/test_stock_reconciliation.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py index 4e76ae781f..7b984d3847 100644 --- a/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py +++ b/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py @@ -729,15 +729,19 @@ def create_stock_reconciliation(**args): sr.expense_account = args.expense_account or ( ( frappe.get_cached_value("Company", sr.company, "stock_adjustment_account") - or "Stock Adjustment - _TC" + or frappe.get_cached_value( + "Account", {"account_type": "Stock Adjustment", "company": sr.company}, "name" + ) ) if frappe.get_all("Stock Ledger Entry", {"company": sr.company}) - else "Temporary Opening - _TC" + else frappe.get_cached_value( + "Account", {"account_type": "Temporary", "company": sr.company}, "name" + ) ) sr.cost_center = ( args.cost_center or frappe.get_cached_value("Company", sr.company, "cost_center") - or "_Test Cost Center - _TC" + or frappe.get_cached_value("Cost Center", filters={"is_group": 0, "company": sr.company}) ) sr.append( From 34571055048839a6c1a53dc6cd690ebde55fbbcd Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 14 Sep 2022 18:31:15 +0530 Subject: [PATCH 07/11] fix: test cases --- .../assets/doctype/asset_repair/test_asset_repair.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/erpnext/assets/doctype/asset_repair/test_asset_repair.py b/erpnext/assets/doctype/asset_repair/test_asset_repair.py index 2786349f7b..6e06f52ac6 100644 --- a/erpnext/assets/doctype/asset_repair/test_asset_repair.py +++ b/erpnext/assets/doctype/asset_repair/test_asset_repair.py @@ -129,6 +129,18 @@ class TestAssetRepair(unittest.TestCase): def test_gl_entries_with_perpetual_inventory(self): set_depreciation_settings_in_company(company="_Test Company with perpetual inventory") + asset_category = frappe.get_doc("Asset Category", "Computers") + asset_category.append( + "accounts", + { + "company_name": "_Test Company with perpetual inventory", + "fixed_asset_account": "_Test Fixed Asset - TCP1", + "accumulated_depreciation_account": "_Test Accumulated Depreciations - TCP1", + "depreciation_expense_account": "_Test Depreciations - TCP1", + }, + ) + asset_category.save() + asset_repair = create_asset_repair( capitalize_repair_cost=1, stock_consumption=1, From c0da948a4ef9f5fb1dd5764ee1908bd6f0475c7e Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 15 Sep 2022 11:27:35 +0530 Subject: [PATCH 08/11] fix: No permission to read doctype --- .../bank_clearance_summary/bank_clearance_summary.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) 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 9d2deea523..449ebdcd92 100644 --- a/erpnext/accounts/report/bank_clearance_summary/bank_clearance_summary.py +++ b/erpnext/accounts/report/bank_clearance_summary/bank_clearance_summary.py @@ -22,8 +22,7 @@ def get_columns(): { "label": _("Payment Document Type"), "fieldname": "payment_document_type", - "fieldtype": "Link", - "options": "Doctype", + "fieldtype": "Data", "width": 130, }, { @@ -33,15 +32,15 @@ def get_columns(): "options": "payment_document_type", "width": 140, }, - {"label": _("Posting Date"), "fieldname": "posting_date", "fieldtype": "Date", "width": 100}, + {"label": _("Posting Date"), "fieldname": "posting_date", "fieldtype": "Date", "width": 120}, {"label": _("Cheque/Reference No"), "fieldname": "cheque_no", "width": 120}, - {"label": _("Clearance Date"), "fieldname": "clearance_date", "fieldtype": "Date", "width": 100}, + {"label": _("Clearance Date"), "fieldname": "clearance_date", "fieldtype": "Date", "width": 120}, { "label": _("Against Account"), "fieldname": "against", "fieldtype": "Link", "options": "Account", - "width": 170, + "width": 200, }, {"label": _("Amount"), "fieldname": "amount", "fieldtype": "Currency", "width": 120}, ] From cb763938dced524f69f28341c57d4cf191f6dacd Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Thu, 15 Sep 2022 11:47:10 +0530 Subject: [PATCH 09/11] fix: consider posting time for internal transfer PO --- erpnext/controllers/buying_controller.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py index 7ab8f81bd9..dd1b1ab2c4 100644 --- a/erpnext/controllers/buying_controller.py +++ b/erpnext/controllers/buying_controller.py @@ -6,6 +6,7 @@ import frappe from frappe import ValidationError, _, msgprint from frappe.contacts.doctype.address.address import get_address_display from frappe.utils import cint, cstr, flt, getdate +from frappe.utils.data import nowtime from erpnext.accounts.doctype.budget.budget import validate_expense_against_budget from erpnext.accounts.party import get_party_details @@ -289,12 +290,16 @@ class BuyingController(SubcontractingController): # Get outgoing rate based on original item cost based on valuation method if not d.get(frappe.scrub(ref_doctype)): + posting_time = self.get("posting_time") + if not posting_time and self.doctype == "Purchase Order": + posting_time = nowtime() + outgoing_rate = get_incoming_rate( { "item_code": d.item_code, "warehouse": d.get("from_warehouse"), "posting_date": self.get("posting_date") or self.get("transation_date"), - "posting_time": self.get("posting_time"), + "posting_time": posting_time, "qty": -1 * flt(d.get("stock_qty")), "serial_no": d.get("serial_no"), "batch_no": d.get("batch_no"), From af21a11e1e3b2e372f19190f9854a26d3e8488bd Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 15 Sep 2022 12:09:18 +0530 Subject: [PATCH 10/11] fix: abbreviation issue on renaming cost center --- erpnext/accounts/doctype/account/account.py | 2 +- .../accounts/doctype/cost_center/cost_center.py | 2 +- erpnext/accounts/utils.py | 14 ++++++-------- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/erpnext/accounts/doctype/account/account.py b/erpnext/accounts/doctype/account/account.py index 2610c8655e..9dff1168fd 100644 --- a/erpnext/accounts/doctype/account/account.py +++ b/erpnext/accounts/doctype/account/account.py @@ -37,7 +37,7 @@ class Account(NestedSet): def autoname(self): from erpnext.accounts.utils import get_autoname_with_number - self.name = get_autoname_with_number(self.account_number, self.account_name, None, self.company) + self.name = get_autoname_with_number(self.account_number, self.account_name, self.company) def validate(self): from erpnext.accounts.utils import validate_field_number diff --git a/erpnext/accounts/doctype/cost_center/cost_center.py b/erpnext/accounts/doctype/cost_center/cost_center.py index 31055c3fb4..e8b34bbf03 100644 --- a/erpnext/accounts/doctype/cost_center/cost_center.py +++ b/erpnext/accounts/doctype/cost_center/cost_center.py @@ -16,7 +16,7 @@ class CostCenter(NestedSet): from erpnext.accounts.utils import get_autoname_with_number self.name = get_autoname_with_number( - self.cost_center_number, self.cost_center_name, None, self.company + self.cost_center_number, self.cost_center_name, self.company ) def validate(self): diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py index f61e8ac960..c5eb7d8733 100644 --- a/erpnext/accounts/utils.py +++ b/erpnext/accounts/utils.py @@ -1037,7 +1037,7 @@ def update_cost_center(docname, cost_center_name, cost_center_number, company, m frappe.db.set_value("Cost Center", docname, "cost_center_name", cost_center_name.strip()) - new_name = get_autoname_with_number(cost_center_number, cost_center_name, docname, company) + new_name = get_autoname_with_number(cost_center_number, cost_center_name, company) if docname != new_name: frappe.rename_doc("Cost Center", docname, new_name, force=1, merge=merge) return new_name @@ -1060,16 +1060,14 @@ def validate_field_number(doctype_name, docname, number_value, company, field_na ) -def get_autoname_with_number(number_value, doc_title, name, company): +def get_autoname_with_number(number_value, doc_title, company): """append title with prefix as number and suffix as company's abbreviation separated by '-'""" - if name: - name_split = name.split("-") - parts = [doc_title.strip(), name_split[len(name_split) - 1].strip()] - else: - abbr = frappe.get_cached_value("Company", company, ["abbr"], as_dict=True) - parts = [doc_title.strip(), abbr.abbr] + company_abbr = frappe.get_cached_value("Company", company, "abbr") + parts = [doc_title.strip(), company_abbr] + if cstr(number_value).strip(): parts.insert(0, cstr(number_value).strip()) + return " - ".join(parts) From 29db084dc314979e07288e34b43ac09292b5ff5b Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 15 Sep 2022 13:11:53 +0530 Subject: [PATCH 11/11] fix: create dunning from sales invoice --- erpnext/accounts/doctype/sales_invoice/sales_invoice.py | 1 - 1 file changed, 1 deletion(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 608f0828fe..e51938b27f 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -2429,7 +2429,6 @@ def create_dunning(source_name, target_doc=None): target.closing_text = letter_text.get("closing_text") target.language = letter_text.get("language") amounts = calculate_interest_and_amount( - target.posting_date, target.outstanding_amount, target.rate_of_interest, target.dunning_fee,