From 287eff533ad63bc3c067440ad9bb66e55ad203ae Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 26 Feb 2024 14:55:06 +0530 Subject: [PATCH 01/12] fix: Reload document on cancel to avoid document modified error --- erpnext/assets/doctype/asset/asset.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py index 166e8c4cfa7..e8bfa0201e9 100644 --- a/erpnext/assets/doctype/asset/asset.py +++ b/erpnext/assets/doctype/asset/asset.py @@ -152,6 +152,7 @@ class Asset(AccountsController): def on_submit(self): self.validate_in_use_date() self.make_asset_movement() + self.reload() if not self.booked_fixed_asset and self.validate_make_gl_entry(): self.make_gl_entries() if self.calculate_depreciation and not self.split_from: @@ -163,6 +164,7 @@ class Asset(AccountsController): self.validate_cancellation() self.cancel_movement_entries() self.cancel_capitalization() + self.reload() self.delete_depreciation_entries() cancel_asset_depr_schedules(self) self.set_status() From 7e301f02df1ac847da334624ae49416128e3cf93 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 12 Mar 2024 12:25:01 +0530 Subject: [PATCH 02/12] fix: convert str to date --- erpnext/assets/doctype/asset/asset.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py index e8bfa0201e9..385797fbd1a 100644 --- a/erpnext/assets/doctype/asset/asset.py +++ b/erpnext/assets/doctype/asset/asset.py @@ -700,7 +700,9 @@ class Asset(AccountsController): fixed_asset_account, cwip_account = self.get_fixed_asset_account(), self.get_cwip_account() if ( - purchase_document and self.purchase_receipt_amount and self.available_for_use_date <= nowdate() + purchase_document + and self.purchase_receipt_amount + and getdate(self.available_for_use_date) <= getdate() ): gl_entries.append( From dedae4fecf1e445e82869207f08b3dd04b1d6e17 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 12 Mar 2024 12:32:57 +0530 Subject: [PATCH 03/12] fix: Book depreciation until the asset disposal date and removed unwanted commits --- erpnext/assets/doctype/asset/depreciation.py | 3 +-- .../asset_depreciation_schedule/asset_depreciation_schedule.py | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/erpnext/assets/doctype/asset/depreciation.py b/erpnext/assets/doctype/asset/depreciation.py index 191675c2ab4..205f4b90a3a 100644 --- a/erpnext/assets/doctype/asset/depreciation.py +++ b/erpnext/assets/doctype/asset/depreciation.py @@ -242,9 +242,7 @@ def make_depreciation_entry( debit_account, accounting_dimensions, ) - frappe.db.commit() except Exception as e: - frappe.db.rollback() depreciation_posting_error = e asset.set_status() @@ -523,6 +521,7 @@ def depreciate_asset(asset_doc, date, notes): make_depreciation_entry_for_all_asset_depr_schedules(asset_doc, date) + asset_doc.reload() cancel_depreciation_entries(asset_doc, date) diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py index 77469df8955..6e165089334 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py @@ -327,7 +327,7 @@ class AssetDepreciationSchedule(Document): schedule_date = get_last_day(schedule_date) # if asset is being sold or scrapped - if date_of_disposal: + if date_of_disposal and getdate(schedule_date) >= getdate(date_of_disposal): from_date = add_months( getdate(asset_doc.available_for_use_date), (asset_doc.number_of_depreciations_booked * row.frequency_of_depreciation), From e786a93c2ece97d9b680127003d058b9a9e21d26 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Tue, 12 Mar 2024 21:29:44 +0530 Subject: [PATCH 04/12] fix: advance journal fetching logic in Advances section --- erpnext/controllers/accounts_controller.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index c543dfc2cd0..9499c47fd56 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -2707,14 +2707,20 @@ def get_advance_journal_entries( else: q = q.where(journal_acc.debit_in_account_currency > 0) + reference_or_condition = [] + if include_unallocated: - q = q.where((journal_acc.reference_name.isnull()) | (journal_acc.reference_name == "")) + reference_or_condition.append(journal_acc.reference_name.isnull()) + reference_or_condition.append(journal_acc.reference_name == "") if order_list: - q = q.where( + reference_or_condition.append( (journal_acc.reference_type == order_doctype) & ((journal_acc.reference_name).isin(order_list)) ) + if reference_or_condition: + q = q.where(Criterion.any(reference_or_condition)) + q = q.orderby(journal_entry.posting_date) journal_entries = q.run(as_dict=True) From 65ae9616ba5555f98c415ff2b4d7cfe17b5042e5 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Wed, 13 Mar 2024 13:59:50 +0530 Subject: [PATCH 05/12] fix: Taxes not getting updated on change --- erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js | 2 ++ .../purchase_taxes_and_charges_template.js | 1 + erpnext/accounts/doctype/sales_invoice/sales_invoice.js | 2 ++ .../sales_taxes_and_charges_template.js | 1 + erpnext/buying/doctype/purchase_order/purchase_order.js | 2 ++ erpnext/selling/doctype/quotation/quotation.js | 2 ++ erpnext/selling/doctype/sales_order/sales_order.js | 2 ++ erpnext/stock/doctype/delivery_note/delivery_note.js | 2 ++ erpnext/stock/doctype/purchase_receipt/purchase_receipt.js | 2 ++ 9 files changed, 16 insertions(+) diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js index d6455b2002a..957611f7858 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js @@ -3,6 +3,8 @@ frappe.provide("erpnext.accounts"); +cur_frm.cscript.tax_table = "Purchase Taxes and Charges"; + erpnext.accounts.payment_triggers.setup("Purchase Invoice"); erpnext.accounts.taxes.setup_tax_filters("Purchase Taxes and Charges"); erpnext.accounts.taxes.setup_tax_validations("Purchase Invoice"); diff --git a/erpnext/accounts/doctype/purchase_taxes_and_charges_template/purchase_taxes_and_charges_template.js b/erpnext/accounts/doctype/purchase_taxes_and_charges_template/purchase_taxes_and_charges_template.js index 66a9cbe8440..4c94503c184 100644 --- a/erpnext/accounts/doctype/purchase_taxes_and_charges_template/purchase_taxes_and_charges_template.js +++ b/erpnext/accounts/doctype/purchase_taxes_and_charges_template/purchase_taxes_and_charges_template.js @@ -1,6 +1,7 @@ // Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors // License: GNU General Public License v3. See license.txt +cur_frm.cscript.tax_table = "Purchase Taxes and Charges"; erpnext.accounts.taxes.setup_tax_validations("Purchase Taxes and Charges Template"); erpnext.accounts.taxes.setup_tax_filters("Purchase Taxes and Charges"); diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js index 17101cd2720..c7505ce007d 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js @@ -3,6 +3,8 @@ frappe.provide("erpnext.accounts"); +cur_frm.cscript.tax_table = "Sales Taxes and Charges"; + erpnext.accounts.taxes.setup_tax_validations("Sales Invoice"); erpnext.accounts.payment_triggers.setup("Sales Invoice"); erpnext.accounts.pos.setup("Sales Invoice"); diff --git a/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template.js b/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template.js index 91d4d047f8f..c42623addb5 100644 --- a/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template.js +++ b/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template.js @@ -1,5 +1,6 @@ // Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors // License: GNU General Public License v3. See license.txt +cur_frm.cscript.tax_table = "Sales Taxes and Charges"; erpnext.accounts.taxes.setup_tax_validations("Sales Taxes and Charges Template"); erpnext.accounts.taxes.setup_tax_filters("Sales Taxes and Charges"); diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js index 7875646ab72..2bb602c27ad 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.js +++ b/erpnext/buying/doctype/purchase_order/purchase_order.js @@ -4,6 +4,8 @@ frappe.provide("erpnext.buying"); frappe.provide("erpnext.accounts.dimensions"); +cur_frm.cscript.tax_table = "Purchase Taxes and Charges"; + erpnext.accounts.taxes.setup_tax_filters("Purchase Taxes and Charges"); erpnext.accounts.taxes.setup_tax_validations("Purchase Order"); erpnext.buying.setup_buying_controller(); diff --git a/erpnext/selling/doctype/quotation/quotation.js b/erpnext/selling/doctype/quotation/quotation.js index 6e2b7262641..95cbfd0f32b 100644 --- a/erpnext/selling/doctype/quotation/quotation.js +++ b/erpnext/selling/doctype/quotation/quotation.js @@ -1,6 +1,8 @@ // Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors // License: GNU General Public License v3. See license.txt +cur_frm.cscript.tax_table = "Sales Taxes and Charges"; + erpnext.accounts.taxes.setup_tax_validations("Sales Taxes and Charges Template"); erpnext.accounts.taxes.setup_tax_filters("Sales Taxes and Charges"); erpnext.pre_sales.set_as_lost("Quotation"); diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js index 161a06474cd..db16982cc15 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.js +++ b/erpnext/selling/doctype/sales_order/sales_order.js @@ -1,6 +1,8 @@ // Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors // License: GNU General Public License v3. See license.txt +cur_frm.cscript.tax_table = "Sales Taxes and Charges"; + erpnext.accounts.taxes.setup_tax_filters("Sales Taxes and Charges"); erpnext.accounts.taxes.setup_tax_validations("Sales Order"); erpnext.sales_common.setup_selling_controller(); diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.js b/erpnext/stock/doctype/delivery_note/delivery_note.js index c04d5c188a0..23d0adc5708 100644 --- a/erpnext/stock/doctype/delivery_note/delivery_note.js +++ b/erpnext/stock/doctype/delivery_note/delivery_note.js @@ -3,6 +3,8 @@ cur_frm.add_fetch("customer", "tax_id", "tax_id"); +cur_frm.cscript.tax_table = "Sales Taxes and Charges"; + frappe.provide("erpnext.stock"); frappe.provide("erpnext.stock.delivery_note"); frappe.provide("erpnext.accounts.dimensions"); diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js index 997cdd0e56f..bfac4381a06 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js @@ -3,6 +3,8 @@ frappe.provide("erpnext.stock"); +cur_frm.cscript.tax_table = "Purchase Taxes and Charges"; + erpnext.accounts.taxes.setup_tax_filters("Purchase Taxes and Charges"); erpnext.accounts.taxes.setup_tax_validations("Purchase Receipt"); erpnext.buying.setup_buying_controller(); From f4a945aee405a3151bd47bf3a91886c3e7448516 Mon Sep 17 00:00:00 2001 From: rohitwaghchaure Date: Wed, 13 Mar 2024 17:48:06 +0530 Subject: [PATCH 06/12] fix: incorrect gross profit on the quotation (#40438) --- erpnext/controllers/accounts_controller.py | 1 + .../doctype/quotation/test_quotation.py | 33 +++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index 250f21bdcc5..b7e687dc1d8 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -89,6 +89,7 @@ force_item_fields = ( "weight_per_unit", "weight_uom", "total_weight", + "valuation_rate", ) diff --git a/erpnext/selling/doctype/quotation/test_quotation.py b/erpnext/selling/doctype/quotation/test_quotation.py index 0b0d6e7faa9..a5259426dd9 100644 --- a/erpnext/selling/doctype/quotation/test_quotation.py +++ b/erpnext/selling/doctype/quotation/test_quotation.py @@ -42,6 +42,39 @@ class TestQuotation(FrappeTestCase): self.assertTrue(sales_order.get("payment_schedule")) + def test_gross_profit(self): + from erpnext.stock.doctype.item.test_item import make_item + from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry + from erpnext.stock.get_item_details import insert_item_price + + item_doc = make_item("_Test Item for Gross Profit", {"is_stock_item": 1}) + item_code = item_doc.name + make_stock_entry(item_code=item_code, qty=10, rate=100, target="_Test Warehouse - _TC") + + selling_price_list = frappe.get_all("Price List", filters={"selling": 1}, limit=1)[0].name + frappe.db.set_single_value("Stock Settings", "auto_insert_price_list_rate_if_missing", 1) + insert_item_price( + frappe._dict( + { + "item_code": item_code, + "price_list": selling_price_list, + "price_list_rate": 300, + "rate": 300, + "conversion_factor": 1, + "discount_amount": 0.0, + "currency": frappe.db.get_value("Price List", selling_price_list, "currency"), + "uom": item_doc.stock_uom, + } + ) + ) + + quotation = make_quotation( + item_code=item_code, qty=1, rate=300, selling_price_list=selling_price_list + ) + self.assertEqual(quotation.items[0].valuation_rate, 100) + self.assertEqual(quotation.items[0].gross_profit, 200) + frappe.db.set_single_value("Stock Settings", "auto_insert_price_list_rate_if_missing", 0) + def test_maintain_rate_in_sales_cycle_is_enforced(self): from erpnext.selling.doctype.quotation.quotation import make_sales_order From cd79dcccb6ce34f2d4be108f41196c12bdbaae84 Mon Sep 17 00:00:00 2001 From: rohitwaghchaure Date: Thu, 14 Mar 2024 11:19:57 +0530 Subject: [PATCH 07/12] fix: Data too long for column 'stock_queue' (#40436) --- .../stock/doctype/stock_ledger_entry/stock_ledger_entry.json | 4 ++-- .../stock/doctype/stock_ledger_entry/stock_ledger_entry.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json index 3a094f1e8f5..e8e82af25ac 100644 --- a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json +++ b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json @@ -230,7 +230,7 @@ }, { "fieldname": "stock_queue", - "fieldtype": "Text", + "fieldtype": "Long Text", "label": "FIFO Stock Queue (qty, rate)", "oldfieldname": "fcfs_stack", "oldfieldtype": "Text", @@ -360,7 +360,7 @@ "in_create": 1, "index_web_pages_for_search": 1, "links": [], - "modified": "2024-02-07 09:18:13.999231", + "modified": "2024-03-13 09:56:13.021696", "modified_by": "Administrator", "module": "Stock", "name": "Stock Ledger Entry", diff --git a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py index a3e51ca60d6..b49fe228831 100644 --- a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py +++ b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py @@ -58,7 +58,7 @@ class StockLedgerEntry(Document): recalculate_rate: DF.Check serial_and_batch_bundle: DF.Link | None serial_no: DF.LongText | None - stock_queue: DF.Text | None + stock_queue: DF.LongText | None stock_uom: DF.Link | None stock_value: DF.Currency stock_value_difference: DF.Currency From ec83d54826d7218aadc18d8ef7ddeb6f8bd99fc3 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Thu, 14 Mar 2024 13:48:51 +0530 Subject: [PATCH 08/12] chore: fix test case --- .../doctype/closing_stock_balance/closing_stock_balance.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/erpnext/stock/doctype/closing_stock_balance/closing_stock_balance.py b/erpnext/stock/doctype/closing_stock_balance/closing_stock_balance.py index 1c7018366af..e99a0b1add2 100644 --- a/erpnext/stock/doctype/closing_stock_balance/closing_stock_balance.py +++ b/erpnext/stock/doctype/closing_stock_balance/closing_stock_balance.py @@ -123,7 +123,9 @@ class ClosingStockBalance(Document): ) ) - create_json_gz_file({"columns": columns, "data": data}, self.doctype, self.name) + create_json_gz_file( + {"columns": columns, "data": data}, self.doctype, self.name, "closing-stock-balance" + ) def get_prepared_data(self): if attachments := get_attachments(self.doctype, self.name): From 437bdc2d8c8ad6e09b890711fab7378dbd160f86 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Wed, 13 Mar 2024 21:24:24 +0530 Subject: [PATCH 09/12] fix: flaky Accounts Receivable test case --- .../report/accounts_receivable/test_accounts_receivable.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py index a0f8af5d419..0a743423d52 100644 --- a/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py +++ b/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py @@ -207,7 +207,6 @@ class TestAccountsReceivable(AccountsTestMixin, FrappeTestCase): # check invoice grand total, invoiced, paid and outstanding column's value after credit note cr_note = self.create_credit_note(si.name, do_not_submit=True) - cr_note.posting_date = add_days(today(), 1) cr_note.update_outstanding_for_self = True cr_note.save().submit() report = execute(filters) @@ -218,10 +217,9 @@ class TestAccountsReceivable(AccountsTestMixin, FrappeTestCase): ] self.assertEqual(len(report[1]), 2) for i in range(2): - row = report[1][i - 1] - # row = report[1][0] + row = report[1][i] self.assertEqual( - expected_data_after_credit_note[i - 1], + expected_data_after_credit_note[i], [ row.invoice_grand_total, row.invoiced, From a9a9b1297e7c6e56a26be900f1a75aaa8bc2774c Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Thu, 14 Mar 2024 09:32:27 +0530 Subject: [PATCH 10/12] fix(test): manually filter rows and assert --- .../test_accounts_receivable.py | 50 ++++++++++++------- 1 file changed, 33 insertions(+), 17 deletions(-) diff --git a/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py index 0a743423d52..de49139adc1 100644 --- a/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py +++ b/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py @@ -182,8 +182,10 @@ class TestAccountsReceivable(AccountsTestMixin, FrappeTestCase): } # check invoice grand total and invoiced column's value for 3 payment terms - si = self.create_sales_invoice(no_payment_schedule=True) - name = si.name + si = self.create_sales_invoice(no_payment_schedule=True, do_not_submit=True) + si.set_posting_time = True + si.posting_date = add_days(today(), -1) + si.save().submit() report = execute(filters) @@ -212,23 +214,37 @@ class TestAccountsReceivable(AccountsTestMixin, FrappeTestCase): report = execute(filters) expected_data_after_credit_note = [ - [100.0, 100.0, 40.0, 0.0, 60.0, self.debit_to], - [0, 0, 100.0, 0.0, -100.0, self.debit_to], + [100.0, 100.0, 40.0, 0.0, 60.0, si.name], + [0, 0, 100.0, 0.0, -100.0, cr_note.name], ] self.assertEqual(len(report[1]), 2) - for i in range(2): - row = report[1][i] - self.assertEqual( - expected_data_after_credit_note[i], - [ - row.invoice_grand_total, - row.invoiced, - row.paid, - row.credit_note, - row.outstanding, - row.party_account, - ], - ) + si_row = [ + [ + row.invoice_grand_total, + row.invoiced, + row.paid, + row.credit_note, + row.outstanding, + row.voucher_no, + ] + for row in report[1] + if row.voucher_no == si.name + ][0] + + cr_note_row = [ + [ + row.invoice_grand_total, + row.invoiced, + row.paid, + row.credit_note, + row.outstanding, + row.voucher_no, + ] + for row in report[1] + if row.voucher_no == cr_note.name + ][0] + self.assertEqual(expected_data_after_credit_note[0], si_row) + self.assertEqual(expected_data_after_credit_note[1], cr_note_row) def test_payment_againt_po_in_receivable_report(self): """ From 898affbee902b5f1d76f3cc7c4876b8d2eeb1a46 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Thu, 14 Mar 2024 16:48:55 +0530 Subject: [PATCH 11/12] refactor: disallow '0' qty return invoices with stock effect --- erpnext/controllers/accounts_controller.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index b7e687dc1d8..604e587f434 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -169,6 +169,13 @@ class AccountsController(TransactionBase): if not self.get("is_return") and not self.get("is_debit_note"): self.validate_qty_is_not_zero() + if ( + self.doctype in ["Sales Invoice", "Purchase Invoice"] + and self.get("is_return") + and self.get("update_stock") + ): + self.validate_zero_qty_for_return_invoices_with_stock() + if self.get("_action") and self._action != "update_after_submit": self.set_missing_values(for_validate=True) @@ -1045,6 +1052,18 @@ class AccountsController(TransactionBase): else: return flt(args.get(field, 0) / self.get("conversion_rate", 1)) + def validate_zero_qty_for_return_invoices_with_stock(self): + rows = [] + for item in self.items: + if not flt(item.qty): + rows.append(item) + if rows: + frappe.throw( + _( + "For Return Invoices with Stock effect, '0' qty Items are not allowed. Following rows are affected: {0}" + ).format(frappe.bold(comma_and(["#" + str(x.idx) for x in rows]))) + ) + def validate_qty_is_not_zero(self): for item in self.items: if self.doctype == "Purchase Receipt" and item.rejected_qty: From 647bba0f00d24a4b88c9e258cc86116783db81fe Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Fri, 15 Mar 2024 10:47:32 +0530 Subject: [PATCH 12/12] test: validation to prevent '0' qty return with stock effect --- .../accounts/doctype/sales_invoice/test_sales_invoice.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index c8a35eb3f09..85e9d162da6 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -1588,6 +1588,12 @@ class TestSalesInvoice(FrappeTestCase): self.assertEqual(frappe.db.get_value("Sales Invoice", si1.name, "outstanding_amount"), -1000) self.assertEqual(frappe.db.get_value("Sales Invoice", si.name, "outstanding_amount"), 2500) + def test_zero_qty_return_invoice_with_stock_effect(self): + cr_note = create_sales_invoice(qty=-1, rate=300, is_return=1, do_not_submit=True) + cr_note.update_stock = True + cr_note.items[0].qty = 0 + self.assertRaises(frappe.ValidationError, cr_note.save) + def test_return_invoice_with_account_mismatch(self): debtors2 = create_account( parent_account="Accounts Receivable - _TC",