From ff5cad1cd617a23d6ffc9903f29d713a8db8d949 Mon Sep 17 00:00:00 2001 From: anandbaburajan Date: Thu, 15 Sep 2022 13:15:34 +0530 Subject: [PATCH 01/22] fix: calculate depreciation properly on asset sale entry and scrap entry --- .../doctype/sales_invoice/sales_invoice.py | 15 ++-- erpnext/assets/doctype/asset/depreciation.py | 89 ++++++++++++++++++- erpnext/controllers/accounts_controller.py | 83 ----------------- 3 files changed, 97 insertions(+), 90 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 608f0828fee..4207156187f 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -22,9 +22,12 @@ from erpnext.accounts.general_ledger import get_round_off_account_and_cost_cente from erpnext.accounts.party import get_due_date, get_party_account, get_party_details from erpnext.accounts.utils import get_account_currency from erpnext.assets.doctype.asset.depreciation import ( + depreciate_asset, get_disposal_account_and_cost_center, get_gl_entries_on_asset_disposal, get_gl_entries_on_asset_regain, + reset_depreciation_schedule, + reverse_depreciation_entry_made_after_disposal, ) from erpnext.controllers.accounts_controller import validate_account_head from erpnext.controllers.selling_controller import SellingController @@ -1086,18 +1089,20 @@ class SalesInvoice(SellingController): asset.db_set("disposal_date", None) if asset.calculate_depreciation: - self.reverse_depreciation_entry_made_after_disposal(asset) - self.reset_depreciation_schedule(asset) + posting_date = frappe.db.get_value("Sales Invoice", self.return_against, "posting_date") + reverse_depreciation_entry_made_after_disposal(asset, posting_date) + reset_depreciation_schedule(asset, self.posting_date) else: + if asset.calculate_depreciation: + depreciate_asset(asset, self.posting_date) + asset.reload() + fixed_asset_gl_entries = get_gl_entries_on_asset_disposal( asset, item.base_net_amount, item.finance_book ) asset.db_set("disposal_date", self.posting_date) - if asset.calculate_depreciation: - self.depreciate_asset(asset) - for gle in fixed_asset_gl_entries: gle["against"] = self.customer gl_entries.append(self.get_gl_dict(gle, item=item)) diff --git a/erpnext/assets/doctype/asset/depreciation.py b/erpnext/assets/doctype/asset/depreciation.py index 74386384c5d..0299e28c119 100644 --- a/erpnext/assets/doctype/asset/depreciation.py +++ b/erpnext/assets/doctype/asset/depreciation.py @@ -4,11 +4,12 @@ import frappe from frappe import _ -from frappe.utils import cint, flt, getdate, today +from frappe.utils import add_months, cint, flt, getdate, nowdate, today from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import ( get_checks_for_pl_and_bs_accounts, ) +from erpnext.accounts.doctype.journal_entry.journal_entry import make_reverse_journal_entry def post_depreciation_entries(date=None, commit=True): @@ -196,6 +197,11 @@ def scrap_asset(asset_name): _("Asset {0} cannot be scrapped, as it is already {1}").format(asset.name, asset.status) ) + date = today() + + depreciate_asset(asset, date) + asset.reload() + depreciation_series = frappe.get_cached_value( "Company", asset.company, "series_for_depreciation_entry" ) @@ -203,7 +209,7 @@ def scrap_asset(asset_name): je = frappe.new_doc("Journal Entry") je.voucher_type = "Journal Entry" je.naming_series = depreciation_series - je.posting_date = today() + je.posting_date = date je.company = asset.company je.remark = "Scrap Entry for asset {0}".format(asset_name) @@ -225,6 +231,9 @@ def scrap_asset(asset_name): def restore_asset(asset_name): asset = frappe.get_doc("Asset", asset_name) + reverse_depreciation_entry_made_after_disposal(asset, asset.disposal_date) + reset_depreciation_schedule(asset, asset.disposal_date) + je = asset.journal_entry_for_scrap asset.db_set("disposal_date", None) @@ -235,6 +244,82 @@ def restore_asset(asset_name): asset.set_status() +def depreciate_asset(asset, date): + asset.flags.ignore_validate_update_after_submit = True + asset.prepare_depreciation_data(date_of_disposal=date) + asset.save() + + make_depreciation_entry(asset.name, date) + + +def reset_depreciation_schedule(asset, date): + asset.flags.ignore_validate_update_after_submit = True + + # recreate original depreciation schedule of the asset + asset.prepare_depreciation_data(date_of_return=date) + + modify_depreciation_schedule_for_asset_repairs(asset) + asset.save() + + +def modify_depreciation_schedule_for_asset_repairs(asset): + asset_repairs = frappe.get_all( + "Asset Repair", filters={"asset": asset.name}, fields=["name", "increase_in_asset_life"] + ) + + for repair in asset_repairs: + if repair.increase_in_asset_life: + asset_repair = frappe.get_doc("Asset Repair", repair.name) + asset_repair.modify_depreciation_schedule() + asset.prepare_depreciation_data() + + +def reverse_depreciation_entry_made_after_disposal(asset, date): + row = -1 + finance_book = asset.get("schedules")[0].get("finance_book") + for schedule in asset.get("schedules"): + if schedule.finance_book != finance_book: + row = 0 + finance_book = schedule.finance_book + else: + row += 1 + + if schedule.schedule_date == date: + if not disposal_was_made_on_original_schedule_date( + asset, schedule, row, date + ) or disposal_happens_in_the_future(date): + + reverse_journal_entry = make_reverse_journal_entry(schedule.journal_entry) + reverse_journal_entry.posting_date = nowdate() + frappe.flags.is_reverse_depr_entry = True + reverse_journal_entry.submit() + + frappe.flags.is_reverse_depr_entry = False + asset.flags.ignore_validate_update_after_submit = True + schedule.journal_entry = None + asset.save() + + +# if the invoice had been posted on the date the depreciation was initially supposed to happen, the depreciation shouldn't be undone +def disposal_was_made_on_original_schedule_date(asset, schedule, row, posting_date_of_disposal): + for finance_book in asset.get("finance_books"): + if schedule.finance_book == finance_book.finance_book: + orginal_schedule_date = add_months( + finance_book.depreciation_start_date, row * cint(finance_book.frequency_of_depreciation) + ) + + if orginal_schedule_date == posting_date_of_disposal: + return True + return False + + +def disposal_happens_in_the_future(posting_date_of_disposal): + if posting_date_of_disposal > getdate(): + return True + + return False + + def get_gl_entries_on_asset_regain(asset, selling_amount=0, finance_book=None): ( fixed_asset_account, diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index 938de63f33a..e9d3c7afba1 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -38,7 +38,6 @@ from erpnext.accounts.party import ( validate_party_frozen_disabled, ) from erpnext.accounts.utils import get_account_currency, get_fiscal_years, validate_fiscal_year -from erpnext.assets.doctype.asset.depreciation import make_depreciation_entry from erpnext.buying.utils import update_last_purchase_rate from erpnext.controllers.print_settings import ( set_print_templates_for_item_table, @@ -1886,88 +1885,6 @@ class AccountsController(TransactionBase): _("Select finance book for the item {0} at row {1}").format(item.item_code, item.idx) ) - def depreciate_asset(self, asset): - asset.flags.ignore_validate_update_after_submit = True - asset.prepare_depreciation_data(date_of_disposal=self.posting_date) - asset.save() - - make_depreciation_entry(asset.name, self.posting_date) - - def reset_depreciation_schedule(self, asset): - asset.flags.ignore_validate_update_after_submit = True - - # recreate original depreciation schedule of the asset - asset.prepare_depreciation_data(date_of_return=self.posting_date) - - self.modify_depreciation_schedule_for_asset_repairs(asset) - asset.save() - - def modify_depreciation_schedule_for_asset_repairs(self, asset): - asset_repairs = frappe.get_all( - "Asset Repair", filters={"asset": asset.name}, fields=["name", "increase_in_asset_life"] - ) - - for repair in asset_repairs: - if repair.increase_in_asset_life: - asset_repair = frappe.get_doc("Asset Repair", repair.name) - asset_repair.modify_depreciation_schedule() - asset.prepare_depreciation_data() - - def reverse_depreciation_entry_made_after_disposal(self, asset): - from erpnext.accounts.doctype.journal_entry.journal_entry import make_reverse_journal_entry - - posting_date_of_original_disposal = self.get_posting_date_of_disposal_entry() - - row = -1 - finance_book = asset.get("schedules")[0].get("finance_book") - for schedule in asset.get("schedules"): - if schedule.finance_book != finance_book: - row = 0 - finance_book = schedule.finance_book - else: - row += 1 - - if schedule.schedule_date == posting_date_of_original_disposal: - if not self.disposal_was_made_on_original_schedule_date( - asset, schedule, row, posting_date_of_original_disposal - ) or self.disposal_happens_in_the_future(posting_date_of_original_disposal): - - reverse_journal_entry = make_reverse_journal_entry(schedule.journal_entry) - reverse_journal_entry.posting_date = nowdate() - frappe.flags.is_reverse_depr_entry = True - reverse_journal_entry.submit() - - frappe.flags.is_reverse_depr_entry = False - asset.flags.ignore_validate_update_after_submit = True - schedule.journal_entry = None - asset.save() - - def get_posting_date_of_disposal_entry(self): - if self.doctype == "Sales Invoice" and self.return_against: - return frappe.db.get_value("Sales Invoice", self.return_against, "posting_date") - else: - return self.posting_date - - # if the invoice had been posted on the date the depreciation was initially supposed to happen, the depreciation shouldn't be undone - def disposal_was_made_on_original_schedule_date( - self, asset, schedule, row, posting_date_of_disposal - ): - for finance_book in asset.get("finance_books"): - if schedule.finance_book == finance_book.finance_book: - orginal_schedule_date = add_months( - finance_book.depreciation_start_date, row * cint(finance_book.frequency_of_depreciation) - ) - - if orginal_schedule_date == posting_date_of_disposal: - return True - return False - - def disposal_happens_in_the_future(self, posting_date_of_disposal): - if posting_date_of_disposal > getdate(): - return True - - return False - @frappe.whitelist() def get_tax_rate(account_head): From 11ac20e5ee1f9ba00bbccd15388144dc4b4eea83 Mon Sep 17 00:00:00 2001 From: anandbaburajan Date: Thu, 15 Sep 2022 22:43:18 +0530 Subject: [PATCH 02/22] fix: asset tests --- erpnext/assets/doctype/asset/depreciation.py | 2 +- erpnext/assets/doctype/asset/test_asset.py | 52 ++++++++++++++------ 2 files changed, 39 insertions(+), 15 deletions(-) diff --git a/erpnext/assets/doctype/asset/depreciation.py b/erpnext/assets/doctype/asset/depreciation.py index 0299e28c119..9f378407f6e 100644 --- a/erpnext/assets/doctype/asset/depreciation.py +++ b/erpnext/assets/doctype/asset/depreciation.py @@ -220,7 +220,7 @@ def scrap_asset(asset_name): je.flags.ignore_permissions = True je.submit() - frappe.db.set_value("Asset", asset_name, "disposal_date", today()) + frappe.db.set_value("Asset", asset_name, "disposal_date", date) frappe.db.set_value("Asset", asset_name, "journal_entry_for_scrap", je.name) asset.set_status("Scrapped") diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py index e7af9bd5bc2..bdda509e91d 100644 --- a/erpnext/assets/doctype/asset/test_asset.py +++ b/erpnext/assets/doctype/asset/test_asset.py @@ -4,7 +4,16 @@ import unittest import frappe -from frappe.utils import add_days, add_months, cstr, flt, get_last_day, getdate, nowdate +from frappe.utils import ( + add_days, + add_months, + cstr, + flt, + get_first_day, + get_last_day, + getdate, + nowdate, +) from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice from erpnext.assets.doctype.asset.asset import make_sales_invoice, split_asset @@ -178,17 +187,20 @@ class TestAsset(AssetSetup): self.assertEqual(doc.items[0].is_fixed_asset, 1) def test_scrap_asset(self): + date = nowdate() + purchase_date = add_months(get_first_day(date), -2) + asset = create_asset( calculate_depreciation=1, - available_for_use_date="2020-01-01", - purchase_date="2020-01-01", + available_for_use_date=purchase_date, + purchase_date=purchase_date, expected_value_after_useful_life=10000, total_number_of_depreciations=10, frequency_of_depreciation=1, submit=1, ) - post_depreciation_entries(date=add_months("2020-01-01", 4)) + post_depreciation_entries(date=add_months(purchase_date, 2)) scrap_asset(asset.name) @@ -196,10 +208,15 @@ class TestAsset(AssetSetup): self.assertEqual(asset.status, "Scrapped") self.assertTrue(asset.journal_entry_for_scrap) + pro_rata_amount, _, _ = asset.get_pro_rata_amt( + asset.finance_books[0], 9000, add_months(get_last_day(purchase_date), 1), date + ) + pro_rata_amount = flt(pro_rata_amount, asset.precision("gross_purchase_amount")) + expected_gle = ( - ("_Test Accumulated Depreciations - _TC", 36000.0, 0.0), + ("_Test Accumulated Depreciations - _TC", 18000.0 + pro_rata_amount, 0.0), ("_Test Fixed Asset - _TC", 0.0, 100000.0), - ("_Test Gain/Loss on Asset Disposal - _TC", 64000.0, 0.0), + ("_Test Gain/Loss on Asset Disposal - _TC", 82000.0 - pro_rata_amount, 0.0), ) gle = frappe.db.sql( @@ -217,18 +234,20 @@ class TestAsset(AssetSetup): self.assertEqual(asset.status, "Partially Depreciated") def test_gle_made_by_asset_sale(self): + date = nowdate() + purchase_date = add_months(get_first_day(date), -2) + asset = create_asset( calculate_depreciation=1, - available_for_use_date="2020-06-06", - purchase_date="2020-01-01", + available_for_use_date=purchase_date, + purchase_date=purchase_date, expected_value_after_useful_life=10000, - total_number_of_depreciations=3, - frequency_of_depreciation=10, - depreciation_start_date="2020-12-31", + total_number_of_depreciations=10, + frequency_of_depreciation=1, submit=1, ) - post_depreciation_entries(date="2021-01-01") + post_depreciation_entries(date=add_months(purchase_date, 2)) si = make_sales_invoice(asset=asset.name, item_code="Macbook Pro", company="_Test Company") si.customer = "_Test Customer" @@ -239,10 +258,15 @@ class TestAsset(AssetSetup): self.assertEqual(frappe.db.get_value("Asset", asset.name, "status"), "Sold") + pro_rata_amount, _, _ = asset.get_pro_rata_amt( + asset.finance_books[0], 9000, add_months(get_last_day(purchase_date), 1), date + ) + pro_rata_amount = flt(pro_rata_amount, asset.precision("gross_purchase_amount")) + expected_gle = ( - ("_Test Accumulated Depreciations - _TC", 20490.2, 0.0), + ("_Test Accumulated Depreciations - _TC", 18000.0 + pro_rata_amount, 0.0), ("_Test Fixed Asset - _TC", 0.0, 100000.0), - ("_Test Gain/Loss on Asset Disposal - _TC", 54509.8, 0.0), + ("_Test Gain/Loss on Asset Disposal - _TC", 57000.0 - pro_rata_amount, 0.0), ("Debtors - _TC", 25000.0, 0.0), ) From 5a8b28c1943d24b7aedf7b96c57fe93d2b5ea5f6 Mon Sep 17 00:00:00 2001 From: anandbaburajan Date: Thu, 15 Sep 2022 22:52:25 +0530 Subject: [PATCH 03/22] fix: refactor asset capitilization --- .../doctype/asset_capitalization/asset_capitalization.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py index 2e6f0ad7b02..30ff0601e4e 100644 --- a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py +++ b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py @@ -12,8 +12,11 @@ from six import string_types import erpnext from erpnext.assets.doctype.asset.depreciation import ( + depreciate_asset, get_gl_entries_on_asset_disposal, get_value_after_depreciation_on_disposal_date, + reset_depreciation_schedule, + reverse_depreciation_entry_made_after_disposal, ) from erpnext.assets.doctype.asset_category.asset_category import get_asset_category_account from erpnext.assets.doctype.asset_value_adjustment.asset_value_adjustment import ( @@ -424,7 +427,7 @@ class AssetCapitalization(StockController): asset = self.get_asset(item) if asset.calculate_depreciation: - self.depreciate_asset(asset) + depreciate_asset(asset, self.posting_date) asset.reload() fixed_asset_gl_entries = get_gl_entries_on_asset_disposal( @@ -516,8 +519,8 @@ class AssetCapitalization(StockController): self.set_consumed_asset_status(asset) if asset.calculate_depreciation: - self.reverse_depreciation_entry_made_after_disposal(asset) - self.reset_depreciation_schedule(asset) + reverse_depreciation_entry_made_after_disposal(asset, self.posting_date) + reset_depreciation_schedule(asset, self.posting_date) def get_asset(self, item): asset = frappe.get_doc("Asset", item.asset) From 43a3400221118cb6ad86c6ef15e201d07bc1941e Mon Sep 17 00:00:00 2001 From: anandbaburajan Date: Thu, 15 Sep 2022 23:25:04 +0530 Subject: [PATCH 04/22] fix: fix restore asset value after depreciation --- erpnext/assets/doctype/asset/depreciation.py | 9 ++++++++ erpnext/assets/doctype/asset/test_asset.py | 24 +++++++++++++++++--- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/erpnext/assets/doctype/asset/depreciation.py b/erpnext/assets/doctype/asset/depreciation.py index 9f378407f6e..e4765634c8d 100644 --- a/erpnext/assets/doctype/asset/depreciation.py +++ b/erpnext/assets/doctype/asset/depreciation.py @@ -297,9 +297,18 @@ def reverse_depreciation_entry_made_after_disposal(asset, date): frappe.flags.is_reverse_depr_entry = False asset.flags.ignore_validate_update_after_submit = True schedule.journal_entry = None + depreciation_amount = get_depreciation_amount_in_je(reverse_journal_entry) + asset.finance_books[0].value_after_depreciation += depreciation_amount asset.save() +def get_depreciation_amount_in_je(journal_entry): + if journal_entry.accounts[0].debit_in_account_currency: + return journal_entry.accounts[0].debit_in_account_currency + else: + return journal_entry.accounts[0].credit_in_account_currency + + # if the invoice had been posted on the date the depreciation was initially supposed to happen, the depreciation shouldn't be undone def disposal_was_made_on_original_schedule_date(asset, schedule, row, posting_date_of_disposal): for finance_book in asset.get("finance_books"): diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py index bdda509e91d..f72b5249a44 100644 --- a/erpnext/assets/doctype/asset/test_asset.py +++ b/erpnext/assets/doctype/asset/test_asset.py @@ -201,17 +201,29 @@ class TestAsset(AssetSetup): ) post_depreciation_entries(date=add_months(purchase_date, 2)) + asset.load_from_db() + + accumulated_depr_amount = flt( + asset.gross_purchase_amount - asset.finance_books[0].value_after_depreciation, + asset.precision("gross_purchase_amount"), + ) + self.assertEquals(accumulated_depr_amount, 18000.0) scrap_asset(asset.name) - asset.load_from_db() - self.assertEqual(asset.status, "Scrapped") - self.assertTrue(asset.journal_entry_for_scrap) + accumulated_depr_amount = flt( + asset.gross_purchase_amount - asset.finance_books[0].value_after_depreciation, + asset.precision("gross_purchase_amount"), + ) pro_rata_amount, _, _ = asset.get_pro_rata_amt( asset.finance_books[0], 9000, add_months(get_last_day(purchase_date), 1), date ) pro_rata_amount = flt(pro_rata_amount, asset.precision("gross_purchase_amount")) + self.assertEquals(accumulated_depr_amount, 18000.00 + pro_rata_amount) + + self.assertEqual(asset.status, "Scrapped") + self.assertTrue(asset.journal_entry_for_scrap) expected_gle = ( ("_Test Accumulated Depreciations - _TC", 18000.0 + pro_rata_amount, 0.0), @@ -233,6 +245,12 @@ class TestAsset(AssetSetup): self.assertFalse(asset.journal_entry_for_scrap) self.assertEqual(asset.status, "Partially Depreciated") + accumulated_depr_amount = flt( + asset.gross_purchase_amount - asset.finance_books[0].value_after_depreciation, + asset.precision("gross_purchase_amount"), + ) + self.assertEquals(accumulated_depr_amount, 18000.0) + def test_gle_made_by_asset_sale(self): date = nowdate() purchase_date = add_months(get_first_day(date), -2) From e683cccf3520812b6f031ce780bf8575e5f6c8db Mon Sep 17 00:00:00 2001 From: Ernesto Ruiz Date: Mon, 26 Sep 2022 07:59:13 -0600 Subject: [PATCH 05/22] fix: add translate function to book appointment html --- erpnext/www/book_appointment/index.html | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/erpnext/www/book_appointment/index.html b/erpnext/www/book_appointment/index.html index 207175f89dc..ad964d93700 100644 --- a/erpnext/www/book_appointment/index.html +++ b/erpnext/www/book_appointment/index.html @@ -12,8 +12,8 @@
-

Book an appointment

-

Select the date and your timezone

+

{{ _("Book an appointment") }}

+

{{ _("Select the date and your timezone") }}

@@ -31,7 +31,7 @@
- +
@@ -39,24 +39,24 @@
-

Add details

-

Selected date is at +

{{ _("Add details") }}

+

{{ _("Selected date is") }} {{ _("at") }}

- + - + + placeholder="{{ _('Notes') }}">
-
-
+
+
From 728ef46048d04b17a583c018d4201e868aa20605 Mon Sep 17 00:00:00 2001 From: Ernesto Ruiz Date: Mon, 26 Sep 2022 08:01:48 -0600 Subject: [PATCH 06/22] fix: add translate function to book appointment index.js --- erpnext/www/book_appointment/index.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/erpnext/www/book_appointment/index.js b/erpnext/www/book_appointment/index.js index 5562cbd4710..46ac15518c7 100644 --- a/erpnext/www/book_appointment/index.js +++ b/erpnext/www/book_appointment/index.js @@ -69,7 +69,7 @@ function on_date_or_timezone_select() { window.selected_timezone = timezone.value; update_time_slots(date_picker.value, timezone.value); let lead_text = document.getElementById('lead-text'); - lead_text.innerHTML = "Select Time" + lead_text.innerHTML = __("Select Time") } async function get_time_slots(date, timezone) { @@ -89,7 +89,7 @@ async function update_time_slots(selected_date, selected_timezone) { clear_time_slots(); if (window.slots.length <= 0) { let message_div = document.createElement('p'); - message_div.innerHTML = "There are no slots available on this date"; + message_div.innerHTML = __("There are no slots available on this date"); timeslot_container.appendChild(message_div); return } @@ -128,7 +128,7 @@ function get_slot_layout(time) { let start_time_string = moment(time).tz(timezone).format("LT"); let end_time = moment(time).tz(timezone).add(window.appointment_settings.appointment_duration, 'minutes'); let end_time_string = end_time.format("LT"); - return `${start_time_string}
to ${end_time_string}`; + return `${start_time_string}
${__("to") } ${end_time_string}`; } function select_time() { @@ -227,9 +227,9 @@ async function submit() { }, callback: (response)=>{ if (response.message.status == "Unverified") { - frappe.show_alert("Please check your email to confirm the appointment") + frappe.show_alert(__("Please check your email to confirm the appointment")) } else { - frappe.show_alert("Appointment Created Successfully"); + frappe.show_alert(__("Appointment Created Successfully")); } setTimeout(()=>{ let redirect_url = "/"; @@ -239,7 +239,7 @@ async function submit() { window.location.href = redirect_url;},5000) }, error: (err)=>{ - frappe.show_alert("Something went wrong please try again"); + frappe.show_alert(__("Something went wrong please try again")); button.disabled = false; } }); From 499ce5139c16b7ac60eb7f062919a3298dca739a Mon Sep 17 00:00:00 2001 From: Ernesto Ruiz Date: Mon, 26 Sep 2022 08:04:14 -0600 Subject: [PATCH 07/22] fix: add translate function to book appointment verify html --- erpnext/www/book_appointment/verify/index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/www/book_appointment/verify/index.html b/erpnext/www/book_appointment/verify/index.html index 9bcd3d202e2..58c07e85ccc 100644 --- a/erpnext/www/book_appointment/verify/index.html +++ b/erpnext/www/book_appointment/verify/index.html @@ -8,11 +8,11 @@ {% if success==True %}
- Your email has been verified and your appointment has been scheduled + {{ _("Your email has been verified and your appointment has been scheduled") }}
{% else %}
- Verification failed please check the link + {{ _("Verification failed please check the link") }}
{% endif %} {% endblock%} From 21095502b9fe0edfb4828a5b918c9375b81f1cc0 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Mon, 26 Sep 2022 17:41:30 +0530 Subject: [PATCH 08/22] chore: clean up purchase invoice and purchase invoice item 1. remove discount accounting related fields from purchase invoice and purchase invoice item 2. clean buying settings doctype --- .../purchase_invoice/purchase_invoice.json | 9 +-- .../purchase_invoice/purchase_invoice.py | 15 ----- .../purchase_invoice_item.json | 9 +-- .../buying_settings/buying_settings.json | 10 +-- .../buying_settings/buying_settings.py | 62 ------------------- 5 files changed, 3 insertions(+), 102 deletions(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json index 986fc038c60..3020e6dc6e3 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json @@ -98,7 +98,6 @@ "section_break_44", "apply_discount_on", "base_discount_amount", - "additional_discount_account", "column_break_46", "additional_discount_percentage", "discount_amount", @@ -1387,12 +1386,6 @@ "print_hide": 1, "read_only": 1 }, - { - "fieldname": "additional_discount_account", - "fieldtype": "Link", - "label": "Additional Discount Account", - "options": "Account" - }, { "default": "0", "fieldname": "ignore_default_payment_terms_template", @@ -1445,7 +1438,7 @@ "idx": 204, "is_submittable": 1, "links": [], - "modified": "2022-09-13 23:39:54.525037", + "modified": "2022-09-27 11:07:55.766844", "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 d1853002891..2b633cb8c34 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -669,9 +669,6 @@ class PurchaseInvoice(BuyingController): exchange_rate_map, net_rate_map = get_purchase_document_details(self) - enable_discount_accounting = cint( - frappe.db.get_single_value("Buying Settings", "enable_discount_accounting") - ) provisional_accounting_for_non_stock_items = cint( frappe.db.get_value( "Company", self.company, "enable_provisional_accounting_for_non_stock_items" @@ -1159,9 +1156,6 @@ class PurchaseInvoice(BuyingController): def make_tax_gl_entries(self, gl_entries): # tax table gl entries valuation_tax = {} - enable_discount_accounting = cint( - frappe.db.get_single_value("Buying Settings", "enable_discount_accounting") - ) for tax in self.get("taxes"): amount, base_amount = self.get_tax_amounts(tax, None) @@ -1249,15 +1243,6 @@ class PurchaseInvoice(BuyingController): ) ) - @property - def enable_discount_accounting(self): - if not hasattr(self, "_enable_discount_accounting"): - self._enable_discount_accounting = cint( - frappe.db.get_single_value("Buying Settings", "enable_discount_accounting") - ) - - return self._enable_discount_accounting - def make_internal_transfer_gl_entries(self, gl_entries): if self.is_internal_transfer() and flt(self.base_total_taxes_and_charges): account_currency = get_account_currency(self.unrealized_profit_loss_account) diff --git a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json index 7fa2fe2a668..fca7e3a8873 100644 --- a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json +++ b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json @@ -74,7 +74,6 @@ "manufacturer_part_no", "accounting", "expense_account", - "discount_account", "col_break5", "is_fixed_asset", "asset_location", @@ -860,12 +859,6 @@ "print_hide": 1, "read_only": 1 }, - { - "fieldname": "discount_account", - "fieldtype": "Link", - "label": "Discount Account", - "options": "Account" - }, { "fieldname": "product_bundle", "fieldtype": "Link", @@ -877,7 +870,7 @@ "idx": 1, "istable": 1, "links": [], - "modified": "2022-06-17 05:31:10.520171", + "modified": "2022-09-27 10:54:23.980713", "modified_by": "Administrator", "module": "Accounts", "name": "Purchase Invoice Item", diff --git a/erpnext/buying/doctype/buying_settings/buying_settings.json b/erpnext/buying/doctype/buying_settings/buying_settings.json index aad26075f2d..28158a31b94 100644 --- a/erpnext/buying/doctype/buying_settings/buying_settings.json +++ b/erpnext/buying/doctype/buying_settings/buying_settings.json @@ -20,7 +20,6 @@ "maintain_same_rate", "allow_multiple_items", "bill_for_rejected_quantity_in_purchase_invoice", - "enable_discount_accounting", "subcontract", "backflush_raw_materials_of_subcontract_based_on", "column_break_11", @@ -134,13 +133,6 @@ { "fieldname": "column_break_12", "fieldtype": "Column Break" - }, - { - "default": "0", - "description": "If enabled, additional ledger entries will be made for discounts in a separate Discount Account", - "fieldname": "enable_discount_accounting", - "fieldtype": "Check", - "label": "Enable Discount Accounting for Buying" } ], "icon": "fa fa-cog", @@ -148,7 +140,7 @@ "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2022-09-01 18:01:34.994657", + "modified": "2022-09-27 10:50:27.050252", "modified_by": "Administrator", "module": "Buying", "name": "Buying Settings", diff --git a/erpnext/buying/doctype/buying_settings/buying_settings.py b/erpnext/buying/doctype/buying_settings/buying_settings.py index 7b18cdbedcd..be1ebdeb64e 100644 --- a/erpnext/buying/doctype/buying_settings/buying_settings.py +++ b/erpnext/buying/doctype/buying_settings/buying_settings.py @@ -5,15 +5,10 @@ import frappe -from frappe.custom.doctype.property_setter.property_setter import make_property_setter from frappe.model.document import Document -from frappe.utils import cint class BuyingSettings(Document): - def on_update(self): - self.toggle_discount_accounting_fields() - def validate(self): for key in ["supplier_group", "supp_master_name", "maintain_same_rate", "buying_price_list"]: frappe.db.set_default(key, self.get(key, "")) @@ -26,60 +21,3 @@ class BuyingSettings(Document): self.get("supp_master_name") == "Naming Series", hide_name_field=False, ) - - def toggle_discount_accounting_fields(self): - enable_discount_accounting = cint(self.enable_discount_accounting) - - make_property_setter( - "Purchase Invoice Item", - "discount_account", - "hidden", - not (enable_discount_accounting), - "Check", - validate_fields_for_doctype=False, - ) - if enable_discount_accounting: - make_property_setter( - "Purchase Invoice Item", - "discount_account", - "mandatory_depends_on", - "eval: doc.discount_amount", - "Code", - validate_fields_for_doctype=False, - ) - else: - make_property_setter( - "Purchase Invoice Item", - "discount_account", - "mandatory_depends_on", - "", - "Code", - validate_fields_for_doctype=False, - ) - - make_property_setter( - "Purchase Invoice", - "additional_discount_account", - "hidden", - not (enable_discount_accounting), - "Check", - validate_fields_for_doctype=False, - ) - if enable_discount_accounting: - make_property_setter( - "Purchase Invoice", - "additional_discount_account", - "mandatory_depends_on", - "eval: doc.discount_amount", - "Code", - validate_fields_for_doctype=False, - ) - else: - make_property_setter( - "Purchase Invoice", - "additional_discount_account", - "mandatory_depends_on", - "", - "Code", - validate_fields_for_doctype=False, - ) From c6a7de0e545746556a7e80e0bd4dcf46159d3f24 Mon Sep 17 00:00:00 2001 From: anandbaburajan Date: Tue, 27 Sep 2022 20:43:08 +0530 Subject: [PATCH 09/22] chore: add blank lines --- erpnext/assets/doctype/asset/depreciation.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/erpnext/assets/doctype/asset/depreciation.py b/erpnext/assets/doctype/asset/depreciation.py index b6e86cdd5a4..97941706aa8 100644 --- a/erpnext/assets/doctype/asset/depreciation.py +++ b/erpnext/assets/doctype/asset/depreciation.py @@ -243,6 +243,7 @@ def restore_asset(asset_name): asset.set_status() + def depreciate_asset(asset, date): asset.flags.ignore_validate_update_after_submit = True asset.prepare_depreciation_data(date_of_disposal=date) @@ -327,6 +328,7 @@ def disposal_happens_in_the_future(posting_date_of_disposal): return False + def get_gl_entries_on_asset_regain( asset, selling_amount=0, finance_book=None, voucher_type=None, voucher_no=None ): From 0439e41a44db1c5e4319feae11a38728e6fba8f8 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Wed, 28 Sep 2022 14:54:53 +0530 Subject: [PATCH 10/22] fix: Item details fetching on making transaction from item dashboard --- erpnext/stock/doctype/item/item.js | 39 ++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/erpnext/stock/doctype/item/item.js b/erpnext/stock/doctype/item/item.js index 7e1476d240a..e61f0f514e3 100644 --- a/erpnext/stock/doctype/item/item.js +++ b/erpnext/stock/doctype/item/item.js @@ -10,6 +10,31 @@ frappe.ui.form.on("Item", { frm.add_fetch('attribute', 'to_range', 'to_range'); frm.add_fetch('attribute', 'increment', 'increment'); frm.add_fetch('tax_type', 'tax_rate', 'tax_rate'); + + frm.make_methods = { + 'Sales Order': () => { + open_form(frm, "Sales Order", "Sales Order Item", "items"); + }, + 'Delivery Note': () => { + open_form(frm, "Delivery Note", "Delivery Note Item", "items"); + }, + 'Sales Invoice': () => { + open_form(frm, "Sales Invoice", "Sales Invoice Item", "items"); + }, + 'Purchase Order': () => { + open_form(frm, "Purchase Order", "Purchase Order Item", "items"); + }, + 'Purchase Receipt': () => { + open_form(frm, "Purchase Receipt", "Purchase Receipt Item", "items"); + }, + 'Purchase Invoice': () => { + open_form(frm, "Purchase Invoice", "Purchase Invoice Item", "items"); + }, + 'Material Request': () => { + open_form(frm, "Material Request", "Material Request Item", "items"); + }, + }; + }, onload: function(frm) { erpnext.item.setup_queries(frm); @@ -858,3 +883,17 @@ frappe.tour['Item'] = [ ]; + +function open_form(frm, doctype, child_doctype, parentfield) { + frappe.model.with_doctype(doctype, () => { + let new_doc = frappe.model.get_new_doc(doctype); + + let new_child_doc = frappe.model.add_child(new_doc, child_doctype, parentfield); + new_child_doc.item_code = frm.doc.name; + new_child_doc.item_name = frm.doc.item_name; + new_child_doc.uom = frm.doc.stock_uom; + new_child_doc.description = frm.doc.description; + + frappe.ui.form.make_quick_entry(doctype, null, null, new_doc); + }); +} From be623ce8e8e9c25d2327383c057b5e810b28c4a7 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Wed, 28 Sep 2022 15:36:59 +0530 Subject: [PATCH 11/22] fix: Disbursement Account in patch to update old loans --- erpnext/patches/v13_0/update_old_loans.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/erpnext/patches/v13_0/update_old_loans.py b/erpnext/patches/v13_0/update_old_loans.py index a1d40b739eb..0bd3fcdec4c 100644 --- a/erpnext/patches/v13_0/update_old_loans.py +++ b/erpnext/patches/v13_0/update_old_loans.py @@ -100,6 +100,7 @@ def execute(): "mode_of_payment": loan.mode_of_payment, "loan_account": loan.loan_account, "payment_account": loan.payment_account, + "disbursement_account": loan.payment_account, "interest_income_account": loan.interest_income_account, "penalty_income_account": loan.penalty_income_account, }, @@ -190,6 +191,7 @@ def create_loan_type(loan, loan_type_name, penalty_account): loan_type_doc.company = loan.company loan_type_doc.mode_of_payment = loan.mode_of_payment loan_type_doc.payment_account = loan.payment_account + loan_type_doc.disbursement_account = loan.payment_account loan_type_doc.loan_account = loan.loan_account loan_type_doc.interest_income_account = loan.interest_income_account loan_type_doc.penalty_income_account = penalty_account From 80080a3d7bc2e4a69c7a18742ce89534920ab118 Mon Sep 17 00:00:00 2001 From: Sagar Sharma Date: Wed, 28 Sep 2022 15:40:07 +0530 Subject: [PATCH 12/22] fix: show `Make Purchase Invoice` button based on permission --- erpnext/templates/pages/order.html | 2 +- erpnext/templates/pages/order.py | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/erpnext/templates/pages/order.html b/erpnext/templates/pages/order.html index a10870db278..ec1d49788bd 100644 --- a/erpnext/templates/pages/order.html +++ b/erpnext/templates/pages/order.html @@ -18,7 +18,7 @@