From 04ca25e199cf62092c283e276104f8de880ae40f Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Thu, 11 Apr 2024 07:38:28 +0000 Subject: [PATCH 01/27] chore(release): Bumped to Version 15.20.0 # [15.20.0](https://github.com/frappe/erpnext/compare/v15.19.2...v15.20.0) (2024-04-11) ### Bug Fixes * check if there is any existing depreciation schedule ([dcb7e27](https://github.com/frappe/erpnext/commit/dcb7e27a5e8a5daf0e933a81016d99fe168bc4cc)) * Default company bank account ([d8c5f15](https://github.com/frappe/erpnext/commit/d8c5f15bc0f2482a79b598e86abca9ddaaf55b64)) * depr amount pro rata and related tests ([350d53d](https://github.com/frappe/erpnext/commit/350d53dbe1c0680d0f29988452eb9e8b2f3decd0)) * depr amount pro rata and related tests ([854d4a9](https://github.com/frappe/erpnext/commit/854d4a9c79101e27553bca9e50fae7c7ad0a9945)) * Don't call get_fiscal_year if setup is not done yet ([9beaf65](https://github.com/frappe/erpnext/commit/9beaf65d19b5a218fa12bd1f227c8ec641d67d79)) * exclude some query builder lines from ruff rules ([41d7c03](https://github.com/frappe/erpnext/commit/41d7c03cbb86baade0d0db0a13a27832c8299da8)) * Fetch outstanding and total amount for reference journal entry ([c72f61e](https://github.com/frappe/erpnext/commit/c72f61ef2f885c6afb80ba34d8aa48eb06b2df3b)) * Get default party bank account and company bank account for a party ([1745673](https://github.com/frappe/erpnext/commit/174567350e232073d4c51756186f7ae894b322ab)) * Get pro-rata amount based on correct days ([1276855](https://github.com/frappe/erpnext/commit/1276855f40328dcea921a3706611f03746487255)) * Get pro-rata amount based on correct days ([5bf7c79](https://github.com/frappe/erpnext/commit/5bf7c799e2bfa2b856838ff91325442572fca6b7)) * group warehouse added in the stock reconciliation ([e6d6172](https://github.com/frappe/erpnext/commit/e6d6172b4c0584717b84b8ec48b9807c3388cd05)) * ignore dimension validation for cancelled entries ([b288c73](https://github.com/frappe/erpnext/commit/b288c734376c09e25c97c53b3aaef6d55c932415)) * Ignore permissions while fetching module settings properties ([5e9f31c](https://github.com/frappe/erpnext/commit/5e9f31cf21e6f274f902d5c488a4be8fe7d96653)) * incorrect currency symbol in General Ledger print ([9f4663b](https://github.com/frappe/erpnext/commit/9f4663b4d081e5015610b833c06992a3992d8d9f)) * incorrect operator causing incorrect validation ([80c2a33](https://github.com/frappe/erpnext/commit/80c2a33fd72fd1f2891ebb01e24d76a674b2204a)) * invalid ledger entries on payment against reverse payments ([f3eb559](https://github.com/frappe/erpnext/commit/f3eb559a71459245e107eb88ded77d2cf51d94a3)) * linter issues ([8016b0a](https://github.com/frappe/erpnext/commit/8016b0aee72e7715df5bf196a544242ee6240057)) * notify update when update outstanding amount ([b10d3c4](https://github.com/frappe/erpnext/commit/b10d3c4da26613329e2f3e594a3b61d83126714d)) * notify update when update outstanding amount - Linters ([f514819](https://github.com/frappe/erpnext/commit/f51481983d3fab7ed3c0cd5d93ee0ad6027aab39)) * pass empty string email content of pos invoice ([7a9291b](https://github.com/frappe/erpnext/commit/7a9291b3d1e0766cf11035a543064c19b922597b)) * pick list validation didn't consider existing draft pick list ([722abf1](https://github.com/frappe/erpnext/commit/722abf1b6b60a68c8a91edc356c497ab3da3e349)) * pro-rata amount for straight line method ([16a5475](https://github.com/frappe/erpnext/commit/16a5475c0c82c9cfc94675652aead57b2a8586b9)) * query_report.trigger_refresh is not a function ([4f48ede](https://github.com/frappe/erpnext/commit/4f48ede7a0aefc78ea14855cd72ba45790a5a971)) * Recalculate sales commission on item update ([5117494](https://github.com/frappe/erpnext/commit/5117494a52dab116d1c35aa2a330158f3362b8b3)) * Receive payment entry from Employee ([0cee954](https://github.com/frappe/erpnext/commit/0cee954f84641b2e658726fe40ffb1a34b6ac222)) * resolved merge conflict ([edd143b](https://github.com/frappe/erpnext/commit/edd143b0840eec5aaf1997bb303439b592904eac)) * Show amount in transaction currency in general ledger report ([67bac41](https://github.com/frappe/erpnext/commit/67bac41df4fdd62a3efda4bb61a7ab80d6b1d0af)) * show currency symbol in base currency in fixed asset register report ([7904389](https://github.com/frappe/erpnext/commit/79043894b2d52152acda8e36f2c95f5c51469979)) * Show itemised TDS breakup based on Apply TDS checkbox on item level ([4e3c885](https://github.com/frappe/erpnext/commit/4e3c885808a16bd08ada57b82673aea60bd182d9)) * **test:** Advance Received should be under liability account ([4f13f47](https://github.com/frappe/erpnext/commit/4f13f4779a470a1e22aa5dfc4873bec68d3ee8b7)) * **test:** for reverse payments, only advance acc should have effect ([3668de7](https://github.com/frappe/erpnext/commit/3668de7cb770ad54b9f102ca9af36539f4e729c8)) * translatable web footer ([#40834](https://github.com/frappe/erpnext/issues/40834)) ([e8497b2](https://github.com/frappe/erpnext/commit/e8497b2d80c2ed0475ae60b7f9ab9c2a1150ec3f)) * **treewide:** manual ruff fixes ([7828eee](https://github.com/frappe/erpnext/commit/7828eee01432e5c3125760308b09154e7ff7dfee)) * use 'eq' and isnull() on qb conditions ([2268995](https://github.com/frappe/erpnext/commit/22689958da2dfd96d19271989afdd54ad57a5990)) * use reference type name to update exc rate ([5b62f20](https://github.com/frappe/erpnext/commit/5b62f2050bd62f7ef4a41f39b2c43e2d1b8658c3)) * Values in transaciton currency ([3b179ba](https://github.com/frappe/erpnext/commit/3b179bad89789af721d1d50272ddc0a833c050b8)) * workstation refresh after prompt ([9f12c96](https://github.com/frappe/erpnext/commit/9f12c964dc0cd69bcd919807244c82f3c25b4034)) * wrong value for total amount in payments ([807def0](https://github.com/frappe/erpnext/commit/807def0f044159d3217e136f01aa2978f83fe57e)) ### Features * ledger health doctype ([5d978c2](https://github.com/frappe/erpnext/commit/5d978c27290fa521aa59dc1c42c254924d5d1608)) * new hook `fields_for_group_similar_items` to group additional fields for print formats ([#40831](https://github.com/frappe/erpnext/issues/40831)) ([4ef4466](https://github.com/frappe/erpnext/commit/4ef4466e6779de4418ff1cb24974f03a6c3c5e85)) --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 78ebd0f139d..7e50c825629 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -3,7 +3,7 @@ import inspect import frappe -__version__ = "15.19.2" +__version__ = "15.20.0" def get_default_company(user=None): From 83a5284ba93e53308f18411864951c045ff17ff9 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Thu, 11 Apr 2024 16:20:55 +0530 Subject: [PATCH 02/27] fix: landed cost voucher for legacy pr with batch (cherry picked from commit fa91cda46cd1271cbd442a4d988cf6775cc64788) (cherry picked from commit 4e215c6b7b88562dcc1bac5265180dd048dc07a3) --- erpnext/controllers/stock_controller.py | 4 +- .../landed_cost_voucher.py | 1 + .../test_landed_cost_voucher.py | 149 ++++++++++++++++++ 3 files changed, 152 insertions(+), 2 deletions(-) diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index af0afb4dd02..73436508282 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -166,7 +166,7 @@ class StockController(AccountsController): # remove extra whitespace and store one serial no on each line row.serial_no = clean_serial_no_string(row.serial_no) - def make_bundle_using_old_serial_batch_fields(self, table_name=None): + def make_bundle_using_old_serial_batch_fields(self, table_name=None, via_landed_cost_voucher=False): if self.get("_action") == "update_after_submit": return @@ -205,7 +205,7 @@ class StockController(AccountsController): "company": self.company, "is_rejected": 1 if row.get("rejected_warehouse") else 0, "use_serial_batch_fields": row.use_serial_batch_fields, - "do_not_submit": True, + "do_not_submit": True if not via_landed_cost_voucher else False, } if row.get("qty") or row.get("consumed_qty"): diff --git a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py index ff6d31a777f..601cde6c905 100644 --- a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py +++ b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py @@ -250,6 +250,7 @@ class LandedCostVoucher(Document): # update stock & gl entries for submit state of PR doc.docstatus = 1 + doc.make_bundle_using_old_serial_batch_fields(via_landed_cost_voucher=True) doc.update_stock_ledger(allow_negative_stock=True, via_landed_cost_voucher=True) doc.make_gl_entries() doc.repost_future_sle_and_gle() diff --git a/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py b/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py index 9ec2d695707..32b384def28 100644 --- a/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py +++ b/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py @@ -596,6 +596,155 @@ class TestLandedCostVoucher(FrappeTestCase): lcv.cancel() pr.cancel() + def test_landed_cost_voucher_with_serial_batch_for_legacy_pr(self): + from erpnext.stock.doctype.item.test_item import make_item + + frappe.flags.ignore_serial_batch_bundle_validation = True + frappe.flags.use_serial_and_batch_fields = True + sn_item = "Test Landed Cost Voucher Serial NO for Legacy PR" + batch_item = "Test Landed Cost Voucher Batch NO for Legacy PR" + sn_item_doc = make_item( + sn_item, + { + "has_serial_no": 1, + "serial_no_series": "SN-TLCVSNO-.####", + "is_stock_item": 1, + }, + ) + + batch_item_doc = make_item( + batch_item, + { + "has_batch_no": 1, + "batch_number_series": "BATCH-TLCVSNO-.####", + "create_new_batch": 1, + "is_stock_item": 1, + }, + ) + + serial_nos = [ + "SN-TLCVSNO-0001", + "SN-TLCVSNO-0002", + "SN-TLCVSNO-0003", + "SN-TLCVSNO-0004", + "SN-TLCVSNO-0005", + ] + + for sn in serial_nos: + if not frappe.db.exists("Serial No", sn): + sn_doc = frappe.get_doc( + { + "doctype": "Serial No", + "item_code": sn_item, + "serial_no": sn, + } + ) + sn_doc.insert() + + if not frappe.db.exists("Batch", "BATCH-TLCVSNO-0001"): + batch_doc = frappe.get_doc( + { + "doctype": "Batch", + "item": batch_item, + "batch_id": "BATCH-TLCVSNO-0001", + } + ) + batch_doc.insert() + + warehouse = "_Test Warehouse - _TC" + company = frappe.db.get_value("Warehouse", warehouse, "company") + + pr = make_purchase_receipt( + company=company, + warehouse=warehouse, + item_code=sn_item, + qty=5, + rate=100, + uom=sn_item_doc.stock_uom, + stock_uom=sn_item_doc.stock_uom, + do_not_submit=True, + ) + + pr.append( + "items", + { + "item_code": batch_item, + "item_name": batch_item, + "description": "Test Batch Item", + "uom": batch_item_doc.stock_uom, + "stock_uom": batch_item_doc.stock_uom, + "qty": 5, + "rate": 100, + "warehouse": warehouse, + }, + ) + + pr.submit() + pr.reload() + + for row in pr.items: + self.assertEqual(row.valuation_rate, 100) + self.assertFalse(row.serial_no) + self.assertFalse(row.batch_no) + self.assertFalse(row.serial_and_batch_bundle) + + if row.item_code == sn_item: + row.db_set("serial_no", ", ".join(serial_nos)) + else: + row.db_set("batch_no", "BATCH-TLCVSNO-0001") + + for sn in serial_nos: + sn_doc = frappe.get_doc("Serial No", sn) + sn_doc.db_set( + { + "warehouse": warehouse, + "status": "Active", + } + ) + + batch_doc.db_set( + { + "batch_qty": 5, + } + ) + + frappe.flags.ignore_serial_batch_bundle_validation = False + frappe.flags.use_serial_and_batch_fields = False + + lcv = make_landed_cost_voucher( + company=pr.company, + receipt_document_type="Purchase Receipt", + receipt_document=pr.name, + charges=20, + distribute_charges_based_on="Qty", + do_not_save=True, + ) + + lcv.get_items_from_purchase_receipts() + lcv.save() + lcv.submit() + + pr.reload() + + for row in pr.items: + self.assertEqual(row.valuation_rate, 102) + self.assertTrue(row.serial_and_batch_bundle) + self.assertEqual( + row.valuation_rate, + frappe.db.get_value("Serial and Batch Bundle", row.serial_and_batch_bundle, "avg_rate"), + ) + + lcv.cancel() + pr.reload() + + for row in pr.items: + self.assertEqual(row.valuation_rate, 100) + self.assertTrue(row.serial_and_batch_bundle) + self.assertEqual( + row.valuation_rate, + frappe.db.get_value("Serial and Batch Bundle", row.serial_and_batch_bundle, "avg_rate"), + ) + def make_landed_cost_voucher(**args): args = frappe._dict(args) From 72fc0836e182581b5cb8c47958a70f430b42a400 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Thu, 11 Apr 2024 17:35:06 +0530 Subject: [PATCH 03/27] fix: zero division error (cherry picked from commit f9e230e758f16a6715534648dadc1003af98401a) (cherry picked from commit e9c6c5a8eb47daa063fbbbeb74284fda338c1b80) --- erpnext/controllers/selling_controller.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py index ef7a5b69f92..e9896fa0fd6 100644 --- a/erpnext/controllers/selling_controller.py +++ b/erpnext/controllers/selling_controller.py @@ -444,7 +444,7 @@ class SellingController(StockController): get_valuation_method(d.item_code) == "Moving Average" and self.get("is_return") ): # Get incoming rate based on original item cost based on valuation method - qty = flt(d.get("stock_qty") or d.get("actual_qty")) + qty = flt(d.get("stock_qty") or d.get("actual_qty") or d.get("qty")) if ( not d.incoming_rate From c24d9675e8b84f7641397a47be468c5c7f27961e Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Thu, 11 Apr 2024 13:23:28 +0000 Subject: [PATCH 04/27] chore(release): Bumped to Version 15.20.1 ## [15.20.1](https://github.com/frappe/erpnext/compare/v15.20.0...v15.20.1) (2024-04-11) ### Bug Fixes * landed cost voucher for legacy pr with batch ([83a5284](https://github.com/frappe/erpnext/commit/83a5284ba93e53308f18411864951c045ff17ff9)) * zero division error ([72fc083](https://github.com/frappe/erpnext/commit/72fc0836e182581b5cb8c47958a70f430b42a400)) --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 7e50c825629..a4f24752bbe 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -3,7 +3,7 @@ import inspect import frappe -__version__ = "15.20.0" +__version__ = "15.20.1" def get_default_company(user=None): From 3d6ba6f21fc60e0393e2f132f43857f5ee34b60d Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Fri, 12 Apr 2024 15:31:40 +0530 Subject: [PATCH 05/27] fix: Subcontracting Receipt GL Entries (backport #40773) (backport #40979) (#40983) fix: Subcontracting Receipt GL Entries (backport #40773) (#40979) * fix: Subcontracting Receipt GL Entries (cherry picked from commit 9808ae92a44328f357c224e2f61c89e79c9255f7) # Conflicts: # erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py * chore: `conflicts` --------- Co-authored-by: s-aga-r (cherry picked from commit 9abc71f9c8f0335c986d4f3953a6147ec77bb557) Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> --- .../subcontracting_receipt.py | 95 ++++++++++++------- .../test_subcontracting_receipt.py | 69 ++++++++++---- 2 files changed, 116 insertions(+), 48 deletions(-) diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py index 87595289179..cc800e4369d 100644 --- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py +++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py @@ -498,9 +498,6 @@ class SubcontractingReceipt(SubcontractingController): return process_gl_map(gl_entries) def make_item_gl_entries(self, gl_entries, warehouse_account=None): - stock_rbnb = self.get_company_default("stock_received_but_not_billed") - expenses_included_in_valuation = self.get_company_default("expenses_included_in_valuation") - warehouse_with_no_account = [] for item in self.items: @@ -518,31 +515,41 @@ class SubcontractingReceipt(SubcontractingController): "stock_value_difference", ) - warehouse_account_name = warehouse_account[item.warehouse]["account"] - warehouse_account_currency = warehouse_account[item.warehouse]["account_currency"] + accepted_warehouse_account = warehouse_account[item.warehouse]["account"] supplier_warehouse_account = warehouse_account.get(self.supplier_warehouse, {}).get( "account" ) - supplier_warehouse_account_currency = warehouse_account.get( - self.supplier_warehouse, {} - ).get("account_currency") remarks = self.get("remarks") or _("Accounting Entry for Stock") - # FG Warehouse Account (Debit) + # Accepted Warehouse Account (Debit) self.add_gl_entry( gl_entries=gl_entries, - account=warehouse_account_name, + account=accepted_warehouse_account, cost_center=item.cost_center, debit=stock_value_diff, credit=0.0, remarks=remarks, - against_account=stock_rbnb, - account_currency=warehouse_account_currency, + against_account=item.expense_account, + account_currency=get_account_currency(accepted_warehouse_account), + project=item.project, + item=item, + ) + # Expense Account (Credit) + self.add_gl_entry( + gl_entries=gl_entries, + account=item.expense_account, + cost_center=item.cost_center, + debit=0.0, + credit=stock_value_diff, + remarks=remarks, + against_account=accepted_warehouse_account, + account_currency=get_account_currency(item.expense_account), + project=item.project, item=item, ) - # Supplier Warehouse Account (Credit) - if flt(item.rm_supp_cost) and warehouse_account.get(self.supplier_warehouse): + if flt(item.rm_supp_cost) and supplier_warehouse_account: + # Supplier Warehouse Account (Credit) self.add_gl_entry( gl_entries=gl_entries, account=supplier_warehouse_account, @@ -550,43 +557,66 @@ class SubcontractingReceipt(SubcontractingController): debit=0.0, credit=flt(item.rm_supp_cost), remarks=remarks, - against_account=warehouse_account_name, - account_currency=supplier_warehouse_account_currency, + against_account=item.expense_account, + account_currency=get_account_currency(supplier_warehouse_account), + project=item.project, item=item, ) - - # Expense Account (Credit) - if flt(item.service_cost_per_qty): + # Expense Account (Debit) self.add_gl_entry( gl_entries=gl_entries, account=item.expense_account, cost_center=item.cost_center, - debit=0.0, - credit=flt(item.service_cost_per_qty) * flt(item.qty), + debit=flt(item.rm_supp_cost), + credit=0.0, remarks=remarks, - against_account=warehouse_account_name, + against_account=supplier_warehouse_account, account_currency=get_account_currency(item.expense_account), + project=item.project, item=item, ) - # Loss Account (Credit) - divisional_loss = flt(item.amount - stock_value_diff, item.precision("amount")) + # Expense Account (Debit) + if item.additional_cost_per_qty: + self.add_gl_entry( + gl_entries=gl_entries, + account=item.expense_account, + cost_center=self.cost_center or self.get_company_default("cost_center"), + debit=item.qty * item.additional_cost_per_qty, + credit=0.0, + remarks=remarks, + against_account=None, + account_currency=get_account_currency(item.expense_account), + ) - if divisional_loss: - if self.is_return: - loss_account = expenses_included_in_valuation - else: - loss_account = item.expense_account + if divisional_loss := flt(item.amount - stock_value_diff, item.precision("amount")): + loss_account = self.get_company_default( + "stock_adjustment_account", ignore_validation=True + ) + # Loss Account (Credit) self.add_gl_entry( gl_entries=gl_entries, account=loss_account, cost_center=item.cost_center, + debit=0.0, + credit=divisional_loss, + remarks=remarks, + against_account=item.expense_account, + account_currency=get_account_currency(loss_account), + project=item.project, + item=item, + ) + # Expense Account (Debit) + self.add_gl_entry( + gl_entries=gl_entries, + account=item.expense_account, + cost_center=item.cost_center, debit=divisional_loss, credit=0.0, remarks=remarks, - against_account=warehouse_account_name, - account_currency=get_account_currency(loss_account), + against_account=loss_account, + account_currency=get_account_currency(item.expense_account), project=item.project, item=item, ) @@ -596,7 +626,6 @@ class SubcontractingReceipt(SubcontractingController): ): warehouse_with_no_account.append(item.warehouse) - # Additional Costs Expense Accounts (Credit) for row in self.additional_costs: credit_amount = ( flt(row.base_amount) @@ -604,6 +633,7 @@ class SubcontractingReceipt(SubcontractingController): else flt(row.amount) ) + # Additional Cost Expense Account (Credit) self.add_gl_entry( gl_entries=gl_entries, account=row.expense_account, @@ -612,6 +642,7 @@ class SubcontractingReceipt(SubcontractingController): credit=credit_amount, remarks=remarks, against_account=None, + account_currency=get_account_currency(row.expense_account), ) if warehouse_with_no_account: diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/test_subcontracting_receipt.py b/erpnext/subcontracting/doctype/subcontracting_receipt/test_subcontracting_receipt.py index 564096ff0fe..996a99065bb 100644 --- a/erpnext/subcontracting/doctype/subcontracting_receipt/test_subcontracting_receipt.py +++ b/erpnext/subcontracting/doctype/subcontracting_receipt/test_subcontracting_receipt.py @@ -10,6 +10,7 @@ from frappe.utils import add_days, cint, flt, nowtime, today import erpnext from erpnext.accounts.doctype.account.test_account import get_inventory_account +from erpnext.accounts.utils import get_company_default from erpnext.controllers.sales_and_purchase_return import make_return_doc from erpnext.controllers.tests.test_subcontracting_controller import ( get_rm_items, @@ -351,26 +352,15 @@ class TestSubcontractingReceipt(FrappeTestCase): self.assertEqual(cint(erpnext.is_perpetual_inventory_enabled(scr.company)), 1) gl_entries = get_gl_entries("Subcontracting Receipt", scr.name) - self.assertTrue(gl_entries) fg_warehouse_ac = get_inventory_account(scr.company, scr.items[0].warehouse) - supplier_warehouse_ac = get_inventory_account(scr.company, scr.supplier_warehouse) expense_account = scr.items[0].expense_account - - if fg_warehouse_ac == supplier_warehouse_ac: - expected_values = { - fg_warehouse_ac: [2100.0, 1000.0], # FG Amount (D), RM Cost (C) - expense_account: [0.0, 1000.0], # Service Cost (C) - additional_costs_expense_account: [0.0, 100.0], # Additional Cost (C) - } - else: - expected_values = { - fg_warehouse_ac: [2100.0, 0.0], # FG Amount (D) - supplier_warehouse_ac: [0.0, 1000.0], # RM Cost (C) - expense_account: [0.0, 1000.0], # Service Cost (C) - additional_costs_expense_account: [0.0, 100.0], # Additional Cost (C) - } + expected_values = { + fg_warehouse_ac: [2100.0, 1000], + expense_account: [1100, 2100], + additional_costs_expense_account: [0.0, 100.0], + } for gle in gl_entries: self.assertEqual(expected_values[gle.account][0], gle.debit) @@ -381,6 +371,53 @@ class TestSubcontractingReceipt(FrappeTestCase): self.assertTrue(get_gl_entries("Subcontracting Receipt", scr.name)) frappe.db.set_single_value("Stock Settings", "use_serial_batch_fields", 1) + @change_settings("Stock Settings", {"use_serial_batch_fields": 0}) + def test_subcontracting_receipt_with_zero_service_cost(self): + warehouse = "Stores - TCP1" + service_items = [ + { + "warehouse": warehouse, + "item_code": "Subcontracted Service Item 7", + "qty": 10, + "rate": 0, + "fg_item": "Subcontracted Item SA7", + "fg_item_qty": 10, + }, + ] + sco = get_subcontracting_order( + company="_Test Company with perpetual inventory", + warehouse=warehouse, + supplier_warehouse="Work In Progress - TCP1", + service_items=service_items, + ) + rm_items = get_rm_items(sco.supplied_items) + itemwise_details = make_stock_in_entry(rm_items=rm_items) + make_stock_transfer_entry( + sco_no=sco.name, + rm_items=rm_items, + itemwise_details=copy.deepcopy(itemwise_details), + ) + scr = make_subcontracting_receipt(sco.name) + scr.save() + scr.submit() + + gl_entries = get_gl_entries("Subcontracting Receipt", scr.name) + self.assertTrue(gl_entries) + + fg_warehouse_ac = get_inventory_account(scr.company, scr.items[0].warehouse) + expense_account = scr.items[0].expense_account + expected_values = { + fg_warehouse_ac: [1000, 1000], + expense_account: [1000, 1000], + } + + for gle in gl_entries: + self.assertEqual(expected_values[gle.account][0], gle.debit) + self.assertEqual(expected_values[gle.account][1], gle.credit) + + scr.reload() + scr.cancel() + def test_supplied_items_consumed_qty(self): # Set Backflush Based On as "Material Transferred for Subcontracting" to transfer RM's more than the required qty set_backflush_based_on("Material Transferred for Subcontract") From 7711b137660e39bc4e3eebaf39a1e212f9abb002 Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Fri, 12 Apr 2024 10:03:02 +0000 Subject: [PATCH 06/27] chore(release): Bumped to Version 15.20.2 ## [15.20.2](https://github.com/frappe/erpnext/compare/v15.20.1...v15.20.2) (2024-04-12) ### Bug Fixes * Subcontracting Receipt GL Entries (backport [#40773](https://github.com/frappe/erpnext/issues/40773)) (backport [#40979](https://github.com/frappe/erpnext/issues/40979)) ([#40983](https://github.com/frappe/erpnext/issues/40983)) ([3d6ba6f](https://github.com/frappe/erpnext/commit/3d6ba6f21fc60e0393e2f132f43857f5ee34b60d)) --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index a4f24752bbe..0791ba95ae3 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -3,7 +3,7 @@ import inspect import frappe -__version__ = "15.20.1" +__version__ = "15.20.2" def get_default_company(user=None): From 7d126744303c95ec98e9b410133133afb1cae279 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Sat, 13 Apr 2024 15:57:41 +0530 Subject: [PATCH 07/27] fix: do not validate batch qty for LCV (backport #40975) (backport #40981) (#40991) fix: do not validate batch qty for LCV (cherry picked from commit baf0c83cc5c98bf74a6a437f4bec2131074a9ae0) (cherry picked from commit 5de9b6ac757246c6578af32f521398ca1629d51d) Co-authored-by: Rohit Waghchaure --- erpnext/controllers/stock_controller.py | 15 +- .../landed_cost_voucher.py | 2 +- .../test_landed_cost_voucher.py | 201 ++++++++++++++++++ .../serial_and_batch_bundle.py | 6 + 4 files changed, 220 insertions(+), 4 deletions(-) diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index 73436508282..219a1d68c52 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -1119,7 +1119,7 @@ class StockController(AccountsController): message += _("Please adjust the qty or edit {0} to proceed.").format(rule_link) return message - def repost_future_sle_and_gle(self, force=False): + def repost_future_sle_and_gle(self, force=False, via_landed_cost_voucher=False): args = frappe._dict( { "posting_date": self.posting_date, @@ -1127,6 +1127,7 @@ class StockController(AccountsController): "voucher_type": self.doctype, "voucher_no": self.name, "company": self.company, + "via_landed_cost_voucher": via_landed_cost_voucher, } ) @@ -1138,7 +1139,11 @@ class StockController(AccountsController): frappe.db.get_single_value("Stock Reposting Settings", "item_based_reposting") ) if item_based_reposting: - create_item_wise_repost_entries(voucher_type=self.doctype, voucher_no=self.name) + create_item_wise_repost_entries( + voucher_type=self.doctype, + voucher_no=self.name, + via_landed_cost_voucher=via_landed_cost_voucher, + ) else: create_repost_item_valuation_entry(args) @@ -1510,11 +1515,14 @@ def create_repost_item_valuation_entry(args): repost_entry.allow_zero_rate = args.allow_zero_rate repost_entry.flags.ignore_links = True repost_entry.flags.ignore_permissions = True + repost_entry.via_landed_cost_voucher = args.via_landed_cost_voucher repost_entry.save() repost_entry.submit() -def create_item_wise_repost_entries(voucher_type, voucher_no, allow_zero_rate=False): +def create_item_wise_repost_entries( + voucher_type, voucher_no, allow_zero_rate=False, via_landed_cost_voucher=False +): """Using a voucher create repost item valuation records for all item-warehouse pairs.""" stock_ledger_entries = get_items_to_be_repost(voucher_type, voucher_no) @@ -1538,6 +1546,7 @@ def create_item_wise_repost_entries(voucher_type, voucher_no, allow_zero_rate=Fa repost_entry.allow_zero_rate = allow_zero_rate repost_entry.flags.ignore_links = True repost_entry.flags.ignore_permissions = True + repost_entry.via_landed_cost_voucher = via_landed_cost_voucher repost_entry.submit() repost_entries.append(repost_entry) diff --git a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py index 601cde6c905..683e946298a 100644 --- a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py +++ b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py @@ -253,7 +253,7 @@ class LandedCostVoucher(Document): doc.make_bundle_using_old_serial_batch_fields(via_landed_cost_voucher=True) doc.update_stock_ledger(allow_negative_stock=True, via_landed_cost_voucher=True) doc.make_gl_entries() - doc.repost_future_sle_and_gle() + doc.repost_future_sle_and_gle(via_landed_cost_voucher=True) def validate_asset_qty_and_status(self, receipt_document_type, receipt_document): for item in self.get("items"): diff --git a/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py b/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py index 32b384def28..13b7f97b7c4 100644 --- a/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py +++ b/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py @@ -745,6 +745,207 @@ class TestLandedCostVoucher(FrappeTestCase): frappe.db.get_value("Serial and Batch Bundle", row.serial_and_batch_bundle, "avg_rate"), ) + def test_do_not_validate_landed_cost_voucher_with_serial_batch_for_legacy_pr(self): + from erpnext.stock.doctype.item.test_item import make_item + from erpnext.stock.doctype.serial_and_batch_bundle.serial_and_batch_bundle import get_auto_batch_nos + + frappe.flags.ignore_serial_batch_bundle_validation = True + frappe.flags.use_serial_and_batch_fields = True + sn_item = "Test Don't Validate Landed Cost Voucher Serial NO for Legacy PR" + batch_item = "Test Don't Validate Landed Cost Voucher Batch NO for Legacy PR" + sn_item_doc = make_item( + sn_item, + { + "has_serial_no": 1, + "serial_no_series": "SN-TDVLCVSNO-.####", + "is_stock_item": 1, + }, + ) + + batch_item_doc = make_item( + batch_item, + { + "has_batch_no": 1, + "batch_number_series": "BATCH-TDVLCVSNO-.####", + "create_new_batch": 1, + "is_stock_item": 1, + }, + ) + + serial_nos = [ + "SN-TDVLCVSNO-0001", + "SN-TDVLCVSNO-0002", + "SN-TDVLCVSNO-0003", + "SN-TDVLCVSNO-0004", + "SN-TDVLCVSNO-0005", + ] + + for sn in serial_nos: + if not frappe.db.exists("Serial No", sn): + sn_doc = frappe.get_doc( + { + "doctype": "Serial No", + "item_code": sn_item, + "serial_no": sn, + } + ) + sn_doc.insert() + + if not frappe.db.exists("Batch", "BATCH-TDVLCVSNO-0001"): + batch_doc = frappe.get_doc( + { + "doctype": "Batch", + "item": batch_item, + "batch_id": "BATCH-TDVLCVSNO-0001", + } + ) + batch_doc.insert() + + warehouse = "_Test Warehouse - _TC" + company = frappe.db.get_value("Warehouse", warehouse, "company") + + pr = make_purchase_receipt( + company=company, + warehouse=warehouse, + item_code=sn_item, + qty=5, + rate=100, + uom=sn_item_doc.stock_uom, + stock_uom=sn_item_doc.stock_uom, + do_not_submit=True, + ) + + pr.append( + "items", + { + "item_code": batch_item, + "item_name": batch_item, + "description": "Test Batch Item", + "uom": batch_item_doc.stock_uom, + "stock_uom": batch_item_doc.stock_uom, + "qty": 5, + "rate": 100, + "warehouse": warehouse, + }, + ) + + pr.submit() + pr.reload() + + for sn in serial_nos: + sn_doc = frappe.get_doc("Serial No", sn) + sn_doc.db_set( + { + "warehouse": warehouse, + "status": "Active", + } + ) + + batch_doc.db_set( + { + "batch_qty": 5, + } + ) + + for row in pr.items: + if row.item_code == sn_item: + row.db_set("serial_no", ", ".join(serial_nos)) + else: + row.db_set("batch_no", "BATCH-TDVLCVSNO-0001") + + stock_ledger_entries = frappe.get_all("Stock Ledger Entry", filters={"voucher_no": pr.name}) + for sle in stock_ledger_entries: + doc = frappe.get_doc("Stock Ledger Entry", sle.name) + if doc.item_code == sn_item: + doc.db_set("serial_no", ", ".join(serial_nos)) + else: + doc.db_set("batch_no", "BATCH-TDVLCVSNO-0001") + + dn = create_delivery_note( + company=company, + warehouse=warehouse, + item_code=sn_item, + qty=5, + rate=100, + uom=sn_item_doc.stock_uom, + stock_uom=sn_item_doc.stock_uom, + do_not_submit=True, + ) + + dn.append( + "items", + { + "item_code": batch_item, + "item_name": batch_item, + "description": "Test Batch Item", + "uom": batch_item_doc.stock_uom, + "stock_uom": batch_item_doc.stock_uom, + "qty": 5, + "rate": 100, + "warehouse": warehouse, + }, + ) + + dn.submit() + + stock_ledger_entries = frappe.get_all("Stock Ledger Entry", filters={"voucher_no": dn.name}) + for sle in stock_ledger_entries: + doc = frappe.get_doc("Stock Ledger Entry", sle.name) + if doc.item_code == sn_item: + doc.db_set("serial_no", ", ".join(serial_nos)) + else: + doc.db_set("batch_no", "BATCH-TDVLCVSNO-0001") + + available_batches = get_auto_batch_nos( + frappe._dict( + { + "item_code": batch_item, + "warehouse": warehouse, + "batch_no": ["BATCH-TDVLCVSNO-0001"], + "consider_negative_batches": True, + } + ) + )[0] + + self.assertFalse(available_batches.get("qty")) + + frappe.flags.ignore_serial_batch_bundle_validation = False + frappe.flags.use_serial_and_batch_fields = False + + lcv = make_landed_cost_voucher( + company=pr.company, + receipt_document_type="Purchase Receipt", + receipt_document=pr.name, + charges=20, + distribute_charges_based_on="Qty", + do_not_save=True, + ) + + lcv.get_items_from_purchase_receipts() + lcv.save() + lcv.submit() + + pr.reload() + + for row in pr.items: + self.assertEqual(row.valuation_rate, 102) + self.assertTrue(row.serial_and_batch_bundle) + self.assertEqual( + row.valuation_rate, + frappe.db.get_value("Serial and Batch Bundle", row.serial_and_batch_bundle, "avg_rate"), + ) + + lcv.cancel() + pr.reload() + + for row in pr.items: + self.assertEqual(row.valuation_rate, 100) + self.assertTrue(row.serial_and_batch_bundle) + self.assertEqual( + row.valuation_rate, + frappe.db.get_value("Serial and Batch Bundle", row.serial_and_batch_bundle, "avg_rate"), + ) + def make_landed_cost_voucher(**args): args = frappe._dict(args) 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 19aad3f6296..286a220c5dd 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 @@ -860,6 +860,12 @@ class SerialandBatchBundle(Document): self.validate_batch_inventory() def validate_batch_inventory(self): + if ( + self.voucher_type in ["Purchase Invoice", "Purchase Receipt"] + and frappe.db.get_value(self.voucher_type, self.voucher_no, "docstatus") == 1 + ): + return + if not self.has_batch_no: return From e07557c9c5ee2a52e56440d1ca30b5a1fc5bc6bd Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Sat, 13 Apr 2024 15:57:50 +0530 Subject: [PATCH 08/27] fix: type of transaction validation for the stock entry (backport #40986) (backport #40992) (#40994) fix: type of transaction validation for the stock entry (backport #40986) (#40992) * fix: type of transaction validation for the stock entry (cherry picked from commit 8ad0295f1b00f56a345c75751936c398afd101f8) * chore: fix test case --------- Co-authored-by: Rohit Waghchaure (cherry picked from commit 4342b891ebdc80350c9e713c0e0a18e84713955d) Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> --- .../stock/doctype/stock_entry/stock_entry.py | 46 +++++++++++++++++-- .../doctype/stock_entry/test_stock_entry.py | 35 ++++++++++++++ 2 files changed, 78 insertions(+), 3 deletions(-) diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index 6bcade1acae..9c94786c803 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -9,7 +9,17 @@ import frappe from frappe import _ from frappe.model.mapper import get_mapped_doc from frappe.query_builder.functions import Sum -from frappe.utils import cint, comma_or, cstr, flt, format_time, formatdate, getdate, nowdate +from frappe.utils import ( + cint, + comma_or, + cstr, + flt, + format_time, + formatdate, + get_link_to_form, + getdate, + nowdate, +) import erpnext from erpnext.accounts.general_ledger import process_gl_map @@ -640,8 +650,8 @@ class StockEntry(StockController): ) ) - work_order_link = frappe.utils.get_link_to_form("Work Order", self.work_order) - job_card_link = frappe.utils.get_link_to_form("Job Card", job_card) + work_order_link = get_link_to_form("Work Order", self.work_order) + job_card_link = get_link_to_form("Job Card", job_card) frappe.throw( _( "Row #{0}: Operation {1} is not completed for {2} qty of finished goods in Work Order {3}. Please update operation status via Job Card {4}." @@ -1350,9 +1360,24 @@ class StockEntry(StockController): return finished_item_row + def validate_serial_batch_bundle_type(self, serial_and_batch_bundle): + if ( + frappe.db.get_value("Serial and Batch Bundle", serial_and_batch_bundle, "type_of_transaction") + != "Outward" + ): + frappe.throw( + _( + "The Serial and Batch Bundle {0} is not valid for this transaction. The 'Type of Transaction' should be 'Outward' instead of 'Inward' in Serial and Batch Bundle {0}" + ).format(get_link_to_form("Serial and Batch Bundle", serial_and_batch_bundle)), + title=_("Invalid Serial and Batch Bundle"), + ) + def get_sle_for_source_warehouse(self, sl_entries, finished_item_row): for d in self.get("items"): if cstr(d.s_warehouse): + if d.serial_and_batch_bundle and self.docstatus == 1: + self.validate_serial_batch_bundle_type(d.serial_and_batch_bundle) + sle = self.get_sl_entries( d, { @@ -1369,6 +1394,21 @@ class StockEntry(StockController): ): sle.dependant_sle_voucher_detail_no = finished_item_row.name + if sle.serial_and_batch_bundle and self.docstatus == 2: + bundle_id = frappe.get_cached_value( + "Serial and Batch Bundle", + { + "voucher_detail_no": d.name, + "voucher_no": self.name, + "is_cancelled": 0, + "type_of_transaction": "Outward", + }, + "name", + ) + + if bundle_id: + sle.serial_and_batch_bundle = bundle_id + sl_entries.append(sle) def make_serial_and_batch_bundle_for_transfer(self): diff --git a/erpnext/stock/doctype/stock_entry/test_stock_entry.py b/erpnext/stock/doctype/stock_entry/test_stock_entry.py index 6c4c825c072..a680b7733d3 100644 --- a/erpnext/stock/doctype/stock_entry/test_stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/test_stock_entry.py @@ -1745,6 +1745,41 @@ class TestStockEntry(FrappeTestCase): self.assertTrue(frappe.db.exists("Serial No", serial_no)) self.assertEqual(frappe.db.get_value("Serial No", serial_no, "status"), "Delivered") + def test_serial_batch_bundle_type_of_transaction(self): + item = make_item( + "Test Use Serial and Batch Item SN Item", + { + "has_batch_no": 1, + "is_stock_item": 1, + "create_new_batch": 1, + "batch_naming_series": "Test-SBBTYT-NNS.#####", + }, + ).name + + se = make_stock_entry( + item_code=item, + qty=2, + target="_Test Warehouse - _TC", + use_serial_batch_fields=1, + ) + + batch_no = get_batch_from_bundle(se.items[0].serial_and_batch_bundle) + + se = make_stock_entry( + item_code=item, + qty=2, + source="_Test Warehouse - _TC", + target="Stores - _TC", + use_serial_batch_fields=0, + batch_no=batch_no, + do_not_submit=True, + ) + + se.reload() + sbb = se.items[0].serial_and_batch_bundle + frappe.db.set_value("Serial and Batch Bundle", sbb, "type_of_transaction", "Inward") + self.assertRaises(frappe.ValidationError, se.submit) + def make_serialized_item(**args): args = frappe._dict(args) From 2febb2965e7a27f0cadd6ebc3670663db265133b Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Sat, 13 Apr 2024 10:29:03 +0000 Subject: [PATCH 09/27] chore(release): Bumped to Version 15.20.3 ## [15.20.3](https://github.com/frappe/erpnext/compare/v15.20.2...v15.20.3) (2024-04-13) ### Bug Fixes * do not validate batch qty for LCV (backport [#40975](https://github.com/frappe/erpnext/issues/40975)) (backport [#40981](https://github.com/frappe/erpnext/issues/40981)) ([#40991](https://github.com/frappe/erpnext/issues/40991)) ([7d12674](https://github.com/frappe/erpnext/commit/7d126744303c95ec98e9b410133133afb1cae279)) * type of transaction validation for the stock entry (backport [#40986](https://github.com/frappe/erpnext/issues/40986)) (backport [#40992](https://github.com/frappe/erpnext/issues/40992)) ([#40994](https://github.com/frappe/erpnext/issues/40994)) ([e07557c](https://github.com/frappe/erpnext/commit/e07557c9c5ee2a52e56440d1ca30b5a1fc5bc6bd)) --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 0791ba95ae3..73679a8cd01 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -3,7 +3,7 @@ import inspect import frappe -__version__ = "15.20.2" +__version__ = "15.20.3" def get_default_company(user=None): From 00d45c34baa3a3c681315681ee4e5eab50b5055d Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Wed, 17 Apr 2024 06:13:12 +0000 Subject: [PATCH 10/27] chore(release): Bumped to Version 15.20.4 ## [15.20.4](https://github.com/frappe/erpnext/compare/v15.20.3...v15.20.4) (2024-04-17) ### Bug Fixes * Delayed Order Report not working (backport [#41037](https://github.com/frappe/erpnext/issues/41037)) ([#41039](https://github.com/frappe/erpnext/issues/41039)) ([40d059c](https://github.com/frappe/erpnext/commit/40d059c7c1f3db7ad53e6947d1cf090ced3a4932)) * do not validate batch qty for LCV ([5de9b6a](https://github.com/frappe/erpnext/commit/5de9b6ac757246c6578af32f521398ca1629d51d)) * Don't set delivery date as today while making SO from Quotation ([fea906b](https://github.com/frappe/erpnext/commit/fea906b883060fecaaf7fbdc95f5c1a97ea5d847)) * expense account set as COGS for stock entry Material Issue (backport [#41026](https://github.com/frappe/erpnext/issues/41026)) ([#41029](https://github.com/frappe/erpnext/issues/41029)) ([f59e433](https://github.com/frappe/erpnext/commit/f59e43320b6bfc58935f8383850d46c5e8e8bdc9)) * get address if multiple companies ([dcfc768](https://github.com/frappe/erpnext/commit/dcfc768d33eac293bf7435bcce29d64039f1e06b)) * get address if multiple companies ([ccdbad9](https://github.com/frappe/erpnext/commit/ccdbad9f90bde08b702e5749b9c2ab0ac98b0655)) * **gp:** SLEs not fetched for correct warehouse ([881dc02](https://github.com/frappe/erpnext/commit/881dc0234944f2ce6e0c928f066f45b98eeaa3c3)) * incorrect exc gain/loss for PE against JE for payable accounts ([361d7f1](https://github.com/frappe/erpnext/commit/361d7f1ba539f670b87dfb00493d6a165b4d5c7c)) * landed cost voucher for legacy pr with batch ([4e215c6](https://github.com/frappe/erpnext/commit/4e215c6b7b88562dcc1bac5265180dd048dc07a3)) * Link Validation Error on Dunning cancellation ([0053d57](https://github.com/frappe/erpnext/commit/0053d57ec4ef33c022d86951fc484d1d87fe5bee)) * Multiple partial payment requests against Purchase Invoice ([e287376](https://github.com/frappe/erpnext/commit/e287376cc8daff44149a34bb552aeb94886d130e)) * not able to submit subcontracting receipt (backport [#41041](https://github.com/frappe/erpnext/issues/41041)) ([#41045](https://github.com/frappe/erpnext/issues/41045)) ([b27ad76](https://github.com/frappe/erpnext/commit/b27ad765576dbb06b9b160939f769d94ea6ccb90)) * Subcontracting Receipt GL Entries (backport [#40773](https://github.com/frappe/erpnext/issues/40773)) ([#40979](https://github.com/frappe/erpnext/issues/40979)) ([9abc71f](https://github.com/frappe/erpnext/commit/9abc71f9c8f0335c986d4f3953a6147ec77bb557)) * Test case ([641b2a4](https://github.com/frappe/erpnext/commit/641b2a4705e8387500e39adecce3576f15ef9645)) * test cases ([0ee91a2](https://github.com/frappe/erpnext/commit/0ee91a2e541b59146a333fde7248c1e2eee2a797)) * type of transaction validation for the stock entry (backport [#40986](https://github.com/frappe/erpnext/issues/40986)) ([#40992](https://github.com/frappe/erpnext/issues/40992)) ([4342b89](https://github.com/frappe/erpnext/commit/4342b891ebdc80350c9e713c0e0a18e84713955d)) * **ux:** Sales Order Stock Reservation Dialog (backport [#40707](https://github.com/frappe/erpnext/issues/40707)) ([#40980](https://github.com/frappe/erpnext/issues/40980)) ([14a1a18](https://github.com/frappe/erpnext/commit/14a1a18243c54108e5e29d1878b5bc7ea97387b6)) * voucher no. is link field for non english user interface ([1c28ed4](https://github.com/frappe/erpnext/commit/1c28ed4d5b570bc64fe45ea7b7dffda7bb264f4e)) * zero division error ([e9c6c5a](https://github.com/frappe/erpnext/commit/e9c6c5a8eb47daa063fbbbeb74284fda338c1b80)) --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 73679a8cd01..f4240eb39a4 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -3,7 +3,7 @@ import inspect import frappe -__version__ = "15.20.3" +__version__ = "15.20.4" def get_default_company(user=None): From a1db5f0f0aa7cdbda8eecc3df04b0d079c172b1c Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Wed, 17 Apr 2024 12:43:31 +0530 Subject: [PATCH 11/27] fix: duplicate serial and batch bundle in stock entry and stock reco (cherry picked from commit 732b6e14176ff3b5fd5205d5b6f11463934ec6c4) (cherry picked from commit c10c21157db10b2892c8b1c7e9bd40f954e7a92c) --- erpnext/public/js/utils.js | 33 +------------------ .../stock/doctype/stock_entry/stock_entry.py | 1 + .../stock_reconciliation.py | 1 + 3 files changed, 3 insertions(+), 32 deletions(-) diff --git a/erpnext/public/js/utils.js b/erpnext/public/js/utils.js index 5456b6553ae..42d4cc51c40 100755 --- a/erpnext/public/js/utils.js +++ b/erpnext/public/js/utils.js @@ -51,38 +51,7 @@ $.extend(erpnext, { }, setup_serial_or_batch_no: function () { - let grid_row = cur_frm.open_grid_row(); - if ( - !grid_row || - !grid_row.grid_form.fields_dict.serial_no || - grid_row.grid_form.fields_dict.serial_no.get_status() !== "Write" - ) - return; - - frappe.model.get_value( - "Item", - { name: grid_row.doc.item_code }, - ["has_serial_no", "has_batch_no"], - ({ has_serial_no, has_batch_no }) => { - Object.assign(grid_row.doc, { has_serial_no, has_batch_no }); - - if (has_serial_no) { - attach_selector_button( - __("Add Serial No"), - grid_row.grid_form.fields_dict.serial_no.$wrapper, - this, - grid_row - ); - } else if (has_batch_no) { - attach_selector_button( - __("Pick Batch No"), - grid_row.grid_form.fields_dict.batch_no.$wrapper, - this, - grid_row - ); - } - } - ); + // Deprecated in v15 }, route_to_adjustment_jv: (args) => { diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index 0ba1b56272d..569d4e9c0a0 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -194,6 +194,7 @@ class StockEntry(StockController): if self.work_order: self.pro_doc = frappe.get_doc("Work Order", self.work_order) + self.validate_duplicate_serial_and_batch_bundle("items") self.validate_posting_time() self.validate_purpose() self.validate_item() diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py index ccd7f64e6e7..64a6b6503cc 100644 --- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py +++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py @@ -70,6 +70,7 @@ class StockReconciliation(StockController): self.validate_posting_time() self.set_current_serial_and_batch_bundle() self.set_new_serial_and_batch_bundle() + self.validate_duplicate_serial_and_batch_bundle("items") self.remove_items_with_no_change() self.validate_data() self.validate_expense_account() From 5ecb022abc51d78c2e2daa91d3c01953c0e62066 Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Wed, 17 Apr 2024 09:25:54 +0000 Subject: [PATCH 12/27] chore(release): Bumped to Version 15.20.5 ## [15.20.5](https://github.com/frappe/erpnext/compare/v15.20.4...v15.20.5) (2024-04-17) ### Bug Fixes * duplicate serial and batch bundle in stock entry and stock reco ([a1db5f0](https://github.com/frappe/erpnext/commit/a1db5f0f0aa7cdbda8eecc3df04b0d079c172b1c)) --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index f4240eb39a4..b2da227ad54 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -3,7 +3,7 @@ import inspect import frappe -__version__ = "15.20.4" +__version__ = "15.20.5" def get_default_company(user=None): From 6cc7c08ccfdb0df1dbf3e9746aa3a354ac1736df Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Wed, 17 Jan 2024 13:09:51 +0530 Subject: [PATCH 13/27] fix: account and stock manager read perm (cherry picked from commit 572e844a917067095c2a52688ca0d70d56adca46) --- erpnext/accounts/doctype/fiscal_year/fiscal_year.json | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/fiscal_year/fiscal_year.json b/erpnext/accounts/doctype/fiscal_year/fiscal_year.json index da7f08fe3d4..fb997847448 100644 --- a/erpnext/accounts/doctype/fiscal_year/fiscal_year.json +++ b/erpnext/accounts/doctype/fiscal_year/fiscal_year.json @@ -87,7 +87,7 @@ "module": "Accounts", "name": "Fiscal Year", "naming_rule": "By fieldname", - "owner": "Administrator", + "owner": "Administrator", "permissions": [ { "create": 1, @@ -119,6 +119,14 @@ { "read": 1, "role": "Employee" + }, + { + "read": 1, + "role": "Accounts Manager" + }, + { + "read": 1, + "role": "Stock Manager" } ], "show_name_in_global_search": 1, From b5825700223863711635aebc0c68dcd75f0a8a56 Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Fri, 19 Apr 2024 08:40:13 +0000 Subject: [PATCH 14/27] chore(release): Bumped to Version 15.20.6 ## [15.20.6](https://github.com/frappe/erpnext/compare/v15.20.5...v15.20.6) (2024-04-19) ### Bug Fixes * account and stock manager read perm ([6cc7c08](https://github.com/frappe/erpnext/commit/6cc7c08ccfdb0df1dbf3e9746aa3a354ac1736df)) --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index b2da227ad54..735aaab654c 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -3,7 +3,7 @@ import inspect import frappe -__version__ = "15.20.5" +__version__ = "15.20.6" def get_default_company(user=None): From 2fb035fe1bf043ac09fe2e097ce221ea5904ba36 Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Wed, 24 Apr 2024 10:48:02 +0000 Subject: [PATCH 15/27] chore(release): Bumped to Version 15.21.0 # [15.21.0](https://github.com/frappe/erpnext/compare/v15.20.6...v15.21.0) (2024-04-24) ### Bug Fixes * account and stock manager read perm ([572e844](https://github.com/frappe/erpnext/commit/572e844a917067095c2a52688ca0d70d56adca46)) * allow Employee role to select cost center & project (accounting dimensions) (backport [#41160](https://github.com/frappe/erpnext/issues/41160)) ([#41162](https://github.com/frappe/erpnext/issues/41162)) ([90d6e55](https://github.com/frappe/erpnext/commit/90d6e550aafab49678993f7ee9ece3891fe37b15)) * Allow updating cost center and project for repostable doctypes ([e278688](https://github.com/frappe/erpnext/commit/e278688a4bff5daf32fd8eff10555941b43b015d)) * balance qty for stock ledger report ([74ed656](https://github.com/frappe/erpnext/commit/74ed656bb93e6027df6682f3c96e49077ddfbec6)) * do not add actual expense twice for validating budget ([c72478c](https://github.com/frappe/erpnext/commit/c72478c74d48e5a5b7984633be0380bc3302ca90)) * do not add qty to supplied items (backport [#41061](https://github.com/frappe/erpnext/issues/41061)) ([#41066](https://github.com/frappe/erpnext/issues/41066)) ([1ae447e](https://github.com/frappe/erpnext/commit/1ae447e4fc62e8a8da18d68a1c02e483b7b86571)) * don't attempt to set gender from salutation (backport [#40997](https://github.com/frappe/erpnext/issues/40997)) ([#41073](https://github.com/frappe/erpnext/issues/41073)) ([ee7aaf0](https://github.com/frappe/erpnext/commit/ee7aaf0ea438d2ad2c78e104212bb5f3c287d529)) * duplicate serial and batch bundle in stock entry and stock reco ([c10c211](https://github.com/frappe/erpnext/commit/c10c21157db10b2892c8b1c7e9bd40f954e7a92c)) * incorrect stock posting for current qty ([05d5c48](https://github.com/frappe/erpnext/commit/05d5c48d29bfcf2edc63eb720c51d9633d3ef930)) * Missing args while fetching items from delivery note ([3b4575a](https://github.com/frappe/erpnext/commit/3b4575af3d5dc50c713f742d7674ba2e807f0689)) * not able to update default supplier from Supplier Quotation Comparison report ([80891da](https://github.com/frappe/erpnext/commit/80891daaed57b28c86df2184a32c153bc0714fb5)) * Party type in Payment Order ([83931e8](https://github.com/frappe/erpnext/commit/83931e872b71bbae6a47693ba26065f9a4ac0e25)) * Payment entry against employee ([060d46a](https://github.com/frappe/erpnext/commit/060d46af42679dc571cd4599054a02c5037add00)) * Permission for lower dedcution certificate ([d7ddb00](https://github.com/frappe/erpnext/commit/d7ddb00e86fbd0849deb256bf972e49a274e880c)) * search not working for so in the Production Plan ([#36459](https://github.com/frappe/erpnext/issues/36459)) ([544e56a](https://github.com/frappe/erpnext/commit/544e56a71cac8751f5ff9fb7c32fe3a0e9f3eb85)) * stock reco negative qty validation ([aee03fe](https://github.com/frappe/erpnext/commit/aee03fe2efb02536bcce8c31e5e2d669e04b3568)) * validate uom is integer for PR item (backport [#41074](https://github.com/frappe/erpnext/issues/41074)) ([#41077](https://github.com/frappe/erpnext/issues/41077)) ([93242ca](https://github.com/frappe/erpnext/commit/93242ca883520553676cb8d913c9d1187ee76e50)) * validation for fraction number in Work Order ([ef2553e](https://github.com/frappe/erpnext/commit/ef2553edf967612bdbf580357d5886c6afacaea2)) * validation for zero qty in SABB ([85796b3](https://github.com/frappe/erpnext/commit/85796b35348d0bbce3c0cfd78096c683e01ec29c)) ### Features * Available batches report as on specific date ([791e426](https://github.com/frappe/erpnext/commit/791e4269d2f80759389c80d8f35198e155772027)) * show expense breakup ([e047e1e](https://github.com/frappe/erpnext/commit/e047e1eb15e5f19cf741b8f59af34a31bdfa1dc2)) --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 735aaab654c..0c44e0476cf 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -3,7 +3,7 @@ import inspect import frappe -__version__ = "15.20.6" +__version__ = "15.21.0" def get_default_company(user=None): From 0dfd6facc141f139655c531043c9c47b2f060aef Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Tue, 23 Apr 2024 10:38:37 +0530 Subject: [PATCH 16/27] fix: mode of payment has precedance Mode of Payment is given precedence over company/party bank account (cherry picked from commit 4aef96987988c66ef2f1c41392661711f9b6e98b) --- erpnext/accounts/doctype/payment_entry/payment_entry.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.js b/erpnext/accounts/doctype/payment_entry/payment_entry.js index c4ef4017fd1..77426ef9740 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.js +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.js @@ -1334,7 +1334,9 @@ frappe.ui.form.on("Payment Entry", { }, callback: function (r) { if (r.message) { - frm.set_value(field, r.message.account); + if (!frm.doc.mode_of_payment) { + frm.set_value(field, r.message.account); + } frm.set_value("bank", r.message.bank); frm.set_value("bank_account_no", r.message.bank_account_no); } From cacb5bfe03da45b6f7c360a35a48c95c48d8f4e3 Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Thu, 25 Apr 2024 03:38:33 +0000 Subject: [PATCH 17/27] chore(release): Bumped to Version 15.21.1 ## [15.21.1](https://github.com/frappe/erpnext/compare/v15.21.0...v15.21.1) (2024-04-25) ### Bug Fixes * mode of payment has precedance ([0dfd6fa](https://github.com/frappe/erpnext/commit/0dfd6facc141f139655c531043c9c47b2f060aef)) --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 0c44e0476cf..037d61f0854 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -3,7 +3,7 @@ import inspect import frappe -__version__ = "15.21.0" +__version__ = "15.21.1" def get_default_company(user=None): From 6da927a57387aa3492b816615e9fe61c78b5ed5e Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Thu, 25 Apr 2024 12:18:11 +0530 Subject: [PATCH 18/27] fix: enable advance in separate acc only for customer and Supplier (cherry picked from commit 3c1af2acf015d7b4ce6aa8e19c333d87f2ea292a) --- erpnext/accounts/doctype/payment_entry/payment_entry.py | 1 + 1 file changed, 1 insertion(+) diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py index 9a4fbe10bd1..26819ef7518 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py @@ -113,6 +113,7 @@ class PaymentEntry(AccountsController): if self.docstatus > 0 or self.payment_type == "Internal Transfer": return + self.book_advance_payments_in_separate_party_account = False if self.party_type not in ("Customer", "Supplier"): return From 6a7b6f62623a5fe443221dc7db1c1d861646ffe3 Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Fri, 26 Apr 2024 02:10:51 +0000 Subject: [PATCH 19/27] chore(release): Bumped to Version 15.21.2 ## [15.21.2](https://github.com/frappe/erpnext/compare/v15.21.1...v15.21.2) (2024-04-26) ### Bug Fixes * enable advance in separate acc only for customer and Supplier ([6da927a](https://github.com/frappe/erpnext/commit/6da927a57387aa3492b816615e9fe61c78b5ed5e)) --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 037d61f0854..228a40a6be3 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -3,7 +3,7 @@ import inspect import frappe -__version__ = "15.21.1" +__version__ = "15.21.2" def get_default_company(user=None): From f62762b4d146f325b33cdba0ac9bb96596e31c50 Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Thu, 2 May 2024 04:23:27 +0000 Subject: [PATCH 20/27] chore(release): Bumped to Version 15.22.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # [15.22.0](https://github.com/frappe/erpnext/compare/v15.21.2...v15.22.0) (2024-05-02) ### Bug Fixes * added brand column in Warehouse wise Item Balance Age and Value … (backport [#41280](https://github.com/frappe/erpnext/issues/41280)) ([#41282](https://github.com/frappe/erpnext/issues/41282)) ([4bbf0a4](https://github.com/frappe/erpnext/commit/4bbf0a46b515334df2cd39bd7124188276c83ae0)) * advance account validation in company master ([dd67b0e](https://github.com/frappe/erpnext/commit/dd67b0ee612a9dd0f0956a6d79b992a55311cdb4)) * args when get the delivery note in delivery trip ([61d6838](https://github.com/frappe/erpnext/commit/61d6838b2c16f6e06bc89758dafcf6ff447a8aa5)) * args when get the delivery note in delivery trip ([e9acacd](https://github.com/frappe/erpnext/commit/e9acacdd5d7f1afe08318fc5dd5487febcaa13ca)) * basic rate for SABB ([7b79873](https://github.com/frappe/erpnext/commit/7b7987363f6e28ac2e5421ee1939a841fd38e6da)) * compute tree-view parent field name ([#41234](https://github.com/frappe/erpnext/issues/41234)) ([c3077ee](https://github.com/frappe/erpnext/commit/c3077ee067c09b14462a4b599b7de6ad9ed64e59)) * display term name for single term invoices ([a7d1a88](https://github.com/frappe/erpnext/commit/a7d1a8851928c17f69df24928c610841ce924ac5)) * duplicate column in the stock ledger report ([a62298a](https://github.com/frappe/erpnext/commit/a62298a635315f294128b0888387cedf9711a10d)) * enable advance in separate acc only for customer and Supplier ([c3073d6](https://github.com/frappe/erpnext/commit/c3073d6e74a7e03eb205ad6365474393e02c4a44)) * expense causing p&l test case to fail ([acfee42](https://github.com/frappe/erpnext/commit/acfee4273533d6e095098b7fd22087f5e9f8331d)) * handle and receivable accounts based on response type ([f65b28a](https://github.com/frappe/erpnext/commit/f65b28a18979a41dbfd053237bc144af4104fc66)) * handle stock balance unbuffered_cursor error (backport [#41186](https://github.com/frappe/erpnext/issues/41186)) ([#41188](https://github.com/frappe/erpnext/issues/41188)) ([b34582e](https://github.com/frappe/erpnext/commit/b34582e6baed79bd479fe44ec84801b3fbd90b21)) * Ignore user perm in Bank Reco Tool for company ([737c480](https://github.com/frappe/erpnext/commit/737c4809e3e768a935e914d669c9bacc0094ef79)) * incorrectly applying TDS when Advance is in previous FY ([08f888a](https://github.com/frappe/erpnext/commit/08f888a326d4d787bb5a878843a8215d914cace2)) * Invoice with no GLEs in deferred report ([44c3ad6](https://github.com/frappe/erpnext/commit/44c3ad6810df2c9a2205f8e6f1f3bd372782dfbc)) * missing def expense if no exp in first month ([0a65a37](https://github.com/frappe/erpnext/commit/0a65a37eed00341d9b9d117b3ebe1a86a7e1f0fc)) * mode of payment has precedance ([c6145a1](https://github.com/frappe/erpnext/commit/c6145a1101d56603047282b92b8be98a8305ed16)) * multiple pricing rules with discount amount and discount percentage not working (backport [#41211](https://github.com/frappe/erpnext/issues/41211)) (backport [#41241](https://github.com/frappe/erpnext/issues/41241)) ([#41275](https://github.com/frappe/erpnext/issues/41275)) ([de77894](https://github.com/frappe/erpnext/commit/de77894e59f963b2edb4676d0b7b7cd90028917c)) * paid amount in bank reconciliation tool ([759c7f5](https://github.com/frappe/erpnext/commit/759c7f5490d179bb94369a7168be2cf19e5a0c73)) * party and party type label on accounting preview ([ee9822f](https://github.com/frappe/erpnext/commit/ee9822fd420a20fc7d0d75304b21ff26a31ccf74)) * permission issue when user permission restricts on company ([8d70a0e](https://github.com/frappe/erpnext/commit/8d70a0e0bc0776005cfe4b9083202dea3ffd8d5d)) * rendering the email template when user HTML ([3068dad](https://github.com/frappe/erpnext/commit/3068dad4108de2a8dfd9ce7fe24e7fc743115924)) * test case for zero deferred expense ([23c3c3c](https://github.com/frappe/erpnext/commit/23c3c3cc0c0eb60077a4787f5767a901ed79c0ab)) * validation to prevent foreign currency advance accounts in PE ([fb4a75c](https://github.com/frappe/erpnext/commit/fb4a75c5aa39f4a0b5725a5f14e87f42b9291c1b)) * validation to prevent overallocation ([ea596eb](https://github.com/frappe/erpnext/commit/ea596eb4a2ab28a66ab6466dcf152a4c31b4ab18)) * warehouse type filter for stock reports ([48351d6](https://github.com/frappe/erpnext/commit/48351d6da82916297149a620074e8cc981a43295)) ### Features * allow to do reposting for all transactions (audit) ([4555f8a](https://github.com/frappe/erpnext/commit/4555f8a9a67f2f79c012e86e960dc2dc5df93906)) --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 228a40a6be3..445d6779d78 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -3,7 +3,7 @@ import inspect import frappe -__version__ = "15.21.2" +__version__ = "15.22.0" def get_default_company(user=None): From 4d312cbc65bda8434a4434e8d1f0b7c84da3afb3 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Wed, 1 May 2024 12:17:08 +0530 Subject: [PATCH 21/27] fix: GL Entries against orders as an advance (cherry picked from commit 8289f3c7247512dd651d7da0ffbd3a5ece7761d9) --- .../doctype/payment_entry/payment_entry.py | 4 +- .../payment_entry/test_payment_entry.py | 62 +++++++++++++++++++ 2 files changed, 63 insertions(+), 3 deletions(-) diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py index 2fb62b79ab1..26c88536e45 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py @@ -1227,7 +1227,7 @@ class PaymentEntry(AccountsController): def add_advance_gl_entries(self, gl_entries: list, entry: object | dict | None): """ - If 'entry' is passed, GL enties only for that reference is added. + If 'entry' is passed, GL entries only for that reference is added. """ if self.book_advance_payments_in_separate_party_account: references = [x for x in self.get("references")] @@ -1239,8 +1239,6 @@ class PaymentEntry(AccountsController): "Sales Invoice", "Purchase Invoice", "Journal Entry", - "Sales Order", - "Purchase Order", "Payment Entry", ): self.add_advance_gl_for_reference(gl_entries, ref) diff --git a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py index cafdaaaa957..26ed33c22b5 100644 --- a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py @@ -1440,6 +1440,68 @@ class TestPaymentEntry(FrappeTestCase): self.check_gl_entries() self.check_pl_entries() + def test_advance_as_liability_against_order(self): + from erpnext.buying.doctype.purchase_order.purchase_order import ( + make_purchase_invoice as _make_purchase_invoice, + ) + from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order + + company = "_Test Company" + + advance_account = create_account( + parent_account="Current Liabilities - _TC", + account_name="Advances Paid", + company=company, + account_type="Liability", + ) + + frappe.db.set_value( + "Company", + company, + { + "book_advance_payments_in_separate_party_account": 1, + "default_advance_paid_account": advance_account, + }, + ) + + po = create_purchase_order(supplier="_Test Supplier") + pe = get_payment_entry("Purchase Order", po.name) + pe.save().submit() + + pre_reconciliation_gle = [ + {"account": advance_account, "debit": 5000.0, "credit": 0.0}, + {"account": "_Test Bank 2 - _TC", "debit": 0.0, "credit": 5000.0}, + ] + + self.voucher_no = pe.name + self.expected_gle = pre_reconciliation_gle + self.check_gl_entries() + + # Make Purchase Invoice against the order + pi = _make_purchase_invoice(po.name) + pi.append( + "advances", + { + "reference_type": pe.doctype, + "reference_name": pe.name, + "reference_row": pe.references[0].name, + "advance_amount": 5000, + "allocated_amount": 5000, + }, + ) + pi.save().submit() + + # # assert General and Payment Ledger entries post partial reconciliation + self.expected_gle = [ + {"account": pi.credit_to, "debit": 5000.0, "credit": 0.0}, + {"account": advance_account, "debit": 5000.0, "credit": 0.0}, + {"account": advance_account, "debit": 0.0, "credit": 5000.0}, + {"account": "_Test Bank 2 - _TC", "debit": 0.0, "credit": 5000.0}, + ] + + self.voucher_no = pe.name + self.check_gl_entries() + def check_pl_entries(self): ple = frappe.qb.DocType("Payment Ledger Entry") pl_entries = ( From 44330a618b9ea4ed10e1e1741e638188c52598d4 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Fri, 3 May 2024 15:56:29 +0530 Subject: [PATCH 22/27] fix: Add PO reference (cherry picked from commit eb310170582ae0bdaa50d36ef5ffa1c443641afb) --- .../doctype/payment_entry/payment_entry.py | 101 ++++++++---------- 1 file changed, 42 insertions(+), 59 deletions(-) diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py index 26c88536e45..453a7b1202d 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py @@ -1131,73 +1131,49 @@ class PaymentEntry(AccountsController): ) dr_or_cr = "credit" if self.payment_type == "Receive" else "debit" - if self.book_advance_payments_in_separate_party_account: + + for d in self.get("references"): + # re-defining dr_or_cr for every reference in order to avoid the last value affecting calculation of reverse + dr_or_cr = "credit" if self.payment_type == "Receive" else "debit" + cost_center = self.cost_center + if d.reference_doctype == "Sales Invoice" and not cost_center: + cost_center = frappe.db.get_value(d.reference_doctype, d.reference_name, "cost_center") + gle = party_gl_dict.copy() - if self.payment_type == "Receive": - amount = self.base_paid_amount - else: - amount = self.base_received_amount + allocated_amount_in_company_currency = self.calculate_base_allocated_amount_for_reference(d) + reverse_dr_or_cr = 0 + + if d.reference_doctype in ["Sales Invoice", "Purchase Invoice"]: + is_return = frappe.db.get_value(d.reference_doctype, d.reference_name, "is_return") + payable_party_types = get_party_types_from_account_type("Payable") + receivable_party_types = get_party_types_from_account_type("Receivable") + if ( + is_return + and self.party_type in receivable_party_types + and (self.payment_type == "Pay") + ): + reverse_dr_or_cr = 1 + elif ( + is_return + and self.party_type in payable_party_types + and (self.payment_type == "Receive") + ): + reverse_dr_or_cr = 1 + + if is_return and not reverse_dr_or_cr: + dr_or_cr = "debit" if dr_or_cr == "credit" else "credit" - exchange_rate = self.get_exchange_rate() - amount_in_account_currency = amount * exchange_rate gle.update( { - dr_or_cr: amount, - dr_or_cr + "_in_account_currency": amount_in_account_currency, - "against_voucher_type": "Payment Entry", - "against_voucher": self.name, - "cost_center": self.cost_center, + dr_or_cr: abs(allocated_amount_in_company_currency), + dr_or_cr + "_in_account_currency": abs(d.allocated_amount), + "against_voucher_type": d.reference_doctype, + "against_voucher": d.reference_name, + "cost_center": cost_center, } ) gl_entries.append(gle) - else: - for d in self.get("references"): - # re-defining dr_or_cr for every reference in order to avoid the last value affecting calculation of reverse - dr_or_cr = "credit" if self.payment_type == "Receive" else "debit" - cost_center = self.cost_center - if d.reference_doctype == "Sales Invoice" and not cost_center: - cost_center = frappe.db.get_value( - d.reference_doctype, d.reference_name, "cost_center" - ) - - gle = party_gl_dict.copy() - - allocated_amount_in_company_currency = self.calculate_base_allocated_amount_for_reference( - d - ) - reverse_dr_or_cr = 0 - - if d.reference_doctype in ["Sales Invoice", "Purchase Invoice"]: - is_return = frappe.db.get_value(d.reference_doctype, d.reference_name, "is_return") - payable_party_types = get_party_types_from_account_type("Payable") - receivable_party_types = get_party_types_from_account_type("Receivable") - if ( - is_return - and self.party_type in receivable_party_types - and (self.payment_type == "Pay") - ): - reverse_dr_or_cr = 1 - elif ( - is_return - and self.party_type in payable_party_types - and (self.payment_type == "Receive") - ): - reverse_dr_or_cr = 1 - - if is_return and not reverse_dr_or_cr: - dr_or_cr = "debit" if dr_or_cr == "credit" else "credit" - - gle.update( - { - dr_or_cr: abs(allocated_amount_in_company_currency), - dr_or_cr + "_in_account_currency": abs(d.allocated_amount), - "against_voucher_type": d.reference_doctype, - "against_voucher": d.reference_name, - "cost_center": cost_center, - } - ) - gl_entries.append(gle) if self.unallocated_amount: dr_or_cr = "credit" if self.payment_type == "Receive" else "debit" @@ -1212,6 +1188,13 @@ class PaymentEntry(AccountsController): } ) + if self.book_advance_payments_in_separate_party_account: + gle.update( + { + "against_voucher_type": "Payment Entry", + "against_voucher": self.name, + } + ) gl_entries.append(gle) def make_advance_gl_entries( From ad0f563816d412c81aa896df833ec66608ee9bd6 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Fri, 3 May 2024 17:04:37 +0530 Subject: [PATCH 23/27] test: Update failing tests (cherry picked from commit 42ef95759d75a572465b26a6aab9a5f9de7a3bbb) --- .../doctype/payment_entry/payment_entry.py | 32 +++++++++---------- .../purchase_order/test_purchase_order.py | 23 +------------ 2 files changed, 17 insertions(+), 38 deletions(-) diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py index 453a7b1202d..9f98649248d 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py @@ -1175,27 +1175,27 @@ class PaymentEntry(AccountsController): ) gl_entries.append(gle) - if self.unallocated_amount: - dr_or_cr = "credit" if self.payment_type == "Receive" else "debit" - exchange_rate = self.get_exchange_rate() - base_unallocated_amount = self.unallocated_amount * exchange_rate + if self.unallocated_amount: + dr_or_cr = "credit" if self.payment_type == "Receive" else "debit" + exchange_rate = self.get_exchange_rate() + base_unallocated_amount = self.unallocated_amount * exchange_rate - gle = party_gl_dict.copy() + gle = party_gl_dict.copy() + gle.update( + { + dr_or_cr + "_in_account_currency": self.unallocated_amount, + dr_or_cr: base_unallocated_amount, + } + ) + + if self.book_advance_payments_in_separate_party_account: gle.update( { - dr_or_cr + "_in_account_currency": self.unallocated_amount, - dr_or_cr: base_unallocated_amount, + "against_voucher_type": "Payment Entry", + "against_voucher": self.name, } ) - - if self.book_advance_payments_in_separate_party_account: - gle.update( - { - "against_voucher_type": "Payment Entry", - "against_voucher": self.name, - } - ) - gl_entries.append(gle) + gl_entries.append(gle) def make_advance_gl_entries( self, entry: object | dict = None, cancel: bool = 0, update_outstanding: str = "Yes" diff --git a/erpnext/buying/doctype/purchase_order/test_purchase_order.py b/erpnext/buying/doctype/purchase_order/test_purchase_order.py index 1d87aac2c36..dbfcbf60b26 100644 --- a/erpnext/buying/doctype/purchase_order/test_purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/test_purchase_order.py @@ -764,12 +764,7 @@ class TestPurchaseOrder(FrappeTestCase): } ).insert() else: - account = frappe.db.get_value( - "Account", - filters={"account_name": account_name, "company": company}, - fieldname="name", - pluck=True, - ) + account = frappe.get_doc("Account", {"account_name": account_name, "company": company}) return account @@ -800,22 +795,6 @@ class TestPurchaseOrder(FrappeTestCase): from erpnext.buying.doctype.purchase_order.purchase_order import make_purchase_invoice - pi = make_purchase_invoice(po_doc.name) - pi.append( - "advances", - { - "reference_type": pe.doctype, - "reference_name": pe.name, - "reference_row": pe.references[0].name, - "advance_amount": 5000, - "allocated_amount": 5000, - }, - ) - pi.save().submit() - pe.reload() - po_doc.reload() - self.assertEqual(po_doc.advance_paid, 0) - company_doc.book_advance_payments_in_separate_party_account = False company_doc.save() From 27f51f12340af93f6944e5f0da75dec33ed479e8 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Fri, 3 May 2024 18:30:47 +0530 Subject: [PATCH 24/27] test: Add bank account (cherry picked from commit eac7be2d0f1fa28e9179aa2a7868475f2b531f19) --- .../accounts/doctype/payment_entry/test_payment_entry.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py index 26ed33c22b5..d22350d20fc 100644 --- a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py @@ -1465,12 +1465,12 @@ class TestPaymentEntry(FrappeTestCase): ) po = create_purchase_order(supplier="_Test Supplier") - pe = get_payment_entry("Purchase Order", po.name) + pe = get_payment_entry("Purchase Order", po.name, bank_account="Cash - _TC") pe.save().submit() pre_reconciliation_gle = [ + {"account": "Cash - _TC", "debit": 0.0, "credit": 5000.0}, {"account": advance_account, "debit": 5000.0, "credit": 0.0}, - {"account": "_Test Bank 2 - _TC", "debit": 0.0, "credit": 5000.0}, ] self.voucher_no = pe.name @@ -1494,9 +1494,9 @@ class TestPaymentEntry(FrappeTestCase): # # assert General and Payment Ledger entries post partial reconciliation self.expected_gle = [ {"account": pi.credit_to, "debit": 5000.0, "credit": 0.0}, + {"account": "Cash - _TC", "debit": 0.0, "credit": 5000.0}, {"account": advance_account, "debit": 5000.0, "credit": 0.0}, {"account": advance_account, "debit": 0.0, "credit": 5000.0}, - {"account": "_Test Bank 2 - _TC", "debit": 0.0, "credit": 5000.0}, ] self.voucher_no = pe.name From fa5462d67478d398988e34059790c826562f142b Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Fri, 3 May 2024 17:32:36 +0000 Subject: [PATCH 25/27] chore(release): Bumped to Version 15.22.1 ## [15.22.1](https://github.com/frappe/erpnext/compare/v15.22.0...v15.22.1) (2024-05-03) ### Bug Fixes * Add PO reference ([44330a6](https://github.com/frappe/erpnext/commit/44330a618b9ea4ed10e1e1741e638188c52598d4)) * GL Entries against orders as an advance ([4d312cb](https://github.com/frappe/erpnext/commit/4d312cbc65bda8434a4434e8d1f0b7c84da3afb3)) --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 445d6779d78..015a70acfb8 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -3,7 +3,7 @@ import inspect import frappe -__version__ = "15.22.0" +__version__ = "15.22.1" def get_default_company(user=None): From ee12ec36cc479679865cd6bda5b65a6c7a19912a Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Mon, 6 May 2024 14:10:08 +0530 Subject: [PATCH 26/27] fix: pick list with multiple batch issue (backport #41335) (backport #41338) (#41340) fix: pick list with multiple batch issue (backport #41335) (#41338) fix: pick list with multiple batch issue (#41335) fix: pick list with batchb issue (cherry picked from commit ebfbe94aaf6c91263daed7074a335f0f0f904064) Co-authored-by: rohitwaghchaure (cherry picked from commit 1b1dfa8893c23691fbfea1754af78cb39266e9a8) Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> --- erpnext/stock/doctype/pick_list/pick_list.py | 31 +++++++++++----- .../stock/doctype/pick_list/test_pick_list.py | 36 +++++++++++++++++++ 2 files changed, 58 insertions(+), 9 deletions(-) diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py index e3dbdb5726b..d7e84d2fb93 100644 --- a/erpnext/stock/doctype/pick_list/pick_list.py +++ b/erpnext/stock/doctype/pick_list/pick_list.py @@ -790,7 +790,7 @@ def get_available_item_locations( locations = get_locations_based_on_required_qty(locations, required_qty) if not ignore_validation: - validate_picked_materials(item_code, required_qty, locations) + validate_picked_materials(item_code, required_qty, locations, picked_item_details) return locations @@ -810,7 +810,7 @@ def get_locations_based_on_required_qty(locations, required_qty): return filtered_locations -def validate_picked_materials(item_code, required_qty, locations): +def validate_picked_materials(item_code, required_qty, locations, picked_item_details=None): for location in list(locations): if location["qty"] < 0: locations.remove(location) @@ -819,15 +819,25 @@ def validate_picked_materials(item_code, required_qty, locations): remaining_qty = required_qty - total_qty_available if remaining_qty > 0: - frappe.msgprint( - _("{0} units of Item {1} is picked in another Pick List.").format( - remaining_qty, get_link_to_form("Item", item_code) - ), - title=_("Already Picked"), - ) + if picked_item_details: + frappe.msgprint( + _("{0} units of Item {1} is picked in another Pick List.").format( + remaining_qty, get_link_to_form("Item", item_code) + ), + title=_("Already Picked"), + ) + + else: + frappe.msgprint( + _("{0} units of Item {1} is not available in any of the warehouses.").format( + remaining_qty, get_link_to_form("Item", item_code) + ), + title=_("Insufficient Stock"), + ) def filter_locations_by_picked_materials(locations, picked_item_details) -> list[dict]: + filterd_locations = [] for row in locations: key = row.warehouse if row.batch_no: @@ -845,7 +855,10 @@ def filter_locations_by_picked_materials(locations, picked_item_details) -> list if row.serial_nos: row.serial_nos = list(set(row.serial_nos) - set(picked_item_details[key].get("serial_no"))) - return locations + if row.qty > 0: + filterd_locations.append(row) + + return filterd_locations def get_available_item_locations_for_serial_and_batched_item( diff --git a/erpnext/stock/doctype/pick_list/test_pick_list.py b/erpnext/stock/doctype/pick_list/test_pick_list.py index 87a71503be5..499eaa84282 100644 --- a/erpnext/stock/doctype/pick_list/test_pick_list.py +++ b/erpnext/stock/doctype/pick_list/test_pick_list.py @@ -977,3 +977,39 @@ class TestPickList(FrappeTestCase): so = make_sales_order(item_code=item, qty=4, rate=100) pl = create_pick_list(so.name) self.assertFalse(hasattr(pl, "locations")) + + def test_pick_list_validation_for_multiple_batches_and_sales_order(self): + warehouse = "_Test Warehouse - _TC" + item = make_item( + "Test Batch Pick List Item For Multiple Batches", + properties={ + "is_stock_item": 1, + "has_batch_no": 1, + "batch_number_series": "SN-BT-BATCH-SPLIMBATCH-.####", + "create_new_batch": 1, + }, + ).name + + make_stock_entry(item=item, to_warehouse=warehouse, qty=5) + make_stock_entry(item=item, to_warehouse=warehouse, qty=5) + + so = make_sales_order(item_code=item, qty=6, rate=100) + + pl1 = create_pick_list(so.name) + pl1.save() + self.assertEqual(pl1.locations[0].qty, 5.0) + self.assertEqual(pl1.locations[1].qty, 1.0) + + so = make_sales_order(item_code=item, qty=4, rate=100) + + pl = create_pick_list(so.name) + pl.save() + self.assertEqual(pl.locations[0].qty, 4.0) + self.assertTrue(hasattr(pl, "locations")) + + pl1.submit() + + pl.reload() + pl.submit() + self.assertEqual(pl.locations[0].qty, 4.0) + self.assertTrue(hasattr(pl, "locations")) From 78637823c83fcd5bf1882dc26fde04d065362507 Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Mon, 6 May 2024 08:41:26 +0000 Subject: [PATCH 27/27] chore(release): Bumped to Version 15.22.2 ## [15.22.2](https://github.com/frappe/erpnext/compare/v15.22.1...v15.22.2) (2024-05-06) ### Bug Fixes * pick list with multiple batch issue (backport [#41335](https://github.com/frappe/erpnext/issues/41335)) (backport [#41338](https://github.com/frappe/erpnext/issues/41338)) ([#41340](https://github.com/frappe/erpnext/issues/41340)) ([ee12ec3](https://github.com/frappe/erpnext/commit/ee12ec36cc479679865cd6bda5b65a6c7a19912a)) --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 015a70acfb8..1ad327da5ee 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -3,7 +3,7 @@ import inspect import frappe -__version__ = "15.22.1" +__version__ = "15.22.2" def get_default_company(user=None):