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 c4a23a640c..0eef3e9a67 100644 --- a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py +++ b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py @@ -10,6 +10,7 @@ from frappe.model.document import Document from frappe.query_builder.custom import ConstantColumn from frappe.utils import cint, flt +from erpnext import get_default_cost_center from erpnext.accounts.doctype.bank_transaction.bank_transaction import get_total_allocated_amount from erpnext.accounts.report.bank_reconciliation_statement.bank_reconciliation_statement import ( get_amounts_not_reflected_in_system, @@ -140,6 +141,9 @@ def create_journal_entry_bts( second_account ) ) + + company = frappe.get_value("Account", company_account, "company") + accounts = [] # Multi Currency? accounts.append( @@ -149,6 +153,7 @@ def create_journal_entry_bts( "debit_in_account_currency": bank_transaction.withdrawal, "party_type": party_type, "party": party, + "cost_center": get_default_cost_center(company), } ) @@ -158,11 +163,10 @@ def create_journal_entry_bts( "bank_account": bank_transaction.bank_account, "credit_in_account_currency": bank_transaction.withdrawal, "debit_in_account_currency": bank_transaction.deposit, + "cost_center": get_default_cost_center(company), } ) - company = frappe.get_value("Account", company_account, "company") - journal_entry_dict = { "voucher_type": entry_type, "company": company, diff --git a/erpnext/accounts/doctype/exchange_rate_revaluation_account/exchange_rate_revaluation_account.json b/erpnext/accounts/doctype/exchange_rate_revaluation_account/exchange_rate_revaluation_account.json index 0a7d0579b1..fd2d931315 100644 --- a/erpnext/accounts/doctype/exchange_rate_revaluation_account/exchange_rate_revaluation_account.json +++ b/erpnext/accounts/doctype/exchange_rate_revaluation_account/exchange_rate_revaluation_account.json @@ -73,6 +73,7 @@ "fieldname": "current_exchange_rate", "fieldtype": "Float", "label": "Current Exchange Rate", + "precision": "9", "read_only": 1 }, { @@ -148,7 +149,7 @@ ], "istable": 1, "links": [], - "modified": "2023-06-20 07:21:40.743460", + "modified": "2023-06-22 12:39:56.446722", "modified_by": "Administrator", "module": "Accounts", "name": "Exchange Rate Revaluation Account", diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js index 2283677634..89fa15172f 100644 --- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js +++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js @@ -85,25 +85,29 @@ erpnext.accounts.PaymentReconciliationController = class PaymentReconciliationCo // check for any running reconciliation jobs if (this.frm.doc.receivable_payable_account) { - frappe.db.get_single_value("Accounts Settings", "auto_reconcile_payments").then((enabled) => { - if(enabled) { - this.frm.call({ - 'method': "erpnext.accounts.doctype.process_payment_reconciliation.process_payment_reconciliation.is_any_doc_running", - "args": { - for_filter: { - company: this.frm.doc.company, - party_type: this.frm.doc.party_type, - party: this.frm.doc.party, - receivable_payable_account: this.frm.doc.receivable_payable_account + this.frm.call({ + doc: this.frm.doc, + method: 'is_auto_process_enabled', + callback: (r) => { + if (r.message) { + this.frm.call({ + 'method': "erpnext.accounts.doctype.process_payment_reconciliation.process_payment_reconciliation.is_any_doc_running", + "args": { + for_filter: { + company: this.frm.doc.company, + party_type: this.frm.doc.party_type, + party: this.frm.doc.party, + receivable_payable_account: this.frm.doc.receivable_payable_account + } } - } - }).then(r => { - if (r.message) { - let doc_link = frappe.utils.get_form_link("Process Payment Reconciliation", r.message, true); - let msg = __("Payment Reconciliation Job: {0} is running for this party. Can't reconcile now.", [doc_link]); - this.frm.dashboard.add_comment(msg, "yellow"); - } - }); + }).then(r => { + if (r.message) { + let doc_link = frappe.utils.get_form_link("Process Payment Reconciliation", r.message, true); + let msg = __("Payment Reconciliation Job: {0} is running for this party. Can't reconcile now.", [doc_link]); + this.frm.dashboard.add_comment(msg, "yellow"); + } + }); + } } }); } diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py index 2c8faecf4b..2e4e3b0e07 100644 --- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py +++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py @@ -252,6 +252,10 @@ class PaymentReconciliation(Document): return difference_amount + @frappe.whitelist() + def is_auto_process_enabled(self): + return frappe.db.get_single_value("Accounts Settings", "auto_reconcile_payments") + @frappe.whitelist() def calculate_difference_on_allocation_change(self, payment_entry, invoice, allocated_amount): invoice_exchange_map = self.get_invoice_exchange_map(invoice, payment_entry) diff --git a/erpnext/controllers/sales_and_purchase_return.py b/erpnext/controllers/sales_and_purchase_return.py index 818c7894b7..954668055e 100644 --- a/erpnext/controllers/sales_and_purchase_return.py +++ b/erpnext/controllers/sales_and_purchase_return.py @@ -320,7 +320,9 @@ def get_returned_qty_map_for_row(return_against, party, row_name, doctype): return data[0] -def make_return_doc(doctype: str, source_name: str, target_doc=None): +def make_return_doc( + doctype: str, source_name: str, target_doc=None, return_against_rejected_qty=False +): from frappe.model.mapper import get_mapped_doc company = frappe.db.get_value("Delivery Note", source_name, "company") @@ -471,7 +473,7 @@ def make_return_doc(doctype: str, source_name: str, target_doc=None): target_doc.qty = -1 * flt(source_doc.qty - (returned_qty_map.get("qty") or 0)) - if hasattr(target_doc, "stock_qty"): + if hasattr(target_doc, "stock_qty") and not return_against_rejected_qty: target_doc.stock_qty = -1 * flt( source_doc.stock_qty - (returned_qty_map.get("stock_qty") or 0) ) @@ -490,6 +492,13 @@ def make_return_doc(doctype: str, source_name: str, target_doc=None): target_doc.rejected_warehouse = source_doc.rejected_warehouse target_doc.purchase_receipt_item = source_doc.name + if doctype == "Purchase Receipt" and return_against_rejected_qty: + target_doc.qty = -1 * flt(source_doc.rejected_qty - (returned_qty_map.get("qty") or 0)) + target_doc.rejected_qty = 0.0 + target_doc.rejected_warehouse = "" + target_doc.warehouse = source_doc.rejected_warehouse + target_doc.received_qty = target_doc.qty + elif doctype == "Purchase Invoice": returned_qty_map = get_returned_qty_map_for_row( source_parent.name, source_parent.supplier, source_doc.name, doctype diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js index 685209c02e..35aad78c1a 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js @@ -213,10 +213,43 @@ erpnext.stock.PurchaseReceiptController = class PurchaseReceiptController extend } make_purchase_return() { - frappe.model.open_mapped_doc({ - method: "erpnext.stock.doctype.purchase_receipt.purchase_receipt.make_purchase_return", - frm: cur_frm + let me = this; + + let has_rejected_items = cur_frm.doc.items.filter((item) => { + if (item.rejected_qty > 0) { + return true; + } }) + + if (has_rejected_items && has_rejected_items.length > 0) { + frappe.prompt([ + { + label: __("Return Qty from Rejected Warehouse"), + fieldtype: "Check", + fieldname: "return_for_rejected_warehouse", + default: 1 + }, + ], function(values){ + if (values.return_for_rejected_warehouse) { + frappe.call({ + method: "erpnext.stock.doctype.purchase_receipt.purchase_receipt.make_purchase_return_against_rejected_warehouse", + args: { + source_name: cur_frm.doc.name + }, + callback: function(r) { + if(r.message) { + frappe.model.sync(r.message); + frappe.set_route("Form", r.message.doctype, r.message.name); + } + } + }) + } else { + cur_frm.cscript._make_purchase_return(); + } + }, __("Return Qty"), __("Make Return Entry")); + } else { + cur_frm.cscript._make_purchase_return(); + } } close_purchase_receipt() { @@ -326,6 +359,13 @@ frappe.ui.form.on('Purchase Receipt Item', { }, }); +cur_frm.cscript._make_purchase_return = function() { + frappe.model.open_mapped_doc({ + method: "erpnext.stock.doctype.purchase_receipt.purchase_receipt.make_purchase_return", + frm: cur_frm + }); +} + cur_frm.cscript['Make Stock Entry'] = function() { frappe.model.open_mapped_doc({ method: "erpnext.stock.doctype.purchase_receipt.purchase_receipt.make_stock_entry", diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py index 387f031380..0b5dc05c3a 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py @@ -1136,6 +1136,13 @@ def get_returned_qty_map(purchase_receipt): return returned_qty_map +@frappe.whitelist() +def make_purchase_return_against_rejected_warehouse(source_name): + from erpnext.controllers.sales_and_purchase_return import make_return_doc + + return make_return_doc("Purchase Receipt", source_name, return_against_rejected_qty=True) + + @frappe.whitelist() def make_purchase_return(source_name, target_doc=None): from erpnext.controllers.sales_and_purchase_return import make_return_doc diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py index ddc055656f..1986722587 100644 --- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py @@ -1827,6 +1827,33 @@ class TestPurchaseReceipt(FrappeTestCase): self.assertEqual(abs(data["stock_value_difference"]), 400.00) + def test_return_from_rejected_warehouse(self): + from erpnext.stock.doctype.purchase_receipt.purchase_receipt import ( + make_purchase_return_against_rejected_warehouse, + ) + + item_code = "_Test Item Return from Rejected Warehouse" + create_item(item_code) + + warehouse = create_warehouse("_Test Warehouse Return Qty Warehouse") + rejected_warehouse = create_warehouse("_Test Rejected Warehouse Return Qty Warehouse") + + # Step 1: Create Purchase Receipt with valuation rate 100 + pr = make_purchase_receipt( + item_code=item_code, + warehouse=warehouse, + qty=10, + rate=100, + rejected_qty=2, + rejected_warehouse=rejected_warehouse, + ) + + pr_return = make_purchase_return_against_rejected_warehouse(pr.name) + self.assertEqual(pr_return.items[0].warehouse, rejected_warehouse) + self.assertEqual(pr_return.items[0].qty, 2.0 * -1) + self.assertEqual(pr_return.items[0].rejected_qty, 0.0) + self.assertEqual(pr_return.items[0].rejected_warehouse, "") + def prepare_data_for_internal_transfer(): from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_internal_supplier