From aa7ee3ca03fef661184b46667ba7aedc7286c132 Mon Sep 17 00:00:00 2001 From: Florian HENRY Date: Mon, 6 Sep 2021 11:40:44 +0200 Subject: [PATCH 01/19] fix: link in dashboard missing on SI from DN --- .../accounts/doctype/sales_invoice/sales_invoice_dashboard.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice_dashboard.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice_dashboard.py index 64b35b2987..2956cdc097 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice_dashboard.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice_dashboard.py @@ -7,7 +7,6 @@ def get_data(): return { 'fieldname': 'sales_invoice', 'non_standard_fieldnames': { - 'Delivery Note': 'against_sales_invoice', 'Journal Entry': 'reference_name', 'Payment Entry': 'reference_name', 'Payment Request': 'reference_name', @@ -15,7 +14,8 @@ def get_data(): 'Auto Repeat': 'reference_document', }, 'internal_links': { - 'Sales Order': ['items', 'sales_order'] + 'Sales Order': ['items', 'sales_order'], + 'Delivery Note': ['items', 'delivery_note'], }, 'transactions': [ { From 5ce6a4c1075f3551608de4d9b70616aaae53d9b4 Mon Sep 17 00:00:00 2001 From: Dany Robert Date: Sun, 26 Sep 2021 18:31:27 +0530 Subject: [PATCH 02/19] fix: tax rate being overridden in case of 0.00 Tax rate could be different for different expenses. Therefore, rate is kept as 0.00 and tax amount entered manually. But fetching used to override the rate(upon saving) and mess up the amount. --- .../expense_taxes_and_charges/expense_taxes_and_charges.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/erpnext/hr/doctype/expense_taxes_and_charges/expense_taxes_and_charges.json b/erpnext/hr/doctype/expense_taxes_and_charges/expense_taxes_and_charges.json index 020457d4ec..4a1064b66b 100644 --- a/erpnext/hr/doctype/expense_taxes_and_charges/expense_taxes_and_charges.json +++ b/erpnext/hr/doctype/expense_taxes_and_charges/expense_taxes_and_charges.json @@ -56,8 +56,6 @@ }, { "columns": 2, - "fetch_from": "account_head.tax_rate", - "fetch_if_empty": 1, "fieldname": "rate", "fieldtype": "Float", "in_list_view": 1, @@ -111,4 +109,4 @@ "sort_field": "modified", "sort_order": "ASC", "track_changes": 1 -} \ No newline at end of file +} From 2b4959fb3be1507e86e86bd0d7c29cae74d3cded Mon Sep 17 00:00:00 2001 From: Dany Robert Date: Wed, 29 Sep 2021 13:01:40 +0530 Subject: [PATCH 03/19] fix: return tax rate since fetch is removed --- erpnext/hr/doctype/expense_claim/test_expense_claim.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/hr/doctype/expense_claim/test_expense_claim.py b/erpnext/hr/doctype/expense_claim/test_expense_claim.py index 9cb65f7e08..941fd58c7b 100644 --- a/erpnext/hr/doctype/expense_claim/test_expense_claim.py +++ b/erpnext/hr/doctype/expense_claim/test_expense_claim.py @@ -176,7 +176,7 @@ def generate_taxes(): account = create_account(company=company_name, account_name="Output Tax CGST", account_type="Tax", parent_account=parent_account) return {'taxes':[{ "account_head": account, - "rate": 0, + "rate": 9, "description": "CGST", "tax_amount": 10, "total": 210 From ad03eb25df6c07beb744a0fe3003a4c6fb19b98e Mon Sep 17 00:00:00 2001 From: Ganga Manoj Date: Tue, 5 Oct 2021 12:26:59 +0530 Subject: [PATCH 04/19] fix: Only calculate first_respone_time if SLA is set (#27789) Co-authored-by: Afshan <33727827+AfshanKhan@users.noreply.github.com> --- erpnext/support/doctype/issue/issue.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/support/doctype/issue/issue.py b/erpnext/support/doctype/issue/issue.py index 7d7399d097..0fe1068a76 100644 --- a/erpnext/support/doctype/issue/issue.py +++ b/erpnext/support/doctype/issue/issue.py @@ -228,7 +228,7 @@ def get_time_in_timedelta(time): def set_first_response_time(communication, method): if communication.get('reference_doctype') == "Issue": issue = get_parent_doc(communication) - if is_first_response(issue): + if is_first_response(issue) and issue.service_level_agreement: first_response_time = calculate_first_response_time(issue, get_datetime(issue.first_responded_on)) issue.db_set("first_response_time", first_response_time) From 7da777880bea281bd6612a3b229dd944feccf8ee Mon Sep 17 00:00:00 2001 From: Alan <2.alan.tom@gmail.com> Date: Tue, 5 Oct 2021 12:35:23 +0530 Subject: [PATCH 05/19] fix: add (uom, brand) Item details in an Item Price (#27561) * fix: add (uom, brand) and update (uom) Item details in an Item Price * fix: order of query interpolation args Co-authored-by: Marica * fix: named interpolation, remove item price * fix: sql error Co-authored-by: Marica Co-authored-by: Ankush Menat --- erpnext/stock/doctype/item/item.py | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py index 768e5eae2d..8cc9f74a42 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -181,6 +181,8 @@ class Item(WebsiteGenerator): "doctype": "Item Price", "price_list": price_list, "item_code": self.name, + "uom": self.stock_uom, + "brand": self.brand, "currency": erpnext.get_default_currency(), "price_list_rate": self.standard_rate }) @@ -634,9 +636,21 @@ class Item(WebsiteGenerator): _("An Item Group exists with same name, please change the item name or rename the item group")) def update_item_price(self): - frappe.db.sql("""update `tabItem Price` set item_name=%s, - item_description=%s, brand=%s where item_code=%s""", - (self.item_name, self.description, self.brand, self.name)) + frappe.db.sql(""" + UPDATE `tabItem Price` + SET + item_name=%(item_name)s, + item_description=%(item_description)s, + brand=%(brand)s + WHERE item_code=%(item_code)s + """, + dict( + item_name=self.item_name, + item_description=self.description, + brand=self.brand, + item_code=self.name + ) + ) def on_trash(self): super(Item, self).on_trash() From f37e4d52d5b30f794fde4f14513ab63c4c538829 Mon Sep 17 00:00:00 2001 From: pateljannat Date: Tue, 5 Oct 2021 12:49:08 +0530 Subject: [PATCH 06/19] docs: frappe school link in readme --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 847904d1dd..87d7d73d5a 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,12 @@ The ERPNext code is licensed as GNU General Public License (v3) and the Document --- +## Learning + +1. [Frappe School](https://frappe.school) - Learn Frappe Framework and ERPNext from the various courses by the maintainers or from the community. + +--- + ## Logo and Trademark The brand name ERPNext and the logo are trademarks of Frappe Technologies Pvt. Ltd. From 3132dcd94aae1dc68037f94a3ef63f7fd1be9b17 Mon Sep 17 00:00:00 2001 From: Noah Jacob Date: Tue, 5 Oct 2021 14:40:40 +0530 Subject: [PATCH 07/19] fix: batch_no not mapped from PR to Stock Entry (#27794) --- erpnext/stock/doctype/purchase_receipt/purchase_receipt.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py index 07a568db86..47c8df9a2c 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py @@ -842,7 +842,8 @@ def make_stock_entry(source_name,target_doc=None): "doctype": "Stock Entry Detail", "field_map": { "warehouse": "s_warehouse", - "parent": "reference_purchase_receipt" + "parent": "reference_purchase_receipt", + "batch_no": "batch_no" }, }, }, target_doc, set_missing_values) From 340859cb3c2bed7bc7e56ddbb7a0e4e0ce9ff93c Mon Sep 17 00:00:00 2001 From: Anupam Date: Tue, 5 Oct 2021 15:11:45 +0530 Subject: [PATCH 08/19] fix: broken lead form actions --- erpnext/crm/doctype/lead/lead.js | 36 ++++++++++++++++---------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/erpnext/crm/doctype/lead/lead.js b/erpnext/crm/doctype/lead/lead.js index 95cf03241b..999599ce95 100644 --- a/erpnext/crm/doctype/lead/lead.js +++ b/erpnext/crm/doctype/lead/lead.js @@ -51,7 +51,7 @@ erpnext.LeadController = class LeadController extends frappe.ui.form.Controller } } - add_lead_to_prospect (frm) { + add_lead_to_prospect () { frappe.prompt([ { fieldname: 'prospect', @@ -65,7 +65,7 @@ erpnext.LeadController = class LeadController extends frappe.ui.form.Controller frappe.call({ method: 'erpnext.crm.doctype.lead.lead.add_lead_to_prospect', args: { - 'lead': frm.doc.name, + 'lead': cur_frm.doc.name, 'prospect': data.prospect }, callback: function(r) { @@ -79,41 +79,41 @@ erpnext.LeadController = class LeadController extends frappe.ui.form.Controller }, __('Add Lead to Prospect'), __('Add')); } - make_customer (frm) { + make_customer () { frappe.model.open_mapped_doc({ method: "erpnext.crm.doctype.lead.lead.make_customer", - frm: frm + frm: cur_frm }) } - make_opportunity (frm) { + make_opportunity () { frappe.model.open_mapped_doc({ method: "erpnext.crm.doctype.lead.lead.make_opportunity", - frm: frm + frm: cur_frm }) } - make_quotation (frm) { + make_quotation () { frappe.model.open_mapped_doc({ method: "erpnext.crm.doctype.lead.lead.make_quotation", - frm: frm + frm: cur_frm }) } - make_prospect (frm) { + make_prospect () { frappe.model.with_doctype("Prospect", function() { let prospect = frappe.model.get_new_doc("Prospect"); - prospect.company_name = frm.doc.company_name; - prospect.no_of_employees = frm.doc.no_of_employees; - prospect.industry = frm.doc.industry; - prospect.market_segment = frm.doc.market_segment; - prospect.territory = frm.doc.territory; - prospect.fax = frm.doc.fax; - prospect.website = frm.doc.website; - prospect.prospect_owner = frm.doc.lead_owner; + prospect.company_name = cur_frm.doc.company_name; + prospect.no_of_employees = cur_frm.doc.no_of_employees; + prospect.industry = cur_frm.doc.industry; + prospect.market_segment = cur_frm.doc.market_segment; + prospect.territory = cur_frm.doc.territory; + prospect.fax = cur_frm.doc.fax; + prospect.website = cur_frm.doc.website; + prospect.prospect_owner = cur_frm.doc.lead_owner; let lead_prospect_row = frappe.model.add_child(prospect, 'prospect_lead'); - lead_prospect_row.lead = frm.doc.name; + lead_prospect_row.lead = cur_frm.doc.name; frappe.set_route("Form", "Prospect", prospect.name); }); From 020f94532bf8e1893fcf4c7e6bb78b9088d8deac Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Tue, 5 Oct 2021 12:20:14 +0530 Subject: [PATCH 09/19] fix: COA Importer showing blank validations (cherry picked from commit 0660d6ed01e0668ce828cf9bae9790aead874233) --- .../chart_of_accounts_importer.js | 91 +++++++++---------- .../chart_of_accounts_importer.py | 7 +- 2 files changed, 49 insertions(+), 49 deletions(-) diff --git a/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.js b/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.js index 66a269e7a7..d61f8a6c01 100644 --- a/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.js +++ b/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.js @@ -10,6 +10,15 @@ frappe.ui.form.on('Chart of Accounts Importer', { // make company mandatory frm.set_df_property('company', 'reqd', frm.doc.company ? 0 : 1); frm.set_df_property('import_file_section', 'hidden', frm.doc.company ? 0 : 1); + + if (frm.doc.import_file) { + frappe.run_serially([ + () => generate_tree_preview(frm), + () => create_import_button(frm), + () => frm.set_df_property('chart_preview', 'hidden', 0) + ]); + } + frm.set_df_property('chart_preview', 'hidden', $(frm.fields_dict['chart_tree'].wrapper).html()!="" ? 0 : 1); }, @@ -72,13 +81,6 @@ frappe.ui.form.on('Chart of Accounts Importer', { if (!frm.doc.import_file) { frm.page.set_indicator(""); $(frm.fields_dict['chart_tree'].wrapper).empty(); // empty wrapper on removing file - } else { - frappe.run_serially([ - () => validate_coa(frm), - () => generate_tree_preview(frm), - () => create_import_button(frm), - () => frm.set_df_property('chart_preview', 'hidden', 0), - ]); } }, @@ -104,26 +106,24 @@ frappe.ui.form.on('Chart of Accounts Importer', { }); var create_import_button = function(frm) { - if (frm.page.show_import_button) { - frm.page.set_primary_action(__("Import"), function () { - return frappe.call({ - method: "erpnext.accounts.doctype.chart_of_accounts_importer.chart_of_accounts_importer.import_coa", - args: { - file_name: frm.doc.import_file, - company: frm.doc.company - }, - freeze: true, - freeze_message: __("Creating Accounts..."), - callback: function(r) { - if (!r.exc) { - clearInterval(frm.page["interval"]); - frm.page.set_indicator(__('Import Successful'), 'blue'); - create_reset_button(frm); - } + frm.page.set_primary_action(__("Import"), function () { + return frappe.call({ + method: "erpnext.accounts.doctype.chart_of_accounts_importer.chart_of_accounts_importer.import_coa", + args: { + file_name: frm.doc.import_file, + company: frm.doc.company + }, + freeze: true, + freeze_message: __("Creating Accounts..."), + callback: function(r) { + if (!r.exc) { + clearInterval(frm.page["interval"]); + frm.page.set_indicator(__('Import Successful'), 'blue'); + create_reset_button(frm); } - }); - }).addClass('btn btn-primary'); - } + } + }); + }).addClass('btn btn-primary'); }; var create_reset_button = function(frm) { @@ -137,7 +137,6 @@ var create_reset_button = function(frm) { var validate_coa = function(frm) { if (frm.doc.import_file) { let parent = __('All Accounts'); - return frappe.call({ 'method': 'erpnext.accounts.doctype.chart_of_accounts_importer.chart_of_accounts_importer.get_coa', 'args': { @@ -157,25 +156,23 @@ var validate_coa = function(frm) { }; var generate_tree_preview = function(frm) { - if (frm.doc.import_file) { - let parent = __('All Accounts'); - $(frm.fields_dict['chart_tree'].wrapper).empty(); // empty wrapper to load new data + let parent = __('All Accounts'); + $(frm.fields_dict['chart_tree'].wrapper).empty(); // empty wrapper to load new data - // generate tree structure based on the csv data - return new frappe.ui.Tree({ - parent: $(frm.fields_dict['chart_tree'].wrapper), - label: parent, - expandable: true, - method: 'erpnext.accounts.doctype.chart_of_accounts_importer.chart_of_accounts_importer.get_coa', - args: { - file_name: frm.doc.import_file, - parent: parent, - doctype: 'Chart of Accounts Importer', - file_type: frm.doc.file_type - }, - onclick: function(node) { - parent = node.value; - } - }); - } + // generate tree structure based on the csv data + return new frappe.ui.Tree({ + parent: $(frm.fields_dict['chart_tree'].wrapper), + label: parent, + expandable: true, + method: 'erpnext.accounts.doctype.chart_of_accounts_importer.chart_of_accounts_importer.get_coa', + args: { + file_name: frm.doc.import_file, + parent: parent, + doctype: 'Chart of Accounts Importer', + file_type: frm.doc.file_type + }, + onclick: function(node) { + parent = node.value; + } + }); }; diff --git a/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.py b/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.py index bd2a6f1b08..5e596f8677 100644 --- a/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.py +++ b/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.py @@ -25,7 +25,9 @@ from erpnext.accounts.doctype.account.chart_of_accounts.chart_of_accounts import class ChartofAccountsImporter(Document): - pass + def validate(self): + if self.import_file: + get_coa('Chart of Accounts Importer', 'All Accounts', file_name=self.import_file, for_validate=1) def validate_columns(data): if not data: @@ -34,7 +36,8 @@ def validate_columns(data): no_of_columns = max([len(d) for d in data]) if no_of_columns > 7: - frappe.throw(_('More columns found than expected. Please compare the uploaded file with standard template')) + frappe.throw(_('More columns found than expected. Please compare the uploaded file with standard template'), + title=(_("Wrong Template"))) @frappe.whitelist() def validate_company(company): From a2b5e678fec3c7157fe3a280ff3e0dbcc15123ec Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Tue, 5 Oct 2021 14:51:35 +0530 Subject: [PATCH 10/19] fix: Use get_list instead of get_all to avoid perm issues (cherry picked from commit 9507b2d752a40c0dd9e8b43ae3ef64435457c85e) --- erpnext/setup/setup_wizard/operations/taxes_setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/setup/setup_wizard/operations/taxes_setup.py b/erpnext/setup/setup_wizard/operations/taxes_setup.py index faa25dfbaa..58a14d20f2 100644 --- a/erpnext/setup/setup_wizard/operations/taxes_setup.py +++ b/erpnext/setup/setup_wizard/operations/taxes_setup.py @@ -192,7 +192,7 @@ def get_or_create_account(company_name, account): default_root_type = 'Liability' root_type = account.get('root_type', default_root_type) - existing_accounts = frappe.get_list('Account', + existing_accounts = frappe.get_all('Account', filters={ 'company': company_name, 'root_type': root_type @@ -247,7 +247,7 @@ def get_or_create_tax_group(company_name, root_type): # Create a new group account named 'Duties and Taxes' or 'Tax Assets' just # below the root account - root_account = frappe.get_list('Account', { + root_account = frappe.get_all('Account', { 'is_group': 1, 'root_type': root_type, 'company': company_name, From 3d3655ed730f793ddac24d610da397741ffc3009 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Tue, 5 Oct 2021 15:52:11 +0530 Subject: [PATCH 11/19] fix: ignore random periodicity in validations --- .../doctype/maintenance_schedule/maintenance_schedule.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py index 0bf5aeae71..a1df9cfd0e 100644 --- a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py +++ b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py @@ -47,7 +47,7 @@ class MaintenanceSchedule(TransactionBase): "Yearly": 365 } for item in self.items: - if item.periodicity and item.start_date: + if item.periodicity and item.periodicity != "Random" and item.start_date: if not item.end_date: if item.no_of_visits: item.end_date = add_days(item.start_date, item.no_of_visits * days_in_period[item.periodicity]) From 233bf5dd294382ce6d5a5cdd7ad02aafe921a584 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Tue, 5 Oct 2021 16:16:21 +0530 Subject: [PATCH 12/19] fix: using DN for transfer w/o internal customer (backport #27798) (backport #27805) (#27807) * fix: using DN for transfer w/o internal customer (backport #27798) (#27805) * fix: using DN for transfer w/o internal customer (#27798) This used to be work before though not "advertised", since a lot of users have started using it as feature, it can't be broken now. (cherry picked from commit df1f8fddf6e2f4106c1a2778614ba9a1dc5ff67e) * fix(ux): use toast instead of popup Co-authored-by: Ankush Menat (cherry picked from commit fa944382c53bdeeb92f2dcc876e2c11ed03e20cc) # Conflicts: # erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py * fix: resolve conflict * fix: resolve conflicts Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> Co-authored-by: Ankush Menat --- .../doctype/sales_invoice/test_sales_invoice.py | 12 ++++-------- erpnext/controllers/selling_controller.py | 8 +++++++- erpnext/stock/doctype/delivery_note/delivery_note.py | 1 - .../delivery_note_item/delivery_note_item.json | 6 +++--- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index 8a2e9450e9..f492a03daf 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -2023,11 +2023,7 @@ class TestSalesInvoice(unittest.TestCase): frappe.local.enable_perpetual_inventory['_Test Company 1'] = old_perpetual_inventory frappe.db.set_value("Stock Settings", None, "allow_negative_stock", old_negative_stock) - def test_sle_if_target_warehouse_exists_accidentally(self): - """ - Check if inward entry exists if Target Warehouse accidentally exists - but Customer is not an internal customer. - """ + def test_sle_for_target_warehouse(self): se = make_stock_entry( item_code="138-CMS Shoe", target="Finished Goods - _TC", @@ -2048,9 +2044,9 @@ class TestSalesInvoice(unittest.TestCase): sles = frappe.get_all("Stock Ledger Entry", filters={"voucher_no": si.name}, fields=["name", "actual_qty"]) - # check if only one SLE for outward entry is created - self.assertEqual(len(sles), 1) - self.assertEqual(sles[0].actual_qty, -1) + # check if both SLEs are created + self.assertEqual(len(sles), 2) + self.assertEqual(sum(d.actual_qty for d in sles), 0.0) # tear down si.cancel() diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py index 0158a1120f..bb269f3db2 100644 --- a/erpnext/controllers/selling_controller.py +++ b/erpnext/controllers/selling_controller.py @@ -424,7 +424,7 @@ class SellingController(StockController): or (cint(self.is_return) and self.docstatus==2)): sl_entries.append(self.get_sle_for_source_warehouse(d)) - if d.target_warehouse and self.get("is_internal_customer"): + if d.target_warehouse: sl_entries.append(self.get_sle_for_target_warehouse(d)) if d.warehouse and ((not cint(self.is_return) and self.docstatus==2) @@ -559,6 +559,12 @@ class SellingController(StockController): frappe.throw(_("Row {0}: Delivery Warehouse ({1}) and Customer Warehouse ({2}) can not be same") .format(d.idx, warehouse, warehouse)) + if not self.get("is_internal_customer") and any(d.get("target_warehouse") for d in items): + msg = _("Target Warehouse is set for some items but the customer is not an internal customer.") + msg += " " + _("This {} will be treated as material transfer.").format(_(self.doctype)) + frappe.msgprint(msg, title="Internal Transfer", alert=True) + + def validate_items(self): # validate items to see if they have is_sales_item enabled from erpnext.controllers.buying_controller import validate_item_type diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py index 5542cd00d4..f75b52cec8 100644 --- a/erpnext/stock/doctype/delivery_note/delivery_note.py +++ b/erpnext/stock/doctype/delivery_note/delivery_note.py @@ -185,7 +185,6 @@ class DeliveryNote(SellingController): if not d['warehouse'] and frappe.db.get_value("Item", d['item_code'], "is_stock_item") == 1: frappe.throw(_("Warehouse required for stock Item {0}").format(d["item_code"])) - def update_current_stock(self): if self.get("_action") and self._action != "update_after_submit": for d in self.get('items'): diff --git a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json index b05090a237..a96c29925e 100644 --- a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json +++ b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json @@ -468,7 +468,7 @@ "width": "100px" }, { - "depends_on": "eval:parent.is_internal_customer", + "depends_on": "eval:parent.is_internal_customer || doc.target_warehouse", "fieldname": "target_warehouse", "fieldtype": "Link", "hidden": 1, @@ -759,7 +759,7 @@ "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2021-02-23 01:04:08.588104", + "modified": "2021-10-05 12:12:44.018872", "modified_by": "Administrator", "module": "Stock", "name": "Delivery Note Item", @@ -767,4 +767,4 @@ "permissions": [], "sort_field": "modified", "sort_order": "DESC" -} \ No newline at end of file +} From cec66d2d10b258c5dd7662e9f173f890e3d62d56 Mon Sep 17 00:00:00 2001 From: Afshan <33727827+AfshanKhan@users.noreply.github.com> Date: Tue, 5 Oct 2021 19:14:39 +0530 Subject: [PATCH 13/19] fix: removed redundant piece of code (#27817) --- erpnext/accounts/doctype/sales_invoice/sales_invoice.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index eb26aa2afa..d909814921 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -229,9 +229,6 @@ class SalesInvoice(SellingController): # this sequence because outstanding may get -ve self.make_gl_entries() - if self.update_stock == 1: - self.repost_future_sle_and_gle() - if self.update_stock == 1: self.repost_future_sle_and_gle() From 35e30bdcaf592d190ae52d67525b344704c9ccd6 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Tue, 5 Oct 2021 21:44:34 +0530 Subject: [PATCH 14/19] ci: fail build if asset bundling fails (#27820) --- .github/workflows/ui-tests.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ui-tests.yml b/.github/workflows/ui-tests.yml index 658892c20e..d765f0482c 100644 --- a/.github/workflows/ui-tests.yml +++ b/.github/workflows/ui-tests.yml @@ -104,6 +104,8 @@ jobs: - name: Build Assets run: cd ~/frappe-bench/ && bench build + env: + CI: Yes - name: UI Tests run: cd ~/frappe-bench/ && bench --site test_site run-ui-tests erpnext --headless From ff7506d4a6bacc1c04e75d0844f965dff4f9b917 Mon Sep 17 00:00:00 2001 From: Marica Date: Wed, 6 Oct 2021 13:35:22 +0530 Subject: [PATCH 15/19] fix: revert "fix: missing link in dashboard missing on SI from DN" (#27832) --- .../accounts/doctype/sales_invoice/sales_invoice_dashboard.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice_dashboard.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice_dashboard.py index 2956cdc097..64b35b2987 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice_dashboard.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice_dashboard.py @@ -7,6 +7,7 @@ def get_data(): return { 'fieldname': 'sales_invoice', 'non_standard_fieldnames': { + 'Delivery Note': 'against_sales_invoice', 'Journal Entry': 'reference_name', 'Payment Entry': 'reference_name', 'Payment Request': 'reference_name', @@ -14,8 +15,7 @@ def get_data(): 'Auto Repeat': 'reference_document', }, 'internal_links': { - 'Sales Order': ['items', 'sales_order'], - 'Delivery Note': ['items', 'delivery_note'], + 'Sales Order': ['items', 'sales_order'] }, 'transactions': [ { From d36849e4f8935fb481b9fa45d517fe9fda70f43b Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Wed, 6 Oct 2021 17:13:34 +0530 Subject: [PATCH 16/19] test: optimise `test_component_amount_dependent_on_another_payment_days_based_component` (#27836) --- .../doctype/salary_slip/test_salary_slip.py | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/erpnext/payroll/doctype/salary_slip/test_salary_slip.py b/erpnext/payroll/doctype/salary_slip/test_salary_slip.py index 9ed6686d48..178cd5c9d0 100644 --- a/erpnext/payroll/doctype/salary_slip/test_salary_slip.py +++ b/erpnext/payroll/doctype/salary_slip/test_salary_slip.py @@ -141,7 +141,6 @@ class TestSalarySlip(unittest.TestCase): create_salary_structure_assignment, ) - no_of_days = self.get_no_of_days() # Payroll based on attendance frappe.db.set_value("Payroll Settings", None, "payroll_based_on", "Attendance") @@ -168,9 +167,6 @@ class TestSalarySlip(unittest.TestCase): ss = make_salary_slip_for_payment_days_dependency_test("test_payment_days_based_component@salary.com", salary_structure.name) self.assertEqual(ss.absent_days, 1) - days_in_month = no_of_days[0] - no_of_holidays = no_of_days[1] - ss.reload() payment_days_based_comp_amount = 0 for component in ss.earnings: @@ -992,13 +988,14 @@ def make_salary_structure_for_payment_days_based_component_dependency(): return salary_structure_doc def make_salary_slip_for_payment_days_dependency_test(employee, salary_structure): - employee = frappe.db.get_value("Employee", { - "user_id": employee - }, + employee = frappe.db.get_value( + "Employee", + {"user_id": employee}, ["name", "company", "employee_name"], - as_dict=True) + as_dict=True + ) - salary_slip_name = frappe.db.get_value("Salary Slip", {"employee": frappe.db.get_value("Employee", {"user_id": employee})}) + salary_slip_name = frappe.db.get_value("Salary Slip", {"employee": employee.name}) if not salary_slip_name: salary_slip = make_salary_slip(salary_structure, employee=employee.name) @@ -1009,4 +1006,4 @@ def make_salary_slip_for_payment_days_dependency_test(employee, salary_structure else: salary_slip = frappe.get_doc("Salary Slip", salary_slip_name) - return salary_slip \ No newline at end of file + return salary_slip From d4b2471cea2d43815b8384dd6bcabf246e285105 Mon Sep 17 00:00:00 2001 From: Alan <2.alan.tom@gmail.com> Date: Wed, 6 Oct 2021 18:16:33 +0530 Subject: [PATCH 17/19] fix: use ceil in case of whole uoms for reorder qty (#27834) * fix: use ceil in case of whole uoms for reorder qty * fix: cache uom query --- erpnext/stock/reorder_item.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/erpnext/stock/reorder_item.py b/erpnext/stock/reorder_item.py index 3cd4cd2761..7c6fbfd9cd 100644 --- a/erpnext/stock/reorder_item.py +++ b/erpnext/stock/reorder_item.py @@ -4,6 +4,7 @@ from __future__ import unicode_literals import json +from math import ceil import frappe from frappe import _ @@ -149,11 +150,16 @@ def create_material_request(material_requests): conversion_factor = frappe.db.get_value("UOM Conversion Detail", {'parent': item.name, 'uom': uom}, 'conversion_factor') or 1.0 + must_be_whole_number = frappe.db.get_value("UOM", uom, "must_be_whole_number", cache=True) + qty = d.reorder_qty / conversion_factor + if must_be_whole_number: + qty = ceil(qty) + mr.append("items", { "doctype": "Material Request Item", "item_code": d.item_code, "schedule_date": add_days(nowdate(),cint(item.lead_time_days)), - "qty": d.reorder_qty / conversion_factor, + "qty": qty, "uom": uom, "stock_uom": item.stock_uom, "warehouse": d.warehouse, From 772d4753e7fdf79b24398accb34990b259a63bbc Mon Sep 17 00:00:00 2001 From: Chillar Anand Date: Wed, 6 Oct 2021 22:28:48 +0530 Subject: [PATCH 18/19] refactor: Clean up mutable defaults and add CI check (#27828) * refactor: Clean up mutable defaults and add CI check --- .github/helper/.flake8_strict | 5 +++++ .pre-commit-config.yaml | 5 ++++- .../accounts/doctype/pos_profile/test_pos_profile.py | 4 +++- erpnext/accounts/doctype/pricing_rule/utils.py | 4 +++- .../doctype/promotional_scheme/promotional_scheme.py | 8 ++++++-- erpnext/accounts/report/cash_flow/cash_flow.py | 4 ++-- erpnext/education/doctype/student/student.py | 4 +++- erpnext/hr/doctype/holiday_list/holiday_list.py | 5 +++-- .../hr/doctype/shift_assignment/shift_assignment.py | 12 +++++++++--- erpnext/hr/doctype/staffing_plan/staffing_plan.py | 6 +++++- .../doctype/material_request/material_request.py | 4 ++-- erpnext/stock/doctype/serial_no/serial_no.py | 4 +++- erpnext/stock/get_item_details.py | 2 +- 13 files changed, 49 insertions(+), 18 deletions(-) diff --git a/.github/helper/.flake8_strict b/.github/helper/.flake8_strict index 4c7f5f82cf..c8337a9c12 100644 --- a/.github/helper/.flake8_strict +++ b/.github/helper/.flake8_strict @@ -65,6 +65,11 @@ ignore = E713, E712, +enable-extensions = + M90 + +select = + M511 max-line-length = 200 exclude=.github/helper/semgrep_rules,test_*.py diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2b3a471f77..e411f11301 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -20,7 +20,10 @@ repos: rev: 3.9.2 hooks: - id: flake8 - args: ['--config', '.github/helper/.flake8_strict'] + additional_dependencies: [ + 'flake8-mutable', + ] + args: ['--select=M511', '--config', '.github/helper/.flake8_strict'] exclude: ".*setup.py$" - repo: https://github.com/timothycrosley/isort diff --git a/erpnext/accounts/doctype/pos_profile/test_pos_profile.py b/erpnext/accounts/doctype/pos_profile/test_pos_profile.py index 83ecfb47bb..7c53f4a0b0 100644 --- a/erpnext/accounts/doctype/pos_profile/test_pos_profile.py +++ b/erpnext/accounts/doctype/pos_profile/test_pos_profile.py @@ -33,7 +33,9 @@ class TestPOSProfile(unittest.TestCase): frappe.db.sql("delete from `tabPOS Profile`") -def get_customers_list(pos_profile={}): +def get_customers_list(pos_profile=None): + if pos_profile is None: + pos_profile = {} cond = "1=1" customer_groups = [] if pos_profile.get('customer_groups'): diff --git a/erpnext/accounts/doctype/pricing_rule/utils.py b/erpnext/accounts/doctype/pricing_rule/utils.py index 12b486e45e..0637fdaef0 100644 --- a/erpnext/accounts/doctype/pricing_rule/utils.py +++ b/erpnext/accounts/doctype/pricing_rule/utils.py @@ -398,7 +398,9 @@ def get_qty_and_rate_for_other_item(doc, pr_doc, pricing_rules): pricing_rules[0].apply_rule_on_other_items = items return pricing_rules -def get_qty_amount_data_for_cumulative(pr_doc, doc, items=[]): +def get_qty_amount_data_for_cumulative(pr_doc, doc, items=None): + if items is None: + items = [] sum_qty, sum_amt = [0, 0] doctype = doc.get('parenttype') or doc.doctype diff --git a/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.py b/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.py index d09f7dc2da..f5391ca4cc 100644 --- a/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.py +++ b/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.py @@ -69,7 +69,9 @@ class PromotionalScheme(Document): {'promotional_scheme': self.name}): frappe.delete_doc('Pricing Rule', rule.name) -def get_pricing_rules(doc, rules = {}): +def get_pricing_rules(doc, rules=None): + if rules is None: + rules = {} new_doc = [] for child_doc, fields in {'price_discount_slabs': price_discount_fields, 'product_discount_slabs': product_discount_fields}.items(): @@ -78,7 +80,9 @@ def get_pricing_rules(doc, rules = {}): return new_doc -def _get_pricing_rules(doc, child_doc, discount_fields, rules = {}): +def _get_pricing_rules(doc, child_doc, discount_fields, rules=None): + if rules is None: + rules = {} new_doc = [] args = get_args_for_pricing_rule(doc) applicable_for = frappe.scrub(doc.get('applicable_for')) diff --git a/erpnext/accounts/report/cash_flow/cash_flow.py b/erpnext/accounts/report/cash_flow/cash_flow.py index d5271885b7..bb8138bfc2 100644 --- a/erpnext/accounts/report/cash_flow/cash_flow.py +++ b/erpnext/accounts/report/cash_flow/cash_flow.py @@ -139,9 +139,9 @@ def get_account_type_based_data(company, account_type, period_list, accumulated_ data["total"] = total return data -def get_account_type_based_gl_data(company, start_date, end_date, account_type, filters={}): +def get_account_type_based_gl_data(company, start_date, end_date, account_type, filters=None): cond = "" - filters = frappe._dict(filters) + filters = frappe._dict(filters or {}) if filters.include_default_book_entries: company_fb = frappe.db.get_value("Company", company, 'default_finance_book') diff --git a/erpnext/education/doctype/student/student.py b/erpnext/education/doctype/student/student.py index ae498ba57d..be4ee560a5 100644 --- a/erpnext/education/doctype/student/student.py +++ b/erpnext/education/doctype/student/student.py @@ -138,7 +138,9 @@ class Student(Document): enrollment.submit() return enrollment - def enroll_in_course(self, course_name, program_enrollment, enrollment_date=frappe.utils.datetime.datetime.now()): + def enroll_in_course(self, course_name, program_enrollment, enrollment_date=None): + if enrollment_date is None: + enrollment_date = frappe.utils.datetime.datetime.now() try: enrollment = frappe.get_doc({ "doctype": "Course Enrollment", diff --git a/erpnext/hr/doctype/holiday_list/holiday_list.py b/erpnext/hr/doctype/holiday_list/holiday_list.py index f46f14d841..7d1b991642 100644 --- a/erpnext/hr/doctype/holiday_list/holiday_list.py +++ b/erpnext/hr/doctype/holiday_list/holiday_list.py @@ -1,4 +1,3 @@ - # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt @@ -94,9 +93,11 @@ def get_events(start, end, filters=None): update={"allDay": 1}) -def is_holiday(holiday_list, date=today()): +def is_holiday(holiday_list, date=None): """Returns true if the given date is a holiday in the given holiday list """ + if date is None: + date = today() if holiday_list: return bool(frappe.get_all('Holiday List', dict(name=holiday_list, holiday_date=date))) diff --git a/erpnext/hr/doctype/shift_assignment/shift_assignment.py b/erpnext/hr/doctype/shift_assignment/shift_assignment.py index 69af5c54c3..05b74a0dde 100644 --- a/erpnext/hr/doctype/shift_assignment/shift_assignment.py +++ b/erpnext/hr/doctype/shift_assignment/shift_assignment.py @@ -139,7 +139,7 @@ def get_shift_type_timing(shift_types): return shift_timing_map -def get_employee_shift(employee, for_date=nowdate(), consider_default_shift=False, next_shift_direction=None): +def get_employee_shift(employee, for_date=None, consider_default_shift=False, next_shift_direction=None): """Returns a Shift Type for the given employee on the given date. (excluding the holidays) :param employee: Employee for which shift is required. @@ -147,6 +147,8 @@ def get_employee_shift(employee, for_date=nowdate(), consider_default_shift=Fals :param consider_default_shift: If set to true, default shift is taken when no shift assignment is found. :param next_shift_direction: One of: None, 'forward', 'reverse'. Direction to look for next shift if shift not found on given date. """ + if for_date is None: + for_date = nowdate() default_shift = frappe.db.get_value('Employee', employee, 'default_shift') shift_type_name = None shift_assignment_details = frappe.db.get_value('Shift Assignment', {'employee':employee, 'start_date':('<=', for_date), 'docstatus': '1', 'status': "Active"}, ['shift_type', 'end_date']) @@ -200,9 +202,11 @@ def get_employee_shift(employee, for_date=nowdate(), consider_default_shift=Fals return get_shift_details(shift_type_name, for_date) -def get_employee_shift_timings(employee, for_timestamp=now_datetime(), consider_default_shift=False): +def get_employee_shift_timings(employee, for_timestamp=None, consider_default_shift=False): """Returns previous shift, current/upcoming shift, next_shift for the given timestamp and employee """ + if for_timestamp is None: + for_timestamp = now_datetime() # write and verify a test case for midnight shift. prev_shift = curr_shift = next_shift = None curr_shift = get_employee_shift(employee, for_timestamp.date(), consider_default_shift, 'forward') @@ -220,7 +224,7 @@ def get_employee_shift_timings(employee, for_timestamp=now_datetime(), consider_ return prev_shift, curr_shift, next_shift -def get_shift_details(shift_type_name, for_date=nowdate()): +def get_shift_details(shift_type_name, for_date=None): """Returns Shift Details which contain some additional information as described below. 'shift_details' contains the following keys: 'shift_type' - Object of DocType Shift Type, @@ -234,6 +238,8 @@ def get_shift_details(shift_type_name, for_date=nowdate()): """ if not shift_type_name: return None + if not for_date: + for_date = nowdate() shift_type = frappe.get_doc('Shift Type', shift_type_name) start_datetime = datetime.combine(for_date, datetime.min.time()) + shift_type.start_time for_date = for_date + timedelta(days=1) if shift_type.start_time > shift_type.end_time else for_date diff --git a/erpnext/hr/doctype/staffing_plan/staffing_plan.py b/erpnext/hr/doctype/staffing_plan/staffing_plan.py index 57a92b0587..93cd4e1f62 100644 --- a/erpnext/hr/doctype/staffing_plan/staffing_plan.py +++ b/erpnext/hr/doctype/staffing_plan/staffing_plan.py @@ -155,7 +155,11 @@ def get_designation_counts(designation, company): return employee_counts @frappe.whitelist() -def get_active_staffing_plan_details(company, designation, from_date=getdate(nowdate()), to_date=getdate(nowdate())): +def get_active_staffing_plan_details(company, designation, from_date=None, to_date=None): + if from_date is None: + from_date = getdate(nowdate()) + if to_date is None: + to_date = getdate(nowdate()) if not company or not designation: frappe.throw(_("Please select Company and Designation")) diff --git a/erpnext/stock/doctype/material_request/material_request.py b/erpnext/stock/doctype/material_request/material_request.py index cf98b19e7a..17df9777b1 100644 --- a/erpnext/stock/doctype/material_request/material_request.py +++ b/erpnext/stock/doctype/material_request/material_request.py @@ -296,7 +296,7 @@ def make_purchase_order(source_name, target_doc=None, args=None): return d.ordered_qty < d.stock_qty and child_filter - doclist = get_mapped_doc("Material Request", source_name, { + doclist = get_mapped_doc("Material Request", source_name, { "Material Request": { "doctype": "Purchase Order", "validation": { @@ -323,7 +323,7 @@ def make_purchase_order(source_name, target_doc=None, args=None): @frappe.whitelist() def make_request_for_quotation(source_name, target_doc=None): - doclist = get_mapped_doc("Material Request", source_name, { + doclist = get_mapped_doc("Material Request", source_name, { "Material Request": { "doctype": "Request for Quotation", "validation": { diff --git a/erpnext/stock/doctype/serial_no/serial_no.py b/erpnext/stock/doctype/serial_no/serial_no.py index 82d8aaed5b..a9254fb9ec 100644 --- a/erpnext/stock/doctype/serial_no/serial_no.py +++ b/erpnext/stock/doctype/serial_no/serial_no.py @@ -611,7 +611,9 @@ def get_pos_reserved_serial_nos(filters): return reserved_sr_nos -def fetch_serial_numbers(filters, qty, do_not_include=[]): +def fetch_serial_numbers(filters, qty, do_not_include=None): + if do_not_include is None: + do_not_include = [] batch_join_selection = "" batch_no_condition = "" batch_nos = filters.get("batch_no") diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index 19597c3d99..cbff2149d6 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -382,7 +382,7 @@ def get_basic_details(args, item, overwrite_warehouse=True): return out -def get_item_warehouse(item, args, overwrite_warehouse, defaults={}): +def get_item_warehouse(item, args, overwrite_warehouse, defaults=None): if not defaults: defaults = frappe._dict({ 'item_defaults' : get_item_defaults(item.name, args.company), From 64c1347d1e8b5d06a05de1db3f4d642d2da648cb Mon Sep 17 00:00:00 2001 From: Saqib Date: Thu, 7 Oct 2021 12:35:34 +0530 Subject: [PATCH 19/19] refactor!: remove abbreviation renaming (#27766) Co-authored-by: Ankush Menat --- erpnext/setup/doctype/company/company.js | 41 ---------------------- erpnext/setup/doctype/company/company.json | 8 +++-- erpnext/setup/doctype/company/company.py | 38 -------------------- 3 files changed, 5 insertions(+), 82 deletions(-) diff --git a/erpnext/setup/doctype/company/company.js b/erpnext/setup/doctype/company/company.js index 8403193df5..95ca3867ee 100644 --- a/erpnext/setup/doctype/company/company.js +++ b/erpnext/setup/doctype/company/company.js @@ -46,43 +46,6 @@ frappe.ui.form.on("Company", { }); }, - change_abbreviation(frm) { - var dialog = new frappe.ui.Dialog({ - title: "Replace Abbr", - fields: [ - {"fieldtype": "Data", "label": "New Abbreviation", "fieldname": "new_abbr", - "reqd": 1 }, - {"fieldtype": "Button", "label": "Update", "fieldname": "update"}, - ] - }); - - dialog.fields_dict.update.$input.click(function() { - var args = dialog.get_values(); - if (!args) return; - frappe.show_alert(__("Update in progress. It might take a while.")); - return frappe.call({ - method: "erpnext.setup.doctype.company.company.enqueue_replace_abbr", - args: { - "company": frm.doc.name, - "old": frm.doc.abbr, - "new": args.new_abbr - }, - callback: function(r) { - if (r.exc) { - frappe.msgprint(__("There were errors.")); - return; - } else { - frm.set_value("abbr", args.new_abbr); - } - dialog.hide(); - frm.refresh(); - }, - btn: this - }); - }); - dialog.show(); - }, - company_name: function(frm) { if(frm.doc.__islocal) { // add missing " " arg in split method @@ -164,10 +127,6 @@ frappe.ui.form.on("Company", { }, __('Manage')); } } - - frm.add_custom_button(__('Change Abbreviation'), () => { - frm.trigger('change_abbreviation'); - }, __('Manage')); } erpnext.company.set_chart_of_accounts_options(frm.doc); diff --git a/erpnext/setup/doctype/company/company.json b/erpnext/setup/doctype/company/company.json index 58cb52c04d..63d96bf85e 100644 --- a/erpnext/setup/doctype/company/company.json +++ b/erpnext/setup/doctype/company/company.json @@ -125,7 +125,8 @@ "label": "Abbr", "oldfieldname": "abbr", "oldfieldtype": "Data", - "reqd": 1 + "reqd": 1, + "set_only_once": 1 }, { "bold": 1, @@ -747,10 +748,11 @@ "image_field": "company_logo", "is_tree": 1, "links": [], - "modified": "2021-07-12 11:27:06.353860", + "modified": "2021-10-04 12:09:25.833133", "modified_by": "Administrator", "module": "Setup", "name": "Company", + "naming_rule": "By fieldname", "nsm_parent_field": "parent_company", "owner": "Administrator", "permissions": [ @@ -808,4 +810,4 @@ "sort_field": "modified", "sort_order": "ASC", "track_changes": 1 -} +} \ No newline at end of file diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py index 87d67a5f9d..0b1b4a1ec0 100644 --- a/erpnext/setup/doctype/company/company.py +++ b/erpnext/setup/doctype/company/company.py @@ -399,44 +399,6 @@ class Company(NestedSet): if not frappe.db.get_value('GL Entry', {'company': self.name}): frappe.db.sql("delete from `tabProcess Deferred Accounting` where company=%s", self.name) -@frappe.whitelist() -def enqueue_replace_abbr(company, old, new): - kwargs = dict(queue="long", company=company, old=old, new=new) - frappe.enqueue('erpnext.setup.doctype.company.company.replace_abbr', **kwargs) - - -@frappe.whitelist() -def replace_abbr(company, old, new): - new = new.strip() - if not new: - frappe.throw(_("Abbr can not be blank or space")) - - frappe.only_for("System Manager") - - def _rename_record(doc): - parts = doc[0].rsplit(" - ", 1) - if len(parts) == 1 or parts[1].lower() == old.lower(): - frappe.rename_doc(dt, doc[0], parts[0] + " - " + new, force=True) - - def _rename_records(dt): - # rename is expensive so let's be economical with memory usage - doc = (d for d in frappe.db.sql("select name from `tab%s` where company=%s" % (dt, '%s'), company)) - for d in doc: - _rename_record(d) - try: - frappe.db.auto_commit_on_many_writes = 1 - for dt in ["Warehouse", "Account", "Cost Center", "Department", - "Sales Taxes and Charges Template", "Purchase Taxes and Charges Template"]: - _rename_records(dt) - frappe.db.commit() - frappe.db.set_value("Company", company, "abbr", new) - - except Exception: - frappe.log_error(title=_('Abbreviation Rename Error')) - finally: - frappe.db.auto_commit_on_many_writes = 0 - - def get_name_with_abbr(name, company): company_abbr = frappe.get_cached_value('Company', company, "abbr") parts = name.split(" - ")