From 25fe08eb740ebeb8e5a6c39189c1d92651f08a6b Mon Sep 17 00:00:00 2001 From: ljain112 Date: Thu, 18 Jul 2024 17:40:19 +0530 Subject: [PATCH 01/37] fix: set pos data if not return doc (cherry picked from commit 65d672da651bacfe847e26c4d19e4c7a4b11a634) --- erpnext/accounts/doctype/sales_invoice/sales_invoice.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js index 1df21b7ebc4..855e4568c9b 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js @@ -502,11 +502,12 @@ erpnext.accounts.SalesInvoiceController = class SalesInvoiceController extends ( frappe.msgprint(__("Please specify Company to proceed")); } else { var me = this; + const for_validate = me.frm.doc.is_return ? true : false; return this.frm.call({ doc: me.frm.doc, method: "set_missing_values", args: { - for_validate: true, + for_validate: for_validate, }, callback: function (r) { if (!r.exc) { From aea8271f7e14ff6179e6f211d00175e086d90758 Mon Sep 17 00:00:00 2001 From: Smit Vora Date: Thu, 18 Jul 2024 10:07:02 +0530 Subject: [PATCH 02/37] fix: ignore duplicates while creating default templates (cherry picked from commit cf55c2ab3d4c935e562cbb551714bdbcc3e2624f) --- erpnext/setup/setup_wizard/operations/taxes_setup.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/erpnext/setup/setup_wizard/operations/taxes_setup.py b/erpnext/setup/setup_wizard/operations/taxes_setup.py index 689af2c75b8..384673448b0 100644 --- a/erpnext/setup/setup_wizard/operations/taxes_setup.py +++ b/erpnext/setup/setup_wizard/operations/taxes_setup.py @@ -163,7 +163,7 @@ def make_taxes_and_charges_template(company_name, doctype, template): doc.flags.ignore_links = True doc.flags.ignore_validate = True doc.flags.ignore_mandatory = True - doc.insert(ignore_permissions=True) + doc.insert(ignore_permissions=True, ignore_if_duplicate=True) return doc @@ -196,7 +196,7 @@ def make_item_tax_template(company_name, template): # Ingone validations to make doctypes faster doc.flags.ignore_links = True doc.flags.ignore_validate = True - doc.insert(ignore_permissions=True) + doc.insert(ignore_permissions=True, ignore_if_duplicate=True) return doc @@ -233,7 +233,7 @@ def get_or_create_account(company_name, account): doc = frappe.get_doc(account) doc.flags.ignore_links = True doc.flags.ignore_validate = True - doc.insert(ignore_permissions=True, ignore_mandatory=True) + doc.insert(ignore_permissions=True, ignore_mandatory=True, ignore_if_duplicate=True) return doc From 9b52d89e034f80f63973dc94220ca670dfdb840c Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Thu, 18 Jul 2024 15:29:30 +0530 Subject: [PATCH 03/37] chore: remove stale code from sales invoice (cherry picked from commit f3fda9ce989f98aa971537799afa9ecf5b848547) --- .../doctype/sales_invoice/sales_invoice.js | 25 ------------------- 1 file changed, 25 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js index 797d00fe3ec..d463ecd5570 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js @@ -68,31 +68,6 @@ erpnext.accounts.SalesInvoiceController = class SalesInvoiceController extends ( this.frm.toggle_reqd("due_date", !this.frm.doc.is_return); - if (this.frm.doc.repost_required && this.frm.doc.docstatus === 1) { - this.frm.set_intro( - __( - "Accounting entries for this invoice needs to be reposted. Please click on 'Repost' button to update." - ) - ); - this.frm - .add_custom_button(__("Repost Accounting Entries"), () => { - this.frm.call({ - doc: this.frm.doc, - method: "repost_accounting_entries", - freeze: true, - freeze_message: __("Reposting..."), - callback: (r) => { - if (!r.exc) { - frappe.msgprint(__("Accounting Entries are reposted")); - me.frm.refresh(); - } - }, - }); - }) - .removeClass("btn-default") - .addClass("btn-warning"); - } - if (this.frm.doc.is_return) { this.frm.return_print_format = "Sales Invoice Return"; } From a8fe0e89a8bff3317d679e85e10d1cf4e6602cbe Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Thu, 18 Jul 2024 15:31:01 +0530 Subject: [PATCH 04/37] chore: remove stale 'repost_required' flag from sales invoice (cherry picked from commit 06c5334f2a6db3114b675dbf393abe94afe9bdb7) # Conflicts: # erpnext/accounts/doctype/sales_invoice/sales_invoice.json --- .../doctype/sales_invoice/sales_invoice.json | 14 ++++---------- .../doctype/sales_invoice/sales_invoice.py | 1 - 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json index 90b6e768092..ac2047a54fd 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json @@ -213,7 +213,6 @@ "is_internal_customer", "is_discounted", "remarks", - "repost_required", "connections_tab" ], "fields": [ @@ -2125,15 +2124,6 @@ "label": "Write Off", "width": "50%" }, - { - "default": "0", - "fieldname": "repost_required", - "fieldtype": "Check", - "hidden": 1, - "label": "Repost Required", - "no_copy": 1, - "read_only": 1 - }, { "fieldname": "incoterm", "fieldtype": "Link", @@ -2188,7 +2178,11 @@ "link_fieldname": "consolidated_invoice" } ], +<<<<<<< HEAD "modified": "2024-06-07 16:49:32.458402", +======= + "modified": "2024-07-18 15:30:39.428519", +>>>>>>> 06c5334f2a (chore: remove stale 'repost_required' flag from sales invoice) "modified_by": "Administrator", "module": "Accounts", "name": "Sales Invoice", diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 0d48cf229e5..7eb3cccbc72 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -161,7 +161,6 @@ class SalesInvoice(SellingController): project: DF.Link | None redeem_loyalty_points: DF.Check remarks: DF.SmallText | None - repost_required: DF.Check represents_company: DF.Link | None return_against: DF.Link | None rounded_total: DF.Currency From 3d8eac9b5aa37569fea0988a44141fd648728e20 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Thu, 18 Jul 2024 15:31:59 +0530 Subject: [PATCH 05/37] chore: remove 'repost_required' from purchase invoice (cherry picked from commit a467888a67088e1a7997bf5d2b800817e64b08cb) --- .../doctype/purchase_invoice/purchase_invoice.json | 12 +----------- .../doctype/purchase_invoice/purchase_invoice.py | 1 - 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json index cf08d08ce4b..79863d0e338 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json @@ -170,7 +170,6 @@ "against_expense_account", "column_break_63", "unrealized_profit_loss_account", - "repost_required", "subscription_section", "subscription", "auto_repeat", @@ -1603,15 +1602,6 @@ "fieldtype": "Check", "label": "Use Company Default Round Off Cost Center" }, - { - "default": "0", - "fieldname": "repost_required", - "fieldtype": "Check", - "hidden": 1, - "label": "Repost Required", - "options": "Account", - "read_only": 1 - }, { "default": "0", "fieldname": "use_transaction_date_exchange_rate", @@ -1639,7 +1629,7 @@ "idx": 204, "is_submittable": 1, "links": [], - "modified": "2024-04-11 11:28:42.802211", + "modified": "2024-07-18 15:31:49.488566", "modified_by": "Administrator", "module": "Accounts", "name": "Purchase Invoice", diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index 15f53d996da..7d1e3ac2f31 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -159,7 +159,6 @@ class PurchaseInvoice(BuyingController): rejected_warehouse: DF.Link | None release_date: DF.Date | None remarks: DF.SmallText | None - repost_required: DF.Check represents_company: DF.Link | None return_against: DF.Link | None rounded_total: DF.Currency From 8b9860902cac01380cb10da970c839ef0f7f7e0c Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Thu, 18 Jul 2024 15:32:51 +0530 Subject: [PATCH 06/37] chore: remove 'repost_required' from Journal Entry (cherry picked from commit e81373bb6ae1bde6c5b3261f776ba647cd9b65e3) # Conflicts: # erpnext/accounts/doctype/journal_entry/journal_entry.json --- .../doctype/journal_entry/journal_entry.json | 16 +++++----------- .../doctype/journal_entry/journal_entry.py | 4 +--- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.json b/erpnext/accounts/doctype/journal_entry/journal_entry.json index 91febb34052..021c9e19c15 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.json +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.json @@ -64,8 +64,7 @@ "stock_entry", "subscription_section", "auto_repeat", - "amended_from", - "repost_required" + "amended_from" ], "fields": [ { @@ -544,15 +543,6 @@ "label": "Is System Generated", "no_copy": 1, "read_only": 1 - }, - { - "default": "0", - "fieldname": "repost_required", - "fieldtype": "Check", - "hidden": 1, - "label": "Repost Required", - "print_hide": 1, - "read_only": 1 } ], "icon": "fa fa-file-text", @@ -567,7 +557,11 @@ "table_fieldname": "payment_entries" } ], +<<<<<<< HEAD "modified": "2023-11-23 12:11:04.128015", +======= + "modified": "2024-07-18 15:32:29.413598", +>>>>>>> e81373bb6a (chore: remove 'repost_required' from Journal Entry) "modified_by": "Administrator", "module": "Accounts", "name": "Journal Entry", diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py index 12b9800e688..07794eb2fd3 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.py +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py @@ -47,9 +47,7 @@ class JournalEntry(AccountsController): if TYPE_CHECKING: from frappe.types import DF - from erpnext.accounts.doctype.journal_entry_account.journal_entry_account import ( - JournalEntryAccount, - ) + from erpnext.accounts.doctype.journal_entry_account.journal_entry_account import JournalEntryAccount accounts: DF.Table[JournalEntryAccount] amended_from: DF.Link | None From 01dfea3ffab90759f72c23c25e19bd975b6d8b33 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Thu, 18 Jul 2024 15:34:02 +0530 Subject: [PATCH 07/37] chore: remove stale UI code related to repost (cherry picked from commit fe46e1d0899724efdbbdd32881be62112b97c11c) --- .../doctype/journal_entry/journal_entry.js | 24 ------------------ .../purchase_invoice/purchase_invoice.js | 25 ------------------- 2 files changed, 49 deletions(-) diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.js b/erpnext/accounts/doctype/journal_entry/journal_entry.js index 2c831cf7c57..d290d794df1 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.js +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.js @@ -25,30 +25,6 @@ frappe.ui.form.on("Journal Entry", { refresh: function (frm) { erpnext.toggle_naming_series(); - if (frm.doc.repost_required && frm.doc.docstatus === 1) { - frm.set_intro( - __( - "Accounting entries for this Journal Entry need to be reposted. Please click on 'Repost' button to update." - ) - ); - frm.add_custom_button(__("Repost Accounting Entries"), () => { - frm.call({ - doc: frm.doc, - method: "repost_accounting_entries", - freeze: true, - freeze_message: __("Reposting..."), - callback: (r) => { - if (!r.exc) { - frappe.msgprint(__("Accounting Entries are reposted.")); - frm.refresh(); - } - }, - }); - }) - .removeClass("btn-default") - .addClass("btn-warning"); - } - if (frm.doc.docstatus > 0) { frm.add_custom_button( __("Ledger"), diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js index c0a43395216..9c8c8cdfb03 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js @@ -77,31 +77,6 @@ erpnext.accounts.PurchaseInvoice = class PurchaseInvoice extends erpnext.buying. erpnext.accounts.ledger_preview.show_stock_ledger_preview(this.frm); } - if (this.frm.doc.repost_required && this.frm.doc.docstatus === 1) { - this.frm.set_intro( - __( - "Accounting entries for this invoice need to be reposted. Please click on 'Repost' button to update." - ) - ); - this.frm - .add_custom_button(__("Repost Accounting Entries"), () => { - this.frm.call({ - doc: this.frm.doc, - method: "repost_accounting_entries", - freeze: true, - freeze_message: __("Reposting..."), - callback: (r) => { - if (!r.exc) { - frappe.msgprint(__("Accounting Entries are reposted.")); - me.frm.refresh(); - } - }, - }); - }) - .removeClass("btn-default") - .addClass("btn-warning"); - } - if (!doc.is_return && doc.docstatus == 1 && doc.outstanding_amount != 0) { if (doc.on_hold) { this.frm.add_custom_button( From 949d7f4b532cc99ee0a12fd0094f616a11c4c379 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Thu, 18 Jul 2024 15:34:59 +0530 Subject: [PATCH 08/37] refactor: repost without checking on flag (cherry picked from commit 09f429ffba15f1b9cd43ad8967efd71eb95b963c) --- erpnext/controllers/accounts_controller.py | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index 0cbf1b320ca..67bfc71ed5b 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -2489,16 +2489,12 @@ class AccountsController(TransactionBase): @frappe.whitelist() def repost_accounting_entries(self): - if self.repost_required: - repost_ledger = frappe.new_doc("Repost Accounting Ledger") - repost_ledger.company = self.company - repost_ledger.append("vouchers", {"voucher_type": self.doctype, "voucher_no": self.name}) - repost_ledger.flags.ignore_permissions = True - repost_ledger.insert() - repost_ledger.submit() - self.db_set("repost_required", 0) - else: - frappe.throw(_("No updates pending for reposting")) + repost_ledger = frappe.new_doc("Repost Accounting Ledger") + repost_ledger.company = self.company + repost_ledger.append("vouchers", {"voucher_type": self.doctype, "voucher_no": self.name}) + repost_ledger.flags.ignore_permissions = True + repost_ledger.insert() + repost_ledger.submit() @frappe.whitelist() From d69361b1c95bceb170f56ba42168517bde88cc0c Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Thu, 18 Jul 2024 15:38:15 +0530 Subject: [PATCH 09/37] refactor: remove attribute check on 'repost_required' (cherry picked from commit 07fc952a4383de79ee7c327719047b7c7e02dcd7) --- .../doctype/journal_entry/journal_entry.py | 12 ++---- .../purchase_invoice/purchase_invoice.py | 24 ++++++------ .../doctype/sales_invoice/sales_invoice.py | 37 +++++++++---------- 3 files changed, 32 insertions(+), 41 deletions(-) diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py index 07794eb2fd3..6adc8be3f7d 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.py +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py @@ -195,14 +195,10 @@ class JournalEntry(AccountsController): self.update_booked_depreciation() def on_update_after_submit(self): - if hasattr(self, "repost_required"): - self.needs_repost = self.check_if_fields_updated( - fields_to_check=[], child_tables={"accounts": []} - ) - if self.needs_repost: - self.validate_for_repost() - self.db_set("repost_required", self.needs_repost) - self.repost_accounting_entries() + self.needs_repost = self.check_if_fields_updated(fields_to_check=[], child_tables={"accounts": []}) + if self.needs_repost: + self.validate_for_repost() + self.repost_accounting_entries() def on_cancel(self): # References for this Journal are removed on the `on_cancel` event in accounts_controller diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index 7d1e3ac2f31..111886048ce 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -795,19 +795,17 @@ class PurchaseInvoice(BuyingController): self.process_common_party_accounting() def on_update_after_submit(self): - if hasattr(self, "repost_required"): - fields_to_check = [ - "cash_bank_account", - "write_off_account", - "unrealized_profit_loss_account", - "is_opening", - ] - child_tables = {"items": ("expense_account",), "taxes": ("account_head",)} - self.needs_repost = self.check_if_fields_updated(fields_to_check, child_tables) - if self.needs_repost: - self.validate_for_repost() - self.db_set("repost_required", self.needs_repost) - self.repost_accounting_entries() + fields_to_check = [ + "cash_bank_account", + "write_off_account", + "unrealized_profit_loss_account", + "is_opening", + ] + child_tables = {"items": ("expense_account",), "taxes": ("account_head",)} + self.needs_repost = self.check_if_fields_updated(fields_to_check, child_tables) + if self.needs_repost: + self.validate_for_repost() + self.repost_accounting_entries() def make_gl_entries(self, gl_entries=None, from_repost=False): update_outstanding = "No" if (cint(self.is_paid) or self.write_off_account) else "Yes" diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 7eb3cccbc72..24e61b0d221 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -555,7 +555,6 @@ class SalesInvoice(SellingController): self.repost_future_sle_and_gle() self.db_set("status", "Cancelled") - self.db_set("repost_required", 0) if frappe.db.get_single_value("Selling Settings", "sales_update_frequency") == "Each Transaction": update_company_current_month_sales(self.company) @@ -705,25 +704,23 @@ class SalesInvoice(SellingController): data.sales_invoice = sales_invoice def on_update_after_submit(self): - if hasattr(self, "repost_required"): - fields_to_check = [ - "additional_discount_account", - "cash_bank_account", - "account_for_change_amount", - "write_off_account", - "loyalty_redemption_account", - "unrealized_profit_loss_account", - "is_opening", - ] - child_tables = { - "items": ("income_account", "expense_account", "discount_account"), - "taxes": ("account_head",), - } - self.needs_repost = self.check_if_fields_updated(fields_to_check, child_tables) - if self.needs_repost: - self.validate_for_repost() - self.db_set("repost_required", self.needs_repost) - self.repost_accounting_entries() + fields_to_check = [ + "additional_discount_account", + "cash_bank_account", + "account_for_change_amount", + "write_off_account", + "loyalty_redemption_account", + "unrealized_profit_loss_account", + "is_opening", + ] + child_tables = { + "items": ("income_account", "expense_account", "discount_account"), + "taxes": ("account_head",), + } + self.needs_repost = self.check_if_fields_updated(fields_to_check, child_tables) + if self.needs_repost: + self.validate_for_repost() + self.repost_accounting_entries() def set_paid_amount(self): paid_amount = 0.0 From e607f3c78dde5edb4dba8761955c0b19b880ccbb Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Thu, 18 Jul 2024 15:39:30 +0530 Subject: [PATCH 10/37] refactor(test): remove assert on 'repost_required' (cherry picked from commit e71cb4eab7f07cad2f4245778a205750e5f0d768) --- .../accounts/doctype/purchase_invoice/test_purchase_invoice.py | 2 -- erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py | 3 --- 2 files changed, 5 deletions(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py index 68e9d2b0e00..eb7c486f2e1 100644 --- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py @@ -2014,8 +2014,6 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin): ["Service - _TC", 1000, 0.0, nowdate()], ] check_gl_entries(self, pi.name, expected_gle, nowdate()) - pi.load_from_db() - self.assertFalse(pi.repost_required) @change_settings("Buying Settings", {"supplier_group": None}) def test_purchase_invoice_without_supplier_group(self): diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index ee4e82b4dfa..9197f2e091a 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -2952,9 +2952,6 @@ class TestSalesInvoice(FrappeTestCase): check_gl_entries(self, si.name, expected_gle, add_days(nowdate(), -1)) - si.load_from_db() - self.assertFalse(si.repost_required) - def test_asset_depreciation_on_sale_with_pro_rata(self): """ Tests if an Asset set to depreciate yearly on June 30, that gets sold on Sept 30, creates an additional depreciation entry on its date of sale. From 2ae94b2af28cf40b3c66236a01104c0bb0fdb0fc Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Wed, 24 Jul 2024 13:01:51 +0530 Subject: [PATCH 11/37] chore: resolve conflicts --- erpnext/accounts/doctype/journal_entry/journal_entry.json | 6 +----- erpnext/accounts/doctype/sales_invoice/sales_invoice.json | 4 ---- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.json b/erpnext/accounts/doctype/journal_entry/journal_entry.json index 021c9e19c15..4184bdaabb9 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.json +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.json @@ -557,11 +557,7 @@ "table_fieldname": "payment_entries" } ], -<<<<<<< HEAD - "modified": "2023-11-23 12:11:04.128015", -======= "modified": "2024-07-18 15:32:29.413598", ->>>>>>> e81373bb6a (chore: remove 'repost_required' from Journal Entry) "modified_by": "Administrator", "module": "Accounts", "name": "Journal Entry", @@ -612,4 +608,4 @@ "states": [], "title_field": "title", "track_changes": 1 -} \ No newline at end of file +} diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json index ac2047a54fd..c44afd555e0 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json @@ -2178,11 +2178,7 @@ "link_fieldname": "consolidated_invoice" } ], -<<<<<<< HEAD - "modified": "2024-06-07 16:49:32.458402", -======= "modified": "2024-07-18 15:30:39.428519", ->>>>>>> 06c5334f2a (chore: remove stale 'repost_required' flag from sales invoice) "modified_by": "Administrator", "module": "Accounts", "name": "Sales Invoice", From 298a5699f138d795d69889b63ece45400328499b Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Wed, 24 Jul 2024 18:37:13 +0530 Subject: [PATCH 12/37] fix: incorrect current qty for the batch in stock reco (backport #42434) (#42459) fix: incorrect current qty for the batch in stock reco (#42434) (cherry picked from commit 9cd33741014e2f84614df73090617a9f53294d01) Co-authored-by: rohitwaghchaure --- .../serial_and_batch_bundle.py | 15 +++ .../stock_reconciliation.py | 25 +++-- .../test_stock_reconciliation.py | 93 +++++++++++++++++++ 3 files changed, 124 insertions(+), 9 deletions(-) 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 9b65e11f430..615d98a448d 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 @@ -2188,6 +2188,8 @@ def get_stock_ledgers_for_serial_nos(kwargs): def get_stock_ledgers_batches(kwargs): + from erpnext.stock.utils import get_combine_datetime + stock_ledger_entry = frappe.qb.DocType("Stock Ledger Entry") batch_table = frappe.qb.DocType("Batch") @@ -2214,6 +2216,19 @@ def get_stock_ledgers_batches(kwargs): else: query = query.where(stock_ledger_entry[field] == kwargs.get(field)) + if kwargs.get("posting_date"): + if kwargs.get("posting_time") is None: + kwargs.posting_time = nowtime() + + timestamp_condition = stock_ledger_entry.posting_datetime <= get_combine_datetime( + kwargs.posting_date, kwargs.posting_time + ) + + query = query.where(timestamp_condition) + + if kwargs.get("ignore_voucher_nos"): + query = query.where(stock_ledger_entry.voucher_no.notin(kwargs.get("ignore_voucher_nos"))) + if kwargs.based_on == "LIFO": query = query.orderby(batch_table.creation, order=frappe.qb.desc) elif kwargs.based_on == "Expiry": diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py index 674624e184b..93e3e69729b 100644 --- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py +++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py @@ -16,7 +16,7 @@ from erpnext.stock.doctype.serial_and_batch_bundle.serial_and_batch_bundle impor get_available_serial_nos, ) from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos -from erpnext.stock.utils import get_stock_balance +from erpnext.stock.utils import get_incoming_rate, get_stock_balance class OpeningEntryAccountError(frappe.ValidationError): @@ -952,14 +952,21 @@ class StockReconciliation(StockController): precesion = row.precision("current_qty") if flt(current_qty, precesion) != flt(row.current_qty, precesion): if not row.serial_no: - val_rate = get_valuation_rate( - row.item_code, - row.warehouse, - self.doctype, - self.name, - company=self.company, - batch_no=row.batch_no, - serial_and_batch_bundle=row.current_serial_and_batch_bundle, + val_rate = get_incoming_rate( + frappe._dict( + { + "item_code": row.item_code, + "warehouse": row.warehouse, + "qty": current_qty * -1, + "serial_and_batch_bundle": row.current_serial_and_batch_bundle, + "batch_no": row.batch_no, + "voucher_type": self.doctype, + "voucher_no": self.name, + "company": self.company, + "posting_date": self.posting_date, + "posting_time": self.posting_time, + } + ) ) row.current_valuation_rate = val_rate diff --git a/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py index 48d67c2cf46..9bb6ba9ec90 100644 --- a/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py +++ b/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py @@ -4,6 +4,7 @@ # ERPNext - web based ERP (http://erpnext.com) # For license information, please see license.txt +import json import frappe from frappe.tests.utils import FrappeTestCase, change_settings @@ -1182,6 +1183,98 @@ class TestStockReconciliation(FrappeTestCase, StockTestMixin): self.assertAlmostEqual(row.incoming_rate, 1000.00) self.assertEqual(row.serial_no, serial_nos[row.idx - 1]) + def test_stock_reco_with_legacy_batch(self): + from erpnext.stock.doctype.batch.batch import get_batch_qty + + batch_item_code = self.make_item( + "Test Batch Item Legacy Batch 1", + { + "is_stock_item": 1, + "has_batch_no": 1, + "create_new_batch": 1, + "batch_number_series": "BH1-NRALL-S-.###", + }, + ).name + + warehouse = "_Test Warehouse - _TC" + + frappe.flags.ignore_serial_batch_bundle_validation = True + frappe.flags.use_serial_and_batch_fields = True + + batch_id = "BH1-NRALL-S-0001" + if not frappe.db.exists("Batch", batch_id): + batch_doc = frappe.get_doc( + { + "doctype": "Batch", + "batch_id": batch_id, + "item": batch_item_code, + "use_batchwise_valuation": 0, + } + ).insert(ignore_permissions=True) + + self.assertTrue(batch_doc.use_batchwise_valuation) + + stock_queue = [] + qty_after_transaction = 0 + balance_value = 0 + i = 0 + for qty, valuation in {10: 100, 20: 200}.items(): + i += 1 + stock_queue.append([qty, valuation]) + qty_after_transaction += qty + balance_value += qty_after_transaction * valuation + + doc = frappe.get_doc( + { + "doctype": "Stock Ledger Entry", + "posting_date": add_days(nowdate(), -2 * i), + "posting_time": nowtime(), + "batch_no": batch_id, + "incoming_rate": valuation, + "qty_after_transaction": qty_after_transaction, + "stock_value_difference": valuation * qty, + "balance_value": balance_value, + "valuation_rate": balance_value / qty_after_transaction, + "actual_qty": qty, + "item_code": batch_item_code, + "warehouse": "_Test Warehouse - _TC", + "stock_queue": json.dumps(stock_queue), + } + ) + + doc.flags.ignore_permissions = True + doc.flags.ignore_mandatory = True + doc.flags.ignore_links = True + doc.flags.ignore_validate = True + doc.submit() + doc.reload() + + frappe.flags.ignore_serial_batch_bundle_validation = False + frappe.flags.use_serial_and_batch_fields = False + + batch_doc = frappe.get_doc("Batch", batch_id) + + qty = get_batch_qty(batch_id, warehouse, batch_item_code) + self.assertEqual(qty, 30) + + sr = create_stock_reconciliation( + item_code=batch_item_code, + posting_date=add_days(nowdate(), -3), + posting_time=nowtime(), + warehouse=warehouse, + qty=100, + rate=1000, + reconcile_all_serial_batch=0, + batch_no=batch_id, + use_serial_batch_fields=1, + ) + + self.assertEqual(sr.items[0].current_qty, 20) + self.assertEqual(sr.items[0].qty, 100) + + qty = get_batch_qty(batch_id, warehouse, batch_item_code) + self.assertEqual(qty, 110) + def create_batch_item_with_batch(item_name, batch_id): batch_item_doc = create_item(item_name, is_stock_item=1) From 219310e817d22144dd1f9ffca50db5c14d90d602 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Wed, 24 Jul 2024 18:13:30 +0530 Subject: [PATCH 13/37] refactor: provision for monthly re-evaluation (cherry picked from commit ce2b9e0f1a69a652ed797453ba04d30e4857c0eb) --- erpnext/setup/doctype/company/company.json | 4 ++-- erpnext/setup/doctype/company/company.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/erpnext/setup/doctype/company/company.json b/erpnext/setup/doctype/company/company.json index 787b0826f01..284bd2b7f22 100644 --- a/erpnext/setup/doctype/company/company.json +++ b/erpnext/setup/doctype/company/company.json @@ -754,7 +754,7 @@ "fieldname": "auto_err_frequency", "fieldtype": "Select", "label": "Frequency", - "options": "Daily\nWeekly" + "options": "Daily\nWeekly\nMonthly" }, { "default": "0", @@ -808,7 +808,7 @@ "image_field": "company_logo", "is_tree": 1, "links": [], - "modified": "2024-06-21 17:46:25.567565", + "modified": "2024-07-24 18:17:56.413971", "modified_by": "Administrator", "module": "Setup", "name": "Company", diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py index 87d14e3c6b4..f79ea60f5c4 100644 --- a/erpnext/setup/doctype/company/company.py +++ b/erpnext/setup/doctype/company/company.py @@ -31,7 +31,7 @@ class Company(NestedSet): accumulated_depreciation_account: DF.Link | None allow_account_creation_against_child_company: DF.Check asset_received_but_not_billed: DF.Link | None - auto_err_frequency: DF.Literal["Daily", "Weekly"] + auto_err_frequency: DF.Literal["Daily", "Weekly", "Monthly"] auto_exchange_rate_revaluation: DF.Check book_advance_payments_in_separate_party_account: DF.Check capital_work_in_progress_account: DF.Link | None From 7b3a78e04e3b28a4effdb3a1a25163bd256dce31 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Wed, 24 Jul 2024 18:16:20 +0530 Subject: [PATCH 14/37] refactor: hooks for monthly re-evaluation jobs (cherry picked from commit fc4e5f165c9628171189a1c080793507e21e0500) --- erpnext/accounts/utils.py | 12 ++++++++++++ erpnext/hooks.py | 1 + 2 files changed, 13 insertions(+) diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py index 2558e976bea..0450221222d 100644 --- a/erpnext/accounts/utils.py +++ b/erpnext/accounts/utils.py @@ -1598,6 +1598,18 @@ def auto_create_exchange_rate_revaluation_weekly() -> None: create_err_and_its_journals(companies) +def auto_create_exchange_rate_revaluation_monthly() -> None: + """ + Executed by background job + """ + companies = frappe.db.get_all( + "Company", + filters={"auto_exchange_rate_revaluation": 1, "auto_err_frequency": "Montly"}, + fields=["name", "submit_err_jv"], + ) + create_err_and_its_journals(companies) + + def get_payment_ledger_entries(gl_entries, cancel=0): ple_map = [] if gl_entries: diff --git a/erpnext/hooks.py b/erpnext/hooks.py index 028acc9cb11..527be6ab337 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -456,6 +456,7 @@ scheduler_events = { ], "monthly_long": [ "erpnext.accounts.deferred_revenue.process_deferred_accounting", + "erpnext.accounts.utils.auto_create_exchange_rate_revaluation_monthly", ], } From 2d2140aad0fb306d9f6a65402aea1fc2d8e13deb Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Thu, 25 Jul 2024 06:48:10 +0530 Subject: [PATCH 15/37] fix: keyerror posting_time (backport #42452) (#42460) fix: keyerror posting_time (#42452) fix: keyerror: posting_time (cherry picked from commit 06e2d7265c2f7dceedf3fc75462f1bb3190b6d4a) Co-authored-by: rohitwaghchaure --- erpnext/stock/stock_ledger.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py index e14b0f87501..8373ea14dec 100644 --- a/erpnext/stock/stock_ledger.py +++ b/erpnext/stock/stock_ledger.py @@ -1588,9 +1588,11 @@ def get_stock_ledger_entries( if not previous_sle.get("posting_date"): previous_sle["posting_datetime"] = "1900-01-01 00:00:00" else: - previous_sle["posting_datetime"] = get_combine_datetime( - previous_sle["posting_date"], previous_sle["posting_time"] - ) + posting_time = previous_sle.get("posting_time") + if not posting_time: + posting_time = "00:00:00" + + previous_sle["posting_datetime"] = get_combine_datetime(previous_sle["posting_date"], posting_time) if operator in (">", "<=") and previous_sle.get("name"): conditions += " and name!=%(name)s" From 422824b9e78963bb20fde2f3967950e20b78525e Mon Sep 17 00:00:00 2001 From: Ninad Parikh <109862100+Ninad1306@users.noreply.github.com> Date: Thu, 25 Jul 2024 10:18:21 +0530 Subject: [PATCH 16/37] fix: Fields Modification for Subcontracting DocTypes (#42383) * fix: fields renaming and reordering for enhanced user experience * fix: dashboard data for stock entry (cherry picked from commit 302339998f89cd1e6482a9c51f70dda98714a8c7) # Conflicts: # erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.json --- .../doctype/stock_entry/stock_entry.json | 9 +- .../stock_entry/stock_entry_dashboard.py | 26 ++++++ .../subcontracting_order.json | 67 +++++++++------ .../subcontracting_receipt.json | 85 +++++++++++-------- 4 files changed, 124 insertions(+), 63 deletions(-) create mode 100644 erpnext/stock/doctype/stock_entry/stock_entry_dashboard.py diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.json b/erpnext/stock/doctype/stock_entry/stock_entry.json index a090b37033b..495af7f173a 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.json +++ b/erpnext/stock/doctype/stock_entry/stock_entry.json @@ -83,7 +83,8 @@ "job_card", "amended_from", "credit_note", - "is_return" + "is_return", + "tab_connections" ], "fields": [ { @@ -683,6 +684,12 @@ "label": "Asset Repair", "options": "Asset Repair", "read_only": 1 + }, + { + "fieldname": "tab_connections", + "fieldtype": "Tab Break", + "label": "Connections", + "show_dashboard": 1 } ], "icon": "fa fa-file-text", diff --git a/erpnext/stock/doctype/stock_entry/stock_entry_dashboard.py b/erpnext/stock/doctype/stock_entry/stock_entry_dashboard.py new file mode 100644 index 00000000000..c1141fe43ec --- /dev/null +++ b/erpnext/stock/doctype/stock_entry/stock_entry_dashboard.py @@ -0,0 +1,26 @@ +from frappe import _ + + +# Todo: non_standard_fieldnames is to be decided +def get_data(): + return { + "fieldname": "stock_entry", + "non_standard_fieldnames": { + # "DocType Name": "Reference field name", + }, + "internal_links": { + "Purchase Order": ["items", "purchase_order"], + "Subcontracting Order": ["items", "subcontracting_order"], + "Subcontracting Receipt": ["items", "subcontracting_receipt"], + }, + "transactions": [ + { + "label": _("Reference"), + "items": [ + "Purchase Order", + "Subcontracting Order", + "Subcontracting Receipt", + ], + }, + ], + } diff --git a/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.json b/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.json index 507e23365cc..6d99a80fa58 100644 --- a/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.json +++ b/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.json @@ -23,18 +23,6 @@ "cost_center", "dimension_col_break", "project", - "address_and_contact_section", - "supplier_address", - "address_display", - "contact_person", - "contact_display", - "contact_mobile", - "contact_email", - "column_break_19", - "shipping_address", - "shipping_address_display", - "billing_address", - "billing_address_display", "section_break_24", "column_break_25", "set_warehouse", @@ -48,10 +36,23 @@ "raw_materials_supplied_section", "set_reserve_warehouse", "supplied_items", - "additional_costs_section", + "tab_address_and_contact", + "supplier_address", + "address_display", + "contact_person", + "contact_display", + "contact_mobile", + "contact_email", + "column_break_19", + "shipping_address", + "shipping_address_display", + "billing_address", + "billing_address_display", + "tab_additional_costs", "distribute_additional_costs_based_on", "additional_costs", "total_additional_costs", + "tab_other_info", "order_status_section", "status", "column_break_39", @@ -59,7 +60,8 @@ "printing_settings_section", "select_print_heading", "column_break_43", - "letter_head" + "letter_head", + "tab_connections" ], "fields": [ { @@ -95,7 +97,7 @@ "fieldtype": "Link", "in_global_search": 1, "in_standard_filter": 1, - "label": "Supplier", + "label": "Job Worker", "options": "Supplier", "print_hide": 1, "reqd": 1, @@ -107,7 +109,7 @@ "fieldname": "supplier_name", "fieldtype": "Data", "in_global_search": 1, - "label": "Supplier Name", + "label": "Job Worker Name", "read_only": 1, "reqd": 1 }, @@ -115,7 +117,7 @@ "depends_on": "supplier", "fieldname": "supplier_warehouse", "fieldtype": "Link", - "label": "Supplier Warehouse", + "label": "Job Worker Warehouse", "options": "Warehouse", "reqd": 1 }, @@ -166,9 +168,8 @@ "read_only": 1 }, { - "collapsible": 1, - "fieldname": "address_and_contact_section", - "fieldtype": "Section Break", + "fieldname": "tab_address_and_contact", + "fieldtype": "Tab Break", "label": "Address and Contact" }, { @@ -176,14 +177,19 @@ "fetch_if_empty": 1, "fieldname": "supplier_address", "fieldtype": "Link", - "label": "Supplier Address", + "label": "Job Worker Address", "options": "Address", "print_hide": 1 }, { "fieldname": "address_display", +<<<<<<< HEAD "fieldtype": "Small Text", "label": "Supplier Address Details", +======= + "fieldtype": "Text Editor", + "label": "Job Worker Address Details", +>>>>>>> 302339998f (fix: Fields Modification for Subcontracting DocTypes (#42383)) "read_only": 1 }, { @@ -191,7 +197,7 @@ "fetch_if_empty": 1, "fieldname": "contact_person", "fieldtype": "Link", - "label": "Supplier Contact", + "label": "Job Worker Contact", "options": "Contact", "print_hide": 1 }, @@ -337,11 +343,9 @@ "read_only": 1 }, { - "collapsible": 1, - "collapsible_depends_on": "total_additional_costs", "depends_on": "eval:(doc.docstatus == 0 || doc.total_additional_costs)", - "fieldname": "additional_costs_section", - "fieldtype": "Section Break", + "fieldname": "tab_additional_costs", + "fieldtype": "Tab Break", "label": "Additional Costs" }, { @@ -449,6 +453,17 @@ "fieldtype": "Link", "label": "Project", "options": "Project" + }, + { + "fieldname": "tab_other_info", + "fieldtype": "Tab Break", + "label": "Other Info" + }, + { + "fieldname": "tab_connections", + "fieldtype": "Tab Break", + "label": "Connections", + "show_dashboard": 1 } ], "icon": "fa fa-file-text", diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.json b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.json index 8bcf97da40d..407d2700380 100644 --- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.json +++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.json @@ -23,18 +23,6 @@ "cost_center", "dimension_col_break", "project", - "section_addresses", - "supplier_address", - "contact_person", - "address_display", - "contact_display", - "contact_mobile", - "contact_email", - "col_break_address", - "shipping_address", - "shipping_address_display", - "billing_address", - "billing_address_display", "sec_warehouse", "set_warehouse", "rejected_warehouse", @@ -53,23 +41,36 @@ "get_current_stock", "raw_material_details", "supplied_items", - "additional_costs_section", - "distribute_additional_costs_based_on", - "additional_costs", - "total_additional_costs", "section_break_46", "in_words", "bill_no", "bill_date", + "tab_addresses", + "supplier_address", + "contact_person", + "address_display", + "contact_display", + "contact_mobile", + "contact_email", + "col_break_address", + "shipping_address", + "shipping_address_display", + "billing_address", + "billing_address_display", + "tab_additional_costs", + "distribute_additional_costs_based_on", + "additional_costs", + "total_additional_costs", + "tab_other_info", "more_info", - "status", - "column_break_39", - "per_returned", - "section_break_47", "amended_from", "range", "column_break4", "represents_company", + "order_status_section", + "status", + "column_break_39", + "per_returned", "subscription_detail", "auto_repeat", "printing_settings", @@ -84,7 +85,8 @@ "transporter_name", "column_break5", "lr_no", - "lr_date" + "lr_date", + "tab_connections" ], "fields": [ { @@ -112,7 +114,7 @@ "fieldname": "supplier", "fieldtype": "Link", "in_global_search": 1, - "label": "Supplier", + "label": "Job Worker", "options": "Supplier", "print_hide": 1, "print_width": "150px", @@ -127,7 +129,7 @@ "fieldname": "supplier_name", "fieldtype": "Data", "in_global_search": 1, - "label": "Supplier Name", + "label": "Job Worker Name", "read_only": 1 }, { @@ -174,15 +176,14 @@ "width": "150px" }, { - "collapsible": 1, - "fieldname": "section_addresses", - "fieldtype": "Section Break", + "fieldname": "tab_addresses", + "fieldtype": "Tab Break", "label": "Address and Contact" }, { "fieldname": "supplier_address", "fieldtype": "Link", - "label": "Select Supplier Address", + "label": "Select Job Worker Address", "options": "Address", "print_hide": 1 }, @@ -269,7 +270,7 @@ { "fieldname": "supplier_warehouse", "fieldtype": "Link", - "label": "Supplier Warehouse", + "label": "Job Worker Warehouse", "no_copy": 1, "options": "Warehouse", "print_hide": 1, @@ -414,6 +415,7 @@ "width": "50%" }, { + "collapsible": 1, "fieldname": "subscription_detail", "fieldtype": "Section Break", "label": "Auto Repeat Detail" @@ -571,10 +573,6 @@ "print_hide": 1, "read_only": 1 }, - { - "fieldname": "section_break_47", - "fieldtype": "Section Break" - }, { "collapsible": 1, "fieldname": "accounting_dimensions_section", @@ -598,11 +596,9 @@ "options": "Project" }, { - "collapsible": 1, - "collapsible_depends_on": "total_additional_costs", "depends_on": "eval:(doc.docstatus == 0 || doc.total_additional_costs)", - "fieldname": "additional_costs_section", - "fieldtype": "Section Break", + "fieldname": "tab_additional_costs", + "fieldtype": "Tab Break", "label": "Additional Costs" }, { @@ -658,6 +654,23 @@ { "fieldname": "column_break_uinr", "fieldtype": "Column Break" + }, + { + "fieldname": "tab_other_info", + "fieldtype": "Tab Break", + "label": "Other Info" + }, + { + "collapsible": 1, + "fieldname": "order_status_section", + "fieldtype": "Section Break", + "label": "Order Status" + }, + { + "fieldname": "tab_connections", + "fieldtype": "Tab Break", + "label": "Connections", + "show_dashboard": 1 } ], "in_create": 1, From 9e99eda3c3d2fa1ca409639fe559a5763b03b6d1 Mon Sep 17 00:00:00 2001 From: Ninad1306 Date: Thu, 25 Jul 2024 18:39:20 +0530 Subject: [PATCH 17/37] fix: field_type is small text for v15 --- .../doctype/subcontracting_order/subcontracting_order.json | 5 ----- 1 file changed, 5 deletions(-) diff --git a/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.json b/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.json index 6d99a80fa58..b8bda832983 100644 --- a/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.json +++ b/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.json @@ -183,13 +183,8 @@ }, { "fieldname": "address_display", -<<<<<<< HEAD "fieldtype": "Small Text", - "label": "Supplier Address Details", -======= - "fieldtype": "Text Editor", "label": "Job Worker Address Details", ->>>>>>> 302339998f (fix: Fields Modification for Subcontracting DocTypes (#42383)) "read_only": 1 }, { From 3e3bdf749148ed226baf5797f80c2dae4b213e0d Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Thu, 25 Jul 2024 19:43:00 +0530 Subject: [PATCH 18/37] refactor: index on Purchase Invoice 'release_date' (cherry picked from commit 764dd12b10d66adfa99b2c351a5e6adb66899b8a) --- .../accounts/doctype/purchase_invoice/purchase_invoice.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json index 79863d0e338..3751c027c97 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json @@ -363,7 +363,8 @@ "description": "Once set, this invoice will be on hold till the set date", "fieldname": "release_date", "fieldtype": "Date", - "label": "Release Date" + "label": "Release Date", + "search_index": 1 }, { "fieldname": "cb_17", @@ -1629,7 +1630,7 @@ "idx": 204, "is_submittable": 1, "links": [], - "modified": "2024-07-18 15:31:49.488566", + "modified": "2024-07-25 19:42:36.931278", "modified_by": "Administrator", "module": "Accounts", "name": "Purchase Invoice", From 322fbe92eed9d0fa6bd5d597d382443bcf819c7a Mon Sep 17 00:00:00 2001 From: ljain112 Date: Tue, 23 Jul 2024 17:36:33 +0530 Subject: [PATCH 19/37] fix: parenttype in item wise purchase and sales register (cherry picked from commit 35981b8730a5ffe6c7cb977aa59332d4bd2069b1) --- .../item_wise_purchase_register.py | 6 ++++-- .../item_wise_sales_register/item_wise_sales_register.py | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py b/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py index 8bc05273092..83f664c984a 100644 --- a/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py +++ b/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py @@ -315,8 +315,9 @@ def apply_conditions(query, pi, pii, filters): def get_items(filters, additional_table_columns): - pi = frappe.qb.DocType("Purchase Invoice") - pii = frappe.qb.DocType("Purchase Invoice Item") + doctype = "Purchase Invoice" + pi = frappe.qb.DocType(doctype) + pii = frappe.qb.DocType(f"{doctype} Item") Item = frappe.qb.DocType("Item") query = ( frappe.qb.from_(pi) @@ -353,6 +354,7 @@ def get_items(filters, additional_table_columns): pi.mode_of_payment, ) .where(pi.docstatus == 1) + .where(pii.parenttype == doctype) ) if filters.get("supplier"): diff --git a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py index cf08e45c537..604c0a6569d 100644 --- a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py +++ b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py @@ -410,8 +410,9 @@ def apply_group_by_conditions(query, si, ii, filters): def get_items(filters, additional_query_columns, additional_conditions=None): - si = frappe.qb.DocType("Sales Invoice") - sii = frappe.qb.DocType("Sales Invoice Item") + doctype = "Sales Invoice" + si = frappe.qb.DocType(doctype) + sii = frappe.qb.DocType(f"{doctype} Item") item = frappe.qb.DocType("Item") query = ( @@ -459,6 +460,7 @@ def get_items(filters, additional_query_columns, additional_conditions=None): sii.qty, ) .where(si.docstatus == 1) + .where(sii.parenttype == doctype) ) if additional_query_columns: From 183ac4155046dc5d18f9a28c560b7586c5f12b4b Mon Sep 17 00:00:00 2001 From: ljain112 Date: Thu, 25 Jul 2024 17:26:52 +0530 Subject: [PATCH 20/37] fix: consider payment entries for checking if tds is deducted (cherry picked from commit 40b59de4cde27da0e056032bffe82ac3e4f9e4d5) --- .../purchase_invoice/purchase_invoice.py | 6 ++--- .../tax_withholding_category.py | 22 ++++++++++++++++++- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index 111886048ce..c33b2c0ff17 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -1702,6 +1702,9 @@ class PurchaseInvoice(BuyingController): self.db_set("release_date", None) def set_tax_withholding(self): + self.set("advance_tax", []) + self.set("tax_withheld_vouchers", []) + if not self.apply_tds: return @@ -1743,8 +1746,6 @@ class PurchaseInvoice(BuyingController): self.remove(d) ## Add pending vouchers on which tax was withheld - self.set("tax_withheld_vouchers", []) - for voucher_no, voucher_details in voucher_wise_amount.items(): self.append( "tax_withheld_vouchers", @@ -1759,7 +1760,6 @@ class PurchaseInvoice(BuyingController): self.calculate_taxes_and_totals() def allocate_advance_tds(self, tax_withholding_details, advance_taxes): - self.set("advance_tax", []) for tax in advance_taxes: allocated_amount = 0 pending_amount = flt(tax.tax_amount - tax.allocated_amount) diff --git a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py index 44096714ca7..8a9d1584f7d 100644 --- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py +++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py @@ -268,6 +268,11 @@ def get_tax_amount(party_type, parties, inv, tax_details, posting_date, pan_no=N vouchers, voucher_wise_amount = get_invoice_vouchers( parties, tax_details, inv.company, party_type=party_type ) + + payment_entry_vouchers = get_payment_entry_vouchers( + parties, tax_details, inv.company, party_type=party_type + ) + advance_vouchers = get_advance_vouchers( parties, company=inv.company, @@ -275,7 +280,8 @@ def get_tax_amount(party_type, parties, inv, tax_details, posting_date, pan_no=N to_date=tax_details.to_date, party_type=party_type, ) - taxable_vouchers = vouchers + advance_vouchers + + taxable_vouchers = vouchers + advance_vouchers + payment_entry_vouchers tax_deducted_on_advances = 0 if inv.doctype == "Purchase Invoice": @@ -387,6 +393,20 @@ def get_invoice_vouchers(parties, tax_details, company, party_type="Supplier"): return vouchers, voucher_wise_amount +def get_payment_entry_vouchers(parties, tax_details, company, party_type="Supplier"): + payment_entry_filters = { + "party_type": party_type, + "party": ("in", parties), + "docstatus": 1, + "apply_tax_withholding_amount": 1, + "posting_date": ["between", (tax_details.from_date, tax_details.to_date)], + "tax_withholding_category": tax_details.get("tax_withholding_category"), + "company": company, + } + + return frappe.db.get_all("Payment Entry", filters=payment_entry_filters, pluck="name") + + def get_advance_vouchers(parties, company=None, from_date=None, to_date=None, party_type="Supplier"): """ Use Payment Ledger to fetch unallocated Advance Payments From 80d4dc2016cd692b5e515b08e559324600b0ce43 Mon Sep 17 00:00:00 2001 From: Ninad1306 Date: Thu, 25 Jul 2024 18:05:31 +0530 Subject: [PATCH 21/37] fix: fields alteration related to subcontracting (cherry picked from commit 77590e60774154f7da00d39250eaa23b1e3ea997) --- .../doctype/subcontracting_receipt/subcontracting_receipt.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.json b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.json index 407d2700380..ad03171f29a 100644 --- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.json +++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.json @@ -639,7 +639,7 @@ { "fieldname": "supplier_delivery_note", "fieldtype": "Data", - "label": "Supplier Delivery Note" + "label": "Job Worker Delivery Note" }, { "fieldname": "raw_materials_consumed_section", From 0c2e9480cb8e4f42a2d90fd6b51e0479be20bb14 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Fri, 26 Jul 2024 08:00:13 +0530 Subject: [PATCH 22/37] fix: incorrect cost_center on AR/AP report (cherry picked from commit 3e19041fa3ede2e151cd137c8e94bb49c6efe621) --- .../accounts/report/accounts_receivable/accounts_receivable.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py index 30775c7fa66..f8511d2f497 100644 --- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py +++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py @@ -139,6 +139,7 @@ class ReceivablePayableReport: paid_in_account_currency=0.0, credit_note_in_account_currency=0.0, outstanding_in_account_currency=0.0, + cost_center=ple.cost_center, ) self.get_invoices(ple) @@ -253,7 +254,7 @@ class ReceivablePayableReport: row.paid -= amount row.paid_in_account_currency -= amount_in_account_currency - if ple.cost_center: + if not row.cost_center and ple.cost_center: row.cost_center = str(ple.cost_center) def update_sub_total_row(self, row, party): From 4b24f8bc044ad0ba9a5520d57df5be1d1e25ca84 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Fri, 26 Jul 2024 18:16:40 +0530 Subject: [PATCH 23/37] test: invoice cost center reported in AR/AP report (cherry picked from commit 9a0894fd65720443adc86c05d09c6fee279f4a03) --- .../test_accounts_receivable.py | 43 ++++++++++++++++++- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py index 5e2adc42d84..c4baa4e4842 100644 --- a/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py +++ b/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py @@ -53,11 +53,13 @@ class TestAccountsReceivable(AccountsTestMixin, FrappeTestCase): si = si.submit() return si - def create_payment_entry(self, docname): + def create_payment_entry(self, docname, do_not_submit=False): pe = get_payment_entry("Sales Invoice", docname, bank_account=self.cash, party_amount=40) pe.paid_from = self.debit_to pe.insert() - pe.submit() + if not do_not_submit: + pe.submit() + return pe def create_credit_note(self, docname, do_not_submit=False): credit_note = create_sales_invoice( @@ -984,3 +986,40 @@ class TestAccountsReceivable(AccountsTestMixin, FrappeTestCase): expected_data_after_payment, [row.invoice_grand_total, row.invoiced, row.paid, row.outstanding], ) + + def test_cost_center_on_report_output(self): + filters = { + "company": self.company, + "report_date": today(), + "range1": 30, + "range2": 60, + "range3": 90, + "range4": 120, + } + + # check invoice grand total and invoiced column's value for 3 payment terms + si = self.create_sales_invoice(no_payment_schedule=True, do_not_submit=True) + si.cost_center = self.cost_center + si.save().submit() + + new_cc = frappe.get_doc( + { + "doctype": "Cost Center", + "cost_center_name": "East Wing", + "parent_cost_center": self.company + " - " + self.company_abbr, + "company": self.company, + } + ) + new_cc.save() + + # check invoice grand total, invoiced, paid and outstanding column's value after payment + pe = self.create_payment_entry(si.name, do_not_submit=True) + pe.cost_center = new_cc.name + pe.save().submit() + report = execute(filters) + + expected_data_after_payment = [si.name, si.cost_center, 60] + + self.assertEqual(len(report[1]), 1) + row = report[1][0] + self.assertEqual(expected_data_after_payment, [row.voucher_no, row.cost_center, row.outstanding]) From ac2ef218968e3855e015cc20cb2225f6d1f32c0c Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Sat, 27 Jul 2024 10:41:07 +0530 Subject: [PATCH 24/37] fix: dynamic condition in the pricing rule not working (backport #42467) (#42495) fix: dynamic condition in the pricing rule not working (#42467) (cherry picked from commit 0e817f42ef96632df164fac6e5b2949a0d18e9f5) Co-authored-by: rohitwaghchaure --- erpnext/public/js/controllers/transaction.js | 2 +- erpnext/stock/get_item_details.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index dfb0ded8139..3e9a286b4cf 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -1796,7 +1796,7 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe me.in_apply_price_list = true; return this.frm.call({ method: "erpnext.stock.get_item_details.apply_price_list", - args: { args: args }, + args: { args: args, doc: me.frm.doc }, callback: function(r) { if (!r.exc) { frappe.run_serially([ diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index a7aa7dce452..fe4d3b8602c 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -1189,7 +1189,7 @@ def get_batch_qty(batch_no, warehouse, item_code): @frappe.whitelist() -def apply_price_list(args, as_doc=False): +def apply_price_list(args, as_doc=False, doc=None): """Apply pricelist on a document-like dict object and return as {'parent': dict, 'children': list} @@ -1228,7 +1228,7 @@ def apply_price_list(args, as_doc=False): for item in item_list: args_copy = frappe._dict(args.copy()) args_copy.update(item) - item_details = apply_price_list_on_item(args_copy) + item_details = apply_price_list_on_item(args_copy, doc=doc) children.append(item_details) if as_doc: @@ -1246,10 +1246,10 @@ def apply_price_list(args, as_doc=False): return {"parent": parent, "children": children} -def apply_price_list_on_item(args): +def apply_price_list_on_item(args, doc=None): item_doc = frappe.db.get_value("Item", args.item_code, ["name", "variant_of"], as_dict=1) item_details = get_price_list_rate(args, item_doc) - item_details.update(get_pricing_rule_for_item(args)) + item_details.update(get_pricing_rule_for_item(args, doc=doc)) return item_details From edf1fcb7429eab23ca54c8c0c5c1d600e1d0dcd5 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Mon, 29 Jul 2024 09:50:02 +0530 Subject: [PATCH 25/37] fix: performance issue for the report Purchase Order Analysis report (backport #42503) (#42507) fix: performance issue for the report Purchase Order Analysis report (#42503) (cherry picked from commit cb522f8f22df6688438994d0d2c47f32984aebd6) Co-authored-by: rohitwaghchaure --- .../purchase_order_analysis/purchase_order_analysis.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/erpnext/buying/report/purchase_order_analysis/purchase_order_analysis.py b/erpnext/buying/report/purchase_order_analysis/purchase_order_analysis.py index 7df96064a0c..da1c70d3179 100644 --- a/erpnext/buying/report/purchase_order_analysis/purchase_order_analysis.py +++ b/erpnext/buying/report/purchase_order_analysis/purchase_order_analysis.py @@ -39,16 +39,14 @@ def validate_filters(filters): def get_data(filters): po = frappe.qb.DocType("Purchase Order") po_item = frappe.qb.DocType("Purchase Order Item") - pi = frappe.qb.DocType("Purchase Invoice") pi_item = frappe.qb.DocType("Purchase Invoice Item") query = ( frappe.qb.from_(po) - .from_(po_item) + .inner_join(po_item) + .on(po_item.parent == po.name) .left_join(pi_item) - .on(pi_item.po_detail == po_item.name & pi_item.docstatus == 1) - .left_join(pi) - .on(pi.name == pi_item.parent & pi.docstatus == 1) + .on((pi_item.po_detail == po_item.name) & (pi_item.docstatus == 1)) .select( po.transaction_date.as_("date"), po_item.schedule_date.as_("required_date"), From f25b38caf58ff5cb469c3c71a080a339c5eaef06 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Mon, 29 Jul 2024 10:21:11 +0530 Subject: [PATCH 26/37] fix: builtins.KeyError: ('ABC', 'Store - CP') (backport #42505) (#42509) fix: builtins.KeyError: ('ABC', 'Store - CP') (#42505) (cherry picked from commit 25dac1f18e5ae3436484830c56ea479c7208abc1) Co-authored-by: rohitwaghchaure --- erpnext/stock/stock_ledger.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py index 8373ea14dec..ac78f1a7f68 100644 --- a/erpnext/stock/stock_ledger.py +++ b/erpnext/stock/stock_ledger.py @@ -275,7 +275,9 @@ def repost_future_sle( ) affected_transactions.update(obj.affected_transactions) - distinct_item_warehouses[(args[i].get("item_code"), args[i].get("warehouse"))].reposting_status = True + key = (args[i].get("item_code"), args[i].get("warehouse")) + if distinct_item_warehouses.get(key): + distinct_item_warehouses[key].reposting_status = True if obj.new_items_found: for _item_wh, data in distinct_item_warehouses.items(): From fc0db1941a5915f7d2d3c9b79e27d7fce8e30b35 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Mon, 29 Jul 2024 15:44:01 +0530 Subject: [PATCH 27/37] fix: Warranty Expiry Date not set in the serial number (backport #42513) (#42515) fix: Warranty Expiry Date not set in the serial number (#42513) * fix: Warranty Expiry Date not set in the serial number * chore: fix linters issue (cherry picked from commit 8eff168d76bca06d181723e7208657eec9575994) Co-authored-by: rohitwaghchaure --- .../delivery_note/test_delivery_note.py | 36 ++++++++++++++++++- .../serial_and_batch_bundle.py | 26 -------------- erpnext/stock/serial_batch_bundle.py | 19 ++++++++-- 3 files changed, 51 insertions(+), 30 deletions(-) diff --git a/erpnext/stock/doctype/delivery_note/test_delivery_note.py b/erpnext/stock/doctype/delivery_note/test_delivery_note.py index f27db868a07..cfe550f2f27 100644 --- a/erpnext/stock/doctype/delivery_note/test_delivery_note.py +++ b/erpnext/stock/doctype/delivery_note/test_delivery_note.py @@ -6,7 +6,7 @@ import json import frappe from frappe.tests.utils import FrappeTestCase -from frappe.utils import add_days, cstr, flt, nowdate, nowtime, today +from frappe.utils import add_days, cstr, flt, getdate, nowdate, nowtime, today from erpnext.accounts.doctype.account.test_account import get_inventory_account from erpnext.accounts.utils import get_balance_on @@ -2005,6 +2005,40 @@ class TestDeliveryNote(FrappeTestCase): self.assertRaises(frappe.ValidationError, dn5.submit) + def test_warranty_expiry_date_for_serial_item(self): + item_code = make_item( + "Test Warranty Expiry Date Item", + properties={ + "has_serial_no": 1, + "serial_no_series": "TWE.#####", + "is_stock_item": 1, + "warranty_period": 100, + }, + ).name + + se = make_stock_entry( + item_code=item_code, + target="_Test Warehouse - _TC", + qty=2, + basic_rate=50, + posting_date=nowdate(), + ) + + serial_nos = get_serial_nos_from_bundle(se.items[0].serial_and_batch_bundle) + create_delivery_note( + item_code=item_code, + qty=2, + rate=300, + use_serial_batch_fields=0, + serial_no=serial_nos, + ) + + for row in serial_nos: + sn = frappe.get_doc("Serial No", row) + self.assertEqual(getdate(sn.warranty_expiry_date), getdate(add_days(nowdate(), 100))) + self.assertEqual(sn.status, "Delivered") + self.assertEqual(sn.warranty_period, 100) + def create_delivery_note(**args): dn = frappe.new_doc("Delivery Note") 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 615d98a448d..95dd735ec57 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 @@ -393,32 +393,6 @@ class SerialandBatchBundle(Document): self.calculate_qty_and_amount(save=True) self.validate_quantity(row, qty_field=qty_field) - self.set_warranty_expiry_date() - - def set_warranty_expiry_date(self): - if self.type_of_transaction != "Outward": - return - - if not (self.docstatus == 1 and self.voucher_type == "Delivery Note" and self.has_serial_no): - return - - warranty_period = frappe.get_cached_value("Item", self.item_code, "warranty_period") - - if not warranty_period: - return - - warranty_expiry_date = add_days(self.posting_date, cint(warranty_period)) - - serial_nos = self.get_serial_nos() - if not serial_nos: - return - - sn_table = frappe.qb.DocType("Serial No") - ( - frappe.qb.update(sn_table) - .set(sn_table.warranty_expiry_date, warranty_expiry_date) - .where(sn_table.name.isin(serial_nos)) - ).run() def validate_voucher_no(self): if not (self.voucher_type and self.voucher_no): diff --git a/erpnext/stock/serial_batch_bundle.py b/erpnext/stock/serial_batch_bundle.py index 4880adab921..aafa04ae52c 100644 --- a/erpnext/stock/serial_batch_bundle.py +++ b/erpnext/stock/serial_batch_bundle.py @@ -4,7 +4,7 @@ import frappe from frappe import _, bold from frappe.model.naming import make_autoname from frappe.query_builder.functions import CombineDatetime, Sum, Timestamp -from frappe.utils import cint, cstr, flt, get_link_to_form, now, nowtime, today +from frappe.utils import add_days, cint, cstr, flt, get_link_to_form, now, nowtime, today from pypika import Order from erpnext.stock.deprecated_serial_batch import ( @@ -338,7 +338,8 @@ class SerialBatchBundle: status = "Delivered" sn_table = frappe.qb.DocType("Serial No") - ( + + query = ( frappe.qb.update(sn_table) .set(sn_table.warehouse, warehouse) .set( @@ -351,7 +352,19 @@ class SerialBatchBundle: ) .set(sn_table.company, self.sle.company) .where(sn_table.name.isin(serial_nos)) - ).run() + ) + + if status == "Delivered": + warranty_period = frappe.get_cached_value("Item", self.sle.item_code, "warranty_period") + if warranty_period: + warranty_expiry_date = add_days(self.sle.posting_date, cint(warranty_period)) + query = query.set(sn_table.warranty_expiry_date, warranty_expiry_date) + query = query.set(sn_table.warranty_period, warranty_period) + else: + query = query.set(sn_table.warranty_expiry_date, None) + query = query.set(sn_table.warranty_period, 0) + + query.run() def set_batch_no_in_serial_nos(self): entries = frappe.get_all( From 1019f6d1584923783a6c72073533f2186a65599c Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Tue, 30 Jul 2024 11:53:47 +0530 Subject: [PATCH 28/37] chore: button name should reflect what it creates (cherry picked from commit 0b6e7f83cd6bb83638f58b82d10a3d289973c453) --- erpnext/accounts/doctype/payment_order/payment_order.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/payment_order/payment_order.js b/erpnext/accounts/doctype/payment_order/payment_order.js index 4033fc08233..7311ed9f8be 100644 --- a/erpnext/accounts/doctype/payment_order/payment_order.js +++ b/erpnext/accounts/doctype/payment_order/payment_order.js @@ -36,7 +36,7 @@ frappe.ui.form.on("Payment Order", { // payment Entry if (frm.doc.docstatus === 1 && frm.doc.payment_order_type === "Payment Request") { - frm.add_custom_button(__("Create Payment Entries"), function () { + frm.add_custom_button(__("Create Journal Entries"), function () { frm.trigger("make_payment_records"); }); } From 596110dd65610de8f250f545780ce98e33485afd Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Fri, 26 Jul 2024 06:47:17 +0530 Subject: [PATCH 29/37] refactor: checkbox to control Payment Request creation (cherry picked from commit ce81fd9ba683da638644503e1bfe9794036a9f54) # Conflicts: # erpnext/accounts/doctype/payment_request/payment_request.py --- .../accounts_settings/accounts_settings.json | 18 ++++++++++++++++-- .../accounts_settings/accounts_settings.py | 1 + .../doctype/payment_request/payment_request.py | 5 +++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json index 31991648158..e9b383776f3 100644 --- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json +++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json @@ -73,7 +73,9 @@ "remarks_section", "general_ledger_remarks_length", "column_break_lvjk", - "receivable_payable_remarks_length" + "receivable_payable_remarks_length", + "payment_request_settings", + "create_pr_in_draft_status" ], "fields": [ { @@ -475,6 +477,18 @@ "fieldname": "calculate_depr_using_total_days", "fieldtype": "Check", "label": "Calculate daily depreciation using total days in depreciation period" + }, + { + "description": "Payment Request created from Sales Order or Purchase Order will be in Draft status. When disabled document will be in unsaved state.", + "fieldname": "payment_request_settings", + "fieldtype": "Tab Break", + "label": "Payment Request" + }, + { + "default": "1", + "fieldname": "create_pr_in_draft_status", + "fieldtype": "Check", + "label": "Create in Draft Status" } ], "icon": "icon-cog", @@ -482,7 +496,7 @@ "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2024-07-12 00:24:20.957726", + "modified": "2024-07-26 06:48:52.714630", "modified_by": "Administrator", "module": "Accounts", "name": "Accounts Settings", diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.py b/erpnext/accounts/doctype/accounts_settings/accounts_settings.py index 93ff1e207c9..608b3a96f2f 100644 --- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.py +++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.py @@ -35,6 +35,7 @@ class AccountsSettings(Document): book_tax_discount_loss: DF.Check calculate_depr_using_total_days: DF.Check check_supplier_invoice_uniqueness: DF.Check + create_pr_in_draft_status: DF.Check credit_controller: DF.Link | None delete_linked_ledger_entries: DF.Check determine_address_tax_category_from: DF.Literal["Billing Address", "Shipping Address"] diff --git a/erpnext/accounts/doctype/payment_request/payment_request.py b/erpnext/accounts/doctype/payment_request/payment_request.py index 03435a26011..1add678dd1d 100644 --- a/erpnext/accounts/doctype/payment_request/payment_request.py +++ b/erpnext/accounts/doctype/payment_request/payment_request.py @@ -497,10 +497,15 @@ def make_payment_request(**args): for dimension in get_accounting_dimensions(): pr.update({dimension: ref_doc.get(dimension)}) +<<<<<<< HEAD if args.order_type == "Shopping Cart" or args.mute_email: pr.flags.mute_email = True pr.insert(ignore_permissions=True) +======= + if frappe.db.get_single_value("Accounts Settings", "create_pr_in_draft_status", cache=True): + pr.insert(ignore_permissions=True) +>>>>>>> ce81fd9ba6 (refactor: checkbox to control Payment Request creation) if args.submit_doc: pr.submit() From f03e58f5f621835aa6150568994cc30ef22f5c16 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Tue, 30 Jul 2024 13:39:14 +0530 Subject: [PATCH 30/37] chore: resolve conflict --- erpnext/accounts/doctype/payment_request/payment_request.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/erpnext/accounts/doctype/payment_request/payment_request.py b/erpnext/accounts/doctype/payment_request/payment_request.py index 1add678dd1d..48bb6f2ae86 100644 --- a/erpnext/accounts/doctype/payment_request/payment_request.py +++ b/erpnext/accounts/doctype/payment_request/payment_request.py @@ -497,15 +497,11 @@ def make_payment_request(**args): for dimension in get_accounting_dimensions(): pr.update({dimension: ref_doc.get(dimension)}) -<<<<<<< HEAD if args.order_type == "Shopping Cart" or args.mute_email: pr.flags.mute_email = True - pr.insert(ignore_permissions=True) -======= if frappe.db.get_single_value("Accounts Settings", "create_pr_in_draft_status", cache=True): pr.insert(ignore_permissions=True) ->>>>>>> ce81fd9ba6 (refactor: checkbox to control Payment Request creation) if args.submit_doc: pr.submit() From 5fa185d480000ead606e8c0dcfe93c303b6b2f82 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Tue, 30 Jul 2024 14:52:23 +0530 Subject: [PATCH 31/37] fix: price_list_currency not found error (backport #42534) (#42539) fix: price_list_currency not found error (#42534) (cherry picked from commit 23fed831a078055d66b78ef1531ada329bc052d6) Co-authored-by: rohitwaghchaure --- erpnext/public/js/controllers/transaction.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index 3e9a286b4cf..4615039fbb5 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -1781,6 +1781,12 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe apply_price_list(item, reset_plc_conversion) { // We need to reset plc_conversion_rate sometimes because the call to // `erpnext.stock.get_item_details.apply_price_list` is sensitive to its value + + + if (this.frm.doc.doctype === "Material Request") { + return; + } + if (!reset_plc_conversion) { this.frm.set_value("plc_conversion_rate", ""); } From 826577c88f12dcb4b25a5a051c97b9158f4a6632 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Tue, 30 Jul 2024 14:53:03 +0530 Subject: [PATCH 32/37] fix: warehouse filter in Product Bundle Balance (backport #42532) (#42537) fix: warehouse filter in Product Bundle Balance (#42532) (cherry picked from commit 0ecfa709d8324e15d2f45a68b9506e7520c4d1e5) Co-authored-by: rohitwaghchaure --- .../product_bundle_balance/product_bundle_balance.js | 8 ++++++++ .../product_bundle_balance/product_bundle_balance.py | 5 ++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/erpnext/stock/report/product_bundle_balance/product_bundle_balance.js b/erpnext/stock/report/product_bundle_balance/product_bundle_balance.js index 5cef5c70341..f8779c64e2d 100644 --- a/erpnext/stock/report/product_bundle_balance/product_bundle_balance.js +++ b/erpnext/stock/report/product_bundle_balance/product_bundle_balance.js @@ -3,6 +3,14 @@ frappe.query_reports["Product Bundle Balance"] = { filters: [ + { + fieldname: "company", + label: __("Company"), + fieldtype: "Link", + options: "Company", + default: frappe.defaults.get_user_default("Company"), + reqd: 1, + }, { fieldname: "date", label: __("Date"), diff --git a/erpnext/stock/report/product_bundle_balance/product_bundle_balance.py b/erpnext/stock/report/product_bundle_balance/product_bundle_balance.py index dd79e7fcaf5..10f8650b525 100644 --- a/erpnext/stock/report/product_bundle_balance/product_bundle_balance.py +++ b/erpnext/stock/report/product_bundle_balance/product_bundle_balance.py @@ -224,6 +224,9 @@ def get_stock_ledger_entries(filters, items): .where((sle2.name.isnull()) & (sle.docstatus < 2) & (sle.item_code.isin(items))) ) + if filters.get("company"): + query = query.where(sle.company == filters.get("company")) + if date := filters.get("date"): query = query.where(sle.posting_date <= date) else: @@ -237,7 +240,7 @@ def get_stock_ledger_entries(filters, items): if warehouse_details: wh = frappe.qb.DocType("Warehouse") query = query.where( - ExistsCriterion( + sle.warehouse.isin( frappe.qb.from_(wh) .select(wh.name) .where((wh.lft >= warehouse_details.lft) & (wh.rgt <= warehouse_details.rgt)) From b7d70ac9286aad917bc73a903dc2557c59c8c64f Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Tue, 30 Jul 2024 14:53:42 +0530 Subject: [PATCH 33/37] fix: purchase return from rejected warehouse (backport #42531) (#42535) fix: purchase return from rejected warehouse (#42531) (cherry picked from commit c5d68333c99acf57a714bb987e032fe2e627e521) Co-authored-by: rohitwaghchaure --- erpnext/controllers/sales_and_purchase_return.py | 7 +++++++ .../doctype/purchase_receipt/test_purchase_receipt.py | 10 ++++++++++ 2 files changed, 17 insertions(+) diff --git a/erpnext/controllers/sales_and_purchase_return.py b/erpnext/controllers/sales_and_purchase_return.py index 76d04c04d6a..a848f6263fb 100644 --- a/erpnext/controllers/sales_and_purchase_return.py +++ b/erpnext/controllers/sales_and_purchase_return.py @@ -640,6 +640,12 @@ def make_return_doc(doctype: str, source_name: str, target_doc=None, return_agai def update_terms(source_doc, target_doc, source_parent): target_doc.payment_amount = -source_doc.payment_amount + def item_condition(doc): + if return_against_rejected_qty: + return doc.rejected_qty + + return doc.qty + doclist = get_mapped_doc( doctype, source_name, @@ -654,6 +660,7 @@ def make_return_doc(doctype: str, source_name: str, target_doc=None, return_agai "doctype": doctype + " Item", "field_map": {"serial_no": "serial_no", "batch_no": "batch_no", "bom": "bom"}, "postprocess": update_item, + "condition": item_condition, }, "Payment Schedule": {"doctype": "Payment Schedule", "postprocess": update_terms}, }, diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py index 736ced72f33..416a2db43c4 100644 --- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py @@ -1886,9 +1886,19 @@ class TestPurchaseReceipt(FrappeTestCase): rate=100, rejected_qty=2, rejected_warehouse=rejected_warehouse, + do_not_save=1, ) + pr.append( + "items", + {"item_code": item_code, "qty": 2, "rate": 100, "warehouse": warehouse, "rejected_qty": 0}, + ) + pr.save() + pr.submit() + self.assertEqual(len(pr.items), 2) + pr_return = make_purchase_return_against_rejected_warehouse(pr.name) + self.assertEqual(len(pr_return.items), 1) self.assertEqual(pr_return.items[0].warehouse, rejected_warehouse) self.assertEqual(pr_return.items[0].qty, 2.0 * -1) self.assertEqual(pr_return.items[0].rejected_qty, 0.0) From 61280e607269bc4991ec863fe166895e55468afd Mon Sep 17 00:00:00 2001 From: rohitwaghchaure Date: Tue, 30 Jul 2024 15:13:19 +0530 Subject: [PATCH 34/37] fix: not able to save BOM Creator (#42540) --- .../doctype/bom_creator/bom_creator.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/erpnext/manufacturing/doctype/bom_creator/bom_creator.py b/erpnext/manufacturing/doctype/bom_creator/bom_creator.py index 71b23ba3202..4062235a32e 100644 --- a/erpnext/manufacturing/doctype/bom_creator/bom_creator.py +++ b/erpnext/manufacturing/doctype/bom_creator/bom_creator.py @@ -365,6 +365,12 @@ def get_children(doctype=None, parent=None, **kwargs): return frappe.get_all("BOM Creator Item", fields=fields, filters=query_filters, order_by="idx") +def get_parent_row_no(doc, name): + for row in doc.items: + if row.name == name: + return row.idx + + @frappe.whitelist() def add_item(**kwargs): if isinstance(kwargs, str): @@ -375,6 +381,11 @@ def add_item(**kwargs): doc = frappe.get_doc("BOM Creator", kwargs.parent) item_info = get_item_details(kwargs.item_code) + + parent_row_no = "" + if kwargs.fg_reference_id and doc.name != kwargs.fg_reference_id: + parent_row_no = get_parent_row_no(doc, kwargs.fg_reference_id) + kwargs.update( { "uom": item_info.stock_uom, @@ -383,6 +394,9 @@ def add_item(**kwargs): } ) + if parent_row_no: + kwargs.update({"parent_row_no": parent_row_no}) + doc.append("items", kwargs) doc.save() From 6840f6cb26054c89b8277bbbd4a06a96b39dcd68 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Tue, 30 Jul 2024 17:01:43 +0530 Subject: [PATCH 35/37] perf: huge number of serial no creation (backport #42522) (#42544) perf: huge number of serial no creation (#42522) (cherry picked from commit 1c7f7c8d1a25733ca230cdab433b9a559b7360f9) Co-authored-by: rohitwaghchaure --- .../serial_and_batch_bundle.py | 12 ++++++++++-- .../doctype/stock_settings/stock_settings.json | 3 +-- erpnext/stock/serial_batch_bundle.py | 17 ++++++++++++++++- 3 files changed, 27 insertions(+), 5 deletions(-) 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 95dd735ec57..ef4d475dca4 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 @@ -92,8 +92,10 @@ class SerialandBatchBundle(Document): if self.type_of_transaction == "Maintenance": return - self.validate_serial_nos_duplicate() - self.check_future_entries_exists() + if not self.flags.ignore_validate_serial_batch or frappe.flags.in_test: + self.validate_serial_nos_duplicate() + self.check_future_entries_exists() + self.set_is_outward() self.calculate_total_qty() self.set_warehouse() @@ -340,6 +342,9 @@ class SerialandBatchBundle(Document): rate = frappe.db.get_value(child_table, self.voucher_detail_no, valuation_field) for d in self.entries: + if (d.incoming_rate == rate) and d.qty and d.stock_value_difference: + continue + d.incoming_rate = flt(rate, precision) if d.qty: d.stock_value_difference = flt(d.qty) * flt(d.incoming_rate) @@ -841,6 +846,9 @@ class SerialandBatchBundle(Document): self.validate_serial_nos_inventory() def set_purchase_document_no(self): + if self.flags.ignore_validate_serial_batch: + return + if not self.has_serial_no: return diff --git a/erpnext/stock/doctype/stock_settings/stock_settings.json b/erpnext/stock/doctype/stock_settings/stock_settings.json index 431fdf681ff..11c4b1c14f7 100644 --- a/erpnext/stock/doctype/stock_settings/stock_settings.json +++ b/erpnext/stock/doctype/stock_settings/stock_settings.json @@ -434,7 +434,6 @@ }, { "default": "1", - "depends_on": "use_serial_batch_fields", "description": "If enabled, do not update serial / batch values in the stock transactions on creation of auto Serial \n / Batch Bundle. ", "fieldname": "do_not_update_serial_batch_on_creation_of_auto_bundle", "fieldtype": "Check", @@ -460,7 +459,7 @@ "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2024-07-15 17:18:23.872161", + "modified": "2024-07-29 14:55:19.093508", "modified_by": "Administrator", "module": "Stock", "name": "Stock Settings", diff --git a/erpnext/stock/serial_batch_bundle.py b/erpnext/stock/serial_batch_bundle.py index aafa04ae52c..07e46312d3e 100644 --- a/erpnext/stock/serial_batch_bundle.py +++ b/erpnext/stock/serial_batch_bundle.py @@ -110,6 +110,7 @@ class SerialBatchBundle: "type_of_transaction": "Inward" if self.sle.actual_qty > 0 else "Outward", "company": self.company, "is_rejected": self.is_rejected_entry(), + "make_bundle_from_sle": 1, } ).make_serial_and_batch_bundle() @@ -160,12 +161,13 @@ class SerialBatchBundle: if msg: error_msg = ( - f"Serial and Batch Bundle not set for item {self.item_code} in warehouse {self.warehouse}." + f"Serial and Batch Bundle not set for item {self.item_code} in warehouse {self.warehouse}" + msg ) frappe.throw(_(error_msg)) def set_serial_and_batch_bundle(self, sn_doc): + self.sle.auto_created_serial_and_batch_bundle = 1 self.sle.db_set({"serial_and_batch_bundle": sn_doc.name, "auto_created_serial_and_batch_bundle": 1}) if sn_doc.is_rejected: @@ -324,6 +326,9 @@ class SerialBatchBundle: def set_warehouse_and_status_in_serial_nos(self): from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos as get_parsed_serial_nos + if self.sle.auto_created_serial_and_batch_bundle and self.sle.actual_qty > 0: + return + serial_nos = get_serial_nos(self.sle.serial_and_batch_bundle) if not self.sle.serial_and_batch_bundle and self.sle.serial_no: serial_nos = get_parsed_serial_nos(self.sle.serial_no) @@ -928,6 +933,10 @@ class SerialBatchCreation: if doc.voucher_no and frappe.get_cached_value(doc.voucher_type, doc.voucher_no, "docstatus") == 2: doc.voucher_no = "" + doc.flags.ignore_validate_serial_batch = False + if self.get("make_bundle_from_sle") and self.type_of_transaction == "Inward": + doc.flags.ignore_validate_serial_batch = True + doc.save() self.validate_qty(doc) @@ -1120,6 +1129,10 @@ class SerialBatchCreation: msg = f"Please set Serial No Series in the item {self.item_code} or create Serial and Batch Bundle manually." frappe.throw(_(msg)) + voucher_no = "" + if self.get("voucher_no"): + voucher_no = self.get("voucher_no") + for _i in range(abs(cint(self.actual_qty))): serial_no = make_autoname(self.serial_no_series, "Serial No") sr_nos.append(serial_no) @@ -1137,6 +1150,7 @@ class SerialBatchCreation: self.item_name, self.description, "Active", + voucher_no, self.batch_no, ) ) @@ -1155,6 +1169,7 @@ class SerialBatchCreation: "item_name", "description", "status", + "purchase_document_no", "batch_no", ] From 9d2ef4d3e8430f358e80a8d171816ef807d4d84d Mon Sep 17 00:00:00 2001 From: Khushi Rawat <142375893+khushi8112@users.noreply.github.com> Date: Mon, 29 Jul 2024 23:50:57 +0530 Subject: [PATCH 36/37] fix: Adjust initial month's depreciation to end of depreciation period (cherry picked from commit cbb749a3a50f8c6511c8a7bed5916b246796a60a) --- erpnext/assets/doctype/asset/test_asset.py | 4 +- .../asset_depreciation_schedule.py | 38 +++++++++++-------- 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py index 742cc3eaa49..586385adb0d 100644 --- a/erpnext/assets/doctype/asset/test_asset.py +++ b/erpnext/assets/doctype/asset/test_asset.py @@ -740,7 +740,7 @@ class TestDepreciationMethods(AssetSetup): available_for_use_date="2030-06-06", is_existing_asset=1, opening_number_of_booked_depreciations=2, - opening_accumulated_depreciation=47095.89, + opening_accumulated_depreciation=47178.08, expected_value_after_useful_life=10000, depreciation_start_date="2032-12-31", total_number_of_depreciations=3, @@ -748,7 +748,7 @@ class TestDepreciationMethods(AssetSetup): ) self.assertEqual(asset.status, "Draft") - expected_schedules = [["2032-12-31", 42904.11, 90000.0]] + expected_schedules = [["2032-12-31", 30000.0, 77178.08], ["2033-06-06", 12821.92, 90000.0]] schedules = [ [cstr(d.schedule_date), flt(d.depreciation_amount, 2), d.accumulated_depreciation_amount] for d in get_depr_schedule(asset.name, "Draft") 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 c533a634a5b..02fcb8efb3d 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py @@ -552,9 +552,18 @@ def _check_is_pro_rata(asset_doc, row, wdv_or_dd_non_yearly=False): # if not existing asset, from_date = available_for_use_date # otherwise, if opening_number_of_booked_depreciations = 2, available_for_use_date = 01/01/2020 and frequency_of_depreciation = 12 # from_date = 01/01/2022 - from_date = _get_modified_available_for_use_date(asset_doc, row, wdv_or_dd_non_yearly=False) - days = date_diff(row.depreciation_start_date, from_date) + 1 - total_days = get_total_days(row.depreciation_start_date, row.frequency_of_depreciation) + if row.depreciation_method in ("Straight Line", "Manual"): + prev_depreciation_start_date = add_months( + row.depreciation_start_date, + (row.frequency_of_depreciation * -1) * asset_doc.opening_number_of_booked_depreciations, + ) + from_date = asset_doc.available_for_use_date + days = date_diff(prev_depreciation_start_date, from_date) + 1 + total_days = get_total_days(prev_depreciation_start_date, row.frequency_of_depreciation) + else: + from_date = _get_modified_available_for_use_date(asset_doc, row, wdv_or_dd_non_yearly=False) + days = date_diff(row.depreciation_start_date, from_date) + 1 + total_days = get_total_days(row.depreciation_start_date, row.frequency_of_depreciation) if days <= 0: frappe.throw( _( @@ -682,20 +691,15 @@ def get_straight_line_or_manual_depr_amount( # if the Depreciation Schedule is being prepared for the first time else: if row.daily_prorata_based: - amount = ( - flt(asset.gross_purchase_amount) - - flt(asset.opening_accumulated_depreciation) - - flt(row.expected_value_after_useful_life) - ) + amount = flt(asset.gross_purchase_amount) - flt(row.expected_value_after_useful_life) return get_daily_prorata_based_straight_line_depr( asset, row, schedule_idx, number_of_pending_depreciations, amount ) else: - return ( - flt(asset.gross_purchase_amount) - - flt(asset.opening_accumulated_depreciation) - - flt(row.expected_value_after_useful_life) - ) / flt(row.total_number_of_depreciations - asset.opening_number_of_booked_depreciations) + depreciation_amount = ( + flt(asset.gross_purchase_amount) - flt(row.expected_value_after_useful_life) + ) / flt(row.total_number_of_depreciations) + return depreciation_amount def get_daily_prorata_based_straight_line_depr( @@ -725,7 +729,11 @@ def get_daily_depr_amount(asset, row, schedule_idx, amount): ) ), add_days( - get_last_day(add_months(row.depreciation_start_date, -1 * row.frequency_of_depreciation)), + add_months( + row.depreciation_start_date, + (row.frequency_of_depreciation * (asset.opening_number_of_booked_depreciations + 1)) + * -1, + ), 1, ), ) @@ -904,7 +912,7 @@ def _get_daily_prorata_based_default_wdv_or_dd_depr_amount( def get_monthly_depr_amount(fb_row, schedule_idx, depreciable_value): - """ " + """ Returns monthly depreciation amount when year changes 1. Calculate per day depr based on new year 2. Calculate monthly amount based on new per day amount From 1390c86fc488e17d64fe6dc5b8bd22c03c08f9e7 Mon Sep 17 00:00:00 2001 From: Khushi Rawat <142375893+khushi8112@users.noreply.github.com> Date: Tue, 30 Jul 2024 01:28:52 +0530 Subject: [PATCH 37/37] fix(tests): added tests for usecase (cherry picked from commit f0768010d9bc256ca39f81b0b820b4362fe84926) --- .../test_asset_depreciation_schedule.py | 110 ++++++++++++++++++ 1 file changed, 110 insertions(+) diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/test_asset_depreciation_schedule.py b/erpnext/assets/doctype/asset_depreciation_schedule/test_asset_depreciation_schedule.py index 107d38057a2..c9fa0ba59da 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/test_asset_depreciation_schedule.py +++ b/erpnext/assets/doctype/asset_depreciation_schedule/test_asset_depreciation_schedule.py @@ -75,6 +75,116 @@ class TestAssetDepreciationSchedule(FrappeTestCase): ] self.assertEqual(schedules, expected_schedules) + def test_schedule_for_slm_for_existing_asset_daily_pro_rata_enabled(self): + frappe.db.set_single_value("Accounts Settings", "calculate_depr_using_total_days", 1) + asset = create_asset( + calculate_depreciation=1, + depreciation_method="Straight Line", + available_for_use_date="2023-10-10", + is_existing_asset=1, + opening_number_of_booked_depreciations=9, + opening_accumulated_depreciation=265, + depreciation_start_date="2024-07-31", + total_number_of_depreciations=24, + frequency_of_depreciation=1, + gross_purchase_amount=731, + daily_prorata_based=1, + ) + + expected_schedules = [ + ["2024-07-31", 31.0, 296.0], + ["2024-08-31", 31.0, 327.0], + ["2024-09-30", 30.0, 357.0], + ["2024-10-31", 31.0, 388.0], + ["2024-11-30", 30.0, 418.0], + ["2024-12-31", 31.0, 449.0], + ["2025-01-31", 31.0, 480.0], + ["2025-02-28", 28.0, 508.0], + ["2025-03-31", 31.0, 539.0], + ["2025-04-30", 30.0, 569.0], + ["2025-05-31", 31.0, 600.0], + ["2025-06-30", 30.0, 630.0], + ["2025-07-31", 31.0, 661.0], + ["2025-08-31", 31.0, 692.0], + ["2025-09-30", 30.0, 722.0], + ["2025-10-10", 9.0, 731.0], + ] + schedules = [ + [cstr(d.schedule_date), flt(d.depreciation_amount, 2), d.accumulated_depreciation_amount] + for d in get_depr_schedule(asset.name, "Draft") + ] + self.assertEqual(schedules, expected_schedules) + frappe.db.set_single_value("Accounts Settings", "calculate_depr_using_total_days", 0) + + def test_schedule_for_slm_for_existing_asset(self): + asset = create_asset( + calculate_depreciation=1, + depreciation_method="Straight Line", + available_for_use_date="2023-10-10", + is_existing_asset=1, + opening_number_of_booked_depreciations=9, + opening_accumulated_depreciation=265.30, + depreciation_start_date="2024-07-31", + total_number_of_depreciations=24, + frequency_of_depreciation=1, + gross_purchase_amount=731, + ) + + expected_schedules = [ + ["2024-07-31", 30.46, 295.76], + ["2024-08-31", 30.46, 326.22], + ["2024-09-30", 30.46, 356.68], + ["2024-10-31", 30.46, 387.14], + ["2024-11-30", 30.46, 417.6], + ["2024-12-31", 30.46, 448.06], + ["2025-01-31", 30.46, 478.52], + ["2025-02-28", 30.46, 508.98], + ["2025-03-31", 30.46, 539.44], + ["2025-04-30", 30.46, 569.9], + ["2025-05-31", 30.46, 600.36], + ["2025-06-30", 30.46, 630.82], + ["2025-07-31", 30.46, 661.28], + ["2025-08-31", 30.46, 691.74], + ["2025-09-30", 30.46, 722.2], + ["2025-10-10", 8.8, 731.0], + ] + schedules = [ + [cstr(d.schedule_date), flt(d.depreciation_amount, 2), d.accumulated_depreciation_amount] + for d in get_depr_schedule(asset.name, "Draft") + ] + self.assertEqual(schedules, expected_schedules) + + def test_schedule_sl_method_for_existing_asset_with_frequency_of_3_months(self): + asset = create_asset( + calculate_depreciation=1, + depreciation_method="Straight Line", + available_for_use_date="2023-11-01", + is_existing_asset=1, + opening_number_of_booked_depreciations=4, + opening_accumulated_depreciation=223.15, + depreciation_start_date="2024-12-31", + total_number_of_depreciations=12, + frequency_of_depreciation=3, + gross_purchase_amount=731, + ) + + expected_schedules = [ + ["2024-12-31", 60.92, 284.07], + ["2025-03-31", 60.92, 344.99], + ["2025-06-30", 60.92, 405.91], + ["2025-09-30", 60.92, 466.83], + ["2025-12-31", 60.92, 527.75], + ["2026-03-31", 60.92, 588.67], + ["2026-06-30", 60.92, 649.59], + ["2026-09-30", 60.92, 710.51], + ["2026-11-01", 20.49, 731.0], + ] + schedules = [ + [cstr(d.schedule_date), flt(d.depreciation_amount, 2), d.accumulated_depreciation_amount] + for d in get_depr_schedule(asset.name, "Draft") + ] + self.assertEqual(schedules, expected_schedules) + # Enable Checkbox to Calculate depreciation using total days in depreciation period def test_daily_prorata_based_depr_after_enabling_configuration(self): frappe.db.set_single_value("Accounts Settings", "calculate_depr_using_total_days", 1)