From 007548b79cc0efdbb5a4221ee8cc6f9ec003b247 Mon Sep 17 00:00:00 2001 From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com> Date: Tue, 31 Mar 2020 10:07:51 +0530 Subject: [PATCH 1/9] fix: Bank Account patch (#21124) --- .../v12_0/move_bank_account_swift_number_to_bank.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/erpnext/patches/v12_0/move_bank_account_swift_number_to_bank.py b/erpnext/patches/v12_0/move_bank_account_swift_number_to_bank.py index 4aad1420e3..3c9758eb84 100644 --- a/erpnext/patches/v12_0/move_bank_account_swift_number_to_bank.py +++ b/erpnext/patches/v12_0/move_bank_account_swift_number_to_bank.py @@ -4,11 +4,12 @@ import frappe def execute(): frappe.reload_doc('accounts', 'doctype', 'bank', force=1) - frappe.db.sql(""" - UPDATE `tabBank` b, `tabBank Account` ba - SET b.swift_number = ba.swift_number, b.branch_code = ba.branch_code - WHERE b.name = ba.bank - """) + if frappe.db.table_exists('Bank') and frappe.db.table_exists('Bank Account'): + frappe.db.sql(""" + UPDATE `tabBank` b, `tabBank Account` ba + SET b.swift_number = ba.swift_number, b.branch_code = ba.branch_code + WHERE b.name = ba.bank + """) frappe.reload_doc('accounts', 'doctype', 'bank_account') frappe.reload_doc('accounts', 'doctype', 'payment_request') \ No newline at end of file From 7806e5a052202ffc64f08c8b58d1322c6373bbb2 Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Tue, 31 Mar 2020 10:30:20 +0530 Subject: [PATCH 2/9] feat: changes for desk pages (#21027) * feat: rename Chart on Getting Started Page * feat: add dashboard and leaderboard to getting started * feat: remove communication Co-authored-by: Prssanna Desai Co-authored-by: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com> --- .../communication/communication.json | 22 ------------------- .../getting_started/getting_started.json | 15 ++++++++++--- 2 files changed, 12 insertions(+), 25 deletions(-) delete mode 100644 erpnext/communication/desk_page/communication/communication.json diff --git a/erpnext/communication/desk_page/communication/communication.json b/erpnext/communication/desk_page/communication/communication.json deleted file mode 100644 index 59318fb8cd..0000000000 --- a/erpnext/communication/desk_page/communication/communication.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "cards": [], - "charts": [], - "creation": "2020-01-28 11:49:55.003637", - "developer_mode_only": 0, - "disable_user_customization": 0, - "docstatus": 0, - "doctype": "Desk Page", - "extends_another_page": 0, - "icon": "", - "idx": 0, - "is_standard": 1, - "label": "Communication", - "modified": "2020-03-12 16:30:40.534226", - "modified_by": "Administrator", - "module": "Communication", - "name": "Communication", - "owner": "Administrator", - "pin_to_bottom": 0, - "pin_to_top": 0, - "shortcuts": [] -} \ No newline at end of file diff --git a/erpnext/setup/desk_page/getting_started/getting_started.json b/erpnext/setup/desk_page/getting_started/getting_started.json index 00236ba5fe..b045b5d083 100644 --- a/erpnext/setup/desk_page/getting_started/getting_started.json +++ b/erpnext/setup/desk_page/getting_started/getting_started.json @@ -41,8 +41,7 @@ "charts": [ { "chart_name": "Bank Balance", - "label": "All Your Money", - "size": "Full" + "label": "Bank Balance" } ], "creation": "2020-01-23 13:46:38.833076", @@ -55,7 +54,7 @@ "idx": 0, "is_standard": 1, "label": "Getting Started", - "modified": "2020-03-12 16:30:37.821762", + "modified": "2020-03-23 11:20:49.161823", "modified_by": "Administrator", "module": "Setup", "name": "Getting Started", @@ -82,6 +81,16 @@ "is_query_report": 0, "link_to": "Sales Invoice", "type": "DocType" + }, + { + "is_query_report": 0, + "link_to": "dashboard", + "type": "Page" + }, + { + "is_query_report": 0, + "link_to": "leaderboard", + "type": "Page" } ] } \ No newline at end of file From 06b3f6f781d04f48b68246bfa02043483734adda Mon Sep 17 00:00:00 2001 From: Ahmad M Abdelrahman Date: Tue, 31 Mar 2020 08:08:49 +0300 Subject: [PATCH 3/9] Remove Campagin restrection (#21024) Lead Source Now is an independent doctype. forcing the user to add Campaign is not valid Solution Show Campaign keeping it optional and keep the user to be free to add or remove data --- erpnext/crm/doctype/lead/lead.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/erpnext/crm/doctype/lead/lead.json b/erpnext/crm/doctype/lead/lead.json index bc007b146f..5299368f42 100644 --- a/erpnext/crm/doctype/lead/lead.json +++ b/erpnext/crm/doctype/lead/lead.json @@ -171,7 +171,6 @@ "options": "Customer" }, { - "depends_on": "eval: doc.source==\"Campaign\"", "fieldname": "campaign_name", "fieldtype": "Link", "label": "Campaign Name", @@ -512,4 +511,4 @@ "sort_field": "modified", "sort_order": "DESC", "title_field": "title" -} \ No newline at end of file +} From b0ab3981ea51bdc5541b3bf2933b2e4c4814dfea Mon Sep 17 00:00:00 2001 From: Raffael Meyer Date: Tue, 31 Mar 2020 07:10:03 +0200 Subject: [PATCH 4/9] fix(regional): header row in DATEV report (#21113) * fix(regional): encoding of DATEV report * feat(regional): filter datev report by voucher type * fix: creation time, coa used, is frozen * add voucher types: Payroll Entry, Bank Reconciliation, Asset, Stock Entry * fix indentation * fix indentation * fix indentation --- erpnext/regional/report/datev/datev.js | 6 +++ erpnext/regional/report/datev/datev.py | 40 ++++++++++++------- .../regional/report/datev/datev_constants.py | 20 ++++++++-- 3 files changed, 49 insertions(+), 17 deletions(-) diff --git a/erpnext/regional/report/datev/datev.js b/erpnext/regional/report/datev/datev.js index 1e000b673e..d8638ab05d 100644 --- a/erpnext/regional/report/datev/datev.js +++ b/erpnext/regional/report/datev/datev.js @@ -21,6 +21,12 @@ frappe.query_reports["DATEV"] = { "default": frappe.datetime.now_date(), "fieldtype": "Date", "reqd": 1 + }, + { + "fieldname": "voucher_type", + "label": __("Voucher Type"), + "fieldtype": "Select", + "options": "\nSales Invoice\nPurchase Invoice\nPayment Entry\nExpense Claim\nPayroll Entry\nBank Reconciliation\nAsset\nStock Entry" } ], onload: function(query_report) { diff --git a/erpnext/regional/report/datev/datev.py b/erpnext/regional/report/datev/datev.py index e9b42356a2..a6579121cb 100644 --- a/erpnext/regional/report/datev/datev.py +++ b/erpnext/regional/report/datev/datev.py @@ -62,6 +62,7 @@ def get_transactions(filters, as_dict=1): filters -- dict of filters to be passed to the sql query as_dict -- return as list of dicts [0,1] """ + filter_by_voucher = 'AND gl.voucher_type = %(voucher_type)s' if filters.get('voucher_type') else '' gl_entries = frappe.db.sql(""" SELECT @@ -80,8 +81,10 @@ def get_transactions(filters, as_dict=1): gl.posting_date as 'Belegdatum', gl.voucher_no as 'Belegfeld 1', gl.remarks as 'Buchungstext', - gl.against_voucher_type as 'Beleginfo - Art 1', - gl.against_voucher as 'Beleginfo - Inhalt 1' + gl.voucher_type as 'Beleginfo - Art 1', + gl.voucher_no as 'Beleginfo - Inhalt 1', + gl.against_voucher_type as 'Beleginfo - Art 2', + gl.against_voucher as 'Beleginfo - Inhalt 2' FROM `tabGL Entry` gl @@ -109,7 +112,8 @@ def get_transactions(filters, as_dict=1): WHERE gl.company = %(company)s AND DATE(gl.posting_date) >= %(from_date)s AND DATE(gl.posting_date) <= %(to_date)s - ORDER BY 'Belegdatum', gl.voucher_no""", filters, as_dict=as_dict) + {} + ORDER BY 'Belegdatum', gl.voucher_no""".format(filter_by_voucher), filters, as_dict=as_dict) return gl_entries @@ -281,24 +285,24 @@ def get_datev_csv(data, filters, csv_class): def get_header(filters, csv_class): coa = frappe.get_value("Company", filters.get("company"), "chart_of_accounts") - coa_used = "SKR04" if "SKR04" in coa else ("SKR03" if "SKR03" in coa else "") + coa_used = "04" if "SKR04" in coa else ("03" if "SKR03" in coa else "") header = [ # DATEV format - # "DTVF" = created by DATEV software, - # "EXTF" = created by other software + # "DTVF" = created by DATEV software, + # "EXTF" = created by other software '"EXTF"', # version of the DATEV format - # 141 = 1.41, - # 510 = 5.10, - # 720 = 7.20 + # 141 = 1.41, + # 510 = 5.10, + # 720 = 7.20 '700', csv_class.DATA_CATEGORY, '"%s"' % csv_class.FORMAT_NAME, # Format version (regarding format name) csv_class.FORMAT_VERSION, # Generated on - datetime.datetime.now().strftime("%Y%m%d%H%M%S"), + datetime.datetime.now().strftime("%Y%m%d%H%M%S") + '000', # Imported on -- stays empty '', # Origin. Any two symbols, will be replaced by "SV" on import. @@ -328,13 +332,21 @@ def get_header(filters, csv_class): # R = Diktatkürzel '', # S = Buchungstyp - # 1 = Transaction batch (Finanzbuchführung), - # 2 = Annual financial statement (Jahresabschluss) + # 1 = Transaction batch (Finanzbuchführung), + # 2 = Annual financial statement (Jahresabschluss) '1' if csv_class.DATA_CATEGORY == DataCategory.TRANSACTIONS else '', # T = Rechnungslegungszweck - '', + # 0 oder leer = vom Rechnungslegungszweck unabhängig + # 50 = Handelsrecht + # 30 = Steuerrecht + # 64 = IFRS + # 40 = Kalkulatorik + # 11 = Reserviert + # 12 = Reserviert + '0', # U = Festschreibung - '', + # TODO: Filter by Accounting Period. In export for closed Accounting Period, this will be "1" + '0', # V = Default currency, for example, "EUR" '"%s"' % frappe.get_value("Company", filters.get("company"), "default_currency"), # reserviert diff --git a/erpnext/regional/report/datev/datev_constants.py b/erpnext/regional/report/datev/datev_constants.py index a4cd5fc10e..a059ed365a 100644 --- a/erpnext/regional/report/datev/datev_constants.py +++ b/erpnext/regional/report/datev/datev_constants.py @@ -498,13 +498,27 @@ QUERY_REPORT_COLUMNS = [ }, { "label": "Beleginfo - Art 1", - "fieldname": "Beleginfo - Art 2", - "fieldtype": "Data", + "fieldname": "Beleginfo - Art 1", + "fieldtype": "Link", + "options": "DocType" }, { "label": "Beleginfo - Inhalt 1", + "fieldname": "Beleginfo - Inhalt 1", + "fieldtype": "Dynamic Link", + "options": "Beleginfo - Art 1" + }, + { + "label": "Beleginfo - Art 2", + "fieldname": "Beleginfo - Art 2", + "fieldtype": "Link", + "options": "DocType" + }, + { + "label": "Beleginfo - Inhalt 2", "fieldname": "Beleginfo - Inhalt 2", - "fieldtype": "Data", + "fieldtype": "Dynamic Link", + "options": "Beleginfo - Art 2" } ] From 3fa03df1e37810aa48ee3f85e974a9b60ac5407f Mon Sep 17 00:00:00 2001 From: prafful1234 <43948551+prafful1234@users.noreply.github.com> Date: Tue, 31 Mar 2020 10:40:42 +0530 Subject: [PATCH 5/9] fix(transaction): Add comment-by from frappe session (#20867) Co-authored-by: prafful1234 --- erpnext/buying/doctype/purchase_order/purchase_order.js | 3 ++- erpnext/selling/doctype/sales_order/sales_order.js | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js index a3264a4c0f..3111a3a7d5 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.js +++ b/erpnext/buying/doctype/purchase_order/purchase_order.js @@ -499,7 +499,8 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend( reference_doctype: me.frm.doctype, reference_name: me.frm.docname, content: __('Reason for hold: ')+data.reason_for_hold, - comment_email: frappe.session.user + comment_email: frappe.session.user, + comment_by: frappe.session.user_fullname }, callback: function(r) { if(!r.exc) { diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js index fa765dfaad..61aa608dd3 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.js +++ b/erpnext/selling/doctype/sales_order/sales_order.js @@ -664,7 +664,8 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend( reference_doctype: me.frm.doctype, reference_name: me.frm.docname, content: __('Reason for hold: ')+data.reason_for_hold, - comment_email: frappe.session.user + comment_email: frappe.session.user, + comment_by: frappe.session.user_fullname }, callback: function(r) { if(!r.exc) { From 5c54adec28c7fda2e290a1bd2bfd1ab7f3c751d0 Mon Sep 17 00:00:00 2001 From: Andy Zhu Date: Tue, 31 Mar 2020 18:13:00 +1300 Subject: [PATCH 6/9] fix: docfield of sales_order is not fetching route options for new doc (#21123) Using the wrong method to get `so` as docfield. frappe.meta changes will not effect the `sales_order` in `frm`. --- erpnext/projects/doctype/project/project.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/projects/doctype/project/project.js b/erpnext/projects/doctype/project/project.js index 3570a0f2be..5862963496 100644 --- a/erpnext/projects/doctype/project/project.js +++ b/erpnext/projects/doctype/project/project.js @@ -18,7 +18,7 @@ frappe.ui.form.on("Project", { }; }, onload: function (frm) { - var so = frappe.meta.get_docfield("Project", "sales_order"); + var so = frm.get_docfield("Project", "sales_order"); so.get_route_options_for_new_doc = function (field) { if (frm.is_new()) return; return { @@ -135,4 +135,4 @@ function open_form(frm, doctype, child_doctype, parentfield) { frappe.ui.form.make_quick_entry(doctype, null, null, new_doc); }); -} \ No newline at end of file +} From fbf6e56d860c041dff6ceb901e1ed129c1db37a2 Mon Sep 17 00:00:00 2001 From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com> Date: Tue, 31 Mar 2020 10:45:32 +0530 Subject: [PATCH 7/9] fix: Expense account currency validation in Landed Cost voucher (#21073) * fix: Expense account currency validation in Landed Cost voucher * fix: Remove unused imports --- erpnext/controllers/queries.py | 14 +++++++++----- .../landed_cost_voucher/landed_cost_voucher.py | 10 ++++++++++ 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/erpnext/controllers/queries.py b/erpnext/controllers/queries.py index d18f8e54d8..163ef72ee1 100644 --- a/erpnext/controllers/queries.py +++ b/erpnext/controllers/queries.py @@ -3,6 +3,7 @@ from __future__ import unicode_literals import frappe +import erpnext from frappe.desk.reportview import get_match_cond, get_filters_cond from frappe.utils import nowdate, getdate from collections import defaultdict @@ -129,23 +130,26 @@ def supplier_query(doctype, txt, searchfield, start, page_len, filters): }) def tax_account_query(doctype, txt, searchfield, start, page_len, filters): + company_currency = erpnext.get_company_currency(filters.get('company')) + tax_accounts = frappe.db.sql("""select name, parent_account from tabAccount where tabAccount.docstatus!=2 and account_type in (%s) and is_group = 0 and company = %s + and account_currency = %s and `%s` LIKE %s order by idx desc, name limit %s, %s""" % - (", ".join(['%s']*len(filters.get("account_type"))), "%s", searchfield, "%s", "%s", "%s"), - tuple(filters.get("account_type") + [filters.get("company"), "%%%s%%" % txt, + (", ".join(['%s']*len(filters.get("account_type"))), "%s", "%s", searchfield, "%s", "%s", "%s"), + tuple(filters.get("account_type") + [filters.get("company"), company_currency, "%%%s%%" % txt, start, page_len])) if not tax_accounts: tax_accounts = frappe.db.sql("""select name, parent_account from tabAccount where tabAccount.docstatus!=2 and is_group = 0 - and company = %s and `%s` LIKE %s limit %s, %s""" - % ("%s", searchfield, "%s", "%s", "%s"), - (filters.get("company"), "%%%s%%" % txt, start, page_len)) + and company = %s and account_currency = %s and `%s` LIKE %s limit %s, %s""" #nosec + % ("%s", "%s", searchfield, "%s", "%s", "%s"), + (filters.get("company"), company_currency, "%%%s%%" % txt, start, page_len)) return tax_accounts diff --git a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py index d97b699a0f..5ad0e13db9 100644 --- a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py +++ b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py @@ -8,6 +8,7 @@ from frappe.utils import flt from frappe.model.meta import get_field_precision from frappe.model.document import Document from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos +from erpnext.accounts.doctype.account.account import get_account_currency class LandedCostVoucher(Document): def get_items_from_purchase_receipts(self): @@ -43,6 +44,7 @@ class LandedCostVoucher(Document): else: self.validate_applicable_charges_for_item() self.validate_purchase_receipts() + self.validate_expense_accounts() self.set_total_taxes_and_charges() def check_mandatory(self): @@ -71,6 +73,14 @@ class LandedCostVoucher(Document): frappe.throw(_("Row {0}: Cost center is required for an item {1}") .format(item.idx, item.item_code)) + def validate_expense_accounts(self): + company_currency = erpnext.get_company_currency(self.company) + for account in self.taxes: + if get_account_currency(account.expense_account) != company_currency: + frappe.throw(msg=_(""" Row {0}: Expense account currency should be same as company's default currency. + Please select expense account with account currency as {1}""") + .format(account.idx, frappe.bold(company_currency)), title=_("Invalid Account Currency")) + def set_total_taxes_and_charges(self): self.total_taxes_and_charges = sum([flt(d.amount) for d in self.get("taxes")]) From bba78f038452fb2f58f63a58389f0a0e2d19dd14 Mon Sep 17 00:00:00 2001 From: Saqib Date: Tue, 31 Mar 2020 10:49:44 +0530 Subject: [PATCH 8/9] fix: auto created asset message (#21108) * fix: auto created asset message * Update erpnext/controllers/buying_controller.py Co-authored-by: Nabin Hait --- erpnext/controllers/buying_controller.py | 33 +++++++++++++++++------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py index 88c8dba4c6..fcc9098ba1 100644 --- a/erpnext/controllers/buying_controller.py +++ b/erpnext/controllers/buying_controller.py @@ -672,19 +672,32 @@ class BuyingController(StockController): # If asset has to be auto created # Check for asset naming series if item_data.get('asset_naming_series'): + created_assets = [] + for qty in range(cint(d.qty)): - self.make_asset(d) - is_plural = 's' if cint(d.qty) != 1 else '' - messages.append(_('{0} Asset{2} Created for {1}').format(cint(d.qty), d.item_code, is_plural)) + asset = self.make_asset(d) + created_assets.append(asset) + + if len(created_assets) > 5: + # dont show asset form links if more than 5 assets are created + messages.append(_('{} Asset{} created for {}').format(len(created_assets), is_plural, frappe.bold(d.item_code))) + else: + assets_link = list(map(lambda d: frappe.utils.get_link_to_form('Asset', d), created_assets)) + assets_link = frappe.bold(','.join(assets_link)) + + is_plural = 's' if len(created_assets) != 1 else '' + messages.append( + _('Asset{} {assets_link} created for {}').format(is_plural, frappe.bold(d.item_code), assets_link=assets_link) + ) else: - frappe.throw(_("Row {1}: Asset Naming Series is mandatory for the auto creation for item {0}") - .format(d.item_code, d.idx)) + frappe.throw(_("Row {}: Asset Naming Series is mandatory for the auto creation for item {}") + .format(d.idx, frappe.bold(d.item_code))) else: - messages.append(_("Assets not created for {0}. You will have to create asset manually.") - .format(d.item_code)) + messages.append(_("Assets not created for {0}. You will have to create asset manually.") + .format(frappe.bold(d.item_code))) for message in messages: - frappe.msgprint(message, title="Success") + frappe.msgprint(message, title="Success", indicator="green") def make_asset(self, row): if not row.asset_location: @@ -716,6 +729,8 @@ class BuyingController(StockController): asset.set_missing_values() asset.insert() + return asset.name + def update_fixed_asset(self, field, delete_asset = False): for d in self.get("items"): if d.is_fixed_asset: @@ -1026,4 +1041,4 @@ def get_batches_with_qty(item_code, fg_item, required_qty, transferred_batch_qty available_batches.append({'batch': batch, 'qty': available_qty}) required_qty -= available_qty - return available_batches \ No newline at end of file + return available_batches From ee0dec8776cbd821318cb7c32d5cdd3c86106a33 Mon Sep 17 00:00:00 2001 From: Anupam Kumar Date: Tue, 31 Mar 2020 10:51:09 +0530 Subject: [PATCH 9/9] fix: email_to, party_type and party are not set in payment request when order made from portal (#21084) Co-authored-by: Anupam K --- erpnext/accounts/doctype/payment_request/payment_request.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/erpnext/accounts/doctype/payment_request/payment_request.py b/erpnext/accounts/doctype/payment_request/payment_request.py index 0fade8c456..7e9211af9f 100644 --- a/erpnext/accounts/doctype/payment_request/payment_request.py +++ b/erpnext/accounts/doctype/payment_request/payment_request.py @@ -317,13 +317,13 @@ def make_payment_request(**args): "payment_request_type": args.get("payment_request_type"), "currency": ref_doc.currency, "grand_total": grand_total, - "email_to": args.recipient_id or "", + "email_to": args.recipient_id or ref_doc.owner, "subject": _("Payment Request for {0}").format(args.dn), "message": gateway_account.get("message") or get_dummy_message(ref_doc), "reference_doctype": args.dt, "reference_name": args.dn, - "party_type": args.get("party_type"), - "party": args.get("party"), + "party_type": args.get("party_type") or "Customer", + "party": args.get("party") or ref_doc.customer, "bank_account": bank_account })