From 7169a4c1138aafdd338abfcc1653c010ef40efa5 Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Mon, 20 Sep 2021 16:41:26 +0530 Subject: [PATCH 01/37] fix(plaid): query to check if bank account exists (#27594) --- .../doctype/plaid_settings/plaid_settings.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py index 75b2bd6b810..67733bad5fd 100644 --- a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py +++ b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py @@ -83,10 +83,8 @@ def add_bank_accounts(response, bank, company): if not acc_subtype: add_account_subtype(account["subtype"]) - existing_bank_account = frappe.db.exists("Bank Account", { - 'account_name': account["name"], - 'bank': bank["bank_name"] - }) + bank_account_name = "{} - {}".format(account["name"], bank["bank_name"]) + existing_bank_account = frappe.db.exists("Bank Account", bank_account_name) if not existing_bank_account: try: @@ -198,6 +196,7 @@ def get_transactions(bank, bank_account=None, start_date=None, end_date=None): plaid = PlaidConnector(access_token) + transactions = [] try: transactions = plaid.get_transactions(start_date=start_date, end_date=end_date, account_id=account_id) except ItemError as e: @@ -206,7 +205,7 @@ def get_transactions(bank, bank_account=None, start_date=None, end_date=None): msg += _("Please refresh or reset the Plaid linking of the Bank {}.").format(bank) + " " frappe.log_error(msg, title=_("Plaid Link Refresh Required")) - return transactions or [] + return transactions def new_bank_transaction(transaction): From 8139672c7afd91abfe6a471afc4db841fbe78fbd Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Mon, 20 Sep 2021 18:19:14 +0530 Subject: [PATCH 02/37] fix: Validate if item exists on uploading items in stock reco (#27538) (#27593) * fix: Validate if item exists on uploading items in stock reco - Uploading non existent item in stock reco and then changing warehouse or batch gave an error - Check for non existent item * chore: translation Co-authored-by: Marica --- .../doctype/stock_reconciliation/stock_reconciliation.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py index 2792c4bfd46..63ec94db66a 100644 --- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py +++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py @@ -537,6 +537,11 @@ def get_stock_balance_for(item_code, warehouse, item_dict = frappe.db.get_value("Item", item_code, ["has_serial_no", "has_batch_no"], as_dict=1) + if not item_dict: + # In cases of data upload to Items table + msg = _("Item {} does not exist.").format(item_code) + frappe.throw(msg, title=_("Missing")) + serial_nos = "" with_serial_no = True if item_dict.get("has_serial_no") else False data = get_stock_balance(item_code, warehouse, posting_date, posting_time, From 999a3f1305144f8184d31384d317870cf5b53c58 Mon Sep 17 00:00:00 2001 From: pateljannat Date: Tue, 28 Sep 2021 10:32:33 +0530 Subject: [PATCH 03/37] Revert 'fix: salary component account filter' --- erpnext/hr/doctype/salary_component/salary_component.js | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/erpnext/hr/doctype/salary_component/salary_component.js b/erpnext/hr/doctype/salary_component/salary_component.js index f2a0e2e715d..247e4d422c0 100644 --- a/erpnext/hr/doctype/salary_component/salary_component.js +++ b/erpnext/hr/doctype/salary_component/salary_component.js @@ -6,16 +6,10 @@ frappe.ui.form.on('Salary Component', { frm.set_query("default_account", "accounts", function(doc, cdt, cdn) { var d = locals[cdt][cdn]; - var root_type = "Liability"; - if (frm.doc.type == "Deduction") { - root_type = "Expense"; - } - return { filters: { "is_group": 0, - "company": d.company, - "root_type": root_type + "company": d.company } }; }); From 4fdff12242e0a7414f115d2f14f0d98ad20f6c58 Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Tue, 28 Sep 2021 13:18:37 +0530 Subject: [PATCH 04/37] fix: set item.qty as mandatory (#27681) * fix: set item.qty as mandatory in picklist (#27680) (cherry picked from commit b91333afddae6b8302ad1429e420ce29b9c347ba) # Conflicts: # erpnext/stock/doctype/pick_list_item/pick_list_item.json * fix: resolve conflicts Co-authored-by: Alan <2.alan.tom@gmail.com> --- erpnext/stock/doctype/pick_list_item/pick_list_item.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/erpnext/stock/doctype/pick_list_item/pick_list_item.json b/erpnext/stock/doctype/pick_list_item/pick_list_item.json index 71fbf9a866a..3d19f361fe5 100644 --- a/erpnext/stock/doctype/pick_list_item/pick_list_item.json +++ b/erpnext/stock/doctype/pick_list_item/pick_list_item.json @@ -36,7 +36,8 @@ "fieldname": "qty", "fieldtype": "Float", "in_list_view": 1, - "label": "Qty" + "label": "Qty", + "reqd": 1 }, { "fieldname": "picked_qty", @@ -180,7 +181,7 @@ ], "istable": 1, "links": [], - "modified": "2020-03-13 19:08:21.995986", + "modified": "2021-09-28 12:02:16.923056", "modified_by": "Administrator", "module": "Stock", "name": "Pick List Item", @@ -190,4 +191,4 @@ "sort_field": "modified", "sort_order": "DESC", "track_changes": 1 -} \ No newline at end of file +} From a2b98bb80c5bfba9ba23ad2476da9f58188d92e5 Mon Sep 17 00:00:00 2001 From: Saqib Date: Tue, 28 Sep 2021 19:47:08 +0530 Subject: [PATCH 05/37] fix: cannot delete a project if linked with sales order (#27690) --- erpnext/projects/doctype/project/project.py | 4 ++++ .../projects/doctype/project/test_project.py | 18 +++++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/erpnext/projects/doctype/project/project.py b/erpnext/projects/doctype/project/project.py index 91437d37ff3..a4719bbd10f 100644 --- a/erpnext/projects/doctype/project/project.py +++ b/erpnext/projects/doctype/project/project.py @@ -86,6 +86,10 @@ class Project(Document): if self.sales_order: frappe.db.set_value("Sales Order", self.sales_order, "project", self.name) + def on_trash(self): + for so in frappe.get_all("Sales Order", {"project": self.name}, ["name"], as_dict=1): + frappe.db.set_value("Sales Order", so.name, "project", "") + def update_percent_complete(self): if self.percent_complete_method == "Manual": if self.status == "Completed": diff --git a/erpnext/projects/doctype/project/test_project.py b/erpnext/projects/doctype/project/test_project.py index 0c4f6f1bdfe..6296f7f5de2 100644 --- a/erpnext/projects/doctype/project/test_project.py +++ b/erpnext/projects/doctype/project/test_project.py @@ -8,7 +8,8 @@ test_records = frappe.get_test_records('Project') test_ignore = ["Sales Order"] from erpnext.projects.doctype.project_template.test_project_template import get_project_template, make_project_template -from erpnext.projects.doctype.project.project import set_project_status +from erpnext.selling.doctype.sales_order.sales_order import make_project as make_project_from_so +from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order from frappe.utils import getdate @@ -32,6 +33,21 @@ class TestProject(unittest.TestCase): self.assertEqual(task4.subject, 'Task 4') self.assertEqual(getdate(task4.exp_end_date), getdate('2019-01-06')) + def test_project_linking_with_sales_order(self): + so = make_sales_order() + project = make_project_from_so(so.name) + + project.save() + self.assertEqual(project.sales_order, so.name) + + so.reload() + self.assertEqual(so.project, project.name) + + project.delete() + + so.reload() + self.assertFalse(so.project) + def get_project(name): template = get_project_template() From 93a744dc12c9db602011fb066bfa208e71925653 Mon Sep 17 00:00:00 2001 From: Noah Jacob Date: Thu, 30 Sep 2021 15:40:37 +0530 Subject: [PATCH 06/37] fix: empty row on new maintenance visit. (#27626) * fix: empty row on new maintenance visit. * fix: check if rows exist --- .../maintenance/doctype/maintenance_visit/maintenance_visit.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js index fff46ad67e3..24f5ad9107d 100644 --- a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js +++ b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js @@ -27,6 +27,9 @@ frappe.ui.form.on('Maintenance Visit', { if (frm.doc.__islocal) { frm.set_value({mntc_date: frappe.datetime.get_today()}); } + if (frm.doc.purposes.length && frm.doc.purposes[0].item_name == undefined) { + frm.clear_table("purposes"); + } }, customer: function(frm) { erpnext.utils.get_party_details(frm); From d1480be5969ed11d3ff573e99a708033cbc22854 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Mon, 4 Oct 2021 22:50:11 +0530 Subject: [PATCH 07/37] fix: set item uom as stock_uom if it isn't set (backport #27623) (#27781) * fix: set item uom as stock_uom if it isn't set (#27623) * fix: set item uom as stock_uom if it isn't set (cherry picked from commit 5c372202d5fb024843fc1b13f843901f832532f7) # Conflicts: # erpnext/stock/doctype/stock_entry/stock_entry.js * fix: resolve conflicts [skip ci] Co-authored-by: Alan <2.alan.tom@gmail.com> Co-authored-by: Ankush Menat --- erpnext/stock/doctype/stock_entry/stock_entry.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js index ee53e3e0e35..85750cf40f5 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.js +++ b/erpnext/stock/doctype/stock_entry/stock_entry.js @@ -282,6 +282,12 @@ frappe.ui.form.on('Stock Entry', { frm.trigger("setup_quality_inspection"); }, + before_save: function(frm) { + frm.doc.items.forEach((item) => { + item.uom = item.uom || item.stock_uom; + }) + }, + purpose: function(frm) { frm.trigger('validate_purpose_consumption'); frm.fields_dict.items.grid.refresh(); From 10c34da17409fda7afb25406a7e7f270b2303e1e Mon Sep 17 00:00:00 2001 From: Saqib Date: Tue, 5 Oct 2021 13:13:20 +0530 Subject: [PATCH 08/37] fix: unexpected keyword argument 'as_dict' (#27799) --- erpnext/projects/doctype/project/project.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/projects/doctype/project/project.py b/erpnext/projects/doctype/project/project.py index a4719bbd10f..d23fa2a8351 100644 --- a/erpnext/projects/doctype/project/project.py +++ b/erpnext/projects/doctype/project/project.py @@ -87,8 +87,8 @@ class Project(Document): frappe.db.set_value("Sales Order", self.sales_order, "project", self.name) def on_trash(self): - for so in frappe.get_all("Sales Order", {"project": self.name}, ["name"], as_dict=1): - frappe.db.set_value("Sales Order", so.name, "project", "") + for so in frappe.get_all("Sales Order", {"project": self.name}, ["name"]): + frappe.db.set_value("Sales Order", so.get('name'), "project", "") def update_percent_complete(self): if self.percent_complete_method == "Manual": From 985fdade7e025e4dc754508f9d0307dce8a63e86 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Tue, 5 Oct 2021 14:14:52 +0530 Subject: [PATCH 09/37] fix(asset): expected value after useful life validation (#27791) --- erpnext/assets/doctype/asset/asset.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py index f03d1e43c42..6fe34bd949a 100644 --- a/erpnext/assets/doctype/asset/asset.py +++ b/erpnext/assets/doctype/asset/asset.py @@ -122,11 +122,6 @@ class Asset(AccountsController): if self.is_existing_asset: return - docname = self.purchase_receipt or self.purchase_invoice - if docname: - doctype = 'Purchase Receipt' if self.purchase_receipt else 'Purchase Invoice' - date = frappe.db.get_value(doctype, docname, 'posting_date') - if self.available_for_use_date and getdate(self.available_for_use_date) < getdate(self.purchase_date): frappe.throw(_("Available-for-use Date should be after purchase date")) @@ -404,9 +399,10 @@ class Asset(AccountsController): if accumulated_depreciation_after_full_schedule: accumulated_depreciation_after_full_schedule = max(accumulated_depreciation_after_full_schedule) - asset_value_after_full_schedule = flt(flt(self.gross_purchase_amount) - - flt(accumulated_depreciation_after_full_schedule), - self.precision('gross_purchase_amount')) + asset_value_after_full_schedule = flt( + flt(self.gross_purchase_amount) - + flt(self.opening_accumulated_depreciation) - + flt(accumulated_depreciation_after_full_schedule), self.precision('gross_purchase_amount')) if (row.expected_value_after_useful_life and row.expected_value_after_useful_life < asset_value_after_full_schedule): From c9e75d2ab59ccf09ddb62aa8ea38f3051b9cc9a6 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Fri, 4 Jun 2021 17:07:45 +0530 Subject: [PATCH 10/37] fix(patch): Handle NULL values from fieldtype change --- erpnext/patches/v11_0/rename_bom_wo_fields.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/erpnext/patches/v11_0/rename_bom_wo_fields.py b/erpnext/patches/v11_0/rename_bom_wo_fields.py index b4a740fabbf..882ec84e644 100644 --- a/erpnext/patches/v11_0/rename_bom_wo_fields.py +++ b/erpnext/patches/v11_0/rename_bom_wo_fields.py @@ -6,6 +6,10 @@ import frappe from frappe.model.utils.rename_field import rename_field def execute(): + # updating column value to handle field change from Data to Currency + changed_field = "base_scrap_material_cost" + frappe.db.sql(f"update `tabBOM` set {changed_field} = '0' where trim(coalesce({changed_field}, ''))= ''") + for doctype in ['BOM Explosion Item', 'BOM Item', 'Work Order Item', 'Item']: if frappe.db.has_column(doctype, 'allow_transfer_for_manufacture'): if doctype != 'Item': From 16ece1251679a56af0959e7d1b9527d0aee9163a Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Sat, 9 Oct 2021 18:11:52 +0530 Subject: [PATCH 11/37] fix: py2 compatible string formatting --- erpnext/patches/v11_0/rename_bom_wo_fields.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/erpnext/patches/v11_0/rename_bom_wo_fields.py b/erpnext/patches/v11_0/rename_bom_wo_fields.py index 882ec84e644..55dce6355cd 100644 --- a/erpnext/patches/v11_0/rename_bom_wo_fields.py +++ b/erpnext/patches/v11_0/rename_bom_wo_fields.py @@ -7,8 +7,7 @@ from frappe.model.utils.rename_field import rename_field def execute(): # updating column value to handle field change from Data to Currency - changed_field = "base_scrap_material_cost" - frappe.db.sql(f"update `tabBOM` set {changed_field} = '0' where trim(coalesce({changed_field}, ''))= ''") + frappe.db.sql(f"update `tabBOM` set base_scrap_material_cost = '0' where trim(coalesce(base_scrap_material_cost, ''))= ''") for doctype in ['BOM Explosion Item', 'BOM Item', 'Work Order Item', 'Item']: if frappe.db.has_column(doctype, 'allow_transfer_for_manufacture'): @@ -30,4 +29,4 @@ def execute(): else: frappe.db.sql(""" UPDATE `tab%s` SET transfer_material_against = 'Work Order' - WHERE docstatus < 2""" % (doctype)) \ No newline at end of file + WHERE docstatus < 2""" % (doctype)) From ad736f17899ec77491cbd653707a342e65cb3253 Mon Sep 17 00:00:00 2001 From: Goh Yan Chang Date: Fri, 1 Oct 2021 16:30:33 +0800 Subject: [PATCH 12/37] Update employee_leave_balance.py fix: Employee Leave Balance report showing wrong figures (cherry picked from commit 632f7848a32f577b9bd094d5368acf675f5121ca) # Conflicts: # erpnext/hr/report/employee_leave_balance/employee_leave_balance.py --- .../report/employee_leave_balance/employee_leave_balance.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py index 0a6386f103f..44b8063a00f 100644 --- a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py +++ b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py @@ -124,11 +124,17 @@ def get_allocated_and_expired_leaves(records, from_date, to_date): def get_leave_ledger_entries(from_date, to_date, employee, leave_type): records= frappe.db.sql(""" SELECT +<<<<<<< HEAD employee, leave_type, from_date, to_date, leaves, transaction_name, transaction_type is_carry_forward, is_expired +======= + employee, leave_type, from_date, to_date, leaves, transaction_name, + transaction_type, is_carry_forward, is_expired +>>>>>>> 632f7848a3 (Update employee_leave_balance.py) FROM `tabLeave Ledger Entry` WHERE employee=%(employee)s AND leave_type=%(leave_type)s AND docstatus=1 + AND transaction_type = 'Leave Allocation' AND (from_date between %(from_date)s AND %(to_date)s OR to_date between %(from_date)s AND %(to_date)s OR (from_date < %(from_date)s AND to_date > %(to_date)s)) From 9ae3f26dbfacfa3221f6b5479abe712eda448693 Mon Sep 17 00:00:00 2001 From: Jannat Patel <31363128+pateljannat@users.noreply.github.com> Date: Wed, 20 Oct 2021 12:34:04 +0530 Subject: [PATCH 13/37] fix: conflicts --- .../report/employee_leave_balance/employee_leave_balance.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py index 44b8063a00f..fe5c74ff4ac 100644 --- a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py +++ b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py @@ -124,13 +124,8 @@ def get_allocated_and_expired_leaves(records, from_date, to_date): def get_leave_ledger_entries(from_date, to_date, employee, leave_type): records= frappe.db.sql(""" SELECT -<<<<<<< HEAD - employee, leave_type, from_date, to_date, leaves, transaction_name, transaction_type - is_carry_forward, is_expired -======= employee, leave_type, from_date, to_date, leaves, transaction_name, transaction_type, is_carry_forward, is_expired ->>>>>>> 632f7848a3 (Update employee_leave_balance.py) FROM `tabLeave Ledger Entry` WHERE employee=%(employee)s AND leave_type=%(leave_type)s AND docstatus=1 From 27e9e47ba8b3847469e63d49f64d83afeae8c1b1 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Fri, 22 Oct 2021 12:16:55 +0530 Subject: [PATCH 14/37] chore: warning for shopify integration deprecation (backport #26701) (#28062) * chore: warning for shopify integration deprecation (#26701) * chore: warning for shopify integration deprecation * fix: warn deprecation during patch for sysadmins (cherry picked from commit e43bdf76a5b8a76e590dd1c15605b06c534187fb) # Conflicts: # erpnext/patches.txt * fix: resolve conflicts Co-authored-by: Ankush Co-authored-by: Ankush Menat --- .../erpnext_integrations/doctype/shopify_log/shopify_log.js | 3 +++ .../doctype/shopify_settings/shopify_settings.js | 4 ++++ erpnext/patches.txt | 2 +- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/erpnext/erpnext_integrations/doctype/shopify_log/shopify_log.js b/erpnext/erpnext_integrations/doctype/shopify_log/shopify_log.js index d3fe7d2b4d6..12faeecc87f 100644 --- a/erpnext/erpnext_integrations/doctype/shopify_log/shopify_log.js +++ b/erpnext/erpnext_integrations/doctype/shopify_log/shopify_log.js @@ -18,5 +18,8 @@ frappe.ui.form.on('Shopify Log', { }) }).addClass('btn-primary'); } + + let app_link = "Ecommerce Integrations" + frm.dashboard.add_comment(__("Shopify Integration will be removed from ERPNext in Version 14. Please install {0} app to continue using it.", [app_link]), "yellow", true); } }); diff --git a/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.js b/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.js index 1574795dfad..a926a7e52a5 100644 --- a/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.js +++ b/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.js @@ -36,6 +36,10 @@ frappe.ui.form.on("Shopify Settings", "refresh", function(frm){ frm.toggle_reqd("delivery_note_series", frm.doc.sync_delivery_note); } + + let app_link = "Ecommerce Integrations" + frm.dashboard.add_comment(__("Shopify Integration will be removed from ERPNext in Version 14. Please install {0} app to continue using it.", [app_link]), "yellow", true); + }) $.extend(erpnext_integrations.shopify_settings, { diff --git a/erpnext/patches.txt b/erpnext/patches.txt index acda0c1955c..613aaa0b2f5 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -686,4 +686,4 @@ erpnext.patches.v12_0.purchase_receipt_status erpnext.patches.v12_0.add_company_link_to_einvoice_settings erpnext.patches.v12_0.add_document_type_field_for_italy_einvoicing erpnext.patches.v12_0.create_taxable_value_field_in_purchase_invoice -erpnext.patches.v12_0.show_einvoice_irn_cancelled_field \ No newline at end of file +erpnext.patches.v12_0.show_einvoice_irn_cancelled_field From 49f93b347c2a7f0f1297d54a67ae540527c11aff Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Fri, 20 Aug 2021 02:19:18 +0530 Subject: [PATCH 15/37] fix: Display data in tree form --- erpnext/accounts/report/gross_profit/gross_profit.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/report/gross_profit/gross_profit.js b/erpnext/accounts/report/gross_profit/gross_profit.js index ba17a94e8d3..c6c43251acf 100644 --- a/erpnext/accounts/report/gross_profit/gross_profit.js +++ b/erpnext/accounts/report/gross_profit/gross_profit.js @@ -36,5 +36,9 @@ frappe.query_reports["Gross Profit"] = { "options": "Invoice\nItem Code\nItem Group\nBrand\nWarehouse\nCustomer\nCustomer Group\nTerritory\nSales Person\nProject", "default": "Invoice" }, - ] + ], + "tree": true, + "name_field": "parent", + "parent_field": "parent_invoice", + "initial_depth": 2 } From 6431243ce366c3f48941ee86ae87ea2884561cc0 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Fri, 20 Aug 2021 02:20:18 +0530 Subject: [PATCH 16/37] fix: Display items as descendants of invoices --- .../report/gross_profit/gross_profit.py | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/erpnext/accounts/report/gross_profit/gross_profit.py b/erpnext/accounts/report/gross_profit/gross_profit.py index ef048bfc3bb..15560b45f43 100644 --- a/erpnext/accounts/report/gross_profit/gross_profit.py +++ b/erpnext/accounts/report/gross_profit/gross_profit.py @@ -99,6 +99,10 @@ class GrossProfitGenerator(object): self.average_buying_rate = {} self.filters = frappe._dict(filters) self.load_invoice_items() + + if filters.group_by == 'Invoice': + self.group_items_by_invoice() + self.load_stock_ledger_entries() self.load_product_bundle() self.load_non_stock_items() @@ -356,6 +360,51 @@ class GrossProfitGenerator(object): .format(conditions=conditions, sales_person_cols=sales_person_cols, sales_team_table=sales_team_table, match_cond = get_match_cond('Sales Invoice')), self.filters, as_dict=1) + def group_items_by_invoice(self): + parents = [] + + for row in self.si_list: + if row.parent not in parents: + parents.append(row.parent) + + parents_index = 0 + for index, row in enumerate(self.si_list): + if parents_index < len(parents) and row.parent == parents[parents_index]: + invoice = frappe._dict({ + 'parent_invoice': "", + 'parent': row.parent, + 'indent': 0.0, + 'posting_date': row.posting_date, + 'posting_time': row.posting_time, + 'project': row.project, + 'update_stock': row.update_stock, + 'customer': row.customer, + 'customer_group': row.customer_group, + 'customer_group': row.customer_group, + 'item_code': None, + 'item_name': None, + 'description': None, + 'warehouse': None, + 'item_group': None, + 'brand': None, + 'dn_detail': None, + 'delivery_note': None, + 'qty': 0, + 'item_row': None, + 'is_return': row.is_return, + 'cost_center': row.cost_center, + 'base_net_amount': 0 + }) + + self.si_list.insert(index, invoice) + parents_index += 1 + + else: + row.indent = 1.0 + row.parent_invoice = row.parent + row.parent = row.item_code + self.si_list[0].base_net_amount += row.base_net_amount + def load_stock_ledger_entries(self): res = frappe.db.sql("""select item_code, voucher_type, voucher_no, voucher_detail_no, stock_value, warehouse, actual_qty as qty From e676a09c185ed4f5343f690f4d7e9a6874e7c2a2 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Fri, 20 Aug 2021 02:38:34 +0530 Subject: [PATCH 17/37] fix: Make Invoice row bold --- .../accounts/report/gross_profit/gross_profit.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/report/gross_profit/gross_profit.js b/erpnext/accounts/report/gross_profit/gross_profit.js index c6c43251acf..b3b16a8852a 100644 --- a/erpnext/accounts/report/gross_profit/gross_profit.js +++ b/erpnext/accounts/report/gross_profit/gross_profit.js @@ -40,5 +40,16 @@ frappe.query_reports["Gross Profit"] = { "tree": true, "name_field": "parent", "parent_field": "parent_invoice", - "initial_depth": 2 + "initial_depth": 2, + "formatter": function(value, row, column, data, default_formatter) { + value = default_formatter(value, row, column, data); + + if (data && !data.parent_invoice) { + value = $(`${value}`); + var $value = $(value).css("font-weight", "bold"); + value = $value.wrap("

").parent().html(); + } + + return value; + }, } From 7cf5dc7dab788a2534ea7cf7caf0b2ff080e16d6 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Fri, 20 Aug 2021 03:54:19 +0530 Subject: [PATCH 18/37] fix: Assign indent and parent_invoice --- .../report/gross_profit/gross_profit.py | 31 +++++++++++++++---- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/erpnext/accounts/report/gross_profit/gross_profit.py b/erpnext/accounts/report/gross_profit/gross_profit.py index 15560b45f43..495e4484ecb 100644 --- a/erpnext/accounts/report/gross_profit/gross_profit.py +++ b/erpnext/accounts/report/gross_profit/gross_profit.py @@ -46,10 +46,26 @@ def execute(filters=None): for col in group_wise_columns.get(scrub(filters.group_by)): row.append(src.get(col)) - row.append(filters.currency) - if idx == len(gross_profit_data.grouped_data)-1: - row[0] = frappe.bold("Total") - data.append(row) + for src in gross_profit_data.si_list: + row = frappe._dict() + row.indent = src.indent + row.parent_invoice = src.parent_invoice + row.currency = filters.currency + + for col in group_wise_columns.get(scrub(filters.group_by)): + row[column_names[col]] = src.get(col) + + data.append(row) + + else: + for src in gross_profit_data.grouped_data: + row = [] + row.append(filters.currency) + + for col in group_wise_columns.get(scrub(filters.group_by)): + row.append(src.get(col)) + + data.append(row) return columns, data @@ -393,7 +409,9 @@ class GrossProfitGenerator(object): 'item_row': None, 'is_return': row.is_return, 'cost_center': row.cost_center, - 'base_net_amount': 0 + 'base_net_amount': 0, + 'indent': 0.0, + 'parent_invoice': '' }) self.si_list.insert(index, invoice) @@ -403,7 +421,8 @@ class GrossProfitGenerator(object): row.indent = 1.0 row.parent_invoice = row.parent row.parent = row.item_code - self.si_list[0].base_net_amount += row.base_net_amount + # ind = parents_index-1 if parents_index > 0 else parents_index + # self.si_list[ind].base_net_amount += row.base_net_amount def load_stock_ledger_entries(self): res = frappe.db.sql("""select item_code, voucher_type, voucher_no, From e4995dc9ed96f2249e470869b4afef546307924f Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Fri, 20 Aug 2021 06:06:47 +0530 Subject: [PATCH 19/37] fix: Set initial_depth to 3 --- erpnext/accounts/report/gross_profit/gross_profit.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/report/gross_profit/gross_profit.js b/erpnext/accounts/report/gross_profit/gross_profit.js index b3b16a8852a..5a6346c1c1d 100644 --- a/erpnext/accounts/report/gross_profit/gross_profit.js +++ b/erpnext/accounts/report/gross_profit/gross_profit.js @@ -40,7 +40,7 @@ frappe.query_reports["Gross Profit"] = { "tree": true, "name_field": "parent", "parent_field": "parent_invoice", - "initial_depth": 2, + "initial_depth": 3, "formatter": function(value, row, column, data, default_formatter) { value = default_formatter(value, row, column, data); From 678960209c5010803b7079668c1107970c4d8c2c Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Fri, 20 Aug 2021 06:07:53 +0530 Subject: [PATCH 20/37] fix: Add items belonging to Product Bundles as children --- .../report/gross_profit/gross_profit.py | 58 ++++++++++++++++--- 1 file changed, 50 insertions(+), 8 deletions(-) diff --git a/erpnext/accounts/report/gross_profit/gross_profit.py b/erpnext/accounts/report/gross_profit/gross_profit.py index 495e4484ecb..5bb0e333466 100644 --- a/erpnext/accounts/report/gross_profit/gross_profit.py +++ b/erpnext/accounts/report/gross_profit/gross_profit.py @@ -377,6 +377,10 @@ class GrossProfitGenerator(object): sales_team_table=sales_team_table, match_cond = get_match_cond('Sales Invoice')), self.filters, as_dict=1) def group_items_by_invoice(self): + """ + Turns list of Sales Invoice Items to a tree of Sales Invoices with their Items as children. + """ + parents = [] for row in self.si_list: @@ -388,15 +392,14 @@ class GrossProfitGenerator(object): if parents_index < len(parents) and row.parent == parents[parents_index]: invoice = frappe._dict({ 'parent_invoice': "", - 'parent': row.parent, 'indent': 0.0, + 'parent': row.parent, 'posting_date': row.posting_date, 'posting_time': row.posting_time, 'project': row.project, 'update_stock': row.update_stock, 'customer': row.customer, 'customer_group': row.customer_group, - 'customer_group': row.customer_group, 'item_code': None, 'item_name': None, 'description': None, @@ -409,21 +412,60 @@ class GrossProfitGenerator(object): 'item_row': None, 'is_return': row.is_return, 'cost_center': row.cost_center, - 'base_net_amount': 0, - 'indent': 0.0, - 'parent_invoice': '' + 'base_net_amount': 0 }) self.si_list.insert(index, invoice) parents_index += 1 else: - row.indent = 1.0 - row.parent_invoice = row.parent - row.parent = row.item_code + # skipping the bundle items rows + if not row.indent: + row.indent = 1.0 + row.parent_invoice = row.parent + row.parent = row.item_code + # ind = parents_index-1 if parents_index > 0 else parents_index # self.si_list[ind].base_net_amount += row.base_net_amount + if frappe.db.exists('Product Bundle', row.item_code): + self.add_bundle_items(row, index) + + def add_bundle_items(self, product_bundle, index): + bundle_items = frappe.get_all( + 'Product Bundle Item', + filters = { + 'parent': product_bundle.item_code + }, + fields = ['item_code', 'qty'] + ) + + for i, item in enumerate(bundle_items): + bundle_item = frappe._dict({ + 'parent_invoice': product_bundle.item_code, + 'indent': product_bundle.indent + 1, + 'parent': item.item_code, + 'posting_date': product_bundle.posting_date, + 'posting_time': product_bundle.posting_time, + 'project': product_bundle.project, + 'customer': product_bundle.customer, + 'customer_group': product_bundle.customer_group, + 'item_code': item.item_code, + 'item_name': frappe.db.get_value('Item', item.item_code, 'item_name'), + 'description': frappe.db.get_value('Item', item.item_code, 'description'), + 'warehouse': product_bundle.warehouse, + 'item_group': frappe.db.get_value('Item', item.item_code, 'item_group'), + 'brand': frappe.db.get_value('Item', item.item_code, 'brand'), + 'dn_detail': product_bundle.dn_detail, + 'delivery_note': product_bundle.delivery_note, + 'qty': (product_bundle.qty * item.qty), + 'item_row': None, + 'is_return': product_bundle.is_return, + 'cost_center': product_bundle.cost_center + }) + + self.si_list.insert((index+i+1), bundle_item) + def load_stock_ledger_entries(self): res = frappe.db.sql("""select item_code, voucher_type, voucher_no, voucher_detail_no, stock_value, warehouse, actual_qty as qty From 7cc02bf861c7da2d4182b1889f1efe6adca0cb47 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Fri, 20 Aug 2021 18:25:36 +0530 Subject: [PATCH 21/37] fix: Display Items in the format Item Code: Item Name --- .../accounts/report/gross_profit/gross_profit.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/erpnext/accounts/report/gross_profit/gross_profit.py b/erpnext/accounts/report/gross_profit/gross_profit.py index 5bb0e333466..952d269860f 100644 --- a/erpnext/accounts/report/gross_profit/gross_profit.py +++ b/erpnext/accounts/report/gross_profit/gross_profit.py @@ -46,6 +46,9 @@ def execute(filters=None): for col in group_wise_columns.get(scrub(filters.group_by)): row.append(src.get(col)) + # to display item as Item Code: Item Name + columns[0] = 'Sales Invoice:Link/Item:300' + for src in gross_profit_data.si_list: row = frappe._dict() row.indent = src.indent @@ -455,12 +458,12 @@ class GrossProfitGenerator(object): 'description': frappe.db.get_value('Item', item.item_code, 'description'), 'warehouse': product_bundle.warehouse, 'item_group': frappe.db.get_value('Item', item.item_code, 'item_group'), - 'brand': frappe.db.get_value('Item', item.item_code, 'brand'), - 'dn_detail': product_bundle.dn_detail, - 'delivery_note': product_bundle.delivery_note, - 'qty': (product_bundle.qty * item.qty), - 'item_row': None, - 'is_return': product_bundle.is_return, + 'brand': frappe.db.get_value('Item', item.item_code, 'brand'), + 'dn_detail': product_bundle.dn_detail, + 'delivery_note': product_bundle.delivery_note, + 'qty': (product_bundle.qty * item.qty), + 'item_row': None, + 'is_return': product_bundle.is_return, 'cost_center': product_bundle.cost_center }) From dd7b02ad7d57e1c1521b717dcb9f0a46e70dee21 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Fri, 20 Aug 2021 18:26:17 +0530 Subject: [PATCH 22/37] fix: Remove Item Code and Item Name columns --- erpnext/accounts/report/gross_profit/gross_profit.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/erpnext/accounts/report/gross_profit/gross_profit.py b/erpnext/accounts/report/gross_profit/gross_profit.py index 952d269860f..5a4b21de827 100644 --- a/erpnext/accounts/report/gross_profit/gross_profit.py +++ b/erpnext/accounts/report/gross_profit/gross_profit.py @@ -48,6 +48,8 @@ def execute(filters=None): # to display item as Item Code: Item Name columns[0] = 'Sales Invoice:Link/Item:300' + # removing Item Code and Item Name columns + del columns[4:6] for src in gross_profit_data.si_list: row = frappe._dict() From 452c613974d45e796a56c9b4a1c40ca5ced15f40 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Mon, 23 Aug 2021 21:17:32 +0530 Subject: [PATCH 23/37] fix: Calculate total buying_amount and gross profit for each invoice --- .../report/gross_profit/gross_profit.py | 42 +++++++++++++++++-- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/erpnext/accounts/report/gross_profit/gross_profit.py b/erpnext/accounts/report/gross_profit/gross_profit.py index 5a4b21de827..ba58d617b74 100644 --- a/erpnext/accounts/report/gross_profit/gross_profit.py +++ b/erpnext/accounts/report/gross_profit/gross_profit.py @@ -137,7 +137,12 @@ class GrossProfitGenerator(object): self.currency_precision = cint(frappe.db.get_default("currency_precision")) or 3 self.float_precision = cint(frappe.db.get_default("float_precision")) or 2 - for row in self.si_list: + grouped_by_invoice = True if self.filters.get("group_by") == "Invoice" else False + + if grouped_by_invoice: + buying_amount = 0 + + for row in reversed(self.si_list): if self.skip_row(row, self.product_bundles): continue @@ -159,6 +164,13 @@ class GrossProfitGenerator(object): row.buying_amount = flt(self.get_buying_amount(row, row.item_code), self.currency_precision) + if grouped_by_invoice: + if row.indent == 1.0: + buying_amount = row.buying_amount + elif row.indent == 0.0: + row.buying_amount = buying_amount + buying_amount = 0 + # get buying rate if row.qty: row.buying_rate = flt(row.buying_amount / row.qty, self.float_precision) @@ -430,12 +442,36 @@ class GrossProfitGenerator(object): row.parent_invoice = row.parent row.parent = row.item_code - # ind = parents_index-1 if parents_index > 0 else parents_index - # self.si_list[ind].base_net_amount += row.base_net_amount + # if not self.si_list[parents_index-1].base_net_amount: + # self.si_list[parents_index-1].base_net_amount = 0 + + # self.si_list[parents_index-1].base_net_amount += row.base_net_amount + + # print("\n\n\n\n\nRow Details: ", index, ". ", row.parent, ": ", row.base_net_amount) + # print("Ind details: ", parents_index-1, ": ", self.si_list[parents_index-1].base_net_amount, "\n\n\n") if frappe.db.exists('Product Bundle', row.item_code): self.add_bundle_items(row, index) + base_net_amount = 0 + for row in reversed(self.si_list): + if row.indent == 1.0: + base_net_amount += row.get('base_net_amount') + + elif row.indent == 0.0: + row.base_net_amount = base_net_amount + base_net_amount = 0 + + # print("\n"*10) + # for index, row in enumerate(self.si_list): + # if row.indent == 0.0: + # print(index, ". ", row.parent, ": ", row.base_net_amount) + # elif row.indent == 1.0: + # print("\t", index, ". ", row.parent, ": ", row.base_net_amount) + # elif row.indent == 2.0: + # print("\t\t", index, ". ", row.parent, ": ", row.base_net_amount) + # print("") + def add_bundle_items(self, product_bundle, index): bundle_items = frappe.get_all( 'Product Bundle Item', From 391bf86e0ac37341cf534759d9d4400ec0d5e21f Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Tue, 24 Aug 2021 23:32:19 +0530 Subject: [PATCH 24/37] fix: Fetch base_net_total for each Invoice --- erpnext/accounts/report/gross_profit/gross_profit.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/erpnext/accounts/report/gross_profit/gross_profit.py b/erpnext/accounts/report/gross_profit/gross_profit.py index ba58d617b74..74ce108bcb3 100644 --- a/erpnext/accounts/report/gross_profit/gross_profit.py +++ b/erpnext/accounts/report/gross_profit/gross_profit.py @@ -429,7 +429,8 @@ class GrossProfitGenerator(object): 'item_row': None, 'is_return': row.is_return, 'cost_center': row.cost_center, - 'base_net_amount': 0 + 'base_net_amount': frappe.db.get_value('Sales Invoice', row.parent, 'base_net_total'), + 'base_rate': None }) self.si_list.insert(index, invoice) @@ -444,7 +445,7 @@ class GrossProfitGenerator(object): # if not self.si_list[parents_index-1].base_net_amount: # self.si_list[parents_index-1].base_net_amount = 0 - + # self.si_list[parents_index-1].base_net_amount += row.base_net_amount # print("\n\n\n\n\nRow Details: ", index, ". ", row.parent, ": ", row.base_net_amount) @@ -459,7 +460,7 @@ class GrossProfitGenerator(object): base_net_amount += row.get('base_net_amount') elif row.indent == 0.0: - row.base_net_amount = base_net_amount + row.base_net_amount = base_net_amount base_net_amount = 0 # print("\n"*10) @@ -471,7 +472,7 @@ class GrossProfitGenerator(object): # elif row.indent == 2.0: # print("\t\t", index, ". ", row.parent, ": ", row.base_net_amount) # print("") - + def add_bundle_items(self, product_bundle, index): bundle_items = frappe.get_all( 'Product Bundle Item', From de660bf9c4a0be2cf940e81575fc097a0099163a Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Tue, 24 Aug 2021 23:38:24 +0530 Subject: [PATCH 25/37] fix: Fetch bundle item details --- .../report/gross_profit/gross_profit.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/erpnext/accounts/report/gross_profit/gross_profit.py b/erpnext/accounts/report/gross_profit/gross_profit.py index 74ce108bcb3..87a663e630c 100644 --- a/erpnext/accounts/report/gross_profit/gross_profit.py +++ b/erpnext/accounts/report/gross_profit/gross_profit.py @@ -483,6 +483,8 @@ class GrossProfitGenerator(object): ) for i, item in enumerate(bundle_items): + item_name, description, item_group, brand = self.get_bundle_item_details(item.item_code) + bundle_item = frappe._dict({ 'parent_invoice': product_bundle.item_code, 'indent': product_bundle.indent + 1, @@ -493,14 +495,14 @@ class GrossProfitGenerator(object): 'customer': product_bundle.customer, 'customer_group': product_bundle.customer_group, 'item_code': item.item_code, - 'item_name': frappe.db.get_value('Item', item.item_code, 'item_name'), - 'description': frappe.db.get_value('Item', item.item_code, 'description'), + 'item_name': item_name, + 'description': description, 'warehouse': product_bundle.warehouse, - 'item_group': frappe.db.get_value('Item', item.item_code, 'item_group'), - 'brand': frappe.db.get_value('Item', item.item_code, 'brand'), + 'item_group': item_group, + 'brand': brand, 'dn_detail': product_bundle.dn_detail, 'delivery_note': product_bundle.delivery_note, - 'qty': (product_bundle.qty * item.qty), + 'qty': (flt(product_bundle.qty) * flt(item.qty)), 'item_row': None, 'is_return': product_bundle.is_return, 'cost_center': product_bundle.cost_center @@ -508,6 +510,13 @@ class GrossProfitGenerator(object): self.si_list.insert((index+i+1), bundle_item) + def get_bundle_item_details(self, item_code): + return frappe.db.get_value( + 'Item', + item_code, + ['item_name', 'description', 'item_group', 'brand'] + ) + def load_stock_ledger_entries(self): res = frappe.db.sql("""select item_code, voucher_type, voucher_no, voucher_detail_no, stock_value, warehouse, actual_qty as qty From 4aede0ea3f7f18d387391358837121e507b942d9 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Wed, 25 Aug 2021 00:09:07 +0530 Subject: [PATCH 26/37] fix: Calculate total buying_amount for each invoice --- erpnext/accounts/report/gross_profit/gross_profit.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/report/gross_profit/gross_profit.py b/erpnext/accounts/report/gross_profit/gross_profit.py index 87a663e630c..fa8441a79a6 100644 --- a/erpnext/accounts/report/gross_profit/gross_profit.py +++ b/erpnext/accounts/report/gross_profit/gross_profit.py @@ -166,7 +166,7 @@ class GrossProfitGenerator(object): if grouped_by_invoice: if row.indent == 1.0: - buying_amount = row.buying_amount + buying_amount += row.buying_amount elif row.indent == 0.0: row.buying_amount = buying_amount buying_amount = 0 From 6fdf4dd03eb701c306147d1cfb128fb55d4ef047 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Wed, 25 Aug 2021 00:33:55 +0530 Subject: [PATCH 27/37] fix: Remove base_rate and buying_rate for Invoice rows --- .../accounts/report/gross_profit/gross_profit.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/erpnext/accounts/report/gross_profit/gross_profit.py b/erpnext/accounts/report/gross_profit/gross_profit.py index fa8441a79a6..c91fcbc70db 100644 --- a/erpnext/accounts/report/gross_profit/gross_profit.py +++ b/erpnext/accounts/report/gross_profit/gross_profit.py @@ -176,7 +176,8 @@ class GrossProfitGenerator(object): row.buying_rate = flt(row.buying_amount / row.qty, self.float_precision) row.base_rate = flt(row.base_amount / row.qty, self.float_precision) else: - row.buying_rate, row.base_rate = 0.0, 0.0 + if self.is_not_invoice_row(row): + row.buying_rate, row.base_rate = 0.0, 0.0 # calculate gross profit row.gross_profit = flt(row.base_amount - row.buying_amount, self.currency_precision) @@ -222,14 +223,17 @@ class GrossProfitGenerator(object): for returned_item_row in returned_item_rows: row.qty += returned_item_row.qty row.base_amount += flt(returned_item_row.base_amount, self.currency_precision) - row.buying_amount = flt(row.qty * row.buying_rate, self.currency_precision) - if row.qty or row.base_amount: + row.buying_amount = flt(flt(row.qty) * flt(row.buying_rate), self.currency_precision) + if (flt(row.qty) or row.base_amount) and self.is_not_invoice_row(row): row = self.set_average_rate(row) self.grouped_data.append(row) self.add_to_totals(row) self.set_average_gross_profit(self.totals) self.grouped_data.append(self.totals) + def is_not_invoice_row(self, row): + return (self.filters.get("group_by") == "Invoice" and row.indent != 0.0) or self.filters.get("group_by") != "Invoice" + def set_average_rate(self, new_row): self.set_average_gross_profit(new_row) new_row.buying_rate = flt(new_row.buying_amount / new_row.qty, self.float_precision) if new_row.qty else 0 @@ -429,8 +433,7 @@ class GrossProfitGenerator(object): 'item_row': None, 'is_return': row.is_return, 'cost_center': row.cost_center, - 'base_net_amount': frappe.db.get_value('Sales Invoice', row.parent, 'base_net_total'), - 'base_rate': None + 'base_net_amount': frappe.db.get_value('Sales Invoice', row.parent, 'base_net_total') }) self.si_list.insert(index, invoice) From ae6e69ebd4c4f65fc31ef94f781ef6f143dcf976 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Wed, 25 Aug 2021 02:49:14 +0530 Subject: [PATCH 28/37] fix: Display only the Invoice rows in bold --- erpnext/accounts/report/gross_profit/gross_profit.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/report/gross_profit/gross_profit.js b/erpnext/accounts/report/gross_profit/gross_profit.js index 5a6346c1c1d..856b97d1645 100644 --- a/erpnext/accounts/report/gross_profit/gross_profit.js +++ b/erpnext/accounts/report/gross_profit/gross_profit.js @@ -44,7 +44,7 @@ frappe.query_reports["Gross Profit"] = { "formatter": function(value, row, column, data, default_formatter) { value = default_formatter(value, row, column, data); - if (data && !data.parent_invoice) { + if (data && data.indent == 0.0) { value = $(`${value}`); var $value = $(value).css("font-weight", "bold"); value = $value.wrap("

").parent().html(); From 70244cee8960414cec17284be3230714228fb1ec Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Wed, 25 Aug 2021 02:52:18 +0530 Subject: [PATCH 29/37] fix: Get data when grouped by invoice and otherwise --- .../report/gross_profit/gross_profit.py | 59 ++++++++++--------- 1 file changed, 32 insertions(+), 27 deletions(-) diff --git a/erpnext/accounts/report/gross_profit/gross_profit.py b/erpnext/accounts/report/gross_profit/gross_profit.py index c91fcbc70db..0a96d98e75e 100644 --- a/erpnext/accounts/report/gross_profit/gross_profit.py +++ b/erpnext/accounts/report/gross_profit/gross_profit.py @@ -41,38 +41,43 @@ def execute(filters=None): columns = get_columns(group_wise_columns, filters) + if filters.group_by == 'Invoice': + get_data_when_grouped_by_invoice(columns, gross_profit_data, filters, group_wise_columns, data) + + else: + get_data_when_not_grouped_by_invoice(gross_profit_data, filters, group_wise_columns, data) + + return columns, data + +def get_data_when_grouped_by_invoice(columns, gross_profit_data, filters, group_wise_columns, data): + column_names = get_column_names() + + # to display item as Item Code: Item Name + columns[0] = 'Sales Invoice:Link/Item:300' + # removing Item Code and Item Name columns + del columns[4:6] + + for src in gross_profit_data.si_list: + row = frappe._dict() + row.indent = src.indent + row.parent_invoice = src.parent_invoice + row.currency = filters.currency + + for col in group_wise_columns.get(scrub(filters.group_by)): + row[column_names[col]] = src.get(col) + + data.append(row) + +def get_data_when_not_grouped_by_invoice(gross_profit_data, filters, group_wise_columns, data): for idx, src in enumerate(gross_profit_data.grouped_data): row = [] for col in group_wise_columns.get(scrub(filters.group_by)): row.append(src.get(col)) - # to display item as Item Code: Item Name - columns[0] = 'Sales Invoice:Link/Item:300' - # removing Item Code and Item Name columns - del columns[4:6] - - for src in gross_profit_data.si_list: - row = frappe._dict() - row.indent = src.indent - row.parent_invoice = src.parent_invoice - row.currency = filters.currency - - for col in group_wise_columns.get(scrub(filters.group_by)): - row[column_names[col]] = src.get(col) - - data.append(row) - - else: - for src in gross_profit_data.grouped_data: - row = [] - row.append(filters.currency) - - for col in group_wise_columns.get(scrub(filters.group_by)): - row.append(src.get(col)) - - data.append(row) - - return columns, data + row.append(filters.currency) + if idx == len(gross_profit_data.grouped_data)-1: + row[0] = frappe.bold("Total") + data.append(row) def get_columns(group_wise_columns, filters): columns = [] From e2e751e26f2dd1d3d923946a9216ecf790415dd7 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Wed, 25 Aug 2021 15:20:27 +0530 Subject: [PATCH 30/37] fix: Remove comments --- .../report/gross_profit/gross_profit.py | 31 ++----------------- 1 file changed, 2 insertions(+), 29 deletions(-) diff --git a/erpnext/accounts/report/gross_profit/gross_profit.py b/erpnext/accounts/report/gross_profit/gross_profit.py index 0a96d98e75e..3349a2ae54f 100644 --- a/erpnext/accounts/report/gross_profit/gross_profit.py +++ b/erpnext/accounts/report/gross_profit/gross_profit.py @@ -451,35 +451,8 @@ class GrossProfitGenerator(object): row.parent_invoice = row.parent row.parent = row.item_code - # if not self.si_list[parents_index-1].base_net_amount: - # self.si_list[parents_index-1].base_net_amount = 0 - - # self.si_list[parents_index-1].base_net_amount += row.base_net_amount - - # print("\n\n\n\n\nRow Details: ", index, ". ", row.parent, ": ", row.base_net_amount) - # print("Ind details: ", parents_index-1, ": ", self.si_list[parents_index-1].base_net_amount, "\n\n\n") - - if frappe.db.exists('Product Bundle', row.item_code): - self.add_bundle_items(row, index) - - base_net_amount = 0 - for row in reversed(self.si_list): - if row.indent == 1.0: - base_net_amount += row.get('base_net_amount') - - elif row.indent == 0.0: - row.base_net_amount = base_net_amount - base_net_amount = 0 - - # print("\n"*10) - # for index, row in enumerate(self.si_list): - # if row.indent == 0.0: - # print(index, ". ", row.parent, ": ", row.base_net_amount) - # elif row.indent == 1.0: - # print("\t", index, ". ", row.parent, ": ", row.base_net_amount) - # elif row.indent == 2.0: - # print("\t\t", index, ". ", row.parent, ": ", row.base_net_amount) - # print("") + if frappe.db.exists('Product Bundle', row.item_code): + self.add_bundle_items(row, index) def add_bundle_items(self, product_bundle, index): bundle_items = frappe.get_all( From 94162e013922fc34eb5483ad2ccf3ad9bd4d307a Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Wed, 25 Aug 2021 15:33:53 +0530 Subject: [PATCH 31/37] fix: Get Bundle Items --- .../report/gross_profit/gross_profit.py | 89 +++++++++++++------ 1 file changed, 63 insertions(+), 26 deletions(-) diff --git a/erpnext/accounts/report/gross_profit/gross_profit.py b/erpnext/accounts/report/gross_profit/gross_profit.py index 3349a2ae54f..d38156ac040 100644 --- a/erpnext/accounts/report/gross_profit/gross_profit.py +++ b/erpnext/accounts/report/gross_profit/gross_profit.py @@ -416,31 +416,7 @@ class GrossProfitGenerator(object): parents_index = 0 for index, row in enumerate(self.si_list): if parents_index < len(parents) and row.parent == parents[parents_index]: - invoice = frappe._dict({ - 'parent_invoice': "", - 'indent': 0.0, - 'parent': row.parent, - 'posting_date': row.posting_date, - 'posting_time': row.posting_time, - 'project': row.project, - 'update_stock': row.update_stock, - 'customer': row.customer, - 'customer_group': row.customer_group, - 'item_code': None, - 'item_name': None, - 'description': None, - 'warehouse': None, - 'item_group': None, - 'brand': None, - 'dn_detail': None, - 'delivery_note': None, - 'qty': 0, - 'item_row': None, - 'is_return': row.is_return, - 'cost_center': row.cost_center, - 'base_net_amount': frappe.db.get_value('Sales Invoice', row.parent, 'base_net_total') - }) - + invoice = self.get_invoice_row(row) self.si_list.insert(index, invoice) parents_index += 1 @@ -454,8 +430,41 @@ class GrossProfitGenerator(object): if frappe.db.exists('Product Bundle', row.item_code): self.add_bundle_items(row, index) + def get_invoice_row(self, row): + return frappe._dict({ + 'parent_invoice': "", + 'indent': 0.0, + 'parent': row.parent, + 'posting_date': row.posting_date, + 'posting_time': row.posting_time, + 'project': row.project, + 'update_stock': row.update_stock, + 'customer': row.customer, + 'customer_group': row.customer_group, + 'item_code': None, + 'item_name': None, + 'description': None, + 'warehouse': None, + 'item_group': None, + 'brand': None, + 'dn_detail': None, + 'delivery_note': None, + 'qty': None, + 'item_row': None, + 'is_return': row.is_return, + 'cost_center': row.cost_center, + 'base_net_amount': frappe.db.get_value('Sales Invoice', row.parent, 'base_net_total') + }) + def add_bundle_items(self, product_bundle, index): - bundle_items = frappe.get_all( + bundle_items = self.get_bundle_items(product_bundle) + + for i, item in enumerate(bundle_items): + bundle_item = self.get_bundle_item_row(product_bundle, item) + self.si_list.insert((index+i+1), bundle_item) + + def get_bundle_items(self, product_bundle): + return frappe.get_all( 'Product Bundle Item', filters = { 'parent': product_bundle.item_code @@ -463,6 +472,7 @@ class GrossProfitGenerator(object): fields = ['item_code', 'qty'] ) +<<<<<<< HEAD for i, item in enumerate(bundle_items): item_name, description, item_group, brand = self.get_bundle_item_details(item.item_code) @@ -490,6 +500,33 @@ class GrossProfitGenerator(object): }) self.si_list.insert((index+i+1), bundle_item) +======= + def get_bundle_item_row(self, product_bundle, item): + item_name, description, item_group, brand = self.get_bundle_item_details(item.item_code) + + return frappe._dict({ + 'parent_invoice': product_bundle.item_code, + 'indent': product_bundle.indent + 1, + 'parent': item.item_code, + 'posting_date': product_bundle.posting_date, + 'posting_time': product_bundle.posting_time, + 'project': product_bundle.project, + 'customer': product_bundle.customer, + 'customer_group': product_bundle.customer_group, + 'item_code': item.item_code, + 'item_name': item_name, + 'description': description, + 'warehouse': product_bundle.warehouse, + 'item_group': item_group, + 'brand': brand, + 'dn_detail': product_bundle.dn_detail, + 'delivery_note': product_bundle.delivery_note, + 'qty': (flt(product_bundle.qty) * flt(item.qty)), + 'item_row': None, + 'is_return': product_bundle.is_return, + 'cost_center': product_bundle.cost_center + }) +>>>>>>> 3135d6dc6a (fix: Get Bundle Items) def get_bundle_item_details(self, item_code): return frappe.db.get_value( From 5bc7d63646fe1893ead67c3c890647178c70edbe Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Wed, 25 Aug 2021 15:33:53 +0530 Subject: [PATCH 32/37] fix: Get Bundle Items --- .../report/gross_profit/gross_profit.py | 30 ------------------- 1 file changed, 30 deletions(-) diff --git a/erpnext/accounts/report/gross_profit/gross_profit.py b/erpnext/accounts/report/gross_profit/gross_profit.py index d38156ac040..8d30af3964e 100644 --- a/erpnext/accounts/report/gross_profit/gross_profit.py +++ b/erpnext/accounts/report/gross_profit/gross_profit.py @@ -472,35 +472,6 @@ class GrossProfitGenerator(object): fields = ['item_code', 'qty'] ) -<<<<<<< HEAD - for i, item in enumerate(bundle_items): - item_name, description, item_group, brand = self.get_bundle_item_details(item.item_code) - - bundle_item = frappe._dict({ - 'parent_invoice': product_bundle.item_code, - 'indent': product_bundle.indent + 1, - 'parent': item.item_code, - 'posting_date': product_bundle.posting_date, - 'posting_time': product_bundle.posting_time, - 'project': product_bundle.project, - 'customer': product_bundle.customer, - 'customer_group': product_bundle.customer_group, - 'item_code': item.item_code, - 'item_name': item_name, - 'description': description, - 'warehouse': product_bundle.warehouse, - 'item_group': item_group, - 'brand': brand, - 'dn_detail': product_bundle.dn_detail, - 'delivery_note': product_bundle.delivery_note, - 'qty': (flt(product_bundle.qty) * flt(item.qty)), - 'item_row': None, - 'is_return': product_bundle.is_return, - 'cost_center': product_bundle.cost_center - }) - - self.si_list.insert((index+i+1), bundle_item) -======= def get_bundle_item_row(self, product_bundle, item): item_name, description, item_group, brand = self.get_bundle_item_details(item.item_code) @@ -526,7 +497,6 @@ class GrossProfitGenerator(object): 'is_return': product_bundle.is_return, 'cost_center': product_bundle.cost_center }) ->>>>>>> 3135d6dc6a (fix: Get Bundle Items) def get_bundle_item_details(self, item_code): return frappe.db.get_value( From 5f2819c9b1f244c68deb4f1cb4ca0e7bfaa5b73b Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Mon, 25 Oct 2021 02:24:19 +0530 Subject: [PATCH 33/37] fix: Add column names --- .../report/gross_profit/gross_profit.py | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/erpnext/accounts/report/gross_profit/gross_profit.py b/erpnext/accounts/report/gross_profit/gross_profit.py index 8d30af3964e..a9323df8098 100644 --- a/erpnext/accounts/report/gross_profit/gross_profit.py +++ b/erpnext/accounts/report/gross_profit/gross_profit.py @@ -119,6 +119,28 @@ def get_columns(group_wise_columns, filters): return columns +def get_column_names(): + return frappe._dict({ + 'parent': 'sales_invoice', + 'customer': 'customer', + 'customer_group': 'customer_group', + 'posting_date': 'posting_date', + 'item_code': 'item_code', + 'item_name': 'item_name', + 'item_group': 'item_group', + 'brand': 'brand', + 'description': 'description', + 'warehouse': 'warehouse', + 'qty': 'qty', + 'base_rate': 'avg._selling_rate', + 'buying_rate': 'valuation_rate', + 'base_amount': 'selling_amount', + 'buying_amount': 'buying_amount', + 'gross_profit': 'gross_profit', + 'gross_profit_percent': 'gross_profit_%', + 'project': 'project' + }) + class GrossProfitGenerator(object): def __init__(self, filters=None): self.data = [] From e60d7ac09ecf84f14a082b1dfd82e6a653d12aaa Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Thu, 28 Oct 2021 23:11:53 +0530 Subject: [PATCH 34/37] fix: python2 string formatting --- erpnext/patches/v11_0/rename_bom_wo_fields.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/patches/v11_0/rename_bom_wo_fields.py b/erpnext/patches/v11_0/rename_bom_wo_fields.py index 55dce6355cd..f055f9450c1 100644 --- a/erpnext/patches/v11_0/rename_bom_wo_fields.py +++ b/erpnext/patches/v11_0/rename_bom_wo_fields.py @@ -7,7 +7,7 @@ from frappe.model.utils.rename_field import rename_field def execute(): # updating column value to handle field change from Data to Currency - frappe.db.sql(f"update `tabBOM` set base_scrap_material_cost = '0' where trim(coalesce(base_scrap_material_cost, ''))= ''") + frappe.db.sql("update `tabBOM` set base_scrap_material_cost = '0' where trim(coalesce(base_scrap_material_cost, ''))= ''") for doctype in ['BOM Explosion Item', 'BOM Item', 'Work Order Item', 'Item']: if frappe.db.has_column(doctype, 'allow_transfer_for_manufacture'): From 7ac656d73797d82b7e04cbdb20dc034524b696ac Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Sat, 30 Oct 2021 14:44:31 +0530 Subject: [PATCH 35/37] chore: change log for v12.26.0 --- erpnext/change_log/v12/v12_26_0.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 erpnext/change_log/v12/v12_26_0.md diff --git a/erpnext/change_log/v12/v12_26_0.md b/erpnext/change_log/v12/v12_26_0.md new file mode 100644 index 00000000000..a681e56d41e --- /dev/null +++ b/erpnext/change_log/v12/v12_26_0.md @@ -0,0 +1,8 @@ +## Version 12.26.0 Release Notes + +### Fixes & Enhancements +- Make Gross Profit Report more readable ([#27124](https://github.com/frappe/erpnext/pull/27124)) +- Set item uom as stock_uom if it isn't set ([#27623](https://github.com/frappe/erpnext/pull/27623)) +- Adding empty row on new maintenance visit ([#27626](https://github.com/frappe/erpnext/pull/27626)) +- Employee Leave Balance report should only consider ledgers of transaction type Leave Allocation ([#28017](https://github.com/frappe/erpnext/pull/28017)) +- Validate if item exists on uploading items in stock reco ([#27538](https://github.com/frappe/erpnext/pull/27538)) \ No newline at end of file From aa0e21e84bd9fbe55a9c9fe39311ebb97bc18280 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Sat, 30 Oct 2021 15:00:32 +0530 Subject: [PATCH 36/37] fix: change log --- erpnext/change_log/v12/v12_26_0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/change_log/v12/v12_26_0.md b/erpnext/change_log/v12/v12_26_0.md index a681e56d41e..557f4484cec 100644 --- a/erpnext/change_log/v12/v12_26_0.md +++ b/erpnext/change_log/v12/v12_26_0.md @@ -1,4 +1,4 @@ -## Version 12.26.0 Release Notes +## ERPNext Version 12.26.0 Release Notes ### Fixes & Enhancements - Make Gross Profit Report more readable ([#27124](https://github.com/frappe/erpnext/pull/27124)) From 1e378cfde06223e5a85ac6a050049dd696779def Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Sat, 30 Oct 2021 15:24:29 +0550 Subject: [PATCH 37/37] bumped to version 12.26.0 --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index d74647b821c..d65b2fa55cc 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -5,7 +5,7 @@ import frappe from erpnext.hooks import regional_overrides from frappe.utils import getdate -__version__ = '12.25.0' +__version__ = '12.26.0' def get_default_company(user=None): '''Get default company for user'''