diff --git a/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.py b/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.py index d8880f70417..003a43c5c2c 100644 --- a/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.py +++ b/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.py @@ -53,19 +53,20 @@ class BankStatementImport(DataImport): if "Bank Account" not in json.dumps(preview["columns"]): frappe.throw(_("Please add the Bank Account column")) - from frappe.utils.background_jobs import is_job_queued + from frappe.utils.background_jobs import is_job_enqueued from frappe.utils.scheduler import is_scheduler_inactive if is_scheduler_inactive() and not frappe.flags.in_test: frappe.throw(_("Scheduler is inactive. Cannot import data."), title=_("Scheduler Inactive")) - if not is_job_queued(self.name): + job_id = f"bank_statement_import::{self.name}" + if not is_job_enqueued(job_id): enqueue( start_import, queue="default", timeout=6000, event="data_import", - job_name=self.name, + job_id=job_id, data_import=self.name, bank_account=self.bank_account, import_file_path=self.import_file, diff --git a/erpnext/accounts/doctype/ledger_merge/ledger_merge.py b/erpnext/accounts/doctype/ledger_merge/ledger_merge.py index 7cd6d04c35c..381083bc304 100644 --- a/erpnext/accounts/doctype/ledger_merge/ledger_merge.py +++ b/erpnext/accounts/doctype/ledger_merge/ledger_merge.py @@ -4,7 +4,7 @@ import frappe from frappe import _ from frappe.model.document import Document -from frappe.utils.background_jobs import is_job_queued +from frappe.utils.background_jobs import is_job_enqueued from erpnext.accounts.doctype.account.account import merge_account @@ -17,13 +17,14 @@ class LedgerMerge(Document): if is_scheduler_inactive() and not frappe.flags.in_test: frappe.throw(_("Scheduler is inactive. Cannot merge accounts."), title=_("Scheduler Inactive")) - if not is_job_queued(self.name): + job_id = f"ledger_merge::{self.name}" + if not is_job_enqueued(job_id): enqueue( start_merge, queue="default", timeout=6000, event="ledger_merge", - job_name=self.name, + job_id=job_id, docname=self.name, now=frappe.conf.developer_mode or frappe.flags.in_test, ) diff --git a/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py b/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py index 47c2ceb6e49..680afb1143b 100644 --- a/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py +++ b/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py @@ -6,7 +6,7 @@ import frappe from frappe import _, scrub from frappe.model.document import Document from frappe.utils import flt, nowdate -from frappe.utils.background_jobs import enqueue, is_job_queued +from frappe.utils.background_jobs import enqueue, is_job_enqueued from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import ( get_accounting_dimensions, @@ -212,13 +212,15 @@ class OpeningInvoiceCreationTool(Document): if is_scheduler_inactive() and not frappe.flags.in_test: frappe.throw(_("Scheduler is inactive. Cannot import data."), title=_("Scheduler Inactive")) - if not is_job_queued(self.name): + job_id = f"opening_invoice::{self.name}" + + if not is_job_enqueued(job_id): enqueue( start_import, queue="default", timeout=6000, event="opening_invoice_creation", - job_name=self.name, + job_id=job_id, invoices=invoices, now=frappe.conf.developer_mode or frappe.flags.in_test, ) diff --git a/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py b/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py index b1e22087dbd..d8aed219e24 100644 --- a/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py +++ b/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py @@ -9,7 +9,7 @@ from frappe import _ from frappe.model.document import Document from frappe.model.mapper import map_child_doc, map_doc from frappe.utils import cint, flt, get_time, getdate, nowdate, nowtime -from frappe.utils.background_jobs import enqueue, is_job_queued +from frappe.utils.background_jobs import enqueue, is_job_enqueued from frappe.utils.scheduler import is_scheduler_inactive @@ -483,15 +483,15 @@ def enqueue_job(job, **kwargs): closing_entry = kwargs.get("closing_entry") or {} - job_name = closing_entry.get("name") - if not is_job_queued(job_name): + job_id = "pos_invoice_merge::" + str(closing_entry.get("name")) + if not is_job_enqueued(job_id): enqueue( job, **kwargs, queue="long", timeout=10000, event="processing_merge_logs", - job_name=job_name, + job_id=job_id, now=frappe.conf.developer_mode or frappe.flags.in_test ) diff --git a/erpnext/accounts/doctype/process_payment_reconciliation/process_payment_reconciliation.py b/erpnext/accounts/doctype/process_payment_reconciliation/process_payment_reconciliation.py index ecb51ce1445..31660306db0 100644 --- a/erpnext/accounts/doctype/process_payment_reconciliation/process_payment_reconciliation.py +++ b/erpnext/accounts/doctype/process_payment_reconciliation/process_payment_reconciliation.py @@ -164,7 +164,7 @@ def trigger_reconciliation_for_queued_docs(): Fetch queued docs and start reconciliation process for each one """ if not frappe.db.get_single_value("Accounts Settings", "auto_reconcile_payments"): - frappe.throw( + frappe.msgprint( _("Auto Reconciliation of Payments has been disabled. Enable it through {0}").format( get_link_to_form("Accounts Settings", "Accounts Settings") ) diff --git a/erpnext/accounts/report/financial_statements.py b/erpnext/accounts/report/financial_statements.py index 76a01db7148..8a47e1c011b 100644 --- a/erpnext/accounts/report/financial_statements.py +++ b/erpnext/accounts/report/financial_statements.py @@ -546,12 +546,13 @@ def apply_additional_conditions(doctype, query, from_date, ignore_closing_entrie ) query = query.where( - (gl_entry.finance_book.isin([cstr(filters.finance_book), cstr(company_fb)])) + (gl_entry.finance_book.isin([cstr(filters.finance_book), cstr(company_fb), ""])) | (gl_entry.finance_book.isnull()) ) else: query = query.where( - (gl_entry.finance_book.isin([cstr(filters.finance_book)])) | (gl_entry.finance_book.isnull()) + (gl_entry.finance_book.isin([cstr(filters.finance_book), ""])) + | (gl_entry.finance_book.isnull()) ) if accounting_dimensions: diff --git a/erpnext/accounts/report/general_ledger/general_ledger.py b/erpnext/accounts/report/general_ledger/general_ledger.py index 0b05c11668a..d47e3da3139 100644 --- a/erpnext/accounts/report/general_ledger/general_ledger.py +++ b/erpnext/accounts/report/general_ledger/general_ledger.py @@ -253,14 +253,14 @@ def get_conditions(filters): _("To use a different finance book, please uncheck 'Include Default Book Entries'") ) else: - conditions.append("(finance_book in (%(finance_book)s) OR finance_book IS NULL)") + conditions.append("(finance_book in (%(finance_book)s, '') OR finance_book IS NULL)") else: - conditions.append("(finance_book in (%(company_fb)s) OR finance_book IS NULL)") + conditions.append("(finance_book in (%(company_fb)s, '') OR finance_book IS NULL)") else: if filters.get("finance_book"): - conditions.append("(finance_book in (%(finance_book)s) OR finance_book IS NULL)") + conditions.append("(finance_book in (%(finance_book)s, '') OR finance_book IS NULL)") else: - conditions.append("(finance_book IS NULL)") + conditions.append("(finance_book in ('') OR finance_book IS NULL)") if not filters.get("show_cancelled_entries"): conditions.append("is_cancelled = 0") diff --git a/erpnext/accounts/report/trial_balance/trial_balance.py b/erpnext/accounts/report/trial_balance/trial_balance.py index 57dac2af491..22bebb7d19b 100644 --- a/erpnext/accounts/report/trial_balance/trial_balance.py +++ b/erpnext/accounts/report/trial_balance/trial_balance.py @@ -256,12 +256,12 @@ def get_opening_balance( ) opening_balance = opening_balance.where( - (closing_balance.finance_book.isin([cstr(filters.finance_book), cstr(company_fb)])) + (closing_balance.finance_book.isin([cstr(filters.finance_book), cstr(company_fb), ""])) | (closing_balance.finance_book.isnull()) ) else: opening_balance = opening_balance.where( - (closing_balance.finance_book.isin([cstr(filters.finance_book)])) + (closing_balance.finance_book.isin([cstr(filters.finance_book), ""])) | (closing_balance.finance_book.isnull()) ) diff --git a/erpnext/manufacturing/doctype/bom/bom.js b/erpnext/manufacturing/doctype/bom/bom.js index ad9aafe0661..f147b46ca7d 100644 --- a/erpnext/manufacturing/doctype/bom/bom.js +++ b/erpnext/manufacturing/doctype/bom/bom.js @@ -48,7 +48,9 @@ frappe.ui.form.on("BOM", { return { query: "erpnext.manufacturing.doctype.bom.bom.item_query", filters: { - "item_code": doc.item + "item_code": doc.item, + "include_item_in_manufacturing": 1, + "is_fixed_asset": 0 } }; }); diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py index b53149affd3..8058a5f8b75 100644 --- a/erpnext/manufacturing/doctype/bom/bom.py +++ b/erpnext/manufacturing/doctype/bom/bom.py @@ -1339,8 +1339,9 @@ def item_query(doctype, txt, searchfield, start, page_len, filters): if not has_variants: query_filters["has_variants"] = 0 - if filters and filters.get("is_stock_item"): - query_filters["is_stock_item"] = 1 + if filters: + for fieldname, value in filters.items(): + query_filters[fieldname] = value return frappe.get_list( "Item", diff --git a/erpnext/manufacturing/doctype/bom/test_bom.py b/erpnext/manufacturing/doctype/bom/test_bom.py index 01bf2e4315f..051b475bcc3 100644 --- a/erpnext/manufacturing/doctype/bom/test_bom.py +++ b/erpnext/manufacturing/doctype/bom/test_bom.py @@ -698,6 +698,45 @@ class TestBOM(FrappeTestCase): bom.update_cost() self.assertFalse(bom.flags.cost_updated) + def test_do_not_include_manufacturing_and_fixed_items(self): + from erpnext.manufacturing.doctype.bom.bom import item_query + + if not frappe.db.exists("Asset Category", "Computers-Test"): + doc = frappe.get_doc({"doctype": "Asset Category", "asset_category_name": "Computers-Test"}) + doc.flags.ignore_mandatory = True + doc.insert() + + for item_code, properties in { + "_Test RM Item 1 Do Not Include In Manufacture": { + "is_stock_item": 1, + "include_item_in_manufacturing": 0, + }, + "_Test RM Item 2 Fixed Asset Item": { + "is_fixed_asset": 1, + "is_stock_item": 0, + "asset_category": "Computers-Test", + }, + "_Test RM Item 3 Manufacture Item": {"is_stock_item": 1, "include_item_in_manufacturing": 1}, + }.items(): + make_item(item_code, properties) + + data = item_query( + "Item", + txt="_Test RM Item", + searchfield="name", + start=0, + page_len=20000, + filters={"include_item_in_manufacturing": 1, "is_fixed_asset": 0}, + ) + + items = [] + for row in data: + items.append(row[0]) + + self.assertTrue("_Test RM Item 1 Do Not Include In Manufacture" not in items) + self.assertTrue("_Test RM Item 2 Fixed Asset Item" not in items) + self.assertTrue("_Test RM Item 3 Manufacture Item" in items) + def get_default_bom(item_code="_Test FG Item 2"): return frappe.db.get_value("BOM", {"item": item_code, "is_active": 1, "is_default": 1}) diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js index 8efc47d18e5..fd961c4aaae 100644 --- a/erpnext/public/js/controllers/taxes_and_totals.js +++ b/erpnext/public/js/controllers/taxes_and_totals.js @@ -92,7 +92,7 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments { _calculate_taxes_and_totals() { const is_quotation = this.frm.doc.doctype == "Quotation"; - this.frm.doc._items = is_quotation ? this.filtered_items() : this.frm.doc.items; + this.frm._items = is_quotation ? this.filtered_items() : this.frm.doc.items; this.validate_conversion_rate(); this.calculate_item_values(); @@ -125,7 +125,7 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments { calculate_item_values() { var me = this; if (!this.discount_amount_applied) { - for (const item of this.frm.doc._items || []) { + for (const item of this.frm._items || []) { frappe.model.round_floats_in(item); item.net_rate = item.rate; item.qty = item.qty === undefined ? (me.frm.doc.is_return ? -1 : 1) : item.qty; @@ -209,7 +209,7 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments { }); if(has_inclusive_tax==false) return; - $.each(me.frm.doc._items || [], function(n, item) { + $.each(me.frm._items || [], function(n, item) { var item_tax_map = me._load_item_tax_rate(item.item_tax_rate); var cumulated_tax_fraction = 0.0; var total_inclusive_tax_amount_per_qty = 0; @@ -280,13 +280,13 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments { var me = this; this.frm.doc.total_qty = this.frm.doc.total = this.frm.doc.base_total = this.frm.doc.net_total = this.frm.doc.base_net_total = 0.0; - $.each(this.frm.doc._items || [], function(i, item) { + $.each(this.frm._items || [], function(i, item) { me.frm.doc.total += item.amount; me.frm.doc.total_qty += item.qty; me.frm.doc.base_total += item.base_amount; me.frm.doc.net_total += item.net_amount; me.frm.doc.base_net_total += item.base_net_amount; - }); + }); } calculate_shipping_charges() { @@ -333,7 +333,7 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments { } }); - $.each(this.frm.doc._items || [], function(n, item) { + $.each(this.frm._items || [], function(n, item) { var item_tax_map = me._load_item_tax_rate(item.item_tax_rate); $.each(me.frm.doc["taxes"] || [], function(i, tax) { // tax_amount represents the amount of tax for the current step @@ -342,7 +342,7 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments { // Adjust divisional loss to the last item if (tax.charge_type == "Actual") { actual_tax_dict[tax.idx] -= current_tax_amount; - if (n == me.frm.doc._items.length - 1) { + if (n == me.frm._items.length - 1) { current_tax_amount += actual_tax_dict[tax.idx]; } } @@ -379,7 +379,7 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments { } // set precision in the last item iteration - if (n == me.frm.doc._items.length - 1) { + if (n == me.frm._items.length - 1) { me.round_off_totals(tax); me.set_in_company_currency(tax, ["tax_amount", "tax_amount_after_discount_amount"]); @@ -602,7 +602,7 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments { _cleanup() { this.frm.doc.base_in_words = this.frm.doc.in_words = ""; - let items = this.frm.doc._items; + let items = this.frm._items; if(items && items.length) { if(!frappe.meta.get_docfield(items[0].doctype, "item_tax_amount", this.frm.doctype)) { @@ -659,7 +659,7 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments { var net_total = 0; // calculate item amount after Discount Amount if (total_for_discount_amount) { - $.each(this.frm.doc._items || [], function(i, item) { + $.each(this.frm._items || [], function(i, item) { distributed_amount = flt(me.frm.doc.discount_amount) * item.net_amount / total_for_discount_amount; item.net_amount = flt(item.net_amount - distributed_amount, precision("base_amount", item)); @@ -667,7 +667,7 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments { // discount amount rounding loss adjustment if no taxes if ((!(me.frm.doc.taxes || []).length || total_for_discount_amount==me.frm.doc.net_total || (me.frm.doc.apply_discount_on == "Net Total")) - && i == (me.frm.doc._items || []).length - 1) { + && i == (me.frm._items || []).length - 1) { var discount_amount_loss = flt(me.frm.doc.net_total - net_total - me.frm.doc.discount_amount, precision("net_total")); item.net_amount = flt(item.net_amount + discount_amount_loss, diff --git a/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.json b/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.json index fe81a87558c..6b1a8efc997 100644 --- a/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.json +++ b/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.json @@ -395,7 +395,8 @@ "no_copy": 1, "options": "Material Request", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "search_index": 1 }, { "fieldname": "material_request_item", @@ -571,7 +572,7 @@ "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2023-01-03 14:51:16.575515", + "modified": "2023-05-09 12:41:18.210864", "modified_by": "Administrator", "module": "Stock", "name": "Stock Entry Detail", diff --git a/erpnext/stock/doctype/stock_reconciliation_item/stock_reconciliation_item.json b/erpnext/stock/doctype/stock_reconciliation_item/stock_reconciliation_item.json index 7c3e151663b..2f65eaa358d 100644 --- a/erpnext/stock/doctype/stock_reconciliation_item/stock_reconciliation_item.json +++ b/erpnext/stock/doctype/stock_reconciliation_item/stock_reconciliation_item.json @@ -99,7 +99,7 @@ }, { "fieldname": "serial_no", - "fieldtype": "Small Text", + "fieldtype": "Long Text", "label": "Serial No" }, { @@ -120,7 +120,7 @@ }, { "fieldname": "current_serial_no", - "fieldtype": "Small Text", + "fieldtype": "Long Text", "label": "Current Serial No", "no_copy": 1, "print_hide": 1, @@ -189,7 +189,7 @@ ], "istable": 1, "links": [], - "modified": "2022-11-02 13:01:23.580937", + "modified": "2023-05-09 18:42:19.224916", "modified_by": "Administrator", "module": "Stock", "name": "Stock Reconciliation Item",