From d8de7fccc2f27efe3b45b6ae1ba89ba8ab96521a Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Fri, 14 May 2021 19:17:28 +0530 Subject: [PATCH 01/20] feat: Show net values in Party Accounts --- .../report/general_ledger/general_ledger.js | 5 ++++ .../report/general_ledger/general_ledger.py | 27 +++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/erpnext/accounts/report/general_ledger/general_ledger.js b/erpnext/accounts/report/general_ledger/general_ledger.js index fb0d359926..84f786814d 100644 --- a/erpnext/accounts/report/general_ledger/general_ledger.js +++ b/erpnext/accounts/report/general_ledger/general_ledger.js @@ -166,6 +166,11 @@ frappe.query_reports["General Ledger"] = { "fieldname": "show_cancelled_entries", "label": __("Show Cancelled Entries"), "fieldtype": "Check" + }, + { + "fieldname": "show_net_values_in_party_account", + "label": __("Show Net Values in Party Account"), + "fieldtype": "Check" } ] } diff --git a/erpnext/accounts/report/general_ledger/general_ledger.py b/erpnext/accounts/report/general_ledger/general_ledger.py index b5d7992604..562df4f6f7 100644 --- a/erpnext/accounts/report/general_ledger/general_ledger.py +++ b/erpnext/accounts/report/general_ledger/general_ledger.py @@ -344,6 +344,9 @@ def get_accountwise_gle(filters, accounting_dimensions, gl_entries, gle_map): consolidated_gle = OrderedDict() group_by = group_by_field(filters.get('group_by')) + if filters.get('show_net_values_in_party_account'): + account_type_map = get_account_type_map(filters.get('company')) + def update_value_in_dict(data, key, gle): data[key].debit += flt(gle.debit) data[key].credit += flt(gle.credit) @@ -351,6 +354,24 @@ def get_accountwise_gle(filters, accounting_dimensions, gl_entries, gle_map): data[key].debit_in_account_currency += flt(gle.debit_in_account_currency) data[key].credit_in_account_currency += flt(gle.credit_in_account_currency) + if filters.get('show_net_values_in_party_account') and \ + account_type_map.get(data[key].account) in ('Receivable', 'Payable'): + net_value = flt(data[key].debit) - flt(data[key].credit) + net_value_in_account_currency = flt(data[key].debit_in_account_currency) \ + - flt(data[key].credit_in_account_currency) + + if net_value < 0: + dr_or_cr = 'credit' + rev_dr_or_cr = 'debit' + else: + dr_or_cr = 'debit' + rev_dr_or_cr = 'credit' + + data[key][dr_or_cr] = abs(net_value) + data[key][dr_or_cr+'_in_account_currency'] = abs(net_value_in_account_currency) + data[key][rev_dr_or_cr] = 0 + data[key][rev_dr_or_cr+'_in_account_currency'] = 0 + if data[key].against_voucher and gle.against_voucher: data[key].against_voucher += ', ' + gle.against_voucher @@ -388,6 +409,12 @@ def get_accountwise_gle(filters, accounting_dimensions, gl_entries, gle_map): return totals, entries +def get_account_type_map(company): + account_type_map = frappe._dict(frappe.get_all('Account', fields=['name', 'account_type'], + filters={'company': company}, as_list=1)) + + return account_type_map + def get_result_as_list(data, filters): balance, balance_in_account_currency = 0, 0 inv_details = get_supplier_invoice_details() From 605ea044f37510cf8f12daf2a5f82a5ea44d3002 Mon Sep 17 00:00:00 2001 From: Anuja P Date: Fri, 21 May 2021 11:24:33 +0530 Subject: [PATCH 02/20] fix: update process SOA format --- .../process_statement_of_accounts.html | 118 ++++++++++-------- .../process_statement_of_accounts.json | 19 ++- .../process_statement_of_accounts.py | 8 +- 3 files changed, 92 insertions(+), 53 deletions(-) diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.html b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.html index f61aacbce2..7328f168e3 100644 --- a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.html +++ b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.html @@ -1,24 +1,42 @@ -

{{ filters.party[0] }}

-

{{ _("Statement of Accounts") }}

+
+
+ {% if letter_head %} +
{{ letter_head.content }}
+
+ {% endif %} +
+ +

{{ _("STATEMENTS OF ACCOUNTS") }}

+
+
{{ _("Customer: ") }} {{filters.party[0] }}
+
+ {{ _("Date: ") }} + {{ frappe.format(filters.from_date, 'Date')}} + {{ _("to") }} + {{ frappe.format(filters.to_date, 'Date')}} +
+
+
-
- {{ frappe.format(filters.from_date, 'Date')}} - {{ _("to") }} - {{ frappe.format(filters.to_date, 'Date')}} -
- - - - - - - - - - - - - +
{{ _("Date") }}{{ _("Ref") }}{{ _("Party") }}{{ _("Debit") }}{{ _("Credit") }}{{ _("Balance (Dr - Cr)") }}
+ + + + + + + + + + + {% for row in data %} {% if(row.posting_date) %} @@ -58,32 +76,34 @@ {% endfor %} -
{{ _("Date") }}{{ _("Reference") }}{{ _("Remarks") }}{{ _("Debit") }}{{ _("Credit") }}{{ _("Balance (Dr - Cr)") }}
-

-{% if ageing %} -

{{ _("Ageing Report Based On ") }} {{ ageing.ageing_based_on }}

-
- {{ _("Up to " ) }} {{ frappe.format(filters.to_date, 'Date')}} -
-
- - - - - - - - - - - - - - - - - - -
30 Days60 Days90 Days120 Days
{{ frappe.utils.fmt_money(ageing.range1, currency=filters.presentation_currency) }}{{ frappe.utils.fmt_money(ageing.range2, currency=filters.presentation_currency) }}{{ frappe.utils.fmt_money(ageing.range3, currency=filters.presentation_currency) }}{{ frappe.utils.fmt_money(ageing.range4, currency=filters.presentation_currency) }}
-{% endif %} -

Printed On {{ frappe.format(frappe.utils.get_datetime(), 'Datetime') }}

\ No newline at end of file + +
+ {% if ageing %} +

{{ _("Ageing Report based on ") }} {{ ageing.ageing_based_on }} + {{ _("up to " ) }} {{ frappe.format(filters.to_date, 'Date')}} +

+ + + + + + + + + + + + + + + + + +
30 Days60 Days90 Days120 Days
{{ frappe.utils.fmt_money(ageing.range1, currency=filters.presentation_currency) }}{{ frappe.utils.fmt_money(ageing.range2, currency=filters.presentation_currency) }}{{ frappe.utils.fmt_money(ageing.range3, currency=filters.presentation_currency) }}{{ frappe.utils.fmt_money(ageing.range4, currency=filters.presentation_currency) }}
+ {% endif %} + {% if terms_and_conditions %} +
+ {{ terms_and_conditions }} +
+ {% endif %} +
\ No newline at end of file diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.json b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.json index 4be0e2ec06..27a5f50ce2 100644 --- a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.json +++ b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.json @@ -1,6 +1,5 @@ { "actions": [], - "allow_workflow": 1, "autoname": "Prompt", "creation": "2020-05-22 16:46:18.712954", "doctype": "DocType", @@ -28,9 +27,11 @@ "customers", "preferences", "orientation", - "section_break_14", "include_ageing", "ageing_based_on", + "section_break_14", + "letter_head", + "terms_and_conditions", "section_break_1", "enable_auto_email", "section_break_18", @@ -270,10 +271,22 @@ "fieldname": "body", "fieldtype": "Text Editor", "label": "Body" + }, + { + "fieldname": "letter_head", + "fieldtype": "Link", + "label": "Letter Head", + "options": "Letter Head" + }, + { + "fieldname": "terms_and_conditions", + "fieldtype": "Link", + "label": "Terms and Conditions", + "options": "Terms and Conditions" } ], "links": [], - "modified": "2020-08-08 08:47:09.185728", + "modified": "2021-05-21 10:14:22.426672", "modified_by": "Administrator", "module": "Accounts", "name": "Process Statement Of Accounts", diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py index a0dbff3db4..2ad455c48f 100644 --- a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py +++ b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py @@ -64,6 +64,9 @@ def get_report_pdf(doc, consolidated=True): tax_id = frappe.get_doc('Customer', entry.customer).tax_id presentation_currency = get_party_account_currency('Customer', entry.customer, doc.company) \ or doc.currency or get_company_currency(doc.company) + if doc.letter_head: + from frappe.www.printview import get_letter_head + letter_head = get_letter_head(doc, 0) filters= frappe._dict({ 'from_date': doc.from_date, @@ -91,7 +94,10 @@ def get_report_pdf(doc, consolidated=True): continue html = frappe.render_template(template_path, \ - {"filters": filters, "data": res, "ageing": ageing[0] if (doc.include_ageing and ageing) else None}) + {"filters": filters, "data": res, "ageing": ageing[0] if doc.include_ageing else None, + "letter_head": letter_head if doc.letter_head else None, + "terms_and_conditions": frappe.db.get_value('Terms and Conditions', doc.terms_and_conditions, 'terms') + if doc.terms_and_conditions else None}) html = frappe.render_template(base_template_path, {"body": html, \ "css": get_print_style(), "title": "Statement For " + entry.customer}) From 795909fdcd0b682c54129b7226a93b99f1240db1 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Fri, 21 May 2021 11:23:20 +0530 Subject: [PATCH 03/20] fix: warehouse not found in stock entry --- erpnext/stock/doctype/stock_entry/stock_entry.js | 4 ++-- erpnext/stock/doctype/stock_entry/stock_entry.json | 4 +++- .../doctype/stock_entry_type/stock_entry_type.json | 12 ++++++++++-- .../doctype/stock_entry_type/stock_entry_type.py | 4 +++- 4 files changed, 18 insertions(+), 6 deletions(-) diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js index daa1e51182..a40ef001ee 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.js +++ b/erpnext/stock/doctype/stock_entry/stock_entry.js @@ -600,7 +600,6 @@ frappe.ui.form.on('Stock Entry', { add_to_transit: function(frm) { if(frm.doc.add_to_transit && frm.doc.purpose=='Material Transfer') { frm.set_value('to_warehouse', ''); - frm.set_value('stock_entry_type', 'Material Transfer'); frm.fields_dict.to_warehouse.get_query = function() { return { filters:{ @@ -615,7 +614,8 @@ frappe.ui.form.on('Stock Entry', { }, set_tansit_warehouse: function(frm) { - if(frm.doc.add_to_transit && frm.doc.purpose == 'Material Transfer' && !frm.doc.to_warehouse) { + if(frm.doc.add_to_transit && frm.doc.purpose == 'Material Transfer' && !frm.doc.to_warehouse + && frm.doc.from_warehouse) { let dt = frm.doc.from_warehouse ? 'Warehouse' : 'Company'; let dn = frm.doc.from_warehouse ? frm.doc.from_warehouse : frm.doc.company; frappe.db.get_value(dt, dn, 'default_in_transit_warehouse', (r) => { diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.json b/erpnext/stock/doctype/stock_entry/stock_entry.json index 98c047a09e..7f94591005 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.json +++ b/erpnext/stock/doctype/stock_entry/stock_entry.json @@ -637,6 +637,8 @@ { "default": "0", "depends_on": "eval: doc.purpose=='Material Transfer' && !doc.outgoing_stock_entry", + "fetch_from": "stock_entry_type.add_to_transit", + "fetch_if_empty": 1, "fieldname": "add_to_transit", "fieldtype": "Check", "label": "Add to Transit", @@ -655,7 +657,7 @@ "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2020-12-09 14:58:13.267321", + "modified": "2021-05-21 11:29:11.917161", "modified_by": "Administrator", "module": "Stock", "name": "Stock Entry", diff --git a/erpnext/stock/doctype/stock_entry_type/stock_entry_type.json b/erpnext/stock/doctype/stock_entry_type/stock_entry_type.json index 0f2b55ec34..eee38be027 100644 --- a/erpnext/stock/doctype/stock_entry_type/stock_entry_type.json +++ b/erpnext/stock/doctype/stock_entry_type/stock_entry_type.json @@ -6,7 +6,8 @@ "editable_grid": 1, "engine": "InnoDB", "field_order": [ - "purpose" + "purpose", + "add_to_transit" ], "fields": [ { @@ -18,10 +19,17 @@ "options": "\nMaterial Issue\nMaterial Receipt\nMaterial Transfer\nMaterial Transfer for Manufacture\nMaterial Consumption for Manufacture\nManufacture\nRepack\nSend to Subcontractor", "reqd": 1, "set_only_once": 1 + }, + { + "default": "0", + "depends_on": "eval: doc.purpose == 'Material Transfer'", + "fieldname": "add_to_transit", + "fieldtype": "Check", + "label": "Add to Transit" } ], "links": [], - "modified": "2020-08-10 23:24:37.160817", + "modified": "2021-05-21 11:27:01.144110", "modified_by": "Administrator", "module": "Stock", "name": "Stock Entry Type", diff --git a/erpnext/stock/doctype/stock_entry_type/stock_entry_type.py b/erpnext/stock/doctype/stock_entry_type/stock_entry_type.py index a4116aba2c..1069ec8713 100644 --- a/erpnext/stock/doctype/stock_entry_type/stock_entry_type.py +++ b/erpnext/stock/doctype/stock_entry_type/stock_entry_type.py @@ -7,4 +7,6 @@ from __future__ import unicode_literals from frappe.model.document import Document class StockEntryType(Document): - pass + def validate(self): + if self.add_to_transit and self.purpose != 'Material Transfer': + self.add_to_transit = 0 From ce88c945cd420c001bf786476a62f6e17ebf7692 Mon Sep 17 00:00:00 2001 From: rohitwaghchaure Date: Mon, 24 May 2021 11:53:27 +0530 Subject: [PATCH 04/20] Update stock_entry.js --- erpnext/stock/doctype/stock_entry/stock_entry.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js index a40ef001ee..de23e769f8 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.js +++ b/erpnext/stock/doctype/stock_entry/stock_entry.js @@ -609,11 +609,11 @@ frappe.ui.form.on('Stock Entry', { } }; }; - frm.trigger('set_tansit_warehouse'); + frm.trigger('set_transit_warehouse'); } }, - set_tansit_warehouse: function(frm) { + set_transit_warehouse: function(frm) { if(frm.doc.add_to_transit && frm.doc.purpose == 'Material Transfer' && !frm.doc.to_warehouse && frm.doc.from_warehouse) { let dt = frm.doc.from_warehouse ? 'Warehouse' : 'Company'; @@ -985,7 +985,7 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({ }, from_warehouse: function(doc) { - this.frm.trigger('set_tansit_warehouse'); + this.frm.trigger('set_transit_warehouse'); this.set_warehouse_in_children(doc.items, "s_warehouse", doc.from_warehouse); }, From dc7afa743c20505883df39f3aa7a151a58ef498f Mon Sep 17 00:00:00 2001 From: Jannat Patel <31363128+pateljannat@users.noreply.github.com> Date: Mon, 24 May 2021 17:33:48 +0530 Subject: [PATCH 05/20] fix: profitability test (#25812) * fix: profitability test * fix: replaced class method * fix: removed print statement --- .../project_profitability/test_project_profitability.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/erpnext/projects/report/project_profitability/test_project_profitability.py b/erpnext/projects/report/project_profitability/test_project_profitability.py index f2b9c2509a..ea6bdb54ca 100644 --- a/erpnext/projects/report/project_profitability/test_project_profitability.py +++ b/erpnext/projects/report/project_profitability/test_project_profitability.py @@ -8,7 +8,7 @@ from erpnext.projects.doctype.timesheet.timesheet import make_salary_slip, make_ from erpnext.projects.report.project_profitability.project_profitability import execute class TestProjectProfitability(unittest.TestCase): - @classmethod + def setUp(self): emp = make_employee('test_employee_9@salary.com', company='_Test Company') if not frappe.db.exists('Salary Component', 'Timesheet Component'): @@ -21,7 +21,7 @@ class TestProjectProfitability(unittest.TestCase): self.sales_invoice.due_date = nowdate() self.sales_invoice.submit() - frappe.db.set_value("HR Settings", "HR Settings", "standard_working_hours", 8) + frappe.db.set_value('HR Settings', None, 'standard_working_hours', 8) def test_project_profitability(self): filters = { @@ -55,4 +55,4 @@ class TestProjectProfitability(unittest.TestCase): def tearDown(self): frappe.get_doc("Sales Invoice", self.sales_invoice.name).cancel() frappe.get_doc("Salary Slip", self.salary_slip.name).cancel() - frappe.get_doc("Timesheet", self.timesheet.name).cancel() \ No newline at end of file + frappe.get_doc("Timesheet", self.timesheet.name).cancel() From b6d061fa8c90c678cfd2095577fbe7e3eab1f218 Mon Sep 17 00:00:00 2001 From: Saqib Date: Mon, 24 May 2021 18:22:03 +0530 Subject: [PATCH 06/20] fix(pos): handle db lock timeout error while pos closing (#25813) --- .../pos_invoice_merge_log.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py b/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py index b0ddea304c..08e072e204 100644 --- a/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py +++ b/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py @@ -42,8 +42,9 @@ class POSInvoiceMergeLog(Document): if return_against_status != "Consolidated": # if return entry is not getting merged in the current pos closing and if it is not consolidated bold_unconsolidated = frappe.bold("not Consolidated") - msg = (_("Row #{}: Original Invoice {} of return invoice {} is {}. ") + msg = (_("Row #{}: Original Invoice {} of return invoice {} is {}.") .format(d.idx, bold_return_against, bold_pos_invoice, bold_unconsolidated)) + msg += " " msg += _("Original invoice should be consolidated before or along with the return invoice.") msg += "

" msg += _("You can add original invoice {} manually to proceed.").format(bold_return_against) @@ -274,9 +275,9 @@ def create_merge_logs(invoice_by_customer, closing_entry=None): closing_entry.db_set('error_message', '') closing_entry.update_opening_entry() - except Exception: + except Exception as e: frappe.db.rollback() - message_log = frappe.message_log.pop() + message_log = frappe.message_log.pop() if frappe.message_log else str(e) error_message = safe_load_json(message_log) if closing_entry: @@ -300,9 +301,9 @@ def cancel_merge_logs(merge_logs, closing_entry=None): closing_entry.db_set('error_message', '') closing_entry.update_opening_entry(for_cancel=True) - except Exception: + except Exception as e: frappe.db.rollback() - message_log = frappe.message_log.pop() + message_log = frappe.message_log.pop() if frappe.message_log else str(e) error_message = safe_load_json(message_log) if closing_entry: @@ -348,11 +349,9 @@ def job_already_enqueued(job_name): return True def safe_load_json(message): - JSONDecodeError = ValueError if six.PY2 else json.JSONDecodeError - try: json_message = json.loads(message).get('message') - except JSONDecodeError: + except Exception: json_message = message return json_message \ No newline at end of file From dd5b31f8c45ac78b12f07b6cff31bedffbb68762 Mon Sep 17 00:00:00 2001 From: Saqib Date: Mon, 24 May 2021 18:23:03 +0530 Subject: [PATCH 07/20] fix: set disable rounded total if it is globally enabled (#25789) --- erpnext/setup/doctype/global_defaults/global_defaults.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/erpnext/setup/doctype/global_defaults/global_defaults.py b/erpnext/setup/doctype/global_defaults/global_defaults.py index e587217181..a0ba1efb5b 100644 --- a/erpnext/setup/doctype/global_defaults/global_defaults.py +++ b/erpnext/setup/doctype/global_defaults/global_defaults.py @@ -59,13 +59,15 @@ class GlobalDefaults(Document): # Make property setters to hide rounded total fields for doctype in ("Quotation", "Sales Order", "Sales Invoice", "Delivery Note", - "Supplier Quotation", "Purchase Order", "Purchase Invoice"): + "Supplier Quotation", "Purchase Order", "Purchase Invoice", "Purchase Receipt"): make_property_setter(doctype, "base_rounded_total", "hidden", self.disable_rounded_total, "Check", validate_fields_for_doctype=False) make_property_setter(doctype, "base_rounded_total", "print_hide", 1, "Check", validate_fields_for_doctype=False) make_property_setter(doctype, "rounded_total", "hidden", self.disable_rounded_total, "Check", validate_fields_for_doctype=False) make_property_setter(doctype, "rounded_total", "print_hide", self.disable_rounded_total, "Check", validate_fields_for_doctype=False) + make_property_setter(doctype, "disable_rounded_total", "default", cint(self.disable_rounded_total), "Text", validate_fields_for_doctype=False) + def toggle_in_words(self): self.disable_in_words = cint(self.disable_in_words) From c348215f61abb478fb0ddb64f4ed9b6e251897ff Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Tue, 18 May 2021 08:38:49 +0530 Subject: [PATCH 08/20] fix: Cashlfow mapper not showing data --- erpnext/accounts/report/cash_flow/custom_cash_flow.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/erpnext/accounts/report/cash_flow/custom_cash_flow.py b/erpnext/accounts/report/cash_flow/custom_cash_flow.py index fe2bc725e0..ff87276a87 100644 --- a/erpnext/accounts/report/cash_flow/custom_cash_flow.py +++ b/erpnext/accounts/report/cash_flow/custom_cash_flow.py @@ -165,7 +165,7 @@ def add_data_for_operating_activities( if profit_data: profit_data.update({ "indent": 1, - "parent_account": get_mapper_for(light_mappers, position=0)['section_header'] + "parent_account": get_mapper_for(light_mappers, position=1)['section_header'] }) data.append(profit_data) section_data.append(profit_data) @@ -312,10 +312,10 @@ def add_data_for_other_activities( def compute_data(filters, company_currency, profit_data, period_list, light_mappers, full_mapper): data = [] - operating_activities_mapper = get_mapper_for(light_mappers, position=0) + operating_activities_mapper = get_mapper_for(light_mappers, position=1) other_mappers = [ - get_mapper_for(light_mappers, position=1), - get_mapper_for(light_mappers, position=2) + get_mapper_for(light_mappers, position=2), + get_mapper_for(light_mappers, position=3) ] if operating_activities_mapper: From 25112244ed5c3a4dc62a14bacd5362d3febff356 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Fri, 14 May 2021 21:31:22 +0530 Subject: [PATCH 09/20] fix: Ignore rounding diff while importig JV using data import --- erpnext/accounts/doctype/journal_entry/journal_entry.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py index fefab82efc..ed1bd28223 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.py +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py @@ -39,7 +39,11 @@ class JournalEntry(AccountsController): self.validate_multi_currency() self.set_amounts_in_company_currency() self.validate_debit_credit_amount() - self.validate_total_debit_and_credit() + + # Do not validate while importing via data import + if not frappe.flags.in_import: + self.validate_total_debit_and_credit() + self.validate_against_jv() self.validate_reference_doc() self.set_against_account() From 5670cf43862d4de29e905e185a25fe9d50b5038c Mon Sep 17 00:00:00 2001 From: Anurag Mishra <32095923+Anurag810@users.noreply.github.com> Date: Mon, 24 May 2021 20:24:20 +0530 Subject: [PATCH 10/20] feat: enhancements in Training Event (#25782) * feat: Some Minor fixes * fix: patch file * fix: patch Co-authored-by: Rucha Mahabal --- .../doctype/training_event/training_event.js | 32 +- .../training_event_employee.json | 301 ++++-------------- .../training_scheduled.json | 8 +- .../training_scheduled/training_scheduled.md | 3 + erpnext/patches.txt | 1 + .../v13_0/set_training_event_attendance.py | 9 + 6 files changed, 113 insertions(+), 241 deletions(-) create mode 100644 erpnext/patches/v13_0/set_training_event_attendance.py diff --git a/erpnext/hr/doctype/training_event/training_event.js b/erpnext/hr/doctype/training_event/training_event.js index 12bc920b18..b7d34b178a 100644 --- a/erpnext/hr/doctype/training_event/training_event.js +++ b/erpnext/hr/doctype/training_event/training_event.js @@ -2,23 +2,41 @@ // For license information, please see license.txt frappe.ui.form.on('Training Event', { - onload_post_render: function(frm) { + onload_post_render: function (frm) { frm.get_field("employees").grid.set_multiple_add("employee"); }, - refresh: function(frm) { - if(!frm.doc.__islocal) { - frm.add_custom_button(__("Training Result"), function() { + refresh: function (frm) { + if (!frm.doc.__islocal) { + frm.add_custom_button(__("Training Result"), function () { frappe.route_options = { training_event: frm.doc.name - } + }; frappe.set_route("List", "Training Result"); }); - frm.add_custom_button(__("Training Feedback"), function() { + frm.add_custom_button(__("Training Feedback"), function () { frappe.route_options = { training_event: frm.doc.name - } + }; frappe.set_route("List", "Training Feedback"); }); } } }); + +frappe.ui.form.on("Training Event Employee", { + employee: function (frm) { + let emp = []; + for (let d in frm.doc.employees) { + if (frm.doc.employees[d].employee) { + emp.push(frm.doc.employees[d].employee); + } + } + frm.set_query("employee", "employees", function () { + return { + filters: { + name: ["NOT IN", emp] + } + }; + }); + } +}); diff --git a/erpnext/hr/doctype/training_event_employee/training_event_employee.json b/erpnext/hr/doctype/training_event_employee/training_event_employee.json index e3a40649b4..2d313e9fac 100644 --- a/erpnext/hr/doctype/training_event_employee/training_event_employee.json +++ b/erpnext/hr/doctype/training_event_employee/training_event_employee.json @@ -1,241 +1,80 @@ { - "allow_copy": 0, - "allow_events_in_timeline": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "beta": 0, - "creation": "2016-08-08 05:33:39.965305", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "", - "editable_grid": 1, + "actions": [], + "creation": "2016-08-08 05:33:39.965305", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "employee", + "employee_name", + "department", + "column_break_3", + "status", + "attendance", + "is_mandatory" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "employee", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Employee", - "length": 0, - "no_copy": 0, - "options": "Employee", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "employee", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Employee", + "options": "Employee" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_from": "employee.employee_name", - "fieldname": "employee_name", - "fieldtype": "Read Only", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Employee Name", - "length": 0, - "no_copy": 0, - "options": "", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fetch_from": "employee.employee_name", + "fieldname": "employee_name", + "fieldtype": "Read Only", + "label": "Employee Name" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_from": "employee.department", - "fieldname": "department", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Department", - "length": 0, - "no_copy": 0, - "options": "Department", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fetch_from": "employee.department", + "fieldname": "department", + "fieldtype": "Link", + "label": "Department", + "options": "Department", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_3", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "column_break_3", + "fieldtype": "Column Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 1, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "Open", - "fieldname": "status", - "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Status", - "length": 0, - "no_copy": 1, - "options": "Open\nInvited\nCompleted\nFeedback Submitted", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "allow_on_submit": 1, + "default": "Open", + "fieldname": "status", + "fieldtype": "Select", + "in_list_view": 1, + "label": "Status", + "no_copy": 1, + "options": "Open\nInvited\nCompleted\nFeedback Submitted" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "attendance", - "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Attendance", - "length": 0, - "no_copy": 0, - "options": "Mandatory\nOptional", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldname": "attendance", + "fieldtype": "Select", + "in_list_view": 1, + "label": "Attendance", + "options": "Present\nAbsent" + }, + { + "columns": 2, + "default": "1", + "fieldname": "is_mandatory", + "fieldtype": "Check", + "in_list_view": 1, + "label": "Is Mandatory" } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 1, - "max_attachments": 0, - "modified": "2019-01-30 11:28:16.170333", - "modified_by": "Administrator", - "module": "HR", - "name": "Training Event Employee", - "name_case": "", - "owner": "Administrator", - "permissions": [], - "quick_entry": 1, - "read_only": 0, - "read_only_onload": 0, - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 0, - "track_seen": 0, - "track_views": 0 + ], + "index_web_pages_for_search": 1, + "istable": 1, + "links": [], + "modified": "2021-05-21 12:41:59.336237", + "modified_by": "Administrator", + "module": "HR", + "name": "Training Event Employee", + "owner": "Administrator", + "permissions": [], + "quick_entry": 1, + "sort_field": "modified", + "sort_order": "DESC" } \ No newline at end of file diff --git a/erpnext/hr/notification/training_scheduled/training_scheduled.json b/erpnext/hr/notification/training_scheduled/training_scheduled.json index 966b887572..e49541e321 100644 --- a/erpnext/hr/notification/training_scheduled/training_scheduled.json +++ b/erpnext/hr/notification/training_scheduled/training_scheduled.json @@ -11,16 +11,18 @@ "event": "Submit", "idx": 0, "is_standard": 1, - "message": "\n \n \n \n \n \n \n \n
\n
\n {{_(\"Training Event:\")}} {{ doc.event_name }}\n
\n
\n\n\n \n \n \n \n \n \n \n
\n
\n
    \n
  • {{ doc.introduction }}
  • \n
  • {{_(\"Event Location\")}}: {{ doc.location }}
  • \n {% set start = frappe.utils.get_datetime(doc.start_time) %}\n {% set end = frappe.utils.get_datetime(doc.end_time) %}\n {% if start.date() == end.date() %}\n
  • {{_(\"Date\")}}: {{ start.strftime(\"%A, %d %b %Y\") }}
  • \n
  • \n {{_(\"Timing\")}}: {{ start.strftime(\"%I:%M %p\") + ' to ' + end.strftime(\"%I:%M %p\") }}\n
  • \n {% else %}\n
  • {{_(\"Start Time\")}}: {{ start.strftime(\"%A, %d %b %Y at %I:%M %p\") }}\n
  • \n
  • {{_(\"End Time\")}}: {{ end.strftime(\"%A, %d %b %Y at %I:%M %p\") }}\n
  • \n {% endif %}\n
\n {{ _('Event Link') }}: {{ frappe.utils.get_link_to_form(doc.doctype, doc.name) }}\n
\n
", - "modified": "2019-11-29 15:38:31.805409", + "message": "\n \n \n \n \n \n \n \n
\n
\n {{_(\"Training Event:\")}} {{ doc.event_name }}\n
\n
\n\n\n \n \n \n \n \n \n \n
\n
\n {{ doc.introduction }}\n
    \n
  • {{_(\"Event Location\")}}: {{ doc.location }}
  • \n {% set start = frappe.utils.get_datetime(doc.start_time) %}\n {% set end = frappe.utils.get_datetime(doc.end_time) %}\n {% if start.date() == end.date() %}\n
  • {{_(\"Date\")}}: {{ start.strftime(\"%A, %d %b %Y\") }}
  • \n
  • \n {{_(\"Timing\")}}: {{ start.strftime(\"%I:%M %p\") + ' to ' + end.strftime(\"%I:%M %p\") }}\n
  • \n {% else %}\n
  • {{_(\"Start Time\")}}: {{ start.strftime(\"%A, %d %b %Y at %I:%M %p\") }}\n
  • \n
  • {{_(\"End Time\")}}: {{ end.strftime(\"%A, %d %b %Y at %I:%M %p\") }}\n
  • \n {% endif %}\n
  • {{ _('Event Link') }}: {{ frappe.utils.get_link_to_form(doc.doctype, doc.name) }}
  • \n {% if doc.is_mandatory %}\n
  • Note: This Training Event is mandatory
  • \n {% endif %}\n
\n
\n
", + "modified": "2021-05-24 16:29:13.165930", "modified_by": "Administrator", "module": "HR", "name": "Training Scheduled", "owner": "Administrator", "recipients": [ { - "email_by_document_field": "employee_emails" + "receiver_by_document_field": "employee_emails" } ], + "send_system_notification": 0, + "send_to_all_assignees": 0, "subject": "Training Scheduled: {{ doc.name }}" } \ No newline at end of file diff --git a/erpnext/hr/notification/training_scheduled/training_scheduled.md b/erpnext/hr/notification/training_scheduled/training_scheduled.md index 374038ac20..418fd4990e 100644 --- a/erpnext/hr/notification/training_scheduled/training_scheduled.md +++ b/erpnext/hr/notification/training_scheduled/training_scheduled.md @@ -35,6 +35,9 @@ {% endif %}
  • {{ _('Event Link') }}: {{ frappe.utils.get_link_to_form(doc.doctype, doc.name) }}
  • + {% if doc.is_mandatory %} +
  • Note: This Training Event is mandatory
  • + {% endif %} diff --git a/erpnext/patches.txt b/erpnext/patches.txt index d4655e19b9..1e8ce3c658 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -780,3 +780,4 @@ erpnext.patches.v13_0.germany_make_custom_fields erpnext.patches.v13_0.germany_fill_debtor_creditor_number erpnext.patches.v13_0.set_pos_closing_as_failed erpnext.patches.v13_0.update_timesheet_changes +erpnext.patches.v13_0.set_training_event_attendance diff --git a/erpnext/patches/v13_0/set_training_event_attendance.py b/erpnext/patches/v13_0/set_training_event_attendance.py new file mode 100644 index 0000000000..18cad8d86c --- /dev/null +++ b/erpnext/patches/v13_0/set_training_event_attendance.py @@ -0,0 +1,9 @@ +from __future__ import unicode_literals +import frappe + +def execute(): + frappe.reload_doc('hr', 'doctype', 'training_event') + frappe.reload_doc('hr', 'doctype', 'training_event_employee') + + frappe.db.sql("update `tabTraining Event Employee` set `attendance` = 'Present'") + frappe.db.sql("update `tabTraining Event Employee` set `is_mandatory` = 1 where `attendance` = 'Mandatory'") \ No newline at end of file From b4f0347c02ded2df18156b5a999ca50b82a5ce38 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Mon, 24 May 2021 20:12:24 +0530 Subject: [PATCH 11/20] fix: removed serial no validation for sales invoice --- .../doctype/sales_invoice/sales_invoice.py | 21 ------------------- .../sales_invoice/test_sales_invoice.py | 6 ------ 2 files changed, 27 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index bb74a02606..1a1f889657 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -1121,7 +1121,6 @@ class SalesInvoice(SellingController): """ self.set_serial_no_against_delivery_note() self.validate_serial_against_delivery_note() - self.validate_serial_against_sales_invoice() def set_serial_no_against_delivery_note(self): for item in self.items: @@ -1152,26 +1151,6 @@ class SalesInvoice(SellingController): frappe.throw(_("Row {0}: {1} Serial numbers required for Item {2}. You have provided {3}.").format( item.idx, item.qty, item.item_code, len(si_serial_nos))) - def validate_serial_against_sales_invoice(self): - """ check if serial number is already used in other sales invoice """ - for item in self.items: - if not item.serial_no: - continue - - for serial_no in item.serial_no.split("\n"): - serial_no_details = frappe.db.get_value("Serial No", serial_no, - ["sales_invoice", "item_code"], as_dict=1) - - if not serial_no_details: - continue - - if serial_no_details.sales_invoice and serial_no_details.item_code == item.item_code \ - and self.name != serial_no_details.sales_invoice: - sales_invoice_company = frappe.db.get_value("Sales Invoice", serial_no_details.sales_invoice, "company") - if sales_invoice_company == self.company: - frappe.throw(_("Serial Number: {0} is already referenced in Sales Invoice: {1}") - .format(serial_no, serial_no_details.sales_invoice)) - def update_project(self): if self.project: project = frappe.get_doc("Project", self.project) diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index 9059d0b040..df6d483904 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -933,12 +933,6 @@ class TestSalesInvoice(unittest.TestCase): self.assertFalse(frappe.db.get_value("Serial No", serial_nos[0], "warehouse")) self.assertEqual(frappe.db.get_value("Serial No", serial_nos[0], "delivery_document_no"), si.name) - self.assertEqual(frappe.db.get_value("Serial No", serial_nos[0], "sales_invoice"), - si.name) - - # check if the serial number is already linked with any other Sales Invoice - _si = frappe.copy_doc(si.as_dict()) - self.assertRaises(frappe.ValidationError, _si.insert) return si From 073dcf7e4265539ee521c489202aceb0c38cf84a Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Tue, 25 May 2021 14:06:10 +0530 Subject: [PATCH 12/20] ci(semgrep): fix false positives (#25823) --- .github/helper/semgrep_rules/translate.py | 8 ++++++++ .github/helper/semgrep_rules/translate.yml | 4 ++-- .github/helper/semgrep_rules/ux.js | 9 +++++++++ .github/helper/semgrep_rules/ux.py | 18 ++++++++--------- .github/helper/semgrep_rules/ux.yml | 23 ++++++++++++++++++---- 5 files changed, 47 insertions(+), 15 deletions(-) create mode 100644 .github/helper/semgrep_rules/ux.js diff --git a/.github/helper/semgrep_rules/translate.py b/.github/helper/semgrep_rules/translate.py index bd6cd9126c..9de6aa94f0 100644 --- a/.github/helper/semgrep_rules/translate.py +++ b/.github/helper/semgrep_rules/translate.py @@ -51,3 +51,11 @@ _(f"what" + f"this is also not cool") _("") # ruleid: frappe-translation-empty-string _('') + + +class Test: + # ok: frappe-translation-python-splitting + def __init__( + args + ): + pass diff --git a/.github/helper/semgrep_rules/translate.yml b/.github/helper/semgrep_rules/translate.yml index fa4ec9e15d..5f03fb9fd0 100644 --- a/.github/helper/semgrep_rules/translate.yml +++ b/.github/helper/semgrep_rules/translate.yml @@ -44,8 +44,8 @@ rules: pattern-either: - pattern: _(...) + _(...) - pattern: _("..." + "...") - - pattern-regex: '_\([^\)]*\\\s*' # lines broken by `\` - - pattern-regex: '_\(\s*\n' # line breaks allowed by python for using ( ) + - pattern-regex: '[\s\.]_\([^\)]*\\\s*' # lines broken by `\` + - pattern-regex: '[\s\.]_\(\s*\n' # line breaks allowed by python for using ( ) message: | Do not split strings inside translate function. Do not concatenate using translate functions. Please refer: https://frappeframework.com/docs/user/en/translations diff --git a/.github/helper/semgrep_rules/ux.js b/.github/helper/semgrep_rules/ux.js new file mode 100644 index 0000000000..ae73f9cc60 --- /dev/null +++ b/.github/helper/semgrep_rules/ux.js @@ -0,0 +1,9 @@ + +// ok: frappe-missing-translate-function-js +frappe.msgprint('{{ _("Both login and password required") }}'); + +// ruleid: frappe-missing-translate-function-js +frappe.msgprint('What'); + +// ok: frappe-missing-translate-function-js +frappe.throw(' {{ _("Both login and password required") }}. '); diff --git a/.github/helper/semgrep_rules/ux.py b/.github/helper/semgrep_rules/ux.py index 4a74457435..a00d3cd8ae 100644 --- a/.github/helper/semgrep_rules/ux.py +++ b/.github/helper/semgrep_rules/ux.py @@ -2,30 +2,30 @@ import frappe from frappe import msgprint, throw, _ -# ruleid: frappe-missing-translate-function +# ruleid: frappe-missing-translate-function-python throw("Error Occured") -# ruleid: frappe-missing-translate-function +# ruleid: frappe-missing-translate-function-python frappe.throw("Error Occured") -# ruleid: frappe-missing-translate-function +# ruleid: frappe-missing-translate-function-python frappe.msgprint("Useful message") -# ruleid: frappe-missing-translate-function +# ruleid: frappe-missing-translate-function-python msgprint("Useful message") -# ok: frappe-missing-translate-function +# ok: frappe-missing-translate-function-python translatedmessage = _("Hello") -# ok: frappe-missing-translate-function +# ok: frappe-missing-translate-function-python throw(translatedmessage) -# ok: frappe-missing-translate-function +# ok: frappe-missing-translate-function-python msgprint(translatedmessage) -# ok: frappe-missing-translate-function +# ok: frappe-missing-translate-function-python msgprint(_("Helpful message")) -# ok: frappe-missing-translate-function +# ok: frappe-missing-translate-function-python frappe.throw(_("Error occured")) diff --git a/.github/helper/semgrep_rules/ux.yml b/.github/helper/semgrep_rules/ux.yml index ed06a6a80c..dd667f36c0 100644 --- a/.github/helper/semgrep_rules/ux.yml +++ b/.github/helper/semgrep_rules/ux.yml @@ -1,15 +1,30 @@ rules: -- id: frappe-missing-translate-function +- id: frappe-missing-translate-function-python pattern-either: - patterns: - pattern: frappe.msgprint("...", ...) - pattern-not: frappe.msgprint(_("..."), ...) - - pattern-not: frappe.msgprint(__("..."), ...) - patterns: - pattern: frappe.throw("...", ...) - pattern-not: frappe.throw(_("..."), ...) - - pattern-not: frappe.throw(__("..."), ...) message: | All user facing text must be wrapped in translate function. Please refer to translation documentation. https://frappeframework.com/docs/user/en/guides/basics/translations - languages: [python, javascript, json] + languages: [python] + severity: ERROR + +- id: frappe-missing-translate-function-js + pattern-either: + - patterns: + - pattern: frappe.msgprint("...", ...) + - pattern-not: frappe.msgprint(__("..."), ...) + # ignore microtemplating e.g. msgprint("{{ _("server side translation") }}") + - pattern-not: frappe.msgprint("=~/\{\{.*\_.*\}\}/i", ...) + - patterns: + - pattern: frappe.throw("...", ...) + - pattern-not: frappe.throw(__("..."), ...) + # ignore microtemplating + - pattern-not: frappe.throw("=~/\{\{.*\_.*\}\}/i", ...) + message: | + All user facing text must be wrapped in translate function. Please refer to translation documentation. https://frappeframework.com/docs/user/en/guides/basics/translations + languages: [javascript] severity: ERROR From 507a211c81c13cf8ea2b2ed401f703d6675b207c Mon Sep 17 00:00:00 2001 From: Rakshith N <36509967+rakshithrddy@users.noreply.github.com> Date: Tue, 25 May 2021 19:03:29 +0530 Subject: [PATCH 13/20] fix: fetch email id from dialog box in pos past order summary' (#25808) --- erpnext/selling/page/point_of_sale/pos_past_order_summary.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/selling/page/point_of_sale/pos_past_order_summary.js b/erpnext/selling/page/point_of_sale/pos_past_order_summary.js index acf4eb371f..cec831d616 100644 --- a/erpnext/selling/page/point_of_sale/pos_past_order_summary.js +++ b/erpnext/selling/page/point_of_sale/pos_past_order_summary.js @@ -241,7 +241,7 @@ erpnext.PointOfSale.PastOrderSummary = class { send_email() { const frm = this.events.get_frm(); - const recipients = this.email_dialog.get_values().recipients; + const recipients = this.email_dialog.get_values().email_id; const doc = this.doc || frm.doc; const print_format = frm.pos_print_format; From 6a62ad325f8d5abb350326a14f81a1e6f91db836 Mon Sep 17 00:00:00 2001 From: Laurynas Sakalauskas Date: Tue, 25 May 2021 16:39:44 +0300 Subject: [PATCH 14/20] fix(plaid): withdrawals and deposits are recorded incorrectly (#25784) --- .../doctype/plaid_settings/plaid_settings.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py index 21f1db619e..ce15e47c5e 100644 --- a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py +++ b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py @@ -183,11 +183,11 @@ def new_bank_transaction(transaction): bank_account = frappe.db.get_value("Bank Account", dict(integration_id=transaction["account_id"])) if float(transaction["amount"]) >= 0: - debit = float(transaction["amount"]) - credit = 0 - else: debit = 0 - credit = abs(float(transaction["amount"])) + credit = float(transaction["amount"]) + else: + debit = abs(float(transaction["amount"])) + credit = 0 status = "Pending" if transaction["pending"] == "True" else "Settled" From 4d61fa249786f294110afa85e6278ffb5a282b85 Mon Sep 17 00:00:00 2001 From: Afshan <33727827+AfshanKhan@users.noreply.github.com> Date: Tue, 25 May 2021 19:16:02 +0530 Subject: [PATCH 15/20] fix: incorrect cr/dr shown in general ledger for multi-currency transactions (#25654) --- erpnext/accounts/report/utils.py | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/erpnext/accounts/report/utils.py b/erpnext/accounts/report/utils.py index 9de8d19f2a..b020d0a506 100644 --- a/erpnext/accounts/report/utils.py +++ b/erpnext/accounts/report/utils.py @@ -81,8 +81,7 @@ def convert_to_presentation_currency(gl_entries, currency_info, company): presentation_currency = currency_info['presentation_currency'] company_currency = currency_info['company_currency'] - pl_accounts = [d.name for d in frappe.get_list('Account', - filters={'report_type': 'Profit and Loss', 'company': company})] + account_currencies = list(set(entry['account_currency'] for entry in gl_entries)) for entry in gl_entries: account = entry['account'] @@ -92,10 +91,15 @@ def convert_to_presentation_currency(gl_entries, currency_info, company): credit_in_account_currency = flt(entry['credit_in_account_currency']) account_currency = entry['account_currency'] - if account_currency != presentation_currency: - value = debit or credit + if len(account_currencies) == 1 and account_currency == presentation_currency: + if entry.get('debit'): + entry['debit'] = debit_in_account_currency - date = entry['posting_date'] if account in pl_accounts else currency_info['report_date'] + if entry.get('credit'): + entry['credit'] = credit_in_account_currency + else: + value = debit or credit + date = currency_info['report_date'] converted_value = convert(value, presentation_currency, company_currency, date) if entry.get('debit'): @@ -104,13 +108,6 @@ def convert_to_presentation_currency(gl_entries, currency_info, company): if entry.get('credit'): entry['credit'] = converted_value - elif account_currency == presentation_currency: - if entry.get('debit'): - entry['debit'] = debit_in_account_currency - - if entry.get('credit'): - entry['credit'] = credit_in_account_currency - converted_gl_list.append(entry) return converted_gl_list From 99636c6aca8a3a0faf6e69f777d75f0d75c3c73b Mon Sep 17 00:00:00 2001 From: Ganga Manoj Date: Tue, 25 May 2021 19:17:01 +0530 Subject: [PATCH 16/20] fix: rearrange buttons for company doctype (#25617) --- erpnext/setup/doctype/company/company.js | 27 ++++++++-------------- erpnext/setup/doctype/company/company.json | 8 +------ 2 files changed, 11 insertions(+), 24 deletions(-) diff --git a/erpnext/setup/doctype/company/company.js b/erpnext/setup/doctype/company/company.js index 9957aad019..b24048d1ce 100644 --- a/erpnext/setup/doctype/company/company.js +++ b/erpnext/setup/doctype/company/company.js @@ -90,12 +90,6 @@ frappe.ui.form.on("Company", { frm.toggle_enable("default_currency", (frm.doc.__onload && !frm.doc.__onload.transactions_exist)); - if (frm.has_perm('write')) { - frm.add_custom_button(__('Create Tax Template'), function() { - frm.trigger("make_default_tax_template"); - }); - } - if (frappe.perm.has_perm("Cost Center", 0, 'read')) { frm.add_custom_button(__('Cost Centers'), function() { frappe.set_route('Tree', 'Cost Center', {'company': frm.doc.name}); @@ -121,17 +115,21 @@ frappe.ui.form.on("Company", { } if (frm.has_perm('write')) { - frm.add_custom_button(__('Default Tax Template'), function() { + frm.add_custom_button(__('Create Tax Template'), function() { frm.trigger("make_default_tax_template"); - }, __('Create')); + }, __('Manage')); + } + + if (frappe.user.has_role('System Manager')) { + if (frm.has_perm('write')) { + frm.add_custom_button(__('Delete Transactions'), function() { + frm.trigger("delete_company_transactions"); + }, __('Manage')); + } } } erpnext.company.set_chart_of_accounts_options(frm.doc); - - if (!frappe.user.has_role('System Manager')) { - frm.get_field("delete_company_transactions").hide(); - } }, make_default_tax_template: function(frm) { @@ -145,11 +143,6 @@ frappe.ui.form.on("Company", { }) }, - onload_post_render: function(frm) { - if(frm.get_field("delete_company_transactions").$input) - frm.get_field("delete_company_transactions").$input.addClass("btn-danger"); - }, - country: function(frm) { 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 83cbf475ab..061986d92d 100644 --- a/erpnext/setup/doctype/company/company.json +++ b/erpnext/setup/doctype/company/company.json @@ -99,7 +99,6 @@ "company_description", "registration_info", "registration_details", - "delete_company_transactions", "lft", "rgt", "old_parent" @@ -666,11 +665,6 @@ "oldfieldname": "registration_details", "oldfieldtype": "Code" }, - { - "fieldname": "delete_company_transactions", - "fieldtype": "Button", - "label": "Delete Company Transactions" - }, { "fieldname": "lft", "fieldtype": "Int", @@ -747,7 +741,7 @@ "image_field": "company_logo", "is_tree": 1, "links": [], - "modified": "2021-02-16 15:53:37.167589", + "modified": "2021-05-07 03:11:28.189740", "modified_by": "Administrator", "module": "Setup", "name": "Company", From 18cfced0320f567bd985db050a4260bd3db31331 Mon Sep 17 00:00:00 2001 From: Ganga Manoj Date: Tue, 25 May 2021 19:54:07 +0530 Subject: [PATCH 17/20] fix(Material Request): Make status on list and form view the same (#24856) --- erpnext/controllers/status_updater.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/controllers/status_updater.py b/erpnext/controllers/status_updater.py index ed3aee5c1a..83d4c33140 100644 --- a/erpnext/controllers/status_updater.py +++ b/erpnext/controllers/status_updater.py @@ -76,12 +76,12 @@ status_map = { ["Stopped", "eval:self.status == 'Stopped'"], ["Cancelled", "eval:self.docstatus == 2"], ["Pending", "eval:self.status != 'Stopped' and self.per_ordered == 0 and self.docstatus == 1"], - ["Partially Ordered", "eval:self.status != 'Stopped' and self.per_ordered < 100 and self.per_ordered > 0 and self.docstatus == 1"], ["Ordered", "eval:self.status != 'Stopped' and self.per_ordered == 100 and self.docstatus == 1 and self.material_request_type == 'Purchase'"], ["Transferred", "eval:self.status != 'Stopped' and self.per_ordered == 100 and self.docstatus == 1 and self.material_request_type == 'Material Transfer'"], ["Issued", "eval:self.status != 'Stopped' and self.per_ordered == 100 and self.docstatus == 1 and self.material_request_type == 'Material Issue'"], ["Received", "eval:self.status != 'Stopped' and self.per_received == 100 and self.docstatus == 1 and self.material_request_type == 'Purchase'"], ["Partially Received", "eval:self.status != 'Stopped' and self.per_received > 0 and self.per_received < 100 and self.docstatus == 1 and self.material_request_type == 'Purchase'"], + ["Partially Ordered", "eval:self.status != 'Stopped' and self.per_ordered < 100 and self.per_ordered > 0 and self.docstatus == 1"], ["Manufactured", "eval:self.status != 'Stopped' and self.per_ordered == 100 and self.docstatus == 1 and self.material_request_type == 'Manufacture'"] ], "Bank Transaction": [ From 81376ea44f8d3afc4db1aad34028ce80eeeed94d Mon Sep 17 00:00:00 2001 From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com> Date: Tue, 25 May 2021 20:39:17 +0530 Subject: [PATCH 18/20] feat: Show net values in Party Accounts (#25714) --- .../report/general_ledger/general_ledger.js | 5 ++++ .../report/general_ledger/general_ledger.py | 27 +++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/erpnext/accounts/report/general_ledger/general_ledger.js b/erpnext/accounts/report/general_ledger/general_ledger.js index fb0d359926..84f786814d 100644 --- a/erpnext/accounts/report/general_ledger/general_ledger.js +++ b/erpnext/accounts/report/general_ledger/general_ledger.js @@ -166,6 +166,11 @@ frappe.query_reports["General Ledger"] = { "fieldname": "show_cancelled_entries", "label": __("Show Cancelled Entries"), "fieldtype": "Check" + }, + { + "fieldname": "show_net_values_in_party_account", + "label": __("Show Net Values in Party Account"), + "fieldtype": "Check" } ] } diff --git a/erpnext/accounts/report/general_ledger/general_ledger.py b/erpnext/accounts/report/general_ledger/general_ledger.py index b5d7992604..562df4f6f7 100644 --- a/erpnext/accounts/report/general_ledger/general_ledger.py +++ b/erpnext/accounts/report/general_ledger/general_ledger.py @@ -344,6 +344,9 @@ def get_accountwise_gle(filters, accounting_dimensions, gl_entries, gle_map): consolidated_gle = OrderedDict() group_by = group_by_field(filters.get('group_by')) + if filters.get('show_net_values_in_party_account'): + account_type_map = get_account_type_map(filters.get('company')) + def update_value_in_dict(data, key, gle): data[key].debit += flt(gle.debit) data[key].credit += flt(gle.credit) @@ -351,6 +354,24 @@ def get_accountwise_gle(filters, accounting_dimensions, gl_entries, gle_map): data[key].debit_in_account_currency += flt(gle.debit_in_account_currency) data[key].credit_in_account_currency += flt(gle.credit_in_account_currency) + if filters.get('show_net_values_in_party_account') and \ + account_type_map.get(data[key].account) in ('Receivable', 'Payable'): + net_value = flt(data[key].debit) - flt(data[key].credit) + net_value_in_account_currency = flt(data[key].debit_in_account_currency) \ + - flt(data[key].credit_in_account_currency) + + if net_value < 0: + dr_or_cr = 'credit' + rev_dr_or_cr = 'debit' + else: + dr_or_cr = 'debit' + rev_dr_or_cr = 'credit' + + data[key][dr_or_cr] = abs(net_value) + data[key][dr_or_cr+'_in_account_currency'] = abs(net_value_in_account_currency) + data[key][rev_dr_or_cr] = 0 + data[key][rev_dr_or_cr+'_in_account_currency'] = 0 + if data[key].against_voucher and gle.against_voucher: data[key].against_voucher += ', ' + gle.against_voucher @@ -388,6 +409,12 @@ def get_accountwise_gle(filters, accounting_dimensions, gl_entries, gle_map): return totals, entries +def get_account_type_map(company): + account_type_map = frappe._dict(frappe.get_all('Account', fields=['name', 'account_type'], + filters={'company': company}, as_list=1)) + + return account_type_map + def get_result_as_list(data, filters): balance, balance_in_account_currency = 0, 0 inv_details = get_supplier_invoice_details() From c262705143bd8c8d52d7dfa58f8a82bd0e4bebf1 Mon Sep 17 00:00:00 2001 From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com> Date: Tue, 25 May 2021 20:39:28 +0530 Subject: [PATCH 19/20] feat: Show net values in Party Accounts (#25714) From 2e0e4a7861ddc800589a788198c0df32a6e9ccb7 Mon Sep 17 00:00:00 2001 From: Anurag Mishra <32095923+Anurag810@users.noreply.github.com> Date: Wed, 26 May 2021 11:13:19 +0530 Subject: [PATCH 20/20] refactor: Additional Salary form clean up (#25785) * feat: additional salary clean up * fix: Label and description * fix: labels Co-authored-by: Rucha Mahabal --- .../additional_salary/additional_salary.json | 51 +++++++++++++++---- 1 file changed, 40 insertions(+), 11 deletions(-) diff --git a/erpnext/payroll/doctype/additional_salary/additional_salary.json b/erpnext/payroll/doctype/additional_salary/additional_salary.json index 5e17a5cbb7..d9efe458dc 100644 --- a/erpnext/payroll/doctype/additional_salary/additional_salary.json +++ b/erpnext/payroll/doctype/additional_salary/additional_salary.json @@ -7,25 +7,30 @@ "editable_grid": 1, "engine": "InnoDB", "field_order": [ + "employee_details_section", "naming_series", "employee", "employee_name", - "salary_component", - "type", - "amount", - "ref_doctype", - "ref_docname", - "amended_from", "column_break_5", "company", "department", + "salary_details_section", + "salary_component", + "type", "currency", + "amount", + "column_break_13", + "is_recurring", + "payroll_date", "from_date", "to_date", - "payroll_date", - "is_recurring", + "properties_and_references_section", + "deduct_full_tax_on_selected_payroll_date", + "ref_doctype", + "ref_docname", + "column_break_22", "overwrite_salary_structure_amount", - "deduct_full_tax_on_selected_payroll_date" + "amended_from" ], "fields": [ { @@ -81,7 +86,7 @@ }, { "depends_on": "eval:(doc.is_recurring==0)", - "description": "Date on which this component is applied", + "description": "The date on which Salary Component with Amount will contribute for Earnings/Deduction in Salary Slip. ", "fieldname": "payroll_date", "fieldtype": "Date", "in_list_view": 1, @@ -159,6 +164,7 @@ "fieldname": "ref_docname", "fieldtype": "Dynamic Link", "label": "Reference Document", + "no_copy": 1, "options": "ref_doctype", "read_only": 1 }, @@ -171,11 +177,34 @@ "print_hide": 1, "read_only": 1, "reqd": 1 + }, + { + "fieldname": "employee_details_section", + "fieldtype": "Section Break", + "label": "Employee Details" + }, + { + "fieldname": "column_break_13", + "fieldtype": "Column Break" + }, + { + "fieldname": "column_break_22", + "fieldtype": "Column Break" + }, + { + "fieldname": "salary_details_section", + "fieldtype": "Section Break", + "label": "Salary Details" + }, + { + "fieldname": "properties_and_references_section", + "fieldtype": "Section Break", + "label": "Properties and References" } ], "is_submittable": 1, "links": [], - "modified": "2021-03-31 22:33:59.098532", + "modified": "2021-05-26 11:10:00.812698", "modified_by": "Administrator", "module": "Payroll", "name": "Additional Salary",