diff --git a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js index b15745d834c..7a653e12c72 100644 --- a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js +++ b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js @@ -120,6 +120,7 @@ frappe.ui.form.on("Bank Reconciliation Tool", { args: { bank_account: frm.doc.bank_account, till_date: frappe.datetime.add_days(frm.doc.bank_statement_from_date, -1), + company: frm.doc.company, }, callback: (response) => { frm.set_value("account_opening_balance", response.message); @@ -135,6 +136,7 @@ frappe.ui.form.on("Bank Reconciliation Tool", { args: { bank_account: frm.doc.bank_account, till_date: frm.doc.bank_statement_to_date, + company: frm.doc.company, }, callback: (response) => { frm.cleared_balance = response.message; diff --git a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py index ce7e9436ad5..62a4c74a933 100644 --- a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py +++ b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py @@ -79,10 +79,17 @@ def get_bank_transactions(bank_account, from_date=None, to_date=None): @frappe.whitelist() -def get_account_balance(bank_account, till_date): +def get_account_balance(bank_account, till_date, company): # returns account balance till the specified date account = frappe.db.get_value("Bank Account", bank_account, "account") - filters = frappe._dict({"account": account, "report_date": till_date, "include_pos_transactions": 1}) + filters = frappe._dict( + { + "account": account, + "report_date": till_date, + "include_pos_transactions": 1, + "company": company, + } + ) data = get_entries(filters) balance_as_per_system = get_balance_on(filters["account"], filters["report_date"]) @@ -94,11 +101,7 @@ def get_account_balance(bank_account, till_date): amounts_not_reflected_in_system = get_amounts_not_reflected_in_system(filters) - bank_bal = ( - flt(balance_as_per_system) - flt(total_debit) + flt(total_credit) + amounts_not_reflected_in_system - ) - - return bank_bal + return flt(balance_as_per_system) - flt(total_debit) + flt(total_credit) + amounts_not_reflected_in_system @frappe.whitelist() diff --git a/erpnext/accounts/doctype/process_payment_reconciliation/process_payment_reconciliation.json b/erpnext/accounts/doctype/process_payment_reconciliation/process_payment_reconciliation.json index 0511571d754..bfd4e0ad63a 100644 --- a/erpnext/accounts/doctype/process_payment_reconciliation/process_payment_reconciliation.json +++ b/erpnext/accounts/doctype/process_payment_reconciliation/process_payment_reconciliation.json @@ -1,7 +1,6 @@ { "actions": [], "autoname": "format:ACC-PPR-{#####}", - "beta": 1, "creation": "2023-03-30 21:28:39.793927", "default_view": "List", "doctype": "DocType", @@ -158,7 +157,7 @@ "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2024-08-27 14:48:56.715320", + "modified": "2025-01-08 08:22:14.798085", "modified_by": "Administrator", "module": "Accounts", "name": "Process Payment Reconciliation", @@ -192,4 +191,4 @@ "sort_order": "DESC", "states": [], "title_field": "company" -} +} \ No newline at end of file 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 882a2c4ad1c..35f1e31af34 100644 --- a/erpnext/accounts/doctype/process_payment_reconciliation/process_payment_reconciliation.py +++ b/erpnext/accounts/doctype/process_payment_reconciliation/process_payment_reconciliation.py @@ -212,7 +212,7 @@ def trigger_reconciliation_for_queued_docs(): unique_filters = set() queue_size = 5 - fields = ["company", "party_type", "party", "receivable_payable_account"] + fields = ["company", "party_type", "party", "receivable_payable_account", "default_advance_account"] def get_filters_as_tuple(fields, doc): filters = () diff --git a/erpnext/accounts/doctype/process_payment_reconciliation_log/process_payment_reconciliation_log.json b/erpnext/accounts/doctype/process_payment_reconciliation_log/process_payment_reconciliation_log.json index b4ac9812cbf..3e3e231fe1d 100644 --- a/erpnext/accounts/doctype/process_payment_reconciliation_log/process_payment_reconciliation_log.json +++ b/erpnext/accounts/doctype/process_payment_reconciliation_log/process_payment_reconciliation_log.json @@ -1,7 +1,6 @@ { "actions": [], "autoname": "format:PPR-LOG-{##}", - "beta": 1, "creation": "2023-03-13 15:00:09.149681", "default_view": "List", "doctype": "DocType", @@ -110,7 +109,7 @@ "in_create": 1, "index_web_pages_for_search": 1, "links": [], - "modified": "2023-11-02 11:32:12.254018", + "modified": "2025-01-08 08:22:19.104975", "modified_by": "Administrator", "module": "Accounts", "name": "Process Payment Reconciliation Log", diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js index 75c71ef6eb3..c07e2a392ae 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js @@ -994,47 +994,51 @@ frappe.ui.form.on("Sales Invoice", { refresh: function (frm) { if (frm.doc.docstatus === 0 && !frm.doc.is_return) { - frm.add_custom_button(__("Fetch Timesheet"), function () { - let d = new frappe.ui.Dialog({ - title: __("Fetch Timesheet"), - fields: [ - { - label: __("From"), - fieldname: "from_time", - fieldtype: "Date", - reqd: 1, + frm.add_custom_button( + __("Timesheet"), + function () { + let d = new frappe.ui.Dialog({ + title: __("Fetch Timesheet"), + fields: [ + { + label: __("From"), + fieldname: "from_time", + fieldtype: "Date", + reqd: 1, + }, + { + fieldtype: "Column Break", + fieldname: "col_break_1", + }, + { + label: __("To"), + fieldname: "to_time", + fieldtype: "Date", + reqd: 1, + }, + { + label: __("Project"), + fieldname: "project", + fieldtype: "Link", + options: "Project", + default: frm.doc.project, + }, + ], + primary_action: function () { + const data = d.get_values(); + frm.events.add_timesheet_data(frm, { + from_time: data.from_time, + to_time: data.to_time, + project: data.project, + }); + d.hide(); }, - { - fieldtype: "Column Break", - fieldname: "col_break_1", - }, - { - label: __("To"), - fieldname: "to_time", - fieldtype: "Date", - reqd: 1, - }, - { - label: __("Project"), - fieldname: "project", - fieldtype: "Link", - options: "Project", - default: frm.doc.project, - }, - ], - primary_action: function () { - const data = d.get_values(); - frm.events.add_timesheet_data(frm, { - from_time: data.from_time, - to_time: data.to_time, - project: data.project, - }); - d.hide(); - }, - primary_action_label: __("Get Timesheets"), - }); - d.show(); - }); + primary_action_label: __("Get Timesheets"), + }); + d.show(); + }, + __("Get Items From") + ); } if (frm.doc.is_debit_note) { diff --git a/erpnext/controllers/subcontracting_controller.py b/erpnext/controllers/subcontracting_controller.py index 0f9431ab440..349a15703fb 100644 --- a/erpnext/controllers/subcontracting_controller.py +++ b/erpnext/controllers/subcontracting_controller.py @@ -1257,6 +1257,7 @@ def add_items_in_ste(ste_doc, row, qty, rm_details, rm_detail_field="sco_rm_deta "item_code": row.item_details["rm_item_code"], "subcontracted_item": row.item_details["main_item_code"], "serial_no": "\n".join(row.serial_no) if row.serial_no else "", + "use_serial_batch_fields": 1, } ) @@ -1297,10 +1298,13 @@ def make_return_stock_entry_for_subcontract( if not value.qty: continue + if item_details := value.get("item_details"): + item_details["serial_and_batch_bundle"] = None + if value.batch_no: for batch_no, qty in value.batch_no.items(): if qty > 0: - add_items_in_ste(ste_doc, value, value.qty, rm_details, rm_detail_field, batch_no) + add_items_in_ste(ste_doc, value, qty, rm_details, rm_detail_field, batch_no) else: add_items_in_ste(ste_doc, value, value.qty, rm_details, rm_detail_field) diff --git a/erpnext/controllers/tests/test_subcontracting_controller.py b/erpnext/controllers/tests/test_subcontracting_controller.py index 0bc348e8876..3b11a0f8029 100644 --- a/erpnext/controllers/tests/test_subcontracting_controller.py +++ b/erpnext/controllers/tests/test_subcontracting_controller.py @@ -282,6 +282,79 @@ class TestSubcontractingController(FrappeTestCase): frappe.db.set_single_value("Stock Settings", "use_serial_batch_fields", 1) + def test_return_non_consumed_batch_materials(self): + """ + - Set backflush based on Material Transfer. + - Create SCO for item Subcontracted Item SA2. + - Transfer the batched components from Stores to Supplier warehouse with serial nos. + - Transfer extra qty of component for the subcontracted item Subcontracted Item SA2. + - Create SCR for full qty against the SCO and change the qty of raw material. + - After that return the non consumed material back to the store from supplier's warehouse. + """ + + frappe.db.set_single_value("Stock Settings", "use_serial_batch_fields", 0) + set_backflush_based_on("Material Transferred for Subcontract") + service_item = make_item("Subcontracted Service FG Item A", properties={"is_stock_item": 0}).name + fg_item = make_item( + "Subcontracted FG Item SA2", properties={"is_stock_item": 1, "is_sub_contracted_item": 1} + ).name + rm_item = make_item( + "Subcontracted Batch RM Item SA2", + properties={ + "is_stock_item": 1, + "create_new_batch": 1, + "has_batch_no": 1, + "batch_number_series": "BATCH-RM-IRM-.####", + }, + ).name + + make_bom(item=fg_item, raw_materials=[rm_item], rate=100, currency="INR") + + service_items = [ + { + "warehouse": "_Test Warehouse - _TC", + "item_code": service_item, + "qty": 5, + "rate": 100, + "fg_item": fg_item, + "fg_item_qty": 5, + }, + ] + sco = get_subcontracting_order(service_items=service_items) + rm_items = get_rm_items(sco.supplied_items) + rm_items[0]["qty"] += 1 + itemwise_details = make_stock_in_entry(rm_items=rm_items) + + for item in rm_items: + item["sco_rm_detail"] = sco.items[0].name + + make_stock_transfer_entry( + sco_no=sco.name, + rm_items=rm_items, + itemwise_details=copy.deepcopy(itemwise_details), + ) + + scr1 = make_subcontracting_receipt(sco.name) + scr1.save() + scr1.supplied_items[0].consumed_qty = 5 + scr1.submit() + + for key, value in get_supplied_items(scr1).items(): + transferred_detais = itemwise_details.get(key) + self.assertEqual(value.qty, 5) + self.assertEqual(sorted(value.serial_no), sorted(transferred_detais.get("serial_no")[0:5])) + + sco.load_from_db() + self.assertEqual(sco.supplied_items[0].consumed_qty, 5) + doc = get_materials_from_supplier(sco.name, [d.name for d in sco.supplied_items]) + doc.save() + self.assertEqual(doc.items[0].qty, 1) + self.assertEqual(doc.items[0].s_warehouse, "_Test Warehouse 1 - _TC") + self.assertEqual(doc.items[0].t_warehouse, "_Test Warehouse - _TC") + self.assertTrue(doc.items[0].batch_no) + self.assertTrue(doc.items[0].use_serial_batch_fields) + frappe.db.set_single_value("Stock Settings", "use_serial_batch_fields", 1) + def test_return_non_consumed_materials(self): """ - Set backflush based on Material Transfer. diff --git a/erpnext/public/js/bank_reconciliation_tool/data_table_manager.js b/erpnext/public/js/bank_reconciliation_tool/data_table_manager.js index 4aa087e99cf..ad5fd528cda 100644 --- a/erpnext/public/js/bank_reconciliation_tool/data_table_manager.js +++ b/erpnext/public/js/bank_reconciliation_tool/data_table_manager.js @@ -16,7 +16,7 @@ erpnext.accounts.bank_reconciliation.DataTableManager = class DataTableManager { } make_dt() { - var me = this; + const me = this; frappe.call({ method: "erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.get_bank_transactions", args: { @@ -193,6 +193,7 @@ erpnext.accounts.bank_reconciliation.DataTableManager = class DataTableManager { args: { bank_account: this.bank_account, till_date: this.bank_statement_to_date, + company: this.company, }, callback: (response) => (this.cleared_balance = response.message), }); diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index b3389b27e84..9e3a76b12ca 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -303,11 +303,10 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe } const me = this; - if (!this.frm.is_new() && this.frm.doc.docstatus === 0 && frappe.model.can_create("Quality Inspection")) { + if (!this.frm.is_new() && this.frm.doc.docstatus === 0 && frappe.model.can_create("Quality Inspection") && this.frm.doc.update_stock) { this.frm.add_custom_button(__("Quality Inspection(s)"), () => { me.make_quality_inspection(); }, __("Create")); - this.frm.page.set_inner_btn_group_as_primary(__('Create')); } const inspection_type = ["Purchase Receipt", "Purchase Invoice", "Subcontracting Receipt"].includes(this.frm.doc.doctype) diff --git a/erpnext/selling/page/point_of_sale/pos_item_details.js b/erpnext/selling/page/point_of_sale/pos_item_details.js index 2c93a0d546b..333b50810c9 100644 --- a/erpnext/selling/page/point_of_sale/pos_item_details.js +++ b/erpnext/selling/page/point_of_sale/pos_item_details.js @@ -210,10 +210,21 @@ erpnext.PointOfSale.ItemDetails = class { make_auto_serial_selection_btn(item) { if (item.has_serial_no || item.has_batch_no) { - const label = item.has_serial_no ? __("Select Serial No") : __("Select Batch No"); - this.$form_container.append( - `
${label}
` - ); + if (item.has_serial_no && item.has_batch_no) { + this.$form_container.append( + `
${__( + "Select Serial No / Batch No" + )}
` + ); + } else { + const classname = item.has_serial_no ? ".serial_no-control" : ".batch_no-control"; + const label = item.has_serial_no ? __("Select Serial No") : __("Select Batch No"); + this.$form_container + .find(classname) + .append( + `
${label}
` + ); + } this.$form_container.find(".serial_no-control").find("textarea").css("height", "6rem"); } } diff --git a/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py b/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py index af378ca2f0b..00076e8ca16 100644 --- a/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py +++ b/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py @@ -1557,7 +1557,7 @@ def get_type_of_transaction(parent_doc, child_row): elif parent_doc.get("doctype") == "Stock Reconciliation": type_of_transaction = "Inward" - if parent_doc.get("is_return"): + if parent_doc.get("is_return") and parent_doc.get("doctype") != "Stock Entry": type_of_transaction = "Inward" if ( parent_doc.get("doctype") in ["Purchase Receipt", "Purchase Invoice"] diff --git a/erpnext/stock/report/stock_balance/stock_balance.py b/erpnext/stock/report/stock_balance/stock_balance.py index 8ea07338cf1..6b5a3661a37 100644 --- a/erpnext/stock/report/stock_balance/stock_balance.py +++ b/erpnext/stock/report/stock_balance/stock_balance.py @@ -317,7 +317,6 @@ class StockBalanceReport: .where((sle.docstatus < 2) & (sle.is_cancelled == 0)) .orderby(sle.posting_datetime) .orderby(sle.creation) - .orderby(sle.actual_qty) ) query = self.apply_inventory_dimensions_filters(query, sle)