From 4a77bd23041e2061585eb9259416d2652dc6748c Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Wed, 18 Aug 2021 00:33:43 +0530 Subject: [PATCH 01/58] fix: Syntax error --- erpnext/accounts/doctype/sales_invoice/sales_invoice.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js index 7a273c7504..fc88747f17 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js @@ -447,7 +447,7 @@ erpnext.accounts.SalesInvoiceController = class SalesInvoiceController extends e this.frm.refresh_field("outstanding_amount"); this.frm.refresh_field("paid_amount"); this.frm.refresh_field("base_paid_amount"); - }, + } currency() { this._super(); From 76921137edcf616f8aad89078a9047017545a268 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Fri, 20 Aug 2021 02:16:49 +0530 Subject: [PATCH 02/58] fix: Return data as dict if the report is grouped by Invoice --- .../report/gross_profit/gross_profit.py | 59 +++++++++++++++++-- 1 file changed, 53 insertions(+), 6 deletions(-) diff --git a/erpnext/accounts/report/gross_profit/gross_profit.py b/erpnext/accounts/report/gross_profit/gross_profit.py index 6d8623c189..b2602792ab 100644 --- a/erpnext/accounts/report/gross_profit/gross_profit.py +++ b/erpnext/accounts/report/gross_profit/gross_profit.py @@ -41,14 +41,35 @@ def execute(filters=None): columns = get_columns(group_wise_columns, filters) - for src in gross_profit_data.grouped_data: - row = [] - for col in group_wise_columns.get(scrub(filters.group_by)): - row.append(src.get(col)) + if filters.group_by == 'Invoice': + column_names = get_column_names() - row.append(filters.currency) - data.append(row) + for src in gross_profit_data.si_list: + row = frappe._dict() + row['currency'] = filters.currency + for col in group_wise_columns.get(scrub(filters.group_by)): + row[column_names[col]] = src.get(col) + + if row.item_code: + row.indent = 1.0 + row.parent_invoice = src.parent_invoice + else: + row.indent = 0.0 + row.parent_invoice = '' + + 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 def get_columns(group_wise_columns, filters): @@ -91,12 +112,38 @@ 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 = [] 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() From 17a154017b92ee83b5ab16f7f366917025d9ea50 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Fri, 20 Aug 2021 02:19:18 +0530 Subject: [PATCH 03/58] 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 ba17a94e8d..c6c43251ac 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 5ffaff8e482b3db65c1799221abe08272945fa7e Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Fri, 20 Aug 2021 02:20:18 +0530 Subject: [PATCH 04/58] fix: Display items as descendants of invoices --- .../report/gross_profit/gross_profit.py | 49 ++++++++++++++++++- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/report/gross_profit/gross_profit.py b/erpnext/accounts/report/gross_profit/gross_profit.py index b2602792ab..15d74bb85d 100644 --- a/erpnext/accounts/report/gross_profit/gross_profit.py +++ b/erpnext/accounts/report/gross_profit/gross_profit.py @@ -141,8 +141,8 @@ class GrossProfitGenerator(object): self.filters = frappe._dict(filters) self.load_invoice_items() - # if filters.group_by == 'Invoice': - # self.group_items_by_invoice() + if filters.group_by == 'Invoice': + self.group_items_by_invoice() self.load_stock_ledger_entries() self.load_product_bundle() @@ -379,6 +379,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 779a1d68a56fef7d2fb448271abd73668dddfb23 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Fri, 20 Aug 2021 02:38:34 +0530 Subject: [PATCH 05/58] 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 c6c43251ac..b3b16a8852 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 97a1d426a324af0f9fd92809ba58d3562be1314f Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Fri, 20 Aug 2021 03:54:19 +0530 Subject: [PATCH 06/58] fix: Assign indent and parent_invoice --- .../report/gross_profit/gross_profit.py | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/erpnext/accounts/report/gross_profit/gross_profit.py b/erpnext/accounts/report/gross_profit/gross_profit.py index 15d74bb85d..549c668c62 100644 --- a/erpnext/accounts/report/gross_profit/gross_profit.py +++ b/erpnext/accounts/report/gross_profit/gross_profit.py @@ -46,18 +46,13 @@ def execute(filters=None): for src in gross_profit_data.si_list: row = frappe._dict() - row['currency'] = filters.currency + 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) - if row.item_code: - row.indent = 1.0 - row.parent_invoice = src.parent_invoice - else: - row.indent = 0.0 - row.parent_invoice = '' - data.append(row) else: @@ -412,7 +407,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) @@ -422,7 +419,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 33f100d75da4d9edc5c85446fb2bf9d960056a68 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Fri, 20 Aug 2021 06:06:47 +0530 Subject: [PATCH 07/58] 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 b3b16a8852..5a6346c1c1 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 b5fac839870961b044bfb0cbf520237e0aa01157 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Fri, 20 Aug 2021 06:07:53 +0530 Subject: [PATCH 08/58] 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 549c668c62..87053a0972 100644 --- a/erpnext/accounts/report/gross_profit/gross_profit.py +++ b/erpnext/accounts/report/gross_profit/gross_profit.py @@ -375,6 +375,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: @@ -386,15 +390,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, @@ -407,21 +410,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 75d4fc99fca4726d90c15d592a8d4c269d5fe25a Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Fri, 20 Aug 2021 18:25:36 +0530 Subject: [PATCH 09/58] fix: Display Items in the format Item Code: Item Name --- erpnext/accounts/report/gross_profit/gross_profit.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/erpnext/accounts/report/gross_profit/gross_profit.py b/erpnext/accounts/report/gross_profit/gross_profit.py index 87053a0972..d202d86fcb 100644 --- a/erpnext/accounts/report/gross_profit/gross_profit.py +++ b/erpnext/accounts/report/gross_profit/gross_profit.py @@ -44,6 +44,9 @@ def execute(filters=None): if filters.group_by == 'Invoice': column_names = get_column_names() + # 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 From d1453c0cd09a10a2090df1ba71fc89ef94a7199a Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Fri, 20 Aug 2021 18:26:17 +0530 Subject: [PATCH 10/58] 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 d202d86fcb..842e32e9a5 100644 --- a/erpnext/accounts/report/gross_profit/gross_profit.py +++ b/erpnext/accounts/report/gross_profit/gross_profit.py @@ -46,6 +46,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 46650cce0d311de0abcae3ee11662319d0173a0b Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Mon, 23 Aug 2021 21:17:32 +0530 Subject: [PATCH 11/58] 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 842e32e9a5..14bd2da742 100644 --- a/erpnext/accounts/report/gross_profit/gross_profit.py +++ b/erpnext/accounts/report/gross_profit/gross_profit.py @@ -157,7 +157,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 @@ -179,6 +184,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) @@ -428,12 +440,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 91af0d6ffb665159716092012281b5695f2a6c33 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Tue, 24 Aug 2021 17:57:55 +0530 Subject: [PATCH 12/58] fix: Add Bundle Items table --- erpnext/selling/doctype/quotation/quotation.json | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/erpnext/selling/doctype/quotation/quotation.json b/erpnext/selling/doctype/quotation/quotation.json index 3eba62bc19..6a638a3c2b 100644 --- a/erpnext/selling/doctype/quotation/quotation.json +++ b/erpnext/selling/doctype/quotation/quotation.json @@ -84,6 +84,8 @@ "rounding_adjustment", "rounded_total", "in_words", + "bundle_items_section", + "packed_items", "payment_schedule_section", "payment_terms_template", "payment_schedule", @@ -926,6 +928,17 @@ "label": "Lost Reasons", "options": "Quotation Lost Reason Detail", "read_only": 1 + }, + { + "fieldname": "packed_items", + "fieldtype": "Table", + "label": "Bundle Items", + "options": "Packed Item" + }, + { + "fieldname": "bundle_items_section", + "fieldtype": "Section Break", + "label": "Bundle Items" } ], "icon": "fa fa-shopping-cart", @@ -933,7 +946,7 @@ "is_submittable": 1, "links": [], "max_attachments": 1, - "modified": "2020-10-30 13:58:59.212060", + "modified": "2021-08-24 17:56:39.199033", "modified_by": "Administrator", "module": "Selling", "name": "Quotation", From 8af5802e42146f40fdbf6092705a4e18faeccb9c Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Tue, 24 Aug 2021 17:58:23 +0530 Subject: [PATCH 13/58] fix: Populate Bundle Items table --- erpnext/selling/doctype/quotation/quotation.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/erpnext/selling/doctype/quotation/quotation.py b/erpnext/selling/doctype/quotation/quotation.py index e4f8a47581..6cd03dd279 100644 --- a/erpnext/selling/doctype/quotation/quotation.py +++ b/erpnext/selling/doctype/quotation/quotation.py @@ -31,6 +31,9 @@ class Quotation(SellingController): if self.items: self.with_items = 1 + from erpnext.stock.doctype.packed_item.packed_item import make_packing_list + make_packing_list(self) + def validate_valid_till(self): if self.valid_till and getdate(self.valid_till) < getdate(self.transaction_date): frappe.throw(_("Valid till date cannot be before transaction date")) From b4b6d10b5dfe4948fd1c7d11a606795a1dc40730 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Tue, 24 Aug 2021 17:59:11 +0530 Subject: [PATCH 14/58] fix: Add editable Rate column --- erpnext/stock/doctype/packed_item/packed_item.json | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/erpnext/stock/doctype/packed_item/packed_item.json b/erpnext/stock/doctype/packed_item/packed_item.json index bb396e806f..00c175f03b 100644 --- a/erpnext/stock/doctype/packed_item/packed_item.json +++ b/erpnext/stock/doctype/packed_item/packed_item.json @@ -16,6 +16,7 @@ "conversion_factor", "column_break_9", "qty", + "rate", "uom", "section_break_9", "serial_no", @@ -215,13 +216,20 @@ "fieldname": "conversion_factor", "fieldtype": "Float", "label": "Conversion Factor" + }, + { + "fetch_from": "item_code.valuation_rate", + "fieldname": "rate", + "fieldtype": "Currency", + "in_list_view": 1, + "label": "Rate" } ], "idx": 1, "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2021-05-26 07:08:05.111385", + "modified": "2021-08-20 23:31:05.393712", "modified_by": "Administrator", "module": "Stock", "name": "Packed Item", From 31482a08dc248eb752838313ade965ff8dc52811 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Tue, 24 Aug 2021 21:42:44 +0530 Subject: [PATCH 15/58] fix: Update Product Bundle price based on the rates of its child Items --- .../stock/doctype/packed_item/packed_item.py | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/erpnext/stock/doctype/packed_item/packed_item.py b/erpnext/stock/doctype/packed_item/packed_item.py index 4ab71bdf62..d2c07d2806 100644 --- a/erpnext/stock/doctype/packed_item/packed_item.py +++ b/erpnext/stock/doctype/packed_item/packed_item.py @@ -85,6 +85,7 @@ def make_packing_list(doc): parent_items.append([d.item_code, d.name]) cleanup_packing_list(doc, parent_items) + update_product_bundle_price(doc, parent_items) def cleanup_packing_list(doc, parent_items): """Remove all those child items which are no longer present in main item table""" @@ -103,6 +104,40 @@ def cleanup_packing_list(doc, parent_items): if d not in delete_list: doc.append("packed_items", d) +def update_product_bundle_price(doc, parent_items): + """Updates the prices of Product Bundles based on the rates of the Items in the bundle.""" + + parent_items_index = 0 + bundle_price = 0 + parent_items_doctype = doc.items[0].doctype + + for bundle_item in doc.get("packed_items"): + if parent_items[parent_items_index][0] == bundle_item.parent_item: + bundle_price += bundle_item.qty * bundle_item.rate + else: + update_parent_item_price(doc, parent_items_doctype, parent_items[parent_items_index][0], bundle_price) + + bundle_price = 0 + parent_items_index += 1 + + # for the last product bundle + update_parent_item_price(doc, parent_items_doctype, parent_items[parent_items_index][0], bundle_price) + doc.reload() + +def update_parent_item_price(doc, parent_items_doctype, parent_item_code, bundle_price): + parent_item_doc_name = frappe.db.get_value( + parent_items_doctype, + { + 'parent': doc.name, + 'item_code': parent_item_code + }, + 'name' + ) + + current_parent_item_price = frappe.db.get_value(parent_items_doctype, parent_item_doc_name, 'amount') + if current_parent_item_price != bundle_price: + frappe.db.set_value(parent_items_doctype, parent_item_doc_name, 'amount', bundle_price) + @frappe.whitelist() def get_items_from_product_bundle(args): args = json.loads(args) From 129df6e129ec74e5d63a8b5f605a4561f0020e28 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Tue, 24 Aug 2021 21:55:54 +0530 Subject: [PATCH 16/58] fix: Update Product Bundle rate based on its updated amount --- erpnext/stock/doctype/packed_item/packed_item.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/erpnext/stock/doctype/packed_item/packed_item.py b/erpnext/stock/doctype/packed_item/packed_item.py index d2c07d2806..ea963ed8e8 100644 --- a/erpnext/stock/doctype/packed_item/packed_item.py +++ b/erpnext/stock/doctype/packed_item/packed_item.py @@ -137,6 +137,11 @@ def update_parent_item_price(doc, parent_items_doctype, parent_item_code, bundle current_parent_item_price = frappe.db.get_value(parent_items_doctype, parent_item_doc_name, 'amount') if current_parent_item_price != bundle_price: frappe.db.set_value(parent_items_doctype, parent_item_doc_name, 'amount', bundle_price) + update_parent_item_rate(parent_items_doctype, parent_item_doc_name, bundle_price) + +def update_parent_item_rate(parent_items_doctype, parent_item_doc_name, bundle_price): + parent_item_qty = frappe.db.get_value(parent_items_doctype, parent_item_doc_name, 'qty') + frappe.db.set_value(parent_items_doctype, parent_item_doc_name, 'rate', (bundle_price/parent_item_qty)) @frappe.whitelist() def get_items_from_product_bundle(args): From 2293ba302a483a5ca0c2dddd02bc5725108a2b41 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Tue, 24 Aug 2021 22:04:03 +0530 Subject: [PATCH 17/58] fix: Add checkbox to enable calculation of Product Bundle price based on child Items' rates --- .../doctype/selling_settings/selling_settings.json | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/erpnext/selling/doctype/selling_settings/selling_settings.json b/erpnext/selling/doctype/selling_settings/selling_settings.json index 717fd9b92e..7ef096dc10 100644 --- a/erpnext/selling/doctype/selling_settings/selling_settings.json +++ b/erpnext/selling/doctype/selling_settings/selling_settings.json @@ -23,6 +23,7 @@ "maintain_same_rate_action", "editable_price_list_rate", "validate_selling_price", + "calculate_product_bundle_price_based_on_child_items_rates", "sales_transactions_settings_section", "so_required", "dn_required", @@ -191,6 +192,12 @@ "fieldname": "sales_transactions_settings_section", "fieldtype": "Section Break", "label": "Transaction Settings" + }, + { + "default": "0", + "fieldname": "calculate_product_bundle_price_based_on_child_items_rates", + "fieldtype": "Check", + "label": "Calculate Product Bundle Price based on Child Items' Rates" } ], "icon": "fa fa-cog", @@ -198,7 +205,7 @@ "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2021-08-06 22:25:50.119458", + "modified": "2021-08-24 22:02:23.949616", "modified_by": "Administrator", "module": "Selling", "name": "Selling Settings", From a575d05a3e536768916b905cf1c2489e2b53b803 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Tue, 24 Aug 2021 22:09:12 +0530 Subject: [PATCH 18/58] fix: Make fieldname more concise --- .../selling/doctype/selling_settings/selling_settings.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/erpnext/selling/doctype/selling_settings/selling_settings.json b/erpnext/selling/doctype/selling_settings/selling_settings.json index 7ef096dc10..531cf653e7 100644 --- a/erpnext/selling/doctype/selling_settings/selling_settings.json +++ b/erpnext/selling/doctype/selling_settings/selling_settings.json @@ -23,7 +23,7 @@ "maintain_same_rate_action", "editable_price_list_rate", "validate_selling_price", - "calculate_product_bundle_price_based_on_child_items_rates", + "editable_bundle_item_rates", "sales_transactions_settings_section", "so_required", "dn_required", @@ -195,7 +195,7 @@ }, { "default": "0", - "fieldname": "calculate_product_bundle_price_based_on_child_items_rates", + "fieldname": "editable_bundle_item_rates", "fieldtype": "Check", "label": "Calculate Product Bundle Price based on Child Items' Rates" } @@ -205,7 +205,7 @@ "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2021-08-24 22:02:23.949616", + "modified": "2021-08-24 22:08:34.470897", "modified_by": "Administrator", "module": "Selling", "name": "Selling Settings", From 1d82c3effe0bfbab8473351cb7783f4acc44be6f Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Tue, 24 Aug 2021 22:25:59 +0530 Subject: [PATCH 19/58] fix: Make Rate editable if editable_bundle_item_rates is checked --- .../selling/doctype/selling_settings/selling_settings.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/erpnext/selling/doctype/selling_settings/selling_settings.py b/erpnext/selling/doctype/selling_settings/selling_settings.py index b219e7ecce..b54559ad28 100644 --- a/erpnext/selling/doctype/selling_settings/selling_settings.py +++ b/erpnext/selling/doctype/selling_settings/selling_settings.py @@ -15,6 +15,7 @@ from frappe.model.document import Document class SellingSettings(Document): def on_update(self): self.toggle_hide_tax_id() + self.toggle_editable_rate_for_bundle_items() def validate(self): for key in ["cust_master_name", "campaign_naming_by", "customer_group", "territory", @@ -33,6 +34,11 @@ class SellingSettings(Document): make_property_setter(doctype, "tax_id", "hidden", self.hide_tax_id, "Check", validate_fields_for_doctype=False) make_property_setter(doctype, "tax_id", "print_hide", self.hide_tax_id, "Check", validate_fields_for_doctype=False) + def toggle_editable_rate_for_bundle_items(self): + editable_bundle_item_rates = cint(self.editable_bundle_item_rates) + + make_property_setter("Packed Item", "rate", "read_only", not(editable_bundle_item_rates), "Check", validate_fields_for_doctype=False) + def set_default_customer_group_and_territory(self): if not self.customer_group: self.customer_group = get_root_of('Customer Group') From 1956f62ad8ac97a64db67df3d3ac645d1d208b28 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Tue, 24 Aug 2021 23:30:50 +0530 Subject: [PATCH 20/58] fix: Remove qty from Sales Invoice rows --- .../report/gross_profit/gross_profit.py | 54 ++++++------------- 1 file changed, 17 insertions(+), 37 deletions(-) diff --git a/erpnext/accounts/report/gross_profit/gross_profit.py b/erpnext/accounts/report/gross_profit/gross_profit.py index 14bd2da742..1a84138241 100644 --- a/erpnext/accounts/report/gross_profit/gross_profit.py +++ b/erpnext/accounts/report/gross_profit/gross_profit.py @@ -192,11 +192,12 @@ class GrossProfitGenerator(object): buying_amount = 0 # get buying rate - if row.qty: - row.buying_rate = flt(row.buying_amount / row.qty, self.float_precision) - row.base_rate = flt(row.base_amount / row.qty, self.float_precision) + if flt(row.qty): + row.buying_rate = flt(row.buying_amount / flt(row.qty), self.float_precision) + row.base_rate = flt(row.base_amount / flt(row.qty), self.float_precision) else: - row.buying_rate, row.base_rate = 0.0, 0.0 + if self.filters.get("group_by") != "Invoice": + 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) @@ -219,7 +220,7 @@ class GrossProfitGenerator(object): if i==0: new_row = row else: - new_row.qty += row.qty + new_row.qty += flt(row.qty) new_row.buying_amount += flt(row.buying_amount, self.currency_precision) new_row.base_amount += flt(row.base_amount, self.currency_precision) new_row = self.set_average_rate(new_row) @@ -230,10 +231,10 @@ class GrossProfitGenerator(object): and row.item_code in self.returned_invoices[row.parent]: returned_item_rows = self.returned_invoices[row.parent][row.item_code] for returned_item_row in returned_item_rows: - row.qty += returned_item_row.qty + row.qty += flt(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) * row.buying_rate, self.currency_precision) + if flt(row.qty) or row.base_amount: row = self.set_average_rate(row) self.grouped_data.append(row) @@ -241,8 +242,8 @@ class GrossProfitGenerator(object): new_row.gross_profit = flt(new_row.base_amount - new_row.buying_amount, self.currency_precision) new_row.gross_profit_percent = flt(((new_row.gross_profit / new_row.base_amount) * 100.0), self.currency_precision) \ if new_row.base_amount else 0 - new_row.buying_rate = flt(new_row.buying_amount / new_row.qty, self.float_precision) if new_row.qty else 0 - new_row.base_rate = flt(new_row.base_amount / new_row.qty, self.float_precision) if new_row.qty else 0 + new_row.buying_rate = flt(new_row.buying_amount / flt(new_row.qty), self.float_precision) if flt(new_row.qty) else 0 + new_row.base_rate = flt(new_row.base_amount / flt(new_row.qty), self.float_precision) if flt(new_row.qty) else 0 return new_row @@ -423,11 +424,12 @@ class GrossProfitGenerator(object): 'brand': None, 'dn_detail': None, 'delivery_note': None, - 'qty': 0, + 'qty': None, 'item_row': None, 'is_return': row.is_return, 'cost_center': row.cost_center, - 'base_net_amount': 0 + 'base_net_amount': 0, + 'base_rate': None }) self.si_list.insert(index, invoice) @@ -445,30 +447,8 @@ class GrossProfitGenerator(object): # 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( @@ -497,7 +477,7 @@ class GrossProfitGenerator(object): '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), + 'qty': (flt(product_bundle.qty) * flt(item.qty)), 'item_row': None, 'is_return': product_bundle.is_return, 'cost_center': product_bundle.cost_center From 257215f479cec3809ad9dc8014aa57b69eb4ff22 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Tue, 24 Aug 2021 23:32:19 +0530 Subject: [PATCH 21/58] fix: Fetch base_net_total 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 1a84138241..e2fb49e9cc 100644 --- a/erpnext/accounts/report/gross_profit/gross_profit.py +++ b/erpnext/accounts/report/gross_profit/gross_profit.py @@ -428,7 +428,7 @@ 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 }) From 3edb1938a92d3d6b6427db7ac8b57ad4a8543262 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Tue, 24 Aug 2021 23:38:24 +0530 Subject: [PATCH 22/58] fix: Fetch bundle item details --- .../report/gross_profit/gross_profit.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/erpnext/accounts/report/gross_profit/gross_profit.py b/erpnext/accounts/report/gross_profit/gross_profit.py index e2fb49e9cc..52f5131ee0 100644 --- a/erpnext/accounts/report/gross_profit/gross_profit.py +++ b/erpnext/accounts/report/gross_profit/gross_profit.py @@ -460,6 +460,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, @@ -470,11 +472,11 @@ 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': (flt(product_bundle.qty) * flt(item.qty)), @@ -485,6 +487,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 2dbf8075eb1f990e5d3c1da8b2c03af480df4020 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Wed, 25 Aug 2021 00:09:07 +0530 Subject: [PATCH 23/58] 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 52f5131ee0..d095828ebd 100644 --- a/erpnext/accounts/report/gross_profit/gross_profit.py +++ b/erpnext/accounts/report/gross_profit/gross_profit.py @@ -186,7 +186,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 77352ae47e1fcf3b755899004d4f8247ae00b470 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Wed, 25 Aug 2021 00:12:43 +0530 Subject: [PATCH 24/58] fix: Only update Product Bundle prices if 'Calculate Product Bundle Price based on Child Items' Rates' is enabled --- erpnext/stock/doctype/packed_item/packed_item.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/erpnext/stock/doctype/packed_item/packed_item.py b/erpnext/stock/doctype/packed_item/packed_item.py index ea963ed8e8..a42bde2a57 100644 --- a/erpnext/stock/doctype/packed_item/packed_item.py +++ b/erpnext/stock/doctype/packed_item/packed_item.py @@ -85,7 +85,9 @@ def make_packing_list(doc): parent_items.append([d.item_code, d.name]) cleanup_packing_list(doc, parent_items) - update_product_bundle_price(doc, parent_items) + + if frappe.db.get_single_value("Selling Settings", "editable_bundle_item_rates"): + update_product_bundle_price(doc, parent_items) def cleanup_packing_list(doc, parent_items): """Remove all those child items which are no longer present in main item table""" From 5f8c2b0946d5d85ff234f3f1901b29a31f5c0eb1 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Wed, 25 Aug 2021 00:33:55 +0530 Subject: [PATCH 25/58] fix: Remove base_rate and buying_rate for Invoice rows --- erpnext/accounts/report/gross_profit/gross_profit.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/erpnext/accounts/report/gross_profit/gross_profit.py b/erpnext/accounts/report/gross_profit/gross_profit.py index d095828ebd..b70f908727 100644 --- a/erpnext/accounts/report/gross_profit/gross_profit.py +++ b/erpnext/accounts/report/gross_profit/gross_profit.py @@ -196,7 +196,7 @@ class GrossProfitGenerator(object): row.buying_rate = flt(row.buying_amount / flt(row.qty), self.float_precision) row.base_rate = flt(row.base_amount / flt(row.qty), self.float_precision) else: - if self.filters.get("group_by") != "Invoice": + if self.is_not_invoice_row(row): row.buying_rate, row.base_rate = 0.0, 0.0 # calculate gross profit @@ -233,11 +233,14 @@ class GrossProfitGenerator(object): for returned_item_row in returned_item_rows: row.qty += flt(returned_item_row.qty) row.base_amount += flt(returned_item_row.base_amount, self.currency_precision) - row.buying_amount = flt(flt(row.qty) * row.buying_rate, self.currency_precision) - if flt(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) + 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): new_row.gross_profit = flt(new_row.base_amount - new_row.buying_amount, self.currency_precision) new_row.gross_profit_percent = flt(((new_row.gross_profit / new_row.base_amount) * 100.0), self.currency_precision) \ @@ -428,8 +431,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 b02effbc47fbe4d3edb5e0c3fa6aec04130543bb Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Wed, 25 Aug 2021 01:00:40 +0530 Subject: [PATCH 26/58] fix: Indentation --- .../accounts/report/gross_profit/gross_profit.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/erpnext/accounts/report/gross_profit/gross_profit.py b/erpnext/accounts/report/gross_profit/gross_profit.py index cdc929b42f..056b56b33e 100644 --- a/erpnext/accounts/report/gross_profit/gross_profit.py +++ b/erpnext/accounts/report/gross_profit/gross_profit.py @@ -62,14 +62,14 @@ def execute(filters=None): else: 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)) + row = [] + 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) + row.append(filters.currency) + if idx == len(gross_profit_data.grouped_data)-1: + row[0] = frappe.bold("Total") + data.append(row) return columns, data From 96909b6c3b4e0fe21919fe44dc89273c49ba0753 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Wed, 25 Aug 2021 02:49:14 +0530 Subject: [PATCH 27/58] 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 5a6346c1c1..856b97d164 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 bea0f7a202b6c0237c2f166983d22c1a60218754 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Wed, 25 Aug 2021 02:52:18 +0530 Subject: [PATCH 28/58] fix: Get data when grouped by invoice and otherwise --- .../report/gross_profit/gross_profit.py | 58 ++++++++++--------- 1 file changed, 32 insertions(+), 26 deletions(-) diff --git a/erpnext/accounts/report/gross_profit/gross_profit.py b/erpnext/accounts/report/gross_profit/gross_profit.py index 056b56b33e..386c9c7242 100644 --- a/erpnext/accounts/report/gross_profit/gross_profit.py +++ b/erpnext/accounts/report/gross_profit/gross_profit.py @@ -42,37 +42,43 @@ def execute(filters=None): columns = get_columns(group_wise_columns, filters) if filters.group_by == 'Invoice': - 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) + get_data_when_grouped_by_invoice(columns, gross_profit_data, filters, group_wise_columns, data) else: - 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)) - - row.append(filters.currency) - if idx == len(gross_profit_data.grouped_data)-1: - row[0] = frappe.bold("Total") - data.append(row) + 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)) + + 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 = [] column_map = frappe._dict({ From 13ae10b3a261fe48ff6b2f28a15d18d9690c36f7 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Wed, 25 Aug 2021 15:20:27 +0530 Subject: [PATCH 29/58] fix: Remove comments --- erpnext/accounts/report/gross_profit/gross_profit.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/erpnext/accounts/report/gross_profit/gross_profit.py b/erpnext/accounts/report/gross_profit/gross_profit.py index 386c9c7242..7c3a9af9fb 100644 --- a/erpnext/accounts/report/gross_profit/gross_profit.py +++ b/erpnext/accounts/report/gross_profit/gross_profit.py @@ -471,11 +471,6 @@ 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 - if frappe.db.exists('Product Bundle', row.item_code): self.add_bundle_items(row, index) From 3135d6dc6ad2a5dea4200503315155e33cc2f549 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Wed, 25 Aug 2021 15:33:53 +0530 Subject: [PATCH 30/58] fix: Get Bundle Items --- .../report/gross_profit/gross_profit.py | 111 ++++++++++-------- 1 file changed, 59 insertions(+), 52 deletions(-) diff --git a/erpnext/accounts/report/gross_profit/gross_profit.py b/erpnext/accounts/report/gross_profit/gross_profit.py index 7c3a9af9fb..8ea5e07aef 100644 --- a/erpnext/accounts/report/gross_profit/gross_profit.py +++ b/erpnext/accounts/report/gross_profit/gross_profit.py @@ -436,31 +436,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': 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') - }) - + invoice = self.get_invoice_row(row) self.si_list.insert(index, invoice) parents_index += 1 @@ -473,9 +449,42 @@ 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 @@ -483,33 +492,31 @@ class GrossProfitGenerator(object): fields = ['item_code', 'qty'] ) - for i, item in enumerate(bundle_items): - item_name, description, item_group, brand = self.get_bundle_item_details(item.item_code) + def get_bundle_item_row(self, product_bundle, item): + 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) + 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 + }) def get_bundle_item_details(self, item_code): return frappe.db.get_value( From e4c25bf4bbc60aaab9c0eaebe35814c97f3677ac Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Wed, 25 Aug 2021 15:40:42 +0530 Subject: [PATCH 31/58] fix: Return if there are no Items --- erpnext/stock/doctype/packed_item/packed_item.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/erpnext/stock/doctype/packed_item/packed_item.py b/erpnext/stock/doctype/packed_item/packed_item.py index a42bde2a57..d8a8959a4d 100644 --- a/erpnext/stock/doctype/packed_item/packed_item.py +++ b/erpnext/stock/doctype/packed_item/packed_item.py @@ -109,6 +109,9 @@ def cleanup_packing_list(doc, parent_items): def update_product_bundle_price(doc, parent_items): """Updates the prices of Product Bundles based on the rates of the Items in the bundle.""" + if not doc.get('items'): + return + parent_items_index = 0 bundle_price = 0 parent_items_doctype = doc.items[0].doctype From d4405c5e5288f3caed530e24c62471af38059571 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Fri, 27 Aug 2021 01:02:34 +0530 Subject: [PATCH 32/58] fix: Calculate Product Bundle price based on the prices of its child items --- .../stock/doctype/packed_item/packed_item.py | 38 ++++++++----------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/erpnext/stock/doctype/packed_item/packed_item.py b/erpnext/stock/doctype/packed_item/packed_item.py index d8a8959a4d..4f1a67597d 100644 --- a/erpnext/stock/doctype/packed_item/packed_item.py +++ b/erpnext/stock/doctype/packed_item/packed_item.py @@ -114,39 +114,31 @@ def update_product_bundle_price(doc, parent_items): parent_items_index = 0 bundle_price = 0 - parent_items_doctype = doc.items[0].doctype for bundle_item in doc.get("packed_items"): if parent_items[parent_items_index][0] == bundle_item.parent_item: - bundle_price += bundle_item.qty * bundle_item.rate + bundle_item_rate = bundle_item.rate if bundle_item.rate else 0 + bundle_price += bundle_item.qty * bundle_item_rate else: - update_parent_item_price(doc, parent_items_doctype, parent_items[parent_items_index][0], bundle_price) + update_parent_item_price(doc, parent_items[parent_items_index][0], bundle_price) bundle_price = 0 parent_items_index += 1 # for the last product bundle - update_parent_item_price(doc, parent_items_doctype, parent_items[parent_items_index][0], bundle_price) - doc.reload() - -def update_parent_item_price(doc, parent_items_doctype, parent_item_code, bundle_price): - parent_item_doc_name = frappe.db.get_value( - parent_items_doctype, - { - 'parent': doc.name, - 'item_code': parent_item_code - }, - 'name' - ) - - current_parent_item_price = frappe.db.get_value(parent_items_doctype, parent_item_doc_name, 'amount') - if current_parent_item_price != bundle_price: - frappe.db.set_value(parent_items_doctype, parent_item_doc_name, 'amount', bundle_price) - update_parent_item_rate(parent_items_doctype, parent_item_doc_name, bundle_price) + if doc.get("packed_items"): + update_parent_item_price(doc, parent_items[parent_items_index][0], bundle_price) + +def update_parent_item_price(doc, parent_item_code, bundle_price): + parent_item_doc = doc.get('items', {'item_code': parent_item_code})[0] -def update_parent_item_rate(parent_items_doctype, parent_item_doc_name, bundle_price): - parent_item_qty = frappe.db.get_value(parent_items_doctype, parent_item_doc_name, 'qty') - frappe.db.set_value(parent_items_doctype, parent_item_doc_name, 'rate', (bundle_price/parent_item_qty)) + current_parent_item_price = parent_item_doc.amount + if current_parent_item_price != bundle_price: + parent_item_doc.amount = bundle_price + update_parent_item_rate(parent_item_doc, bundle_price) + +def update_parent_item_rate(parent_item_doc, bundle_price): + parent_item_doc.rate = bundle_price/parent_item_doc.qty @frappe.whitelist() def get_items_from_product_bundle(args): From e506cd6a2fb67d1550284a3f8588257583e4a32d Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Fri, 27 Aug 2021 01:06:48 +0530 Subject: [PATCH 33/58] fix: Enable Fetch If Empty for Rate --- erpnext/stock/doctype/packed_item/packed_item.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/erpnext/stock/doctype/packed_item/packed_item.json b/erpnext/stock/doctype/packed_item/packed_item.json index 00c175f03b..729ab2c586 100644 --- a/erpnext/stock/doctype/packed_item/packed_item.json +++ b/erpnext/stock/doctype/packed_item/packed_item.json @@ -219,6 +219,7 @@ }, { "fetch_from": "item_code.valuation_rate", + "fetch_if_empty": 1, "fieldname": "rate", "fieldtype": "Currency", "in_list_view": 1, @@ -229,7 +230,7 @@ "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2021-08-20 23:31:05.393712", + "modified": "2021-08-27 01:04:30.242238", "modified_by": "Administrator", "module": "Stock", "name": "Packed Item", From 6c03af815e88d8872828f9077024919c34f80b24 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Fri, 27 Aug 2021 01:14:23 +0530 Subject: [PATCH 34/58] fix: Display Bundle Items right below the Items table --- erpnext/selling/doctype/quotation/quotation.json | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/erpnext/selling/doctype/quotation/quotation.json b/erpnext/selling/doctype/quotation/quotation.json index 6a638a3c2b..007fa33837 100644 --- a/erpnext/selling/doctype/quotation/quotation.json +++ b/erpnext/selling/doctype/quotation/quotation.json @@ -43,6 +43,7 @@ "ignore_pricing_rule", "items_section", "items", + "packed_items", "pricing_rule_details", "pricing_rules", "sec_break23", @@ -84,8 +85,6 @@ "rounding_adjustment", "rounded_total", "in_words", - "bundle_items_section", - "packed_items", "payment_schedule_section", "payment_terms_template", "payment_schedule", @@ -934,11 +933,6 @@ "fieldtype": "Table", "label": "Bundle Items", "options": "Packed Item" - }, - { - "fieldname": "bundle_items_section", - "fieldtype": "Section Break", - "label": "Bundle Items" } ], "icon": "fa fa-shopping-cart", @@ -946,7 +940,7 @@ "is_submittable": 1, "links": [], "max_attachments": 1, - "modified": "2021-08-24 17:56:39.199033", + "modified": "2021-08-27 01:09:54.587572", "modified_by": "Administrator", "module": "Selling", "name": "Quotation", From 99e6e2ce3f2c46b04df31678b633c7c9e980f516 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Fri, 27 Aug 2021 01:15:01 +0530 Subject: [PATCH 35/58] fix: Make Rate column read only by default --- erpnext/stock/doctype/packed_item/packed_item.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/erpnext/stock/doctype/packed_item/packed_item.json b/erpnext/stock/doctype/packed_item/packed_item.json index 729ab2c586..e85d04966e 100644 --- a/erpnext/stock/doctype/packed_item/packed_item.json +++ b/erpnext/stock/doctype/packed_item/packed_item.json @@ -223,14 +223,15 @@ "fieldname": "rate", "fieldtype": "Currency", "in_list_view": 1, - "label": "Rate" + "label": "Rate", + "read_only": 1 } ], "idx": 1, "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2021-08-27 01:04:30.242238", + "modified": "2021-08-27 01:13:40.138203", "modified_by": "Administrator", "module": "Stock", "name": "Packed Item", From c33f5cad01c00c6f0ccd6ededecbe6952a521850 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Fri, 27 Aug 2021 01:21:52 +0530 Subject: [PATCH 36/58] fix: Hide Rate of Bundle Items while printing --- erpnext/stock/doctype/packed_item/packed_item.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/stock/doctype/packed_item/packed_item.json b/erpnext/stock/doctype/packed_item/packed_item.json index e85d04966e..6f0f527d13 100644 --- a/erpnext/stock/doctype/packed_item/packed_item.json +++ b/erpnext/stock/doctype/packed_item/packed_item.json @@ -224,14 +224,14 @@ "fieldtype": "Currency", "in_list_view": 1, "label": "Rate", - "read_only": 1 + "print_hide": 1 } ], "idx": 1, "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2021-08-27 01:13:40.138203", + "modified": "2021-08-27 01:20:55.308822", "modified_by": "Administrator", "module": "Stock", "name": "Packed Item", From 681c92d6463f17376e90499025a39ef67d1dd7b5 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Fri, 27 Aug 2021 01:48:46 +0530 Subject: [PATCH 37/58] fix: Make Sales Order field editable so the PO can be linked with an SO later --- .../doctype/purchase_order_item/purchase_order_item.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json index 132dd1769c..01526fc65a 100644 --- a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json +++ b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json @@ -488,7 +488,6 @@ "no_copy": 1, "options": "Sales Order", "print_hide": 1, - "read_only": 1, "search_index": 1 }, { @@ -836,7 +835,7 @@ "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2021-06-28 19:22:22.715365", + "modified": "2021-08-27 01:35:37.755413", "modified_by": "Administrator", "module": "Buying", "name": "Purchase Order Item", From efd8a8b28e7062a10af870e7d248be7b521c109d Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Fri, 27 Aug 2021 01:49:28 +0530 Subject: [PATCH 38/58] feat: Add Bundle Items table --- .../purchase_order/purchase_order.json | 477 +++++------------- 1 file changed, 124 insertions(+), 353 deletions(-) diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.json b/erpnext/buying/doctype/purchase_order/purchase_order.json index a55a0b7f9f..873ab70999 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.json +++ b/erpnext/buying/doctype/purchase_order/purchase_order.json @@ -61,6 +61,7 @@ "set_warehouse", "items_section", "items", + "packed_items", "sb_last_purchase", "total_qty", "base_total", @@ -144,9 +145,7 @@ { "fieldname": "supplier_section", "fieldtype": "Section Break", - "options": "fa fa-user", - "show_days": 1, - "show_seconds": 1 + "options": "fa fa-user" }, { "allow_on_submit": 1, @@ -156,9 +155,7 @@ "hidden": 1, "label": "Title", "no_copy": 1, - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "naming_series", @@ -170,9 +167,7 @@ "options": "PUR-ORD-.YYYY.-", "print_hide": 1, "reqd": 1, - "set_only_once": 1, - "show_days": 1, - "show_seconds": 1 + "set_only_once": 1 }, { "bold": 1, @@ -186,18 +181,14 @@ "options": "Supplier", "print_hide": 1, "reqd": 1, - "search_index": 1, - "show_days": 1, - "show_seconds": 1 + "search_index": 1 }, { "depends_on": "eval:doc.supplier && doc.docstatus===0 && (!(doc.items && doc.items.length) || (doc.items.length==1 && !doc.items[0].item_code))", "description": "Fetch items based on Default Supplier.", "fieldname": "get_items_from_open_material_requests", "fieldtype": "Button", - "label": "Get Items from Open Material Requests", - "show_days": 1, - "show_seconds": 1 + "label": "Get Items from Open Material Requests" }, { "bold": 1, @@ -206,9 +197,7 @@ "fieldtype": "Data", "in_global_search": 1, "label": "Supplier Name", - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "company", @@ -220,17 +209,13 @@ "options": "Company", "print_hide": 1, "remember_last_selected_value": 1, - "reqd": 1, - "show_days": 1, - "show_seconds": 1 + "reqd": 1 }, { "fieldname": "column_break1", "fieldtype": "Column Break", "oldfieldtype": "Column Break", "print_width": "50%", - "show_days": 1, - "show_seconds": 1, "width": "50%" }, { @@ -242,35 +227,27 @@ "oldfieldname": "transaction_date", "oldfieldtype": "Date", "reqd": 1, - "search_index": 1, - "show_days": 1, - "show_seconds": 1 + "search_index": 1 }, { "allow_on_submit": 1, "fieldname": "schedule_date", "fieldtype": "Date", - "label": "Required By", - "show_days": 1, - "show_seconds": 1 + "label": "Required By" }, { "allow_on_submit": 1, "depends_on": "eval:doc.docstatus===1", "fieldname": "order_confirmation_no", "fieldtype": "Data", - "label": "Order Confirmation No", - "show_days": 1, - "show_seconds": 1 + "label": "Order Confirmation No" }, { "allow_on_submit": 1, "depends_on": "eval:doc.order_confirmation_no", "fieldname": "order_confirmation_date", "fieldtype": "Date", - "label": "Order Confirmation Date", - "show_days": 1, - "show_seconds": 1 + "label": "Order Confirmation Date" }, { "fieldname": "amended_from", @@ -282,25 +259,19 @@ "oldfieldtype": "Data", "options": "Purchase Order", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "drop_ship", "fieldtype": "Section Break", - "label": "Drop Ship", - "show_days": 1, - "show_seconds": 1 + "label": "Drop Ship" }, { "fieldname": "customer", "fieldtype": "Link", "label": "Customer", "options": "Customer", - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "bold": 1, @@ -308,41 +279,31 @@ "fieldtype": "Data", "label": "Customer Name", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "column_break_19", - "fieldtype": "Column Break", - "show_days": 1, - "show_seconds": 1 + "fieldtype": "Column Break" }, { "fieldname": "customer_contact_person", "fieldtype": "Link", "label": "Customer Contact", - "options": "Contact", - "show_days": 1, - "show_seconds": 1 + "options": "Contact" }, { "fieldname": "customer_contact_display", "fieldtype": "Small Text", "hidden": 1, "label": "Customer Contact", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "customer_contact_mobile", "fieldtype": "Small Text", "hidden": 1, "label": "Customer Mobile No", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "customer_contact_email", @@ -350,35 +311,27 @@ "hidden": 1, "label": "Customer Contact Email", "options": "Email", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "collapsible": 1, "fieldname": "section_addresses", "fieldtype": "Section Break", - "label": "Address and Contact", - "show_days": 1, - "show_seconds": 1 + "label": "Address and Contact" }, { "fieldname": "supplier_address", "fieldtype": "Link", "label": "Supplier Address", "options": "Address", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "contact_person", "fieldtype": "Link", "label": "Supplier Contact", "options": "Contact", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "address_display", @@ -405,42 +358,32 @@ "label": "Contact Email", "options": "Email", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "col_break_address", - "fieldtype": "Column Break", - "show_days": 1, - "show_seconds": 1 + "fieldtype": "Column Break" }, { "fieldname": "shipping_address", "fieldtype": "Link", "label": "Company Shipping Address", "options": "Address", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "shipping_address_display", "fieldtype": "Small Text", "label": "Shipping Address Details", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "collapsible": 1, "fieldname": "currency_and_price_list", "fieldtype": "Section Break", "label": "Currency and Price List", - "options": "fa fa-tag", - "show_days": 1, - "show_seconds": 1 + "options": "fa fa-tag" }, { "fieldname": "currency", @@ -450,9 +393,7 @@ "oldfieldtype": "Select", "options": "Currency", "print_hide": 1, - "reqd": 1, - "show_days": 1, - "show_seconds": 1 + "reqd": 1 }, { "fieldname": "conversion_rate", @@ -462,24 +403,18 @@ "oldfieldtype": "Currency", "precision": "9", "print_hide": 1, - "reqd": 1, - "show_days": 1, - "show_seconds": 1 + "reqd": 1 }, { "fieldname": "cb_price_list", - "fieldtype": "Column Break", - "show_days": 1, - "show_seconds": 1 + "fieldtype": "Column Break" }, { "fieldname": "buying_price_list", "fieldtype": "Link", "label": "Price List", "options": "Price List", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "price_list_currency", @@ -487,18 +422,14 @@ "label": "Price List Currency", "options": "Currency", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "plc_conversion_rate", "fieldtype": "Float", "label": "Price List Exchange Rate", "precision": "9", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "default": "0", @@ -507,9 +438,7 @@ "label": "Ignore Pricing Rule", "no_copy": 1, "permlevel": 1, - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "sec_warehouse", @@ -522,15 +451,11 @@ "fieldtype": "Link", "label": "Set Target Warehouse", "options": "Warehouse", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "col_break_warehouse", - "fieldtype": "Column Break", - "show_days": 1, - "show_seconds": 1 + "fieldtype": "Column Break" }, { "default": "No", @@ -539,35 +464,27 @@ "in_standard_filter": 1, "label": "Supply Raw Materials", "options": "No\nYes", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "depends_on": "eval:doc.is_subcontracted==\"Yes\"", "fieldname": "supplier_warehouse", "fieldtype": "Link", "label": "Supplier Warehouse", - "options": "Warehouse", - "show_days": 1, - "show_seconds": 1 + "options": "Warehouse" }, { "fieldname": "items_section", "fieldtype": "Section Break", "hide_border": 1, "oldfieldtype": "Section Break", - "options": "fa fa-shopping-cart", - "show_days": 1, - "show_seconds": 1 + "options": "fa fa-shopping-cart" }, { "fieldname": "scan_barcode", "fieldtype": "Data", "label": "Scan Barcode", - "options": "Barcode", - "show_days": 1, - "show_seconds": 1 + "options": "Barcode" }, { "allow_bulk_edit": 1, @@ -577,34 +494,26 @@ "oldfieldname": "po_details", "oldfieldtype": "Table", "options": "Purchase Order Item", - "reqd": 1, - "show_days": 1, - "show_seconds": 1 + "reqd": 1 }, { "collapsible": 1, "fieldname": "section_break_48", "fieldtype": "Section Break", - "label": "Pricing Rules", - "show_days": 1, - "show_seconds": 1 + "label": "Pricing Rules" }, { "fieldname": "pricing_rules", "fieldtype": "Table", "label": "Purchase Order Pricing Rule", "options": "Pricing Rule Detail", - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "collapsible_depends_on": "supplied_items", "fieldname": "raw_material_details", "fieldtype": "Section Break", - "label": "Raw Materials Supplied", - "show_days": 1, - "show_seconds": 1 + "label": "Raw Materials Supplied" }, { "fieldname": "supplied_items", @@ -615,23 +524,17 @@ "oldfieldtype": "Table", "options": "Purchase Order Item Supplied", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "sb_last_purchase", - "fieldtype": "Section Break", - "show_days": 1, - "show_seconds": 1 + "fieldtype": "Section Break" }, { "fieldname": "total_qty", "fieldtype": "Float", "label": "Total Quantity", - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "base_total", @@ -639,9 +542,7 @@ "label": "Total (Company Currency)", "options": "Company:company:default_currency", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "base_net_total", @@ -652,24 +553,18 @@ "oldfieldtype": "Currency", "options": "Company:company:default_currency", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "column_break_26", - "fieldtype": "Column Break", - "show_days": 1, - "show_seconds": 1 + "fieldtype": "Column Break" }, { "fieldname": "total", "fieldtype": "Currency", "label": "Total", "options": "currency", - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "net_total", @@ -679,26 +574,20 @@ "oldfieldtype": "Currency", "options": "currency", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "total_net_weight", "fieldtype": "Float", "label": "Total Net Weight", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "taxes_section", "fieldtype": "Section Break", "oldfieldtype": "Section Break", - "options": "fa fa-money", - "show_days": 1, - "show_seconds": 1 + "options": "fa fa-money" }, { "fieldname": "taxes_and_charges", @@ -707,24 +596,18 @@ "oldfieldname": "purchase_other_charges", "oldfieldtype": "Link", "options": "Purchase Taxes and Charges Template", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "column_break_50", - "fieldtype": "Column Break", - "show_days": 1, - "show_seconds": 1 + "fieldtype": "Column Break" }, { "fieldname": "shipping_rule", "fieldtype": "Link", "label": "Shipping Rule", "options": "Shipping Rule", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "section_break_52", @@ -737,17 +620,13 @@ "label": "Purchase Taxes and Charges", "oldfieldname": "purchase_tax_details", "oldfieldtype": "Table", - "options": "Purchase Taxes and Charges", - "show_days": 1, - "show_seconds": 1 + "options": "Purchase Taxes and Charges" }, { "collapsible": 1, "fieldname": "sec_tax_breakup", "fieldtype": "Section Break", - "label": "Tax Breakup", - "show_days": 1, - "show_seconds": 1 + "label": "Tax Breakup" }, { "fieldname": "other_charges_calculation", @@ -756,18 +635,14 @@ "no_copy": 1, "oldfieldtype": "HTML", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "totals", "fieldtype": "Section Break", "label": "Taxes and Charges", "oldfieldtype": "Section Break", - "options": "fa fa-money", - "show_days": 1, - "show_seconds": 1 + "options": "fa fa-money" }, { "depends_on": "base_taxes_and_charges_added", @@ -778,9 +653,7 @@ "oldfieldtype": "Currency", "options": "Company:company:default_currency", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "depends_on": "base_taxes_and_charges_deducted", @@ -791,9 +664,7 @@ "oldfieldtype": "Currency", "options": "Company:company:default_currency", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "depends_on": "base_total_taxes_and_charges", @@ -805,15 +676,11 @@ "oldfieldtype": "Currency", "options": "Company:company:default_currency", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "column_break_39", - "fieldtype": "Column Break", - "show_days": 1, - "show_seconds": 1 + "fieldtype": "Column Break" }, { "depends_on": "taxes_and_charges_added", @@ -824,9 +691,7 @@ "oldfieldtype": "Currency", "options": "currency", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "depends_on": "taxes_and_charges_deducted", @@ -837,9 +702,7 @@ "oldfieldtype": "Currency", "options": "currency", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "depends_on": "total_taxes_and_charges", @@ -848,18 +711,14 @@ "label": "Total Taxes and Charges", "options": "currency", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "collapsible": 1, "collapsible_depends_on": "apply_discount_on", "fieldname": "discount_section", "fieldtype": "Section Break", - "label": "Additional Discount", - "show_days": 1, - "show_seconds": 1 + "label": "Additional Discount" }, { "default": "Grand Total", @@ -867,9 +726,7 @@ "fieldtype": "Select", "label": "Apply Additional Discount On", "options": "\nGrand Total\nNet Total", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "base_discount_amount", @@ -877,32 +734,24 @@ "label": "Additional Discount Amount (Company Currency)", "options": "Company:company:default_currency", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "column_break_45", - "fieldtype": "Column Break", - "show_days": 1, - "show_seconds": 1 + "fieldtype": "Column Break" }, { "fieldname": "additional_discount_percentage", "fieldtype": "Float", "label": "Additional Discount Percentage", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "discount_amount", "fieldtype": "Currency", "label": "Additional Discount Amount", "options": "currency", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "totals_section", @@ -918,9 +767,7 @@ "oldfieldtype": "Currency", "options": "Company:company:default_currency", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "depends_on": "eval:!doc.disable_rounded_total", @@ -930,9 +777,7 @@ "no_copy": 1, "options": "Company:company:default_currency", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "description": "In Words will be visible once you save the Purchase Order.", @@ -943,9 +788,7 @@ "oldfieldname": "in_words", "oldfieldtype": "Data", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "base_rounded_total", @@ -955,16 +798,12 @@ "oldfieldtype": "Currency", "options": "Company:company:default_currency", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "column_break4", "fieldtype": "Column Break", - "oldfieldtype": "Column Break", - "show_days": 1, - "show_seconds": 1 + "oldfieldtype": "Column Break" }, { "fieldname": "grand_total", @@ -974,9 +813,7 @@ "oldfieldname": "grand_total_import", "oldfieldtype": "Currency", "options": "currency", - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "depends_on": "eval:!doc.disable_rounded_total", @@ -986,26 +823,20 @@ "no_copy": 1, "options": "currency", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "rounded_total", "fieldtype": "Currency", "label": "Rounded Total", "options": "currency", - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "default": "0", "fieldname": "disable_rounded_total", "fieldtype": "Check", - "label": "Disable Rounded Total", - "show_days": 1, - "show_seconds": 1 + "label": "Disable Rounded Total" }, { "fieldname": "in_words", @@ -1015,9 +846,7 @@ "oldfieldname": "in_words_import", "oldfieldtype": "Data", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "advance_paid", @@ -1026,25 +855,19 @@ "no_copy": 1, "options": "party_account_currency", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "collapsible": 1, "fieldname": "payment_schedule_section", "fieldtype": "Section Break", - "label": "Payment Terms", - "show_days": 1, - "show_seconds": 1 + "label": "Payment Terms" }, { "fieldname": "payment_terms_template", "fieldtype": "Link", "label": "Payment Terms Template", - "options": "Payment Terms Template", - "show_days": 1, - "show_seconds": 1 + "options": "Payment Terms Template" }, { "fieldname": "payment_schedule", @@ -1052,9 +875,7 @@ "label": "Payment Schedule", "no_copy": 1, "options": "Payment Schedule", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "collapsible": 1, @@ -1063,9 +884,7 @@ "fieldtype": "Section Break", "label": "Terms and Conditions", "oldfieldtype": "Section Break", - "options": "fa fa-legal", - "show_days": 1, - "show_seconds": 1 + "options": "fa fa-legal" }, { "fieldname": "tc_name", @@ -1074,27 +893,21 @@ "oldfieldname": "tc_name", "oldfieldtype": "Link", "options": "Terms and Conditions", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "terms", "fieldtype": "Text Editor", "label": "Terms and Conditions", "oldfieldname": "terms", - "oldfieldtype": "Text Editor", - "show_days": 1, - "show_seconds": 1 + "oldfieldtype": "Text Editor" }, { "collapsible": 1, "fieldname": "more_info", "fieldtype": "Section Break", "label": "More Information", - "oldfieldtype": "Section Break", - "show_days": 1, - "show_seconds": 1 + "oldfieldtype": "Section Break" }, { "default": "Draft", @@ -1109,9 +922,7 @@ "print_hide": 1, "read_only": 1, "reqd": 1, - "search_index": 1, - "show_days": 1, - "show_seconds": 1 + "search_index": 1 }, { "fieldname": "ref_sq", @@ -1122,9 +933,7 @@ "oldfieldtype": "Data", "options": "Supplier Quotation", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "party_account_currency", @@ -1134,24 +943,18 @@ "no_copy": 1, "options": "Currency", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "inter_company_order_reference", "fieldtype": "Link", "label": "Inter Company Order Reference", "options": "Sales Order", - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "column_break_74", - "fieldtype": "Column Break", - "show_days": 1, - "show_seconds": 1 + "fieldtype": "Column Break" }, { "depends_on": "eval:!doc.__islocal", @@ -1161,9 +964,7 @@ "label": "% Received", "no_copy": 1, "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "depends_on": "eval:!doc.__islocal", @@ -1173,9 +974,7 @@ "label": "% Billed", "no_copy": 1, "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "collapsible": 1, @@ -1185,8 +984,6 @@ "oldfieldtype": "Column Break", "print_hide": 1, "print_width": "50%", - "show_days": 1, - "show_seconds": 1, "width": "50%" }, { @@ -1197,9 +994,7 @@ "oldfieldname": "letter_head", "oldfieldtype": "Select", "options": "Letter Head", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "allow_on_submit": 1, @@ -1211,15 +1006,11 @@ "oldfieldtype": "Link", "options": "Print Heading", "print_hide": 1, - "report_hide": 1, - "show_days": 1, - "show_seconds": 1 + "report_hide": 1 }, { "fieldname": "column_break_86", - "fieldtype": "Column Break", - "show_days": 1, - "show_seconds": 1 + "fieldtype": "Column Break" }, { "allow_on_submit": 1, @@ -1227,25 +1018,19 @@ "fieldname": "group_same_items", "fieldtype": "Check", "label": "Group same items", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "language", "fieldtype": "Data", "label": "Print Language", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "collapsible": 1, "fieldname": "subscription_section", "fieldtype": "Section Break", - "label": "Subscription Section", - "show_days": 1, - "show_seconds": 1 + "label": "Subscription Section" }, { "allow_on_submit": 1, @@ -1253,9 +1038,7 @@ "fieldtype": "Date", "label": "From Date", "no_copy": 1, - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "allow_on_submit": 1, @@ -1263,15 +1046,11 @@ "fieldtype": "Date", "label": "To Date", "no_copy": 1, - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "column_break_97", - "fieldtype": "Column Break", - "show_days": 1, - "show_seconds": 1 + "fieldtype": "Column Break" }, { "fieldname": "auto_repeat", @@ -1280,35 +1059,27 @@ "no_copy": 1, "options": "Auto Repeat", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "allow_on_submit": 1, "depends_on": "eval: doc.auto_repeat", "fieldname": "update_auto_repeat_reference", "fieldtype": "Button", - "label": "Update Auto Repeat Reference", - "show_days": 1, - "show_seconds": 1 + "label": "Update Auto Repeat Reference" }, { "fieldname": "tax_category", "fieldtype": "Link", "label": "Tax Category", - "options": "Tax Category", - "show_days": 1, - "show_seconds": 1 + "options": "Tax Category" }, { "depends_on": "supplied_items", "fieldname": "set_reserve_warehouse", "fieldtype": "Link", "label": "Set Reserve Warehouse", - "options": "Warehouse", - "show_days": 1, - "show_seconds": 1 + "options": "Warehouse" }, { "collapsible": 1, @@ -1318,9 +1089,7 @@ }, { "fieldname": "column_break_75", - "fieldtype": "Column Break", - "show_days": 1, - "show_seconds": 1 + "fieldtype": "Column Break" }, { "fieldname": "billing_address", @@ -1361,25 +1130,27 @@ "default": "0", "fieldname": "apply_tds", "fieldtype": "Check", - "label": "Apply Tax Withholding Amount", - "show_days": 1, - "show_seconds": 1 + "label": "Apply Tax Withholding Amount" }, { "depends_on": "eval: doc.apply_tds", "fieldname": "tax_withholding_category", "fieldtype": "Link", "label": "Tax Withholding Category", - "options": "Tax Withholding Category", - "show_days": 1, - "show_seconds": 1 + "options": "Tax Withholding Category" + }, + { + "fieldname": "packed_items", + "fieldtype": "Table", + "label": "Bundle Items", + "options": "Packed Item" } ], "icon": "fa fa-file-text", "idx": 105, "is_submittable": 1, "links": [], - "modified": "2021-08-17 20:16:12.737743", + "modified": "2021-08-27 01:46:33.944417", "modified_by": "Administrator", "module": "Buying", "name": "Purchase Order", From 20cfe60e84b6bbc285a7aa3f6e9f3b6ec0b3c463 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Fri, 27 Aug 2021 01:49:58 +0530 Subject: [PATCH 39/58] feat: Populate Bundle Items table --- erpnext/buying/doctype/purchase_order/purchase_order.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py index ca3bd90960..e7d422d9cc 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/purchase_order.py @@ -67,6 +67,9 @@ class PurchaseOrder(BuyingController): self.set_received_qty_for_drop_ship_items() validate_inter_company_party(self.doctype, self.supplier, self.company, self.inter_company_order_reference) + from erpnext.stock.doctype.packed_item.packed_item import make_packing_list + make_packing_list(self) + def validate_with_previous_doc(self): super(PurchaseOrder, self).validate_with_previous_doc({ "Supplier Quotation": { From bdbd4f83ab5ed2b228fd29c5018c9c7230c7d639 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Fri, 27 Aug 2021 02:29:47 +0530 Subject: [PATCH 40/58] fix: Create separate section for Bundle Items --- .../buying/doctype/purchase_order/purchase_order.json | 11 ++++++++++- erpnext/selling/doctype/quotation/quotation.json | 11 ++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.json b/erpnext/buying/doctype/purchase_order/purchase_order.json index 873ab70999..e37d31a674 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.json +++ b/erpnext/buying/doctype/purchase_order/purchase_order.json @@ -61,6 +61,7 @@ "set_warehouse", "items_section", "items", + "bundle_items_section", "packed_items", "sb_last_purchase", "total_qty", @@ -1144,13 +1145,21 @@ "fieldtype": "Table", "label": "Bundle Items", "options": "Packed Item" + }, + { + "collapsible": 1, + "collapsible_depends_on": "packed_items", + "fieldname": "bundle_items_section", + "fieldtype": "Section Break", + "label": "Bundle Items", + "options": "fa fa-suitcase" } ], "icon": "fa fa-file-text", "idx": 105, "is_submittable": 1, "links": [], - "modified": "2021-08-27 01:46:33.944417", + "modified": "2021-08-27 02:18:07.342249", "modified_by": "Administrator", "module": "Buying", "name": "Purchase Order", diff --git a/erpnext/selling/doctype/quotation/quotation.json b/erpnext/selling/doctype/quotation/quotation.json index 007fa33837..6bfb2c2a73 100644 --- a/erpnext/selling/doctype/quotation/quotation.json +++ b/erpnext/selling/doctype/quotation/quotation.json @@ -43,6 +43,7 @@ "ignore_pricing_rule", "items_section", "items", + "bundle_items_section", "packed_items", "pricing_rule_details", "pricing_rules", @@ -933,6 +934,14 @@ "fieldtype": "Table", "label": "Bundle Items", "options": "Packed Item" + }, + { + "collapsible": 1, + "collapsible_depends_on": "packed_items", + "fieldname": "bundle_items_section", + "fieldtype": "Section Break", + "label": "Bundle Items", + "options": "fa fa-suitcase" } ], "icon": "fa fa-shopping-cart", @@ -940,7 +949,7 @@ "is_submittable": 1, "links": [], "max_attachments": 1, - "modified": "2021-08-27 01:09:54.587572", + "modified": "2021-08-27 02:23:33.460607", "modified_by": "Administrator", "module": "Selling", "name": "Quotation", From 4353c5e3397a184ffb6307a3bf5a20fae30c9fa9 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Fri, 27 Aug 2021 02:32:34 +0530 Subject: [PATCH 41/58] fix: Disable Add Row and Delete Row for Bundle Items --- erpnext/buying/doctype/purchase_order/purchase_order.js | 3 +++ erpnext/selling/doctype/quotation/quotation.js | 2 ++ 2 files changed, 5 insertions(+) diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js index 521432d296..d6f0f0e61c 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.js +++ b/erpnext/buying/doctype/purchase_order/purchase_order.js @@ -28,6 +28,9 @@ frappe.ui.form.on("Purchase Order", { } }); + frm.set_df_property('packed_items', 'cannot_add_rows', true); + frm.set_df_property('packed_items', 'cannot_delete_rows', true); + }, company: function(frm) { diff --git a/erpnext/selling/doctype/quotation/quotation.js b/erpnext/selling/doctype/quotation/quotation.js index 1223449549..0e1a915deb 100644 --- a/erpnext/selling/doctype/quotation/quotation.js +++ b/erpnext/selling/doctype/quotation/quotation.js @@ -18,6 +18,8 @@ frappe.ui.form.on('Quotation', { } }); + frm.set_df_property('packed_items', 'cannot_add_rows', true); + frm.set_df_property('packed_items', 'cannot_delete_rows', true); }, refresh: function(frm) { From 535dd2d36d7a0593fbd14e0027cef2f298f86a45 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Fri, 27 Aug 2021 02:47:11 +0530 Subject: [PATCH 42/58] fix: Move Packed Items table right below the Items table --- erpnext/selling/doctype/sales_order/sales_order.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/erpnext/selling/doctype/sales_order/sales_order.json b/erpnext/selling/doctype/sales_order/sales_order.json index 38ea5c81d4..6c4a4033ba 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.json +++ b/erpnext/selling/doctype/sales_order/sales_order.json @@ -55,6 +55,8 @@ "items_section", "scan_barcode", "items", + "packing_list", + "packed_items", "pricing_rule_details", "pricing_rules", "section_break_31", @@ -101,8 +103,6 @@ "in_words", "advance_paid", "disable_rounded_total", - "packing_list", - "packed_items", "payment_schedule_section", "payment_terms_template", "payment_schedule", @@ -1511,7 +1511,7 @@ "idx": 105, "is_submittable": 1, "links": [], - "modified": "2021-08-17 20:15:26.531553", + "modified": "2021-08-27 02:45:54.968867", "modified_by": "Administrator", "module": "Selling", "name": "Sales Order", From a7be02fe326829cbaf93d559e9ae41bd9816b19a Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Fri, 27 Aug 2021 19:59:20 +0530 Subject: [PATCH 43/58] fix: Only add Item to packed_items list if it's not already there --- erpnext/stock/doctype/packed_item/packed_item.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/erpnext/stock/doctype/packed_item/packed_item.py b/erpnext/stock/doctype/packed_item/packed_item.py index 4f1a67597d..eea00ec06c 100644 --- a/erpnext/stock/doctype/packed_item/packed_item.py +++ b/erpnext/stock/doctype/packed_item/packed_item.py @@ -39,8 +39,10 @@ def update_packing_list_item(doc, packing_item_code, qty, main_item_row, descrip # check if exists exists = 0 for d in doc.get("packed_items"): - if d.parent_item == main_item_row.item_code and d.item_code == packing_item_code and\ - d.parent_detail_docname == main_item_row.name: + if d.parent_item == main_item_row.item_code and d.item_code == packing_item_code: + if d.parent_detail_docname != main_item_row.name: + d.parent_detail_docname = main_item_row.name + pi, exists = d, 1 break From a2b394b195a575e80affa7a5865f4f08199b0826 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Fri, 27 Aug 2021 20:06:22 +0530 Subject: [PATCH 44/58] fix: Enable Print Hide for Bundle Items --- erpnext/buying/doctype/purchase_order/purchase_order.json | 8 +++++--- erpnext/selling/doctype/quotation/quotation.json | 8 +++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.json b/erpnext/buying/doctype/purchase_order/purchase_order.json index e37d31a674..3eee5066f1 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.json +++ b/erpnext/buying/doctype/purchase_order/purchase_order.json @@ -1144,7 +1144,8 @@ "fieldname": "packed_items", "fieldtype": "Table", "label": "Bundle Items", - "options": "Packed Item" + "options": "Packed Item", + "print_hide": 1 }, { "collapsible": 1, @@ -1152,14 +1153,15 @@ "fieldname": "bundle_items_section", "fieldtype": "Section Break", "label": "Bundle Items", - "options": "fa fa-suitcase" + "options": "fa fa-suitcase", + "print_hide": 1 } ], "icon": "fa fa-file-text", "idx": 105, "is_submittable": 1, "links": [], - "modified": "2021-08-27 02:18:07.342249", + "modified": "2021-08-27 20:05:54.869308", "modified_by": "Administrator", "module": "Buying", "name": "Purchase Order", diff --git a/erpnext/selling/doctype/quotation/quotation.json b/erpnext/selling/doctype/quotation/quotation.json index 6bfb2c2a73..7185bb94de 100644 --- a/erpnext/selling/doctype/quotation/quotation.json +++ b/erpnext/selling/doctype/quotation/quotation.json @@ -933,7 +933,8 @@ "fieldname": "packed_items", "fieldtype": "Table", "label": "Bundle Items", - "options": "Packed Item" + "options": "Packed Item", + "print_hide": 1 }, { "collapsible": 1, @@ -941,7 +942,8 @@ "fieldname": "bundle_items_section", "fieldtype": "Section Break", "label": "Bundle Items", - "options": "fa fa-suitcase" + "options": "fa fa-suitcase", + "print_hide": 1 } ], "icon": "fa fa-shopping-cart", @@ -949,7 +951,7 @@ "is_submittable": 1, "links": [], "max_attachments": 1, - "modified": "2021-08-27 02:23:33.460607", + "modified": "2021-08-27 20:04:26.357378", "modified_by": "Administrator", "module": "Selling", "name": "Quotation", From e44567754dcc6128867cb642454e1430c57304d9 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Fri, 27 Aug 2021 20:16:13 +0530 Subject: [PATCH 45/58] fix: Display Packed/Bundle Items table only if it exists --- .../doctype/pos_invoice/pos_invoice.json | 4 +++- .../doctype/sales_invoice/sales_invoice.json | 16 ++++++---------- .../doctype/purchase_order/purchase_order.json | 4 +++- erpnext/selling/doctype/quotation/quotation.json | 4 +++- .../selling/doctype/sales_order/sales_order.json | 4 +++- erpnext/selling/sales_common.js | 5 +---- .../doctype/delivery_note/delivery_note.json | 4 +++- 7 files changed, 22 insertions(+), 19 deletions(-) diff --git a/erpnext/accounts/doctype/pos_invoice/pos_invoice.json b/erpnext/accounts/doctype/pos_invoice/pos_invoice.json index 19c6c8f347..bff8587278 100644 --- a/erpnext/accounts/doctype/pos_invoice/pos_invoice.json +++ b/erpnext/accounts/doctype/pos_invoice/pos_invoice.json @@ -622,6 +622,7 @@ "read_only": 1 }, { + "depends_on": "packed_items", "fieldname": "packing_list", "fieldtype": "Section Break", "label": "Packing List", @@ -629,6 +630,7 @@ "print_hide": 1 }, { + "depends_on": "packed_items", "fieldname": "packed_items", "fieldtype": "Table", "label": "Packed Items", @@ -1564,7 +1566,7 @@ "icon": "fa fa-file-text", "is_submittable": 1, "links": [], - "modified": "2021-08-24 18:19:20.728433", + "modified": "2021-08-27 20:12:57.306772", "modified_by": "Administrator", "module": "Accounts", "name": "POS Invoice", diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json index d8aa32e224..b5620ae6a9 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json @@ -247,7 +247,7 @@ "depends_on": "customer", "fetch_from": "customer.customer_name", "fieldname": "customer_name", - "fieldtype": "Small Text", + "fieldtype": "Data", "hide_days": 1, "hide_seconds": 1, "in_global_search": 1, @@ -695,7 +695,6 @@ "hide_days": 1, "hide_seconds": 1, "label": "Scan Barcode", - "length": 1, "options": "Barcode" }, { @@ -727,6 +726,7 @@ "read_only": 1 }, { + "depends_on": "packed_items", "fieldname": "packing_list", "fieldtype": "Section Break", "hide_days": 1, @@ -736,6 +736,7 @@ "print_hide": 1 }, { + "depends_on": "packed_items", "fieldname": "packed_items", "fieldtype": "Table", "hide_days": 1, @@ -1060,7 +1061,6 @@ "hide_days": 1, "hide_seconds": 1, "label": "Apply Additional Discount On", - "length": 15, "options": "\nGrand Total\nNet Total", "print_hide": 1 }, @@ -1147,7 +1147,7 @@ { "description": "In Words will be visible once you save the Sales Invoice.", "fieldname": "base_in_words", - "fieldtype": "Small Text", + "fieldtype": "Data", "hide_days": 1, "hide_seconds": 1, "label": "In Words (Company Currency)", @@ -1207,7 +1207,7 @@ }, { "fieldname": "in_words", - "fieldtype": "Small Text", + "fieldtype": "Data", "hide_days": 1, "hide_seconds": 1, "label": "In Words", @@ -1560,7 +1560,6 @@ "hide_days": 1, "hide_seconds": 1, "label": "Print Language", - "length": 6, "print_hide": 1, "read_only": 1 }, @@ -1648,7 +1647,6 @@ "hide_seconds": 1, "in_standard_filter": 1, "label": "Status", - "length": 30, "no_copy": 1, "options": "\nDraft\nReturn\nCredit Note Issued\nSubmitted\nPaid\nUnpaid\nUnpaid and Discounted\nOverdue and Discounted\nOverdue\nCancelled\nInternal Transfer", "print_hide": 1, @@ -1708,7 +1706,6 @@ "hide_days": 1, "hide_seconds": 1, "label": "Is Opening Entry", - "length": 4, "oldfieldname": "is_opening", "oldfieldtype": "Select", "options": "No\nYes", @@ -1720,7 +1717,6 @@ "hide_days": 1, "hide_seconds": 1, "label": "C-Form Applicable", - "length": 4, "no_copy": 1, "options": "No\nYes", "print_hide": 1 @@ -2021,7 +2017,7 @@ "link_fieldname": "consolidated_invoice" } ], - "modified": "2021-08-25 14:46:05.279588", + "modified": "2021-08-27 20:13:40.456462", "modified_by": "Administrator", "module": "Accounts", "name": "Sales Invoice", diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.json b/erpnext/buying/doctype/purchase_order/purchase_order.json index 3eee5066f1..dd88c2d850 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.json +++ b/erpnext/buying/doctype/purchase_order/purchase_order.json @@ -1141,6 +1141,7 @@ "options": "Tax Withholding Category" }, { + "depends_on": "packed_items", "fieldname": "packed_items", "fieldtype": "Table", "label": "Bundle Items", @@ -1150,6 +1151,7 @@ { "collapsible": 1, "collapsible_depends_on": "packed_items", + "depends_on": "packed_items", "fieldname": "bundle_items_section", "fieldtype": "Section Break", "label": "Bundle Items", @@ -1161,7 +1163,7 @@ "idx": 105, "is_submittable": 1, "links": [], - "modified": "2021-08-27 20:05:54.869308", + "modified": "2021-08-27 20:11:23.509147", "modified_by": "Administrator", "module": "Buying", "name": "Purchase Order", diff --git a/erpnext/selling/doctype/quotation/quotation.json b/erpnext/selling/doctype/quotation/quotation.json index 7185bb94de..43a44900fc 100644 --- a/erpnext/selling/doctype/quotation/quotation.json +++ b/erpnext/selling/doctype/quotation/quotation.json @@ -930,6 +930,7 @@ "read_only": 1 }, { + "depends_on": "packed_items", "fieldname": "packed_items", "fieldtype": "Table", "label": "Bundle Items", @@ -939,6 +940,7 @@ { "collapsible": 1, "collapsible_depends_on": "packed_items", + "depends_on": "packed_items", "fieldname": "bundle_items_section", "fieldtype": "Section Break", "label": "Bundle Items", @@ -951,7 +953,7 @@ "is_submittable": 1, "links": [], "max_attachments": 1, - "modified": "2021-08-27 20:04:26.357378", + "modified": "2021-08-27 20:10:07.864951", "modified_by": "Administrator", "module": "Selling", "name": "Quotation", diff --git a/erpnext/selling/doctype/sales_order/sales_order.json b/erpnext/selling/doctype/sales_order/sales_order.json index 6c4a4033ba..212bbde123 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.json +++ b/erpnext/selling/doctype/sales_order/sales_order.json @@ -1019,6 +1019,7 @@ { "collapsible": 1, "collapsible_depends_on": "packed_items", + "depends_on": "packed_items", "fieldname": "packing_list", "fieldtype": "Section Break", "hide_days": 1, @@ -1029,6 +1030,7 @@ "print_hide": 1 }, { + "depends_on": "packed_items", "fieldname": "packed_items", "fieldtype": "Table", "hide_days": 1, @@ -1511,7 +1513,7 @@ "idx": 105, "is_submittable": 1, "links": [], - "modified": "2021-08-27 02:45:54.968867", + "modified": "2021-08-27 20:11:57.748736", "modified_by": "Administrator", "module": "Selling", "name": "Sales Order", diff --git a/erpnext/selling/sales_common.js b/erpnext/selling/sales_common.js index 2de57c87f1..e440f33020 100644 --- a/erpnext/selling/sales_common.js +++ b/erpnext/selling/sales_common.js @@ -90,10 +90,7 @@ erpnext.selling.SellingController = class SellingController extends erpnext.Tran this.frm.toggle_display("customer_name", (this.frm.doc.customer_name && this.frm.doc.customer_name!==this.frm.doc.customer)); - if(this.frm.fields_dict.packed_items) { - var packing_list_exists = (this.frm.doc.packed_items || []).length; - this.frm.toggle_display("packing_list", packing_list_exists ? true : false); - } + this.toggle_editable_price_list_rate(); } diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.json b/erpnext/stock/doctype/delivery_note/delivery_note.json index 958189614f..fdc8763baa 100644 --- a/erpnext/stock/doctype/delivery_note/delivery_note.json +++ b/erpnext/stock/doctype/delivery_note/delivery_note.json @@ -543,6 +543,7 @@ { "collapsible": 1, "collapsible_depends_on": "packed_items", + "depends_on": "packed_items", "fieldname": "packing_list", "fieldtype": "Section Break", "label": "Packing List", @@ -551,6 +552,7 @@ "print_hide": 1 }, { + "depends_on": "packed_items", "fieldname": "packed_items", "fieldtype": "Table", "label": "Packed Items", @@ -1306,7 +1308,7 @@ "idx": 146, "is_submittable": 1, "links": [], - "modified": "2021-08-17 20:15:50.574966", + "modified": "2021-08-27 20:14:40.215231", "modified_by": "Administrator", "module": "Stock", "name": "Delivery Note", From 055ac82b394174222df6c6f755f6de421aaa8e1a Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Mon, 30 Aug 2021 20:04:24 +0530 Subject: [PATCH 46/58] fix: Remove Bundle Items table --- .../doctype/purchase_order/purchase_order.js | 3 --- .../purchase_order/purchase_order.json | 22 +------------------ .../doctype/purchase_order/purchase_order.py | 3 --- 3 files changed, 1 insertion(+), 27 deletions(-) diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js index d6f0f0e61c..521432d296 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.js +++ b/erpnext/buying/doctype/purchase_order/purchase_order.js @@ -28,9 +28,6 @@ frappe.ui.form.on("Purchase Order", { } }); - frm.set_df_property('packed_items', 'cannot_add_rows', true); - frm.set_df_property('packed_items', 'cannot_delete_rows', true); - }, company: function(frm) { diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.json b/erpnext/buying/doctype/purchase_order/purchase_order.json index dd88c2d850..ef54538fcd 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.json +++ b/erpnext/buying/doctype/purchase_order/purchase_order.json @@ -61,8 +61,6 @@ "set_warehouse", "items_section", "items", - "bundle_items_section", - "packed_items", "sb_last_purchase", "total_qty", "base_total", @@ -1139,31 +1137,13 @@ "fieldtype": "Link", "label": "Tax Withholding Category", "options": "Tax Withholding Category" - }, - { - "depends_on": "packed_items", - "fieldname": "packed_items", - "fieldtype": "Table", - "label": "Bundle Items", - "options": "Packed Item", - "print_hide": 1 - }, - { - "collapsible": 1, - "collapsible_depends_on": "packed_items", - "depends_on": "packed_items", - "fieldname": "bundle_items_section", - "fieldtype": "Section Break", - "label": "Bundle Items", - "options": "fa fa-suitcase", - "print_hide": 1 } ], "icon": "fa fa-file-text", "idx": 105, "is_submittable": 1, "links": [], - "modified": "2021-08-27 20:11:23.509147", + "modified": "2021-08-30 20:03:14.008804", "modified_by": "Administrator", "module": "Buying", "name": "Purchase Order", diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py index e7d422d9cc..ca3bd90960 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/purchase_order.py @@ -67,9 +67,6 @@ class PurchaseOrder(BuyingController): self.set_received_qty_for_drop_ship_items() validate_inter_company_party(self.doctype, self.supplier, self.company, self.inter_company_order_reference) - from erpnext.stock.doctype.packed_item.packed_item import make_packing_list - make_packing_list(self) - def validate_with_previous_doc(self): super(PurchaseOrder, self).validate_with_previous_doc({ "Supplier Quotation": { From a067d55865c189e23e30d1d4ce1965f8c1a92418 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Mon, 30 Aug 2021 20:07:06 +0530 Subject: [PATCH 47/58] fix: Add Product Bundle field in Items table --- .../purchase_order_item/purchase_order_item.json | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json index 01526fc65a..87cd57517e 100644 --- a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json +++ b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json @@ -10,6 +10,7 @@ "item_code", "supplier_part_no", "item_name", + "product_bundle", "column_break_4", "schedule_date", "expected_delivery_date", @@ -829,13 +830,20 @@ "label": "Production Plan Sub Assembly Item", "no_copy": 1, "read_only": 1 + }, + { + "fieldname": "product_bundle", + "fieldtype": "Link", + "label": "Product Bundle", + "options": "Product Bundle", + "read_only": 1 } ], "idx": 1, "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2021-08-27 01:35:37.755413", + "modified": "2021-08-30 20:06:26.712097", "modified_by": "Administrator", "module": "Buying", "name": "Purchase Order Item", From eb24e87637c0e0d3e77b6943239d8c6ef4d8bee5 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Tue, 31 Aug 2021 18:44:29 +0530 Subject: [PATCH 48/58] fix: Replace Product Bundles in the Items table with their child items --- .../doctype/sales_order/sales_order.py | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index 5d44582aab..ff459cb13f 100755 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -950,8 +950,56 @@ def make_purchase_order(source_name, selected_items=None, target_doc=None): "condition": lambda doc: doc.ordered_qty < doc.stock_qty and doc.item_code in items_to_map } }, target_doc, set_missing_values) + + doc.items = replace_product_bundles_with_bundle_items(doc.items, source_name) + return doc +def replace_product_bundles_with_bundle_items(items, sales_order_name): + updated_items = [] + + for item in items: + if is_product_bundle(item.item_code): + bundle_items = get_bundle_items(item.item_code, sales_order_name) + insert_bundle_items(updated_items, bundle_items, item, sales_order_name) + else: + updated_items.append(item) + + items = updated_items + + return items + +def is_product_bundle(item_code): + return frappe.db.exists('Product Bundle', item_code) + +def get_bundle_items(item_code, so_name): + return frappe.get_all( + 'Packed Item', + filters = { + 'parent': so_name, + 'parent_item': item_code + }, + fields = ['item_code', 'item_name', 'qty', 'rate', 'uom'] + ) + +def insert_bundle_items(updated_items, bundle_items, item, sales_order): + for bundle_item in bundle_items: + new_item = frappe.get_doc({ + 'doctype': 'Purchase Order Item', + 'item_code': bundle_item.item_code, + 'item_name': bundle_item.item_name, + 'product_bundle': item.item_code, + 'qty': bundle_item.qty, + 'rate': bundle_item.rate, + 'uom': bundle_item.uom, + 'schedule_date': item.schedule_date, + 'sales_order': sales_order, + 'expense_account': item.expense_account, + 'cost_center': item.cost_center + }) + + updated_items.append(new_item) + @frappe.whitelist() def make_work_orders(items, sales_order, company, project=None): '''Make Work Orders against the given Sales Order for the given `items`''' From 65796853f344b946e6206f62a3da0bed2e0e842b Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Tue, 31 Aug 2021 20:31:22 +0530 Subject: [PATCH 49/58] fix: Map Packed Items to Items table of PO --- .../doctype/sales_order/sales_order.py | 75 ++++++++----------- 1 file changed, 32 insertions(+), 43 deletions(-) diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index ff459cb13f..f190081acc 100755 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -947,59 +947,48 @@ def make_purchase_order(source_name, selected_items=None, target_doc=None): "pricing_rules" ], "postprocess": update_item, - "condition": lambda doc: doc.ordered_qty < doc.stock_qty and doc.item_code in items_to_map + "condition": lambda doc: doc.ordered_qty < doc.stock_qty and doc.item_code in items_to_map and not is_product_bundle(doc.item_code) + }, + "Packed Item": { + "doctype": "Purchase Order Item", + "field_map": [ + ["parent", "sales_order"], + ["uom", "uom"], + ["conversion_factor", "conversion_factor"], + ["parent_item", "product_bundle"], + ["rate", "rate"] + ], + "field_no_map": [ + "rate", + "price_list_rate", + "item_tax_template", + "discount_percentage", + "discount_amount", + "supplier", + "pricing_rules" + ], } }, target_doc, set_missing_values) - doc.items = replace_product_bundles_with_bundle_items(doc.items, source_name) - + set_delivery_date(doc.items, source_name) + return doc -def replace_product_bundles_with_bundle_items(items, sales_order_name): - updated_items = [] - +def set_delivery_date(items, sales_order): for item in items: - if is_product_bundle(item.item_code): - bundle_items = get_bundle_items(item.item_code, sales_order_name) - insert_bundle_items(updated_items, bundle_items, item, sales_order_name) - else: - updated_items.append(item) - - items = updated_items - - return items + if item.product_bundle: + item.schedule_date = frappe.get_value( + 'Sales Order Item', + { + 'parent': sales_order, + 'item_code': item.product_bundle + }, + 'delivery_date' + ) def is_product_bundle(item_code): return frappe.db.exists('Product Bundle', item_code) -def get_bundle_items(item_code, so_name): - return frappe.get_all( - 'Packed Item', - filters = { - 'parent': so_name, - 'parent_item': item_code - }, - fields = ['item_code', 'item_name', 'qty', 'rate', 'uom'] - ) - -def insert_bundle_items(updated_items, bundle_items, item, sales_order): - for bundle_item in bundle_items: - new_item = frappe.get_doc({ - 'doctype': 'Purchase Order Item', - 'item_code': bundle_item.item_code, - 'item_name': bundle_item.item_name, - 'product_bundle': item.item_code, - 'qty': bundle_item.qty, - 'rate': bundle_item.rate, - 'uom': bundle_item.uom, - 'schedule_date': item.schedule_date, - 'sales_order': sales_order, - 'expense_account': item.expense_account, - 'cost_center': item.cost_center - }) - - updated_items.append(new_item) - @frappe.whitelist() def make_work_orders(items, sales_order, company, project=None): '''Make Work Orders against the given Sales Order for the given `items`''' From 912bfb234fe63a8b543ec0a97c372aaa6fc06dd8 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Wed, 1 Sep 2021 02:09:31 +0530 Subject: [PATCH 50/58] fix: Test if Product Bundles in SOs are replaced with their child items on creating POs --- .../doctype/sales_order/test_sales_order.py | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py index d685fbff82..054791e9e4 100644 --- a/erpnext/selling/doctype/sales_order/test_sales_order.py +++ b/erpnext/selling/doctype/sales_order/test_sales_order.py @@ -906,6 +906,38 @@ class TestSalesOrder(unittest.TestCase): self.assertEqual(purchase_orders[0].supplier, '_Test Supplier') self.assertEqual(purchase_orders[1].supplier, '_Test Supplier 1') + def test_product_bundles_in_so_are_replaced_with_bundle_items_in_po(self): + """ + Tests if the the Product Bundles in the Items table of Sales Orders are replaced with + their child items(from the Packed Items table) on creating a Purchase Order from it. + """ + from erpnext.selling.doctype.sales_order.sales_order import make_purchase_order + + product_bundle = make_item("_Test Product Bundle", {"is_stock_item": 0}) + make_item("_Test Bundle Item 1", {"is_stock_item": 1}) + make_item("_Test Bundle Item 2", {"is_stock_item": 1}) + + make_product_bundle("_Test Product Bundle", + ["_Test Bundle Item 1", "_Test Bundle Item 2"]) + + so_items = [ + { + "item_code": product_bundle.item_code, + "warehouse": "", + "qty": 2, + "rate": 400, + "delivered_by_supplier": 1, + "supplier": '_Test Supplier' + } + ] + + so = make_sales_order(item_list=so_items) + + purchase_order = make_purchase_order(so.name, selected_items=so_items) + + self.assertEqual(purchase_order.items[0].item_code, "_Test Bundle Item 1") + self.assertEqual(purchase_order.items[1].item_code, "_Test Bundle Item 2") + def test_reserved_qty_for_closing_so(self): bin = frappe.get_all("Bin", filters={"item_code": "_Test Item", "warehouse": "_Test Warehouse - _TC"}, fields=["reserved_qty"]) From 0c3d3bb35750fa39ceab0ca36f90112125eed31d Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Wed, 1 Sep 2021 02:33:53 +0530 Subject: [PATCH 51/58] fix: Test if Product Bundles are mapped properly on creating a Sales Order --- .../doctype/quotation/test_quotation.py | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/erpnext/selling/doctype/quotation/test_quotation.py b/erpnext/selling/doctype/quotation/test_quotation.py index 527a999aef..0fc985f45b 100644 --- a/erpnext/selling/doctype/quotation/test_quotation.py +++ b/erpnext/selling/doctype/quotation/test_quotation.py @@ -226,6 +226,36 @@ class TestQuotation(unittest.TestCase): expired_quotation.reload() self.assertEqual(expired_quotation.status, "Expired") + def test_product_bundle_mapping_on_creating_so(self): + from erpnext.stock.doctype.item.test_item import make_item + from erpnext.selling.doctype.product_bundle.test_product_bundle import make_product_bundle + from erpnext.selling.doctype.quotation.quotation import make_sales_order + + make_item("_Test Product Bundle", {"is_stock_item": 0}) + make_item("_Test Bundle Item 1", {"is_stock_item": 1}) + make_item("_Test Bundle Item 2", {"is_stock_item": 1}) + + make_product_bundle("_Test Product Bundle", + ["_Test Bundle Item 1", "_Test Bundle Item 2"]) + + quotation = make_quotation(item_code="_Test Product Bundle", qty=1, rate=100) + sales_order = make_sales_order(quotation.name) + + quotation_item = [quotation.items[0].item_code, quotation.items[0].rate, quotation.items[0].qty, quotation.items[0].amount] + so_item = [sales_order.items[0].item_code, sales_order.items[0].rate, sales_order.items[0].qty, sales_order.items[0].amount] + + self.assertEqual(quotation_item, so_item) + + quotation_packed_items = [ + [quotation.packed_items[0].parent_item, quotation.packed_items[0].item_code, quotation.packed_items[0].qty], + [quotation.packed_items[1].parent_item, quotation.packed_items[1].item_code, quotation.packed_items[1].qty] + ] + so_packed_items = [ + [sales_order.packed_items[0].parent_item, sales_order.packed_items[0].item_code, sales_order.packed_items[0].qty], + [sales_order.packed_items[1].parent_item, sales_order.packed_items[1].item_code, sales_order.packed_items[1].qty] + ] + + self.assertEqual(quotation_packed_items, so_packed_items) test_records = frappe.get_test_records('Quotation') From 0e457265b7b14a3d076f10a4d888e9e42cbf0a1c Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Wed, 1 Sep 2021 02:50:29 +0530 Subject: [PATCH 52/58] fix: Test Product Bundle price calculation --- .../doctype/quotation/test_quotation.py | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/erpnext/selling/doctype/quotation/test_quotation.py b/erpnext/selling/doctype/quotation/test_quotation.py index 0fc985f45b..854260059c 100644 --- a/erpnext/selling/doctype/quotation/test_quotation.py +++ b/erpnext/selling/doctype/quotation/test_quotation.py @@ -257,8 +257,56 @@ class TestQuotation(unittest.TestCase): self.assertEqual(quotation_packed_items, so_packed_items) + def test_product_bundle_price_calculation_when_calculate_bundle_price_is_unchecked(self): + from erpnext.stock.doctype.item.test_item import make_item + from erpnext.selling.doctype.product_bundle.test_product_bundle import make_product_bundle + + make_item("_Test Product Bundle", {"is_stock_item": 0}) + bundle_item1 = make_item("_Test Bundle Item 1", {"is_stock_item": 1}) + bundle_item2 = make_item("_Test Bundle Item 2", {"is_stock_item": 1}) + + make_product_bundle("_Test Product Bundle", + ["_Test Bundle Item 1", "_Test Bundle Item 2"]) + + bundle_item1.valuation_rate = 100 + bundle_item1.save() + + bundle_item2.valuation_rate = 200 + bundle_item2.save() + + quotation = make_quotation(item_code="_Test Product Bundle", qty=2, rate=100) + self.assertEqual(quotation.items[0].amount, 200) + + def test_product_bundle_price_calculation_when_calculate_bundle_price_is_checked(self): + from erpnext.stock.doctype.item.test_item import make_item + from erpnext.selling.doctype.product_bundle.test_product_bundle import make_product_bundle + + make_item("_Test Product Bundle", {"is_stock_item": 0}) + make_item("_Test Bundle Item 1", {"is_stock_item": 1}) + make_item("_Test Bundle Item 2", {"is_stock_item": 1}) + + make_product_bundle("_Test Product Bundle", + ["_Test Bundle Item 1", "_Test Bundle Item 2"]) + + enable_calculate_bundle_price() + + quotation = make_quotation(item_code="_Test Product Bundle", qty=2, rate=100, do_not_submit=1) + quotation.packed_items[0].rate = 100 + quotation.packed_items[1].rate = 200 + quotation.save() + + self.assertEqual(quotation.items[0].amount, 600) + self.assertEqual(quotation.items[0].rate, 300) + + enable_calculate_bundle_price(enable=0) + test_records = frappe.get_test_records('Quotation') +def enable_calculate_bundle_price(enable=1): + selling_settings = frappe.get_doc("Selling Settings") + selling_settings.editable_bundle_item_rates = enable + selling_settings.save() + def get_quotation_dict(party_name=None, item_code=None): if not party_name: party_name = '_Test Customer' From 816ba55b7467b688a08b0f128d5070ad270250f1 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Wed, 1 Sep 2021 15:11:08 +0530 Subject: [PATCH 53/58] fix: Make Rate read-only by default --- erpnext/stock/doctype/packed_item/packed_item.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/erpnext/stock/doctype/packed_item/packed_item.json b/erpnext/stock/doctype/packed_item/packed_item.json index 6f0f527d13..830d5469bf 100644 --- a/erpnext/stock/doctype/packed_item/packed_item.json +++ b/erpnext/stock/doctype/packed_item/packed_item.json @@ -224,14 +224,15 @@ "fieldtype": "Currency", "in_list_view": 1, "label": "Rate", - "print_hide": 1 + "print_hide": 1, + "read_only": 1 } ], "idx": 1, "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2021-08-27 01:20:55.308822", + "modified": "2021-09-01 15:10:29.646399", "modified_by": "Administrator", "module": "Stock", "name": "Packed Item", From 17a6a9b036cfb490a22a751dc2017510acc0af79 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Wed, 1 Sep 2021 15:13:29 +0530 Subject: [PATCH 54/58] fix: Uncheck read-only for Packed Items table --- erpnext/selling/doctype/sales_order/sales_order.json | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/erpnext/selling/doctype/sales_order/sales_order.json b/erpnext/selling/doctype/sales_order/sales_order.json index 212bbde123..85282ca1a0 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.json +++ b/erpnext/selling/doctype/sales_order/sales_order.json @@ -1037,8 +1037,7 @@ "hide_seconds": 1, "label": "Packed Items", "options": "Packed Item", - "print_hide": 1, - "read_only": 1 + "print_hide": 1 }, { "fieldname": "payment_schedule_section", @@ -1513,7 +1512,7 @@ "idx": 105, "is_submittable": 1, "links": [], - "modified": "2021-08-27 20:11:57.748736", + "modified": "2021-09-01 15:12:24.115483", "modified_by": "Administrator", "module": "Selling", "name": "Sales Order", From 4d8f833cc9975a848066daf76ec713106c74de49 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Wed, 1 Sep 2021 15:20:40 +0530 Subject: [PATCH 55/58] fix: Remove Add Row and Delete Row options for Packed Items table --- erpnext/accounts/doctype/sales_invoice/sales_invoice.js | 3 +++ erpnext/selling/doctype/sales_order/sales_order.js | 3 +++ 2 files changed, 6 insertions(+) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js index 2dd3d690e9..2cb9acfa2a 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js @@ -578,6 +578,9 @@ frappe.ui.form.on('Sales Invoice', { frm.add_fetch('payment_term', 'invoice_portion', 'invoice_portion'); frm.add_fetch('payment_term', 'description', 'description'); + frm.set_df_property('packed_items', 'cannot_add_rows', true); + frm.set_df_property('packed_items', 'cannot_delete_rows', true); + frm.set_query("account_for_change_amount", function() { return { filters: { diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js index b42c615312..f6926906b8 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.js +++ b/erpnext/selling/doctype/sales_order/sales_order.js @@ -43,6 +43,9 @@ frappe.ui.form.on("Sales Order", { } } }); + + frm.set_df_property('packed_items', 'cannot_add_rows', true); + frm.set_df_property('packed_items', 'cannot_delete_rows', true); }, refresh: function(frm) { if(frm.doc.docstatus === 1 && frm.doc.status !== 'Closed' From 471fd9718c57b61b27b883b2a90339e32d01eee9 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Wed, 1 Sep 2021 15:36:07 +0530 Subject: [PATCH 56/58] fix: Set Product Bundle's Delivery Dates in SO as Bundle Items' Delivery Dates in PO --- .../doctype/sales_order/sales_order.py | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index f190081acc..5d59aa1870 100755 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -975,16 +975,21 @@ def make_purchase_order(source_name, selected_items=None, target_doc=None): return doc def set_delivery_date(items, sales_order): + delivery_dates = frappe.get_all( + 'Sales Order Item', + filters = { + 'parent': sales_order + }, + fields = ['delivery_date', 'item_code'] + ) + + delivery_by_item = frappe._dict() + for date in delivery_dates: + delivery_by_item[date.item_code] = date.delivery_date + for item in items: if item.product_bundle: - item.schedule_date = frappe.get_value( - 'Sales Order Item', - { - 'parent': sales_order, - 'item_code': item.product_bundle - }, - 'delivery_date' - ) + item.schedule_date = delivery_by_item[item.product_bundle] def is_product_bundle(item_code): return frappe.db.exists('Product Bundle', item_code) From bbb9fa4bf86aab4dc991aea4f6baafe028439930 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Wed, 1 Sep 2021 16:00:59 +0530 Subject: [PATCH 57/58] fix: Remove Rate from field_no_map --- erpnext/selling/doctype/sales_order/sales_order.py | 1 - 1 file changed, 1 deletion(-) diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index 5d59aa1870..47ebfe90d3 100755 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -959,7 +959,6 @@ def make_purchase_order(source_name, selected_items=None, target_doc=None): ["rate", "rate"] ], "field_no_map": [ - "rate", "price_list_rate", "item_tax_template", "discount_percentage", From bc79084dac7643362047353deb0c956504cbdc7b Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Wed, 1 Sep 2021 16:06:47 +0530 Subject: [PATCH 58/58] fix: Add Product Bundle field in Items table --- .../purchase_invoice_item/purchase_invoice_item.json | 10 +++++++++- .../purchase_receipt_item/purchase_receipt_item.json | 10 +++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json index a7618e2c74..d39a9fc058 100644 --- a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json +++ b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json @@ -8,6 +8,7 @@ "engine": "InnoDB", "field_order": [ "item_code", + "product_bundle", "col_break1", "item_name", "description_section", @@ -857,12 +858,19 @@ "fieldtype": "Link", "label": "Discount Account", "options": "Account" + }, + { + "fieldname": "product_bundle", + "fieldtype": "Link", + "label": "Product Bundle", + "options": "Product Bundle", + "read_only": 1 } ], "idx": 1, "istable": 1, "links": [], - "modified": "2021-08-12 20:14:48.506639", + "modified": "2021-09-01 16:04:03.538643", "modified_by": "Administrator", "module": "Accounts", "name": "Purchase Invoice Item", diff --git a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json index 82cc98e7f7..3efa66e02e 100644 --- a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json +++ b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json @@ -10,6 +10,7 @@ "barcode", "section_break_2", "item_code", + "product_bundle", "supplier_part_no", "column_break_2", "item_name", @@ -956,12 +957,19 @@ "no_copy": 1, "print_hide": 1, "read_only": 1 + }, + { + "fieldname": "product_bundle", + "fieldtype": "Link", + "label": "Product Bundle", + "options": "Product Bundle", + "read_only": 1 } ], "idx": 1, "istable": 1, "links": [], - "modified": "2021-03-29 04:17:00.336298", + "modified": "2021-09-01 16:02:40.338597", "modified_by": "Administrator", "module": "Stock", "name": "Purchase Receipt Item",