From 9ac4903909bdca3b5b20791773b96f2cb2419964 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Fri, 15 Oct 2021 21:19:41 +0530 Subject: [PATCH 01/16] fix: Account number and name incorrectly import using COA importer (cherry picked from commit 17a8649500dee2989b2f1231434a207288c7e3a7) --- .../account/chart_of_accounts/chart_of_accounts.py | 13 ++++++++----- .../chart_of_accounts_importer.py | 7 +++++-- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/erpnext/accounts/doctype/account/chart_of_accounts/chart_of_accounts.py b/erpnext/accounts/doctype/account/chart_of_accounts/chart_of_accounts.py index d6ccd1693622..05caafe1c473 100644 --- a/erpnext/accounts/doctype/account/chart_of_accounts/chart_of_accounts.py +++ b/erpnext/accounts/doctype/account/chart_of_accounts/chart_of_accounts.py @@ -12,7 +12,7 @@ from unidecode import unidecode -def create_charts(company, chart_template=None, existing_company=None, custom_chart=None): +def create_charts(company, chart_template=None, existing_company=None, custom_chart=None, from_coa_importer=None): chart = custom_chart or get_chart(chart_template, existing_company) if chart: accounts = [] @@ -22,7 +22,7 @@ def _import_accounts(children, parent, root_type, root_account=False): if root_account: root_type = child.get("root_type") - if account_name not in ["account_number", "account_type", + if account_name not in ["account_name", "account_number", "account_type", "root_type", "is_group", "tax_rate"]: account_number = cstr(child.get("account_number")).strip() @@ -35,7 +35,7 @@ def _import_accounts(children, parent, root_type, root_account=False): account = frappe.get_doc({ "doctype": "Account", - "account_name": account_name, + "account_name": child.get('account_name') if from_coa_importer else account_name, "company": company, "parent_account": parent, "is_group": is_group, @@ -213,7 +213,7 @@ def _get_account_names(account_master): return (bank_account in accounts) @frappe.whitelist() -def build_tree_from_json(chart_template, chart_data=None): +def build_tree_from_json(chart_template, chart_data=None, from_coa_importer=False): ''' get chart template from its folder and parse the json to be rendered as tree ''' chart = chart_data or get_chart(chart_template) @@ -226,9 +226,12 @@ def _import_accounts(children, parent): ''' recursively called to form a parent-child based list of dict from chart template ''' for account_name, child in iteritems(children): account = {} - if account_name in ["account_number", "account_type",\ + if account_name in ["account_name", "account_number", "account_type",\ "root_type", "is_group", "tax_rate"]: continue + if from_coa_importer: + account_name = child['account_name'] + account['parent_account'] = parent account['expandable'] = True if identify_is_group(child) else False account['value'] = (cstr(child.get('account_number')).strip() + ' - ' + account_name) \ 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 e856ce95565e..c87b788d40c9 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 @@ -69,7 +69,7 @@ def import_coa(file_name, company): frappe.local.flags.ignore_root_company_validation = True forest = build_forest(data) - create_charts(company, custom_chart=forest) + create_charts(company, custom_chart=forest, from_coa_importer=True) # trigger on_update for company to reset default accounts set_default_accounts(company) @@ -148,7 +148,7 @@ def get_coa(doctype, parent, is_root=False, file_name=None, for_validate=0): if not for_validate: forest = build_forest(data) - accounts = build_tree_from_json("", chart_data=forest) # returns a list of dict in a tree render-able form + accounts = build_tree_from_json("", chart_data=forest, from_coa_importer=True) # returns a list of dict in a tree render-able form # filter out to show data for the selected node only accounts = [d for d in accounts if d['parent_account']==parent] @@ -212,11 +212,14 @@ def return_parent(data, child): if not account_name: error_messages.append("Row {0}: Please enter Account Name".format(line_no)) + name = account_name if account_number: account_number = cstr(account_number).strip() account_name = "{} - {}".format(account_number, account_name) charts_map[account_name] = {} + charts_map[account_name]['account_name'] = name + if account_number: charts_map[account_name]["account_number"] = account_number if cint(is_group) == 1: charts_map[account_name]["is_group"] = is_group if account_type: charts_map[account_name]["account_type"] = account_type if root_type: charts_map[account_name]["root_type"] = root_type From 9ee84515874bb83563b13af545c9451d529bc310 Mon Sep 17 00:00:00 2001 From: Francisco Roldan Date: Thu, 19 May 2022 09:20:56 -0300 Subject: [PATCH 02/16] fix --- .../doctype/sales_invoice/sales_invoice.js | 13 ++++++++----- .../doctype/sales_invoice/sales_invoice.json | 18 +++++++++--------- .../sales_invoice_timesheet.json | 9 ++++++--- .../projects/doctype/timesheet/timesheet.py | 6 ------ 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js index 27d5e78e13fd..d959806020dd 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js @@ -442,12 +442,15 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte }, currency() { + var me = this; this._super(); - $.each(cur_frm.doc.timesheets, function(i, d) { - let row = frappe.get_doc(d.doctype, d.name) - set_timesheet_detail_rate(row.doctype, row.name, cur_frm.doc.currency, row.timesheet_detail) - }); - calculate_total_billing_amount(cur_frm) + if (this.frm.doc.timesheets) { + this.frm.doc.timesheets.forEach((d) => { + let row = frappe.get_doc(d.doctype, d.name) + set_timesheet_detail_rate(row.doctype, row.name, me.frm.doc.currency, row.timesheet_detail) + }); + frm.trigger("calculate_timesheet_totals"); + } } }); diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json index 7e020d23b296..5553e4fad341 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json @@ -1996,14 +1996,6 @@ "label": "Additional Discount Account", "options": "Account" }, - { - "default": "0", - "fieldname": "ignore_default_payment_terms_template", - "fieldtype": "Check", - "hidden": 1, - "label": "Ignore Default Payment Terms Template", - "read_only": 1 - }, { "allow_on_submit": 1, "fieldname": "dispatch_address_name", @@ -2019,6 +2011,14 @@ "label": "Dispatch Address", "read_only": 1 }, + { + "default": "0", + "fieldname": "ignore_default_payment_terms_template", + "fieldtype": "Check", + "hidden": 1, + "label": "Ignore Default Payment Terms Template", + "read_only": 1 + }, { "fieldname": "total_billing_hours", "fieldtype": "Float", @@ -2037,7 +2037,7 @@ "link_fieldname": "consolidated_invoice" } ], - "modified": "2022-02-25 11:51:44.271169", + "modified": "2022-02-26 11:51:44.271169", "modified_by": "Administrator", "module": "Accounts", "name": "Sales Invoice", diff --git a/erpnext/accounts/doctype/sales_invoice_timesheet/sales_invoice_timesheet.json b/erpnext/accounts/doctype/sales_invoice_timesheet/sales_invoice_timesheet.json index 2cddbbfceee9..efc51bc07ef9 100644 --- a/erpnext/accounts/doctype/sales_invoice_timesheet/sales_invoice_timesheet.json +++ b/erpnext/accounts/doctype/sales_invoice_timesheet/sales_invoice_timesheet.json @@ -16,9 +16,9 @@ "column_break_9", "billing_amount", "section_break_11", + "time_sheet", "timesheet_detail", "column_break_5", - "time_sheet", "project_name" ], "fields": [ @@ -91,7 +91,6 @@ "fieldtype": "Column Break" }, { - "fieldname": "section_break_7", "fieldtype": "Section Break", "label": "Totals" @@ -110,11 +109,15 @@ "fieldtype": "Data", "label": "Project Name", "read_only": 1 + }, + { + "fieldname": "column_break_13", + "fieldtype": "Column Break" } ], "istable": 1, "links": [], - "modified": "2021-08-15 18:37:08.084930", + "modified": "2021-08-16 18:37:08.084930", "modified_by": "Administrator", "module": "Accounts", "name": "Sales Invoice Timesheet", diff --git a/erpnext/projects/doctype/timesheet/timesheet.py b/erpnext/projects/doctype/timesheet/timesheet.py index a20c70a6dacf..82bcbc2561b8 100644 --- a/erpnext/projects/doctype/timesheet/timesheet.py +++ b/erpnext/projects/doctype/timesheet/timesheet.py @@ -225,7 +225,6 @@ def get_projectwise_timesheet_data(project=None, parent=None, from_time=None, to query = f""" SELECT - tsd.name as name, tsd.parent as time_sheet, tsd.from_time as from_time, @@ -236,20 +235,15 @@ def get_projectwise_timesheet_data(project=None, parent=None, from_time=None, to tsd.description as description, ts.currency as currency, tsd.project_name as project_name - FROM `tabTimesheet Detail` tsd - INNER JOIN `tabTimesheet` ts ON ts.name = tsd.parent - WHERE - tsd.parenttype = 'Timesheet' AND tsd.docstatus = 1 AND tsd.is_billable = 1 AND tsd.sales_invoice is NULL {condition} - ORDER BY tsd.from_time ASC """ From f4f45a5c89ceaec4fb12b5fe8787897919d2d748 Mon Sep 17 00:00:00 2001 From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com> Date: Tue, 19 Oct 2021 15:08:05 +0530 Subject: [PATCH 03/16] fix: Totals row incorrect value in GL Entry (#27867) (cherry picked from commit ebe68c1a7a47f5e711cc9fc1d40c07e140b76888) --- erpnext/accounts/report/general_ledger/general_ledger.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/erpnext/accounts/report/general_ledger/general_ledger.py b/erpnext/accounts/report/general_ledger/general_ledger.py index d8f53333b211..4ba164701185 100644 --- a/erpnext/accounts/report/general_ledger/general_ledger.py +++ b/erpnext/accounts/report/general_ledger/general_ledger.py @@ -424,8 +424,6 @@ def update_value_in_dict(data, key, gle): update_value_in_dict(totals, 'closing', gle) elif gle.posting_date <= to_date: - update_value_in_dict(gle_map[gle.get(group_by)].totals, 'total', gle) - update_value_in_dict(totals, 'total', gle) if filters.get("group_by") != 'Group by Voucher (Consolidated)': gle_map[gle.get(group_by)].entries.append(gle) elif filters.get("group_by") == 'Group by Voucher (Consolidated)': @@ -439,10 +437,11 @@ def update_value_in_dict(data, key, gle): else: update_value_in_dict(consolidated_gle, key, gle) - update_value_in_dict(gle_map[gle.get(group_by)].totals, 'closing', gle) - update_value_in_dict(totals, 'closing', gle) - for key, value in consolidated_gle.items(): + update_value_in_dict(gle_map[value.get(group_by)].totals, 'total', value) + update_value_in_dict(totals, 'total', value) + update_value_in_dict(gle_map[value.get(group_by)].totals, 'closing', value) + update_value_in_dict(totals, 'closing', value) entries.append(value) return totals, entries From 3a5e9c0785420d5bc9aff26af16c7fd911439cb9 Mon Sep 17 00:00:00 2001 From: Francisco Roldan Date: Thu, 19 May 2022 09:24:55 -0300 Subject: [PATCH 04/16] #27862 --- erpnext/selling/doctype/sales_order/sales_order.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index 93676094218b..dcf478bda6ea 100755 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -110,7 +110,7 @@ def validate_delivery_date(self): if self.order_type == 'Sales' and not self.skip_delivery_note: delivery_date_list = [d.delivery_date for d in self.get("items") if d.delivery_date] max_delivery_date = max(delivery_date_list) if delivery_date_list else None - if not self.delivery_date: + if (max_delivery_date and not self.delivery_date) or (max_delivery_date and getdate(self.delivery_date) != getdate(max_delivery_date)): self.delivery_date = max_delivery_date if self.delivery_date: for d in self.get("items"): @@ -119,8 +119,6 @@ def validate_delivery_date(self): if getdate(self.transaction_date) > getdate(d.delivery_date): frappe.msgprint(_("Expected Delivery Date should be after Sales Order Date"), indicator='orange', title=_('Warning')) - if getdate(self.delivery_date) != getdate(max_delivery_date): - self.delivery_date = max_delivery_date else: frappe.throw(_("Please enter Delivery Date")) From ad956daaa44efecc391859e0fd8dcd7d9e3ecf34 Mon Sep 17 00:00:00 2001 From: Francisco Roldan Date: Thu, 19 May 2022 09:31:33 -0300 Subject: [PATCH 05/16] #27915 --- erpnext/accounts/doctype/payment_entry/payment_entry.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py index 607f85c87bd5..9da08662bf65 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py @@ -709,10 +709,14 @@ def add_party_gl_entries(self, gl_entries): dr_or_cr = "credit" if erpnext.get_party_account_type(self.party_type) == 'Receivable' else "debit" for d in self.get("references"): + cost_center = self.cost_center + if d.reference_doctype == "Sales Invoice" and not cost_center: + cost_center = frappe.db.get_value(d.reference_doctype, d.reference_name, "cost_center") gle = party_gl_dict.copy() gle.update({ "against_voucher_type": d.reference_doctype, - "against_voucher": d.reference_name + "against_voucher": d.reference_name, + "cost_center": cost_center }) allocated_amount_in_company_currency = flt(flt(d.allocated_amount) * flt(d.exchange_rate), From 9c3f0ceb377fd8b3c28b4198b6b5b0c5f0bccbfd Mon Sep 17 00:00:00 2001 From: marination Date: Tue, 12 Oct 2021 19:53:38 +0530 Subject: [PATCH 06/16] fix: Item Variant selection empty popup on website - pass item_code instead of website item name to fetch attributes --- erpnext/templates/generators/item/item_configure.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/templates/generators/item/item_configure.html b/erpnext/templates/generators/item/item_configure.html index fcab594402b4..e97a275fbd8e 100644 --- a/erpnext/templates/generators/item/item_configure.html +++ b/erpnext/templates/generators/item/item_configure.html @@ -4,8 +4,8 @@
{% if cart_settings.enable_variants | int %} From e60089d7290bd9300a0aed45822924b8514c3207 Mon Sep 17 00:00:00 2001 From: Saqib Date: Mon, 4 Oct 2021 11:44:46 +0530 Subject: [PATCH 07/16] perf: fetching of account balance in chart of accounts (#27661) (cherry picked from commit 9051735529dfac9c890b0c8078c3986bb6316c4d) --- .../accounts/doctype/account/account_tree.js | 61 +++++++++++++------ erpnext/accounts/utils.py | 29 ++++++--- 2 files changed, 65 insertions(+), 25 deletions(-) diff --git a/erpnext/accounts/doctype/account/account_tree.js b/erpnext/accounts/doctype/account/account_tree.js index 425d2894e777..a43ece8b9b22 100644 --- a/erpnext/accounts/doctype/account/account_tree.js +++ b/erpnext/accounts/doctype/account/account_tree.js @@ -45,6 +45,49 @@ frappe.treeview_settings["Account"] = { ], root_label: "Accounts", get_tree_nodes: 'erpnext.accounts.utils.get_children', + on_get_node: function(nodes, deep=false) { + if (frappe.boot.user.can_read.indexOf("GL Entry") == -1) return; + + let accounts = []; + if (deep) { + // in case of `get_all_nodes` + accounts = nodes.reduce((acc, node) => [...acc, ...node.data], []); + } else { + accounts = nodes; + } + + const get_balances = frappe.call({ + method: 'erpnext.accounts.utils.get_account_balances', + args: { + accounts: accounts, + company: cur_tree.args.company + }, + }); + + get_balances.then(r => { + if (!r.message || r.message.length == 0) return; + + for (let account of r.message) { + + const node = cur_tree.nodes && cur_tree.nodes[account.value]; + if (!node || node.is_root) continue; + + // show Dr if positive since balance is calculated as debit - credit else show Cr + const balance = account.balance_in_account_currency || account.balance; + const dr_or_cr = balance > 0 ? "Dr": "Cr"; + const format = (value, currency) => format_currency(Math.abs(value), currency); + + if (account.balance!==undefined) { + $('' + + (account.balance_in_account_currency ? + (format(account.balance_in_account_currency, account.account_currency) + " / ") : "") + + format(account.balance, account.company_currency) + + " " + dr_or_cr + + '').insertBefore(node.$ul); + } + } + }); + }, add_tree_node: 'erpnext.accounts.utils.add_ac', menu_items:[ { @@ -122,24 +165,6 @@ frappe.treeview_settings["Account"] = { } }, "add"); }, - onrender: function(node) { - if (frappe.boot.user.can_read.indexOf("GL Entry") !== -1) { - - // show Dr if positive since balance is calculated as debit - credit else show Cr - let balance = node.data.balance_in_account_currency || node.data.balance; - let dr_or_cr = balance > 0 ? "Dr": "Cr"; - - if (node.data && node.data.balance!==undefined) { - $('' - + (node.data.balance_in_account_currency ? - (format_currency(Math.abs(node.data.balance_in_account_currency), - node.data.account_currency) + " / ") : "") - + format_currency(Math.abs(node.data.balance), node.data.company_currency) - + " " + dr_or_cr - + '').insertBefore(node.$ul); - } - } - }, toolbar: [ { label:__("Add Child"), diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py index b9bc7770dce4..2c0976e9fbce 100644 --- a/erpnext/accounts/utils.py +++ b/erpnext/accounts/utils.py @@ -4,11 +4,14 @@ from __future__ import unicode_literals +from json import loads + import frappe import frappe.defaults from frappe import _, throw from frappe.model.meta import get_field_precision from frappe.utils import cint, cstr, flt, formatdate, get_number_format_info, getdate, now, nowdate +from six import string_types import erpnext @@ -789,16 +792,28 @@ def get_children(doctype, parent, company, is_root=False): if doctype == 'Account': sort_accounts(acc, is_root, key="value") - company_currency = frappe.get_cached_value('Company', company, "default_currency") - for each in acc: - each["company_currency"] = company_currency - each["balance"] = flt(get_balance_on(each.get("value"), in_account_currency=False, company=company)) - - if each.account_currency != company_currency: - each["balance_in_account_currency"] = flt(get_balance_on(each.get("value"), company=company)) return acc +@frappe.whitelist() +def get_account_balances(accounts, company): + + if isinstance(accounts, string_types): + accounts = loads(accounts) + + if not accounts: + return [] + + company_currency = frappe.get_cached_value("Company", company, "default_currency") + + for account in accounts: + account["company_currency"] = company_currency + account["balance"] = flt(get_balance_on(account["value"], in_account_currency=False, company=company)) + if account["account_currency"] and account["account_currency"] != company_currency: + account["balance_in_account_currency"] = flt(get_balance_on(account["value"], company=company)) + + return accounts + def create_payment_gateway_account(gateway, payment_channel="Email"): from erpnext.setup.setup_wizard.operations.install_fixtures import create_bank_account From 83f07076b694f687670e62bf66097c4ce20c17cd Mon Sep 17 00:00:00 2001 From: Francisco Roldan Date: Thu, 19 May 2022 09:40:04 -0300 Subject: [PATCH 08/16] #27748 --- .../chart_of_accounts_importer.js | 44 ++++++++++++------- 1 file changed, 27 insertions(+), 17 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 2284c1ee4eef..5785d13f517f 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 @@ -80,6 +80,13 @@ 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), + ]); } }, @@ -105,24 +112,26 @@ frappe.ui.form.on('Chart of Accounts Importer', { }); var create_import_button = function(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); + 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); + } } - } - }); - }).addClass('btn btn-primary'); + }); + }).addClass('btn btn-primary'); + } }; var create_reset_button = function(frm) { @@ -136,6 +145,7 @@ 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': { From cc38ac06a822b932d41642eb7d4ace0507695294 Mon Sep 17 00:00:00 2001 From: marination Date: Thu, 30 Sep 2021 18:34:26 +0530 Subject: [PATCH 09/16] fix: Website Items with same Item name unhandled, thumbnails missing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Use naming series for Website Item. There could be two items with same name and different item code - Fix: Website Item Page view breaks if cart is disabled - Fix: thumbnails not created for Website Items after patch - Fix: ‘Request for Quote’ button & cart summary not visible if checkout is disabled (cherry picked from commit 36b519c962920ef08d693639077648df787a4630) --- erpnext/e_commerce/doctype/website_item/website_item.py | 1 - 1 file changed, 1 deletion(-) diff --git a/erpnext/e_commerce/doctype/website_item/website_item.py b/erpnext/e_commerce/doctype/website_item/website_item.py index c7c68cf09cf5..a34912625005 100644 --- a/erpnext/e_commerce/doctype/website_item/website_item.py +++ b/erpnext/e_commerce/doctype/website_item/website_item.py @@ -36,7 +36,6 @@ class WebsiteItem(WebsiteGenerator): def autoname(self): # use naming series to accomodate items with same name (different item code) from frappe.model.naming import make_autoname - from erpnext.setup.doctype.naming_series.naming_series import get_default_naming_series naming_series = get_default_naming_series("Website Item") From 2d35dfa8973a5c93a4fbc3096fcd45d1cc2e7ee6 Mon Sep 17 00:00:00 2001 From: marination Date: Thu, 30 Sep 2021 18:54:51 +0530 Subject: [PATCH 10/16] fix: Pre-commit formatting (cherry picked from commit 77d4849ce8eb8d25de4e2615571e0cbe6c5c9cf5) --- erpnext/e_commerce/doctype/website_item/website_item.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/erpnext/e_commerce/doctype/website_item/website_item.py b/erpnext/e_commerce/doctype/website_item/website_item.py index a34912625005..33c94ece4ea5 100644 --- a/erpnext/e_commerce/doctype/website_item/website_item.py +++ b/erpnext/e_commerce/doctype/website_item/website_item.py @@ -38,6 +38,8 @@ def autoname(self): from frappe.model.naming import make_autoname from erpnext.setup.doctype.naming_series.naming_series import get_default_naming_series + from erpnext.setup.doctype.naming_series.naming_series import get_default_naming_series + naming_series = get_default_naming_series("Website Item") if not self.name and naming_series: self.name = make_autoname(naming_series, doc=self) From 4fcb9e877151f1572cf2b56f772e55b5b8a00c78 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Tue, 5 Oct 2021 10:14:01 +0530 Subject: [PATCH 11/16] fix: Delete linked Transaction Deletion Record docs on deleting company (cherry picked from commit 38c7e42f0c4e8be7d36b3ebd61d26fed28c08ea5) --- erpnext/setup/doctype/company/company.py | 1 + 1 file changed, 1 insertion(+) diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py index d79b47b1eee4..93f80db23cd9 100644 --- a/erpnext/setup/doctype/company/company.py +++ b/erpnext/setup/doctype/company/company.py @@ -393,6 +393,7 @@ def on_trash(self): frappe.db.sql("delete from tabEmployee where company=%s", self.name) frappe.db.sql("delete from tabDepartment where company=%s", self.name) frappe.db.sql("delete from `tabTax Withholding Account` where company=%s", self.name) + frappe.db.sql("delete from `tabTransaction Deletion Record` where company=%s", self.name) # delete tax templates frappe.db.sql("delete from `tabSales Taxes and Charges Template` where company=%s", self.name) From 73b0cca5d2bfd1553af1369ce0a2019a1d343f83 Mon Sep 17 00:00:00 2001 From: Francisco Roldan Date: Thu, 19 May 2022 09:46:04 -0300 Subject: [PATCH 12/16] fix --- erpnext/accounts/doctype/payment_entry/payment_entry.py | 3 +++ erpnext/translations/es.csv | 1 + 2 files changed, 4 insertions(+) diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py index 9da08662bf65..8e799c7bccb8 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py @@ -390,6 +390,9 @@ def update_payment_schedule(self, cancel=0): invoice_paid_amount_map[invoice_key]['discounted_amt'] = ref.total_amount * (term.discount / 100) for key, allocated_amount in iteritems(invoice_payment_amount_map): + if not invoice_paid_amount_map.get(key): + frappe.throw(_('Payment term {0} not used in {1}').format(key[0], key[1])) + outstanding = flt(invoice_paid_amount_map.get(key, {}).get('outstanding')) discounted_amt = flt(invoice_paid_amount_map.get(key, {}).get('discounted_amt')) diff --git a/erpnext/translations/es.csv b/erpnext/translations/es.csv index 1d14f7424a9b..b5c0b4c7e9c3 100644 --- a/erpnext/translations/es.csv +++ b/erpnext/translations/es.csv @@ -10818,3 +10818,4 @@ Expense Claims,Reclamaciones de gastos, Fleet Management,Gestión de la flota, Loans,Préstamos, Performance,Rendimiento, +Payment term {0} not used in {1},Término de pago {0} no utilizado en {1}, From fc1c93c18aa2329ac616eb389a95338e54a992cd Mon Sep 17 00:00:00 2001 From: Francisco Roldan Date: Thu, 19 May 2022 09:48:49 -0300 Subject: [PATCH 13/16] #27732 --- erpnext/manufacturing/doctype/bom/bom.js | 27 +++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/erpnext/manufacturing/doctype/bom/bom.js b/erpnext/manufacturing/doctype/bom/bom.js index 8d05f6a296b0..cb2e9efa081a 100644 --- a/erpnext/manufacturing/doctype/bom/bom.js +++ b/erpnext/manufacturing/doctype/bom/bom.js @@ -215,7 +215,32 @@ frappe.ui.form.on("BOM", { label: __('Qty To Manufacture'), fieldname: 'qty', reqd: 1, - default: 1 + default: 1, + onchange: () => { + const { quantity, items: rm } = frm.doc; + const variant_items_map = rm.reduce((acc, item) => { + acc[item.item_code] = item.qty; + return acc; + }, {}); + const mf_qty = cur_dialog.fields_list.filter( + (f) => f.df.fieldname === "qty" + )[0]?.value; + const items = cur_dialog.fields.filter( + (f) => f.fieldname === "items" + )[0]?.data; + + if (!items) { + return; + } + + items.forEach((item) => { + item.qty = + (variant_items_map[item.item_code] * mf_qty) / + quantity; + }); + + cur_dialog.refresh(); + } }); } From ea3bae4b2d12173a0f4232c53b3d30f9cef9d6c4 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Fri, 8 Oct 2021 10:41:18 +0530 Subject: [PATCH 14/16] fix: consolidated report not consider company currency (cherry picked from commit dc4206428d86304d7b441532e0674b725b55d48d) --- erpnext/accounts/doctype/account/account.py | 6 +- .../consolidated_financial_statement.js | 5 +- .../consolidated_financial_statement.py | 72 ++++++++++++------- 3 files changed, 54 insertions(+), 29 deletions(-) diff --git a/erpnext/accounts/doctype/account/account.py b/erpnext/accounts/doctype/account/account.py index f6198eb23baa..6cfbc6d15212 100644 --- a/erpnext/accounts/doctype/account/account.py +++ b/erpnext/accounts/doctype/account/account.py @@ -4,6 +4,7 @@ from __future__ import unicode_literals import frappe +import erpnext from frappe import _, throw from frappe.utils import cint, cstr from frappe.utils.nestedset import NestedSet, get_ancestors_of, get_descendants_of @@ -196,7 +197,7 @@ def create_account_for_child_company(self, parent_acc_name_map, descendants, par "company": company, # parent account's currency should be passed down to child account's curreny # if it is None, it picks it up from default company currency, which might be unintended - "account_currency": self.account_currency, + "account_currency": erpnext.get_company_currency(company), "parent_account": parent_acc_name_map[company] }) @@ -207,8 +208,7 @@ def create_account_for_child_company(self, parent_acc_name_map, descendants, par # update the parent company's value in child companies doc = frappe.get_doc("Account", child_account) parent_value_changed = False - for field in ['account_type', 'account_currency', - 'freeze_account', 'balance_must_be']: + for field in ['account_type', 'freeze_account', 'balance_must_be']: if doc.get(field) != self.get(field): parent_value_changed = True doc.set(field, self.get(field)) diff --git a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.js b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.js index 6a8301a6f91f..e24a5f991847 100644 --- a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.js +++ b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.js @@ -103,8 +103,11 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() { column.is_tree = true; } - value = default_formatter(value, row, column, data); + if (data && data.account && column.apply_currency_formatter) { + data.currency = erpnext.get_currency(column.company_name); + } + value = default_formatter(value, row, column, data); if (!data.parent_account) { value = $(`${value}`); diff --git a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py index b0cfbac9cb1e..bca13d507926 100644 --- a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py +++ b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py @@ -7,6 +7,7 @@ from frappe import _ from frappe.utils import cint, flt, getdate +import erpnext from erpnext.accounts.report.balance_sheet.balance_sheet import ( check_opening_balance, get_chart_data, @@ -31,7 +32,7 @@ from erpnext.accounts.report.profit_and_loss_statement.profit_and_loss_statement import ( get_report_summary as get_pl_summary, ) -from erpnext.accounts.report.utils import convert_to_presentation_currency +from erpnext.accounts.report.utils import convert, convert_to_presentation_currency def execute(filters=None): @@ -42,7 +43,7 @@ def execute(filters=None): fiscal_year = get_fiscal_year_data(filters.get('from_fiscal_year'), filters.get('to_fiscal_year')) companies_column, companies = get_companies(filters) - columns = get_columns(companies_column) + columns = get_columns(companies_column, filters) if filters.get('report') == "Balance Sheet": data, message, chart, report_summary = get_balance_sheet_data(fiscal_year, companies, columns, filters) @@ -193,30 +194,37 @@ def get_account_type_based_data(account_type, companies, fiscal_year, filters): data["total"] = total return data -def get_columns(companies): - columns = [{ - "fieldname": "account", - "label": _("Account"), - "fieldtype": "Link", - "options": "Account", - "width": 300 - }] - - columns.append({ - "fieldname": "currency", - "label": _("Currency"), - "fieldtype": "Link", - "options": "Currency", - "hidden": 1 - }) +def get_columns(companies, filters): + columns = [ + { + "fieldname": "account", + "label": _("Account"), + "fieldtype": "Link", + "options": "Account", + "width": 300 + }, { + "fieldname": "currency", + "label": _("Currency"), + "fieldtype": "Link", + "options": "Currency", + "hidden": 1 + } + ] for company in companies: + apply_currency_formatter = 1 if not filters.presentation_currency else 0 + currency = filters.presentation_currency + if not currency: + currency = erpnext.get_company_currency(company) + columns.append({ "fieldname": company, - "label": company, + "label": f'{company} ({currency})', "fieldtype": "Currency", "options": "currency", - "width": 150 + "width": 150, + "apply_currency_formatter": apply_currency_formatter, + "company_name": company }) return columns @@ -236,6 +244,8 @@ def get_data(companies, root_type, balance_must_be, fiscal_year, filters=None, i start_date = filters.period_start_date if filters.report != 'Balance Sheet' else None end_date = filters.period_end_date + filters.end_date = end_date + gl_entries_by_account = {} for root in frappe.db.sql("""select lft, rgt from tabAccount where root_type=%s and ifnull(parent_account, '') = ''""", root_type, as_dict=1): @@ -246,7 +256,7 @@ def get_data(companies, root_type, balance_must_be, fiscal_year, filters=None, i calculate_values(accounts_by_name, gl_entries_by_account, companies, start_date, filters) accumulate_values_into_parents(accounts, accounts_by_name, companies) - out = prepare_data(accounts, start_date, end_date, balance_must_be, companies, company_currency) + out = prepare_data(accounts, start_date, end_date, balance_must_be, companies, company_currency, filters) if out: add_total_row(out, root_type, balance_must_be, companies, company_currency) @@ -271,10 +281,20 @@ def calculate_values(accounts_by_name, gl_entries_by_account, companies, start_d # check if posting date is within the period if (entry.company == company or (filters.get('accumulated_in_group_company')) and entry.company in companies.get(company)): - d[company] = d.get(company, 0.0) + flt(entry.debit) - flt(entry.credit) + parent_company_currency = erpnext.get_company_currency(d.company) + child_company_currency = erpnext.get_company_currency(entry.company) + + debit, credit = flt(entry.debit), flt(entry.credit) + + if (entry.company != company and parent_company_currency != child_company_currency + and filters.get('accumulated_in_group_company')): + debit = convert(debit, parent_company_currency, child_company_currency, filters.end_date) + credit = convert(credit, parent_company_currency, child_company_currency, filters.end_date) + + d[company] = d.get(company, 0.0) + flt(debit) - flt(credit) if entry.posting_date < getdate(start_date): - d["opening_balance"] = d.get("opening_balance", 0.0) + flt(entry.debit) - flt(entry.credit) + d["opening_balance"] = d.get("opening_balance", 0.0) + flt(debit) - flt(credit) def accumulate_values_into_parents(accounts, accounts_by_name, companies): """accumulate children's values in parent accounts""" @@ -353,7 +373,7 @@ def get_accounts(root_type, filters): `tabAccount` where company = %s and root_type = %s """ , (filters.get('company'), root_type), as_dict=1) -def prepare_data(accounts, start_date, end_date, balance_must_be, companies, company_currency): +def prepare_data(accounts, start_date, end_date, balance_must_be, companies, company_currency, filters): data = [] for d in accounts: @@ -368,9 +388,10 @@ def prepare_data(accounts, start_date, end_date, balance_must_be, companies, com "indent": flt(d.indent), "year_start_date": start_date, "year_end_date": end_date, - "currency": company_currency, + "currency": filters.presentation_currency, "opening_balance": d.get("opening_balance", 0.0) * (1 if balance_must_be == "Debit" else -1) }) + for company in companies: if d.get(company) and balance_must_be == "Credit": # change sign based on Debit or Credit, since calculation is done using (debit - credit) @@ -385,6 +406,7 @@ def prepare_data(accounts, start_date, end_date, balance_must_be, companies, com row["has_value"] = has_value row["total"] = total + data.append(row) return data From 35f0ff74289d2c02ed18ad265d163b34543751c9 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Sun, 10 Oct 2021 14:00:25 +0530 Subject: [PATCH 15/16] fix: opening balance to calculate 'Unclosed Fiscal Years Profit / Loss (Credit)' (cherry picked from commit 19d14da0d485c82223a58dd57d3c22512ef337c0) --- erpnext/accounts/doctype/account/account.py | 3 +- .../consolidated_financial_statement.py | 94 +++++++++++++++---- 2 files changed, 79 insertions(+), 18 deletions(-) diff --git a/erpnext/accounts/doctype/account/account.py b/erpnext/accounts/doctype/account/account.py index 6cfbc6d15212..605262f7b3ec 100644 --- a/erpnext/accounts/doctype/account/account.py +++ b/erpnext/accounts/doctype/account/account.py @@ -4,11 +4,12 @@ from __future__ import unicode_literals import frappe -import erpnext from frappe import _, throw from frappe.utils import cint, cstr from frappe.utils.nestedset import NestedSet, get_ancestors_of, get_descendants_of +import erpnext + class RootNotEditable(frappe.ValidationError): pass class BalanceMismatchError(frappe.ValidationError): pass diff --git a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py index bca13d507926..e093f9618b47 100644 --- a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py +++ b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py @@ -8,8 +8,8 @@ from frappe.utils import cint, flt, getdate import erpnext +from collections import defaultdict from erpnext.accounts.report.balance_sheet.balance_sheet import ( - check_opening_balance, get_chart_data, get_provisional_profit_loss, ) @@ -74,21 +74,24 @@ def get_balance_sheet_data(fiscal_year, companies, columns, filters): provisional_profit_loss, total_credit = get_provisional_profit_loss(asset, liability, equity, companies, filters.get('company'), company_currency, True) - message, opening_balance = check_opening_balance(asset, liability, equity) + message, opening_balance = prepare_companywise_opening_balance(asset, liability, equity, companies) - if opening_balance and round(opening_balance,2) !=0: - unclosed ={ + if opening_balance: + unclosed = { "account_name": "'" + _("Unclosed Fiscal Years Profit / Loss (Credit)") + "'", "account": "'" + _("Unclosed Fiscal Years Profit / Loss (Credit)") + "'", "warn_if_negative": True, "currency": company_currency } + for company in companies: - unclosed[company] = opening_balance - if provisional_profit_loss: - provisional_profit_loss[company] = provisional_profit_loss[company] - opening_balance + unclosed[company] = opening_balance.get(company) + if provisional_profit_loss and provisional_profit_loss.get(company): + provisional_profit_loss[company] = ( + flt(provisional_profit_loss[company]) - flt(opening_balance.get(company)) + ) - unclosed["total"]=opening_balance + unclosed["total"] = opening_balance.get(company) data.append(unclosed) if provisional_profit_loss: @@ -103,6 +106,37 @@ def get_balance_sheet_data(fiscal_year, companies, columns, filters): return data, message, chart, report_summary +def prepare_companywise_opening_balance(asset_data, liability_data, equity_data, companies): + opening_balance = {} + for company in companies: + opening_value = 0 + + # opening_value = Aseet - liability - equity + for data in [asset_data, liability_data, equity_data]: + account_name = get_root_account_name(data[0].root_type, company) + opening_value += get_opening_balance(account_name, data, company) + + opening_balance[company] = opening_value + + if opening_balance: + return _("Previous Financial Year is not closed"), opening_balance + + return '', {} + +def get_opening_balance(account_name, data, company): + for row in data: + if row.get('account_name') == account_name: + return row.get('company_wise_opening_bal', {}).get(company, 0.0) + +def get_root_account_name(root_type, company): + return frappe.get_all( + 'Account', + fields=['account_name'], + filters = {'root_type': root_type, 'is_group': 1, + 'company': company, 'parent_account': ('is', 'not set')}, + as_list=1 + )[0][0] + def get_profit_loss_data(fiscal_year, companies, columns, filters): income, expense, net_profit_loss = get_income_expense_data(companies, fiscal_year, filters) company_currency = get_company_currency(filters) @@ -254,8 +288,9 @@ def get_data(companies, root_type, balance_must_be, fiscal_year, filters=None, i end_date, root.lft, root.rgt, filters, gl_entries_by_account, accounts_by_name, accounts, ignore_closing_entries=False) - calculate_values(accounts_by_name, gl_entries_by_account, companies, start_date, filters) + calculate_values(accounts_by_name, gl_entries_by_account, companies, filters, fiscal_year) accumulate_values_into_parents(accounts, accounts_by_name, companies) + out = prepare_data(accounts, start_date, end_date, balance_must_be, companies, company_currency, filters) if out: @@ -267,7 +302,10 @@ def get_company_currency(filters=None): return (filters.get('presentation_currency') or frappe.get_cached_value('Company', filters.company, "default_currency")) -def calculate_values(accounts_by_name, gl_entries_by_account, companies, start_date, filters): +def calculate_values(accounts_by_name, gl_entries_by_account, companies, filters, fiscal_year): + start_date = (fiscal_year.year_start_date + if filters.filter_based_on == 'Fiscal Year' else filters.period_start_date) + for entries in gl_entries_by_account.values(): for entry in entries: if entry.account_number: @@ -276,7 +314,9 @@ def calculate_values(accounts_by_name, gl_entries_by_account, companies, start_d account_name = entry.account_name d = accounts_by_name.get(account_name) + if d: + debit, credit = 0, 0 for company in companies: # check if posting date is within the period if (entry.company == company or (filters.get('accumulated_in_group_company')) @@ -286,13 +326,18 @@ def calculate_values(accounts_by_name, gl_entries_by_account, companies, start_d debit, credit = flt(entry.debit), flt(entry.credit) - if (entry.company != company and parent_company_currency != child_company_currency + if (not filters.get('presentation_currency') + and entry.company != company + and parent_company_currency != child_company_currency and filters.get('accumulated_in_group_company')): debit = convert(debit, parent_company_currency, child_company_currency, filters.end_date) credit = convert(credit, parent_company_currency, child_company_currency, filters.end_date) d[company] = d.get(company, 0.0) + flt(debit) - flt(credit) + if entry.posting_date < getdate(start_date): + d['company_wise_opening_bal'][company] += (flt(debit) - flt(credit)) + if entry.posting_date < getdate(start_date): d["opening_balance"] = d.get("opening_balance", 0.0) + flt(debit) - flt(credit) @@ -302,17 +347,18 @@ def accumulate_values_into_parents(accounts, accounts_by_name, companies): if d.parent_account: account = d.parent_account_name - if not accounts_by_name.get(account): - continue + # if not accounts_by_name.get(account): + # continue for company in companies: accounts_by_name[account][company] = \ accounts_by_name[account].get(company, 0.0) + d.get(company, 0.0) + accounts_by_name[account]['company_wise_opening_bal'][company] += d.get('company_wise_opening_bal', {}).get(company, 0.0) + accounts_by_name[account]["opening_balance"] = \ accounts_by_name[account].get("opening_balance", 0.0) + d.get("opening_balance", 0.0) - def get_account_heads(root_type, companies, filters): accounts = get_accounts(root_type, filters) @@ -387,8 +433,10 @@ def prepare_data(accounts, start_date, end_date, balance_must_be, companies, com "parent_account": _(d.parent_account), "indent": flt(d.indent), "year_start_date": start_date, + "root_type": d.root_type, "year_end_date": end_date, "currency": filters.presentation_currency, + "company_wise_opening_bal": d.company_wise_opening_bal, "opening_balance": d.get("opening_balance", 0.0) * (1 if balance_must_be == "Debit" else -1) }) @@ -469,6 +517,7 @@ def get_account_details(account): 'is_group', 'account_name', 'account_number', 'parent_account', 'lft', 'rgt'], as_dict=1) def validate_entries(key, entry, accounts_by_name, accounts): + # If an account present in the child company and not in the parent company if key not in accounts_by_name: args = get_account_details(entry.account) @@ -478,12 +527,23 @@ def validate_entries(key, entry, accounts_by_name, accounts): args.update({ 'lft': parent_args.lft + 1, 'rgt': parent_args.rgt - 1, + 'indent': 3, 'root_type': parent_args.root_type, - 'report_type': parent_args.report_type + 'report_type': parent_args.report_type, + 'parent_account_name': parent_args.account_name, + 'company_wise_opening_bal': defaultdict(float) }) accounts_by_name.setdefault(key, args) - accounts.append(args) + + idx = len(accounts) + # To identify parent account index + for index, row in enumerate(accounts): + if row.parent_account_name == args.parent_account_name: + idx = index + break + + accounts.insert(idx+1, args) def get_additional_conditions(from_date, ignore_closing_entries, filters): additional_conditions = [] @@ -513,7 +573,6 @@ def add_total_row(out, root_type, balance_must_be, companies, company_currency): for company in companies: total_row.setdefault(company, 0.0) total_row[company] += row.get(company, 0.0) - row[company] = 0.0 total_row.setdefault("total", 0.0) total_row["total"] += flt(row["total"]) @@ -533,6 +592,7 @@ def filter_accounts(accounts, depth=10): account_name = d.account_number + ' - ' + d.account_name else: account_name = d.account_name + d['company_wise_opening_bal'] = defaultdict(float) accounts_by_name[account_name] = d parent_children_map.setdefault(d.parent_account or None, []).append(d) From c592506f313a49e6938dfe8e9fb5b291b3f8e486 Mon Sep 17 00:00:00 2001 From: Francisco Roldan Date: Thu, 19 May 2022 09:52:41 -0300 Subject: [PATCH 16/16] #27804 --- 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 5c9dedce2485..35bb5dfe6d8d 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py @@ -803,7 +803,8 @@ def set_missing_values(source, target): "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)