From 4a77bd23041e2061585eb9259416d2652dc6748c Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Wed, 18 Aug 2021 00:33:43 +0530 Subject: [PATCH 001/121] 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 002/121] 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 003/121] 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 004/121] 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 005/121] 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 006/121] 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 007/121] 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 008/121] 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 009/121] 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 010/121] 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 011/121] 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 012/121] 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 013/121] 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 014/121] 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 015/121] 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 016/121] 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 017/121] 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 018/121] 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 019/121] 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 020/121] 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 021/121] 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 022/121] 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 023/121] 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 024/121] 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 025/121] 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 026/121] 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 027/121] 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 028/121] 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 029/121] 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 030/121] 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 031/121] 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 032/121] 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 033/121] 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 034/121] 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 035/121] 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 036/121] 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 037/121] 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 038/121] 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 039/121] 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 040/121] 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 041/121] 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 042/121] 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 bf72ec0598de4688af03d80c34c0241c5b5fb194 Mon Sep 17 00:00:00 2001 From: marination Date: Fri, 27 Aug 2021 14:57:42 +0530 Subject: [PATCH 043/121] feat: (consistency) Add Primary Address and Contact section in Supplier - The same is present in customer and is inconsistent with supplier - Helps quickly create primary address and contact via quick entry --- erpnext/buying/doctype/supplier/supplier.js | 43 +++++++++++ erpnext/buying/doctype/supplier/supplier.json | 51 ++++++++++++- erpnext/buying/doctype/supplier/supplier.py | 45 +++++++++++ erpnext/public/build.json | 1 + .../public/js/utils/supplier_quick_entry.js | 75 +++++++++++++++++++ 5 files changed, 214 insertions(+), 1 deletion(-) create mode 100644 erpnext/public/js/utils/supplier_quick_entry.js diff --git a/erpnext/buying/doctype/supplier/supplier.js b/erpnext/buying/doctype/supplier/supplier.js index 1766c2c80c..7ee91961ca 100644 --- a/erpnext/buying/doctype/supplier/supplier.js +++ b/erpnext/buying/doctype/supplier/supplier.js @@ -24,7 +24,26 @@ frappe.ui.form.on("Supplier", { } } }); + + frm.set_query("supplier_primary_contact", function(doc) { + return { + query: "erpnext.buying.doctype.supplier.supplier.get_supplier_primary_contact", + filters: { + "supplier": doc.name + } + }; + }); + + frm.set_query("supplier_primary_address", function(doc) { + return { + filters: { + "link_doctype": "Supplier", + "link_name": doc.name + } + }; + }); }, + refresh: function (frm) { frappe.dynamic_link = { doc: frm.doc, fieldname: 'name', doctype: 'Supplier' } @@ -78,6 +97,30 @@ frappe.ui.form.on("Supplier", { }); }, + supplier_primary_address: function(frm) { + if (frm.doc.supplier_primary_address) { + frappe.call({ + method: 'frappe.contacts.doctype.address.address.get_address_display', + args: { + "address_dict": frm.doc.supplier_primary_address + }, + callback: function(r) { + frm.set_value("primary_address", r.message); + } + }); + } + if (!frm.doc.supplier_primary_address) { + frm.set_value("primary_address", ""); + } + }, + + supplier_primary_contact: function(frm) { + if (!frm.doc.supplier_primary_contact) { + frm.set_value("mobile_no", ""); + frm.set_value("email_id", ""); + } + }, + is_internal_supplier: function(frm) { if (frm.doc.is_internal_supplier == 1) { frm.toggle_reqd("represents_company", true); diff --git a/erpnext/buying/doctype/supplier/supplier.json b/erpnext/buying/doctype/supplier/supplier.json index 38b8dfdf48..22e689c101 100644 --- a/erpnext/buying/doctype/supplier/supplier.json +++ b/erpnext/buying/doctype/supplier/supplier.json @@ -49,6 +49,13 @@ "address_html", "column_break1", "contact_html", + "primary_address_and_contact_detail_section", + "supplier_primary_contact", + "mobile_no", + "email_id", + "column_break_44", + "supplier_primary_address", + "primary_address", "default_payable_accounts", "accounts", "default_tax_withholding_config", @@ -378,6 +385,48 @@ "fieldname": "allow_purchase_invoice_creation_without_purchase_receipt", "fieldtype": "Check", "label": "Allow Purchase Invoice Creation Without Purchase Receipt" + }, + { + "fieldname": "primary_address_and_contact_detail_section", + "fieldtype": "Section Break", + "label": "Primary Address and Contact Detail" + }, + { + "description": "Reselect, if the chosen contact is edited after save", + "fieldname": "supplier_primary_contact", + "fieldtype": "Link", + "label": "Supplier Primary Contact", + "options": "Contact" + }, + { + "depends_on": "mobile_no", + "fetch_from": "supplier_primary_contact.mobile_no", + "fieldname": "mobile_no", + "fieldtype": "Read Only", + "label": "Mobile No" + }, + { + "fetch_from": "supplier_primary_contact.email_id", + "fieldname": "email_id", + "fieldtype": "Read Only", + "label": "Email Id" + }, + { + "fieldname": "column_break_44", + "fieldtype": "Column Break" + }, + { + "fieldname": "primary_address", + "fieldtype": "Text", + "label": "Primary Address", + "read_only": 1 + }, + { + "description": "Reselect, if the chosen address is edited after save", + "fieldname": "supplier_primary_address", + "fieldtype": "Link", + "label": "Supplier Primary Address", + "options": "Address" } ], "icon": "fa fa-user", @@ -390,7 +439,7 @@ "link_fieldname": "supplier" } ], - "modified": "2021-05-18 15:10:11.087191", + "modified": "2021-08-27 13:46:18.212802", "modified_by": "Administrator", "module": "Buying", "name": "Supplier", diff --git a/erpnext/buying/doctype/supplier/supplier.py b/erpnext/buying/doctype/supplier/supplier.py index fd16b23c22..8252b40566 100644 --- a/erpnext/buying/doctype/supplier/supplier.py +++ b/erpnext/buying/doctype/supplier/supplier.py @@ -42,6 +42,8 @@ class Supplier(TransactionBase): if not self.naming_series: self.naming_series = '' + self.create_primary_contact() + def validate(self): # validation for Naming Series mandatory field... if frappe.defaults.get_global_default('supp_master_name') == 'Naming Series': @@ -76,7 +78,32 @@ class Supplier(TransactionBase): frappe.throw(_("Internal Supplier for company {0} already exists").format( frappe.bold(self.represents_company))) + def create_primary_contact(self): + from erpnext.selling.doctype.customer.customer import make_contact + + if not self.supplier_primary_contact: + if self.mobile_no or self.email_id: + contact = make_contact(self) + self.db_set('supplier_primary_contact', contact.name) + self.db_set('mobile_no', self.mobile_no) + self.db_set('email_id', self.email_id) + + def create_primary_address(self): + from erpnext.selling.doctype.customer.customer import make_address + + if self.flags.is_new_doc and self.get('address_line1'): + make_address(self) + def on_trash(self): + if self.supplier_primary_contact: + frappe.db.sql(f""" + UPDATE `tabSupplier` + SET + supplier_primary_contact=null, + mobile_no=null, + email_id=null + WHERE name='{self.name}'""") + delete_contact_and_address('Supplier', self.name) def after_rename(self, olddn, newdn, merge=False): @@ -104,3 +131,21 @@ class Supplier(TransactionBase): doc.name, args.get('supplier_email_' + str(i))) except frappe.NameError: pass + +@frappe.whitelist() +@frappe.validate_and_sanitize_search_inputs +def get_supplier_primary_contact(doctype, txt, searchfield, start, page_len, filters): + supplier = filters.get("supplier") + return frappe.db.sql(""" + SELECT + `tabContact`.name from `tabContact`, + `tabDynamic Link` + WHERE + `tabContact`.name = `tabDynamic Link`.parent + and `tabDynamic Link`.link_name = %(supplier)s + and `tabDynamic Link`.link_doctype = 'Supplier' + and `tabContact`.name like %(txt)s + """, { + 'supplier': supplier, + 'txt': '%%%s%%' % txt + }) diff --git a/erpnext/public/build.json b/erpnext/public/build.json index 3c60e3ee50..6b70dab803 100644 --- a/erpnext/public/build.json +++ b/erpnext/public/build.json @@ -38,6 +38,7 @@ "public/js/templates/item_quick_entry.html", "public/js/utils/item_quick_entry.js", "public/js/utils/customer_quick_entry.js", + "public/js/utils/supplier_quick_entry.js", "public/js/education/student_button.html", "public/js/education/assessment_result_tool.html", "public/js/hub/hub_factory.js", diff --git a/erpnext/public/js/utils/supplier_quick_entry.js b/erpnext/public/js/utils/supplier_quick_entry.js new file mode 100644 index 0000000000..f650d1f101 --- /dev/null +++ b/erpnext/public/js/utils/supplier_quick_entry.js @@ -0,0 +1,75 @@ +frappe.provide('frappe.ui.form'); + +frappe.ui.form.SupplierQuickEntryForm = class SupplierQuickEntryForm extends frappe.ui.form.QuickEntryForm { + constructor(doctype, after_insert, init_callback, doc, force) { + super(doctype, after_insert, init_callback, doc, force); + this.skip_redirect_on_error = true; + } + + render_dialog() { + this.mandatory = this.mandatory.concat(this.get_variant_fields()); + super.render_dialog(); + } + + get_variant_fields() { + var variant_fields = [{ + fieldtype: "Section Break", + label: __("Primary Contact Details"), + collapsible: 1 + }, + { + label: __("Email Id"), + fieldname: "email_id", + fieldtype: "Data" + }, + { + fieldtype: "Column Break" + }, + { + label: __("Mobile Number"), + fieldname: "mobile_no", + fieldtype: "Data" + }, + { + fieldtype: "Section Break", + label: __("Primary Address Details"), + collapsible: 1 + }, + { + label: __("Address Line 1"), + fieldname: "address_line1", + fieldtype: "Data" + }, + { + label: __("Address Line 2"), + fieldname: "address_line2", + fieldtype: "Data" + }, + { + label: __("ZIP Code"), + fieldname: "pincode", + fieldtype: "Data" + }, + { + fieldtype: "Column Break" + }, + { + label: __("City"), + fieldname: "city", + fieldtype: "Data" + }, + { + label: __("State"), + fieldname: "state", + fieldtype: "Data" + }, + { + label: __("Country"), + fieldname: "country", + fieldtype: "Link", + options: "Country" + }]; + + return variant_fields; + } +}; From 2a3ef03388c4581550a247e2dbe99d8ca496883c Mon Sep 17 00:00:00 2001 From: marination Date: Fri, 27 Aug 2021 18:06:51 +0530 Subject: [PATCH 044/121] fix: Popup stale build and data consistency - Include `supplier_quick_entry.js` in erpnext.bundle.js - Create primary supplier address on update - Set newly created address (quick entry) in Supplier and Customer - Clear address set in supplier and customer on delete (dependency) --- erpnext/buying/doctype/supplier/supplier.json | 3 +-- erpnext/buying/doctype/supplier/supplier.py | 14 +++++++++++-- erpnext/public/js/erpnext.bundle.js | 1 + .../public/js/utils/supplier_quick_entry.js | 3 ++- erpnext/selling/doctype/customer/customer.py | 20 +++++++++++++++---- 5 files changed, 32 insertions(+), 9 deletions(-) diff --git a/erpnext/buying/doctype/supplier/supplier.json b/erpnext/buying/doctype/supplier/supplier.json index 22e689c101..c7a5db5994 100644 --- a/erpnext/buying/doctype/supplier/supplier.json +++ b/erpnext/buying/doctype/supplier/supplier.json @@ -399,7 +399,6 @@ "options": "Contact" }, { - "depends_on": "mobile_no", "fetch_from": "supplier_primary_contact.mobile_no", "fieldname": "mobile_no", "fieldtype": "Read Only", @@ -439,7 +438,7 @@ "link_fieldname": "supplier" } ], - "modified": "2021-08-27 13:46:18.212802", + "modified": "2021-08-27 18:02:44.314077", "modified_by": "Administrator", "module": "Buying", "name": "Supplier", diff --git a/erpnext/buying/doctype/supplier/supplier.py b/erpnext/buying/doctype/supplier/supplier.py index 8252b40566..207485e1bc 100644 --- a/erpnext/buying/doctype/supplier/supplier.py +++ b/erpnext/buying/doctype/supplier/supplier.py @@ -43,8 +43,11 @@ class Supplier(TransactionBase): self.naming_series = '' self.create_primary_contact() + self.create_primary_address() def validate(self): + self.flags.is_new_doc = self.is_new() + # validation for Naming Series mandatory field... if frappe.defaults.get_global_default('supp_master_name') == 'Naming Series': if not self.naming_series: @@ -90,9 +93,14 @@ class Supplier(TransactionBase): def create_primary_address(self): from erpnext.selling.doctype.customer.customer import make_address + from frappe.contacts.doctype.address.address import get_address_display if self.flags.is_new_doc and self.get('address_line1'): - make_address(self) + address = make_address(self) + address_display = get_address_display(address.name) + + self.db_set("supplier_primary_address", address.name) + self.db_set("primary_address", address_display) def on_trash(self): if self.supplier_primary_contact: @@ -100,8 +108,10 @@ class Supplier(TransactionBase): UPDATE `tabSupplier` SET supplier_primary_contact=null, + supplier_primary_address=null, mobile_no=null, - email_id=null + email_id=null, + primary_address=null WHERE name='{self.name}'""") delete_contact_and_address('Supplier', self.name) diff --git a/erpnext/public/js/erpnext.bundle.js b/erpnext/public/js/erpnext.bundle.js index 9f7f29ad72..febdb24da3 100644 --- a/erpnext/public/js/erpnext.bundle.js +++ b/erpnext/public/js/erpnext.bundle.js @@ -15,6 +15,7 @@ import "./agriculture/ternary_plot"; import "./templates/item_quick_entry.html"; import "./utils/item_quick_entry"; import "./utils/customer_quick_entry"; +import "./utils/supplier_quick_entry"; import "./education/student_button.html"; import "./education/assessment_result_tool.html"; import "./hub/hub_factory"; diff --git a/erpnext/public/js/utils/supplier_quick_entry.js b/erpnext/public/js/utils/supplier_quick_entry.js index f650d1f101..e4a3812cf4 100644 --- a/erpnext/public/js/utils/supplier_quick_entry.js +++ b/erpnext/public/js/utils/supplier_quick_entry.js @@ -12,7 +12,8 @@ frappe.ui.form.SupplierQuickEntryForm = class SupplierQuickEntryForm extends fra } get_variant_fields() { - var variant_fields = [{ + var variant_fields = [ + { fieldtype: "Section Break", label: __("Primary Contact Details"), collapsible: 1 diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py index abf146c43f..05cabcbbe2 100644 --- a/erpnext/selling/doctype/customer/customer.py +++ b/erpnext/selling/doctype/customer/customer.py @@ -150,8 +150,14 @@ class Customer(TransactionBase): self.db_set('email_id', self.email_id) def create_primary_address(self): + from frappe.contacts.doctype.address.address import get_address_display + if self.flags.is_new_doc and self.get('address_line1'): - make_address(self) + address = make_address(self) + address_display = get_address_display(address.name) + + self.db_set("customer_primary_address", address.name) + self.db_set("primary_address", address_display) def update_lead_status(self): '''If Customer created from Lead, update lead status to "Converted" @@ -246,9 +252,15 @@ class Customer(TransactionBase): def on_trash(self): if self.customer_primary_contact: - frappe.db.sql("""update `tabCustomer` - set customer_primary_contact=null, mobile_no=null, email_id=null - where name=%s""", self.name) + frappe.db.sql(f""" + UPDATE `tabCustomer` + SET + customer_primary_contact=null, + customer_primary_address=null, + mobile_no=null, + email_id=null, + primary_address=null + WHERE name='{self.name}'""") delete_contact_and_address('Customer', self.name) if self.lead_name: From a7be02fe326829cbaf93d559e9ae41bd9816b19a Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Fri, 27 Aug 2021 19:59:20 +0530 Subject: [PATCH 045/121] 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 046/121] 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 047/121] 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 7b78473da35fa66476d93c5212f30fd07b63336d Mon Sep 17 00:00:00 2001 From: marination Date: Mon, 30 Aug 2021 12:50:24 +0530 Subject: [PATCH 048/121] fix: Indentation and removed f-strings - Sider: fixed indentation in js - Dont use f-strings in queries --- erpnext/buying/doctype/supplier/supplier.py | 4 +- .../public/js/utils/supplier_quick_entry.js | 115 +++++++++--------- erpnext/selling/doctype/customer/customer.py | 4 +- 3 files changed, 62 insertions(+), 61 deletions(-) diff --git a/erpnext/buying/doctype/supplier/supplier.py b/erpnext/buying/doctype/supplier/supplier.py index 207485e1bc..c9750caa65 100644 --- a/erpnext/buying/doctype/supplier/supplier.py +++ b/erpnext/buying/doctype/supplier/supplier.py @@ -104,7 +104,7 @@ class Supplier(TransactionBase): def on_trash(self): if self.supplier_primary_contact: - frappe.db.sql(f""" + frappe.db.sql(""" UPDATE `tabSupplier` SET supplier_primary_contact=null, @@ -112,7 +112,7 @@ class Supplier(TransactionBase): mobile_no=null, email_id=null, primary_address=null - WHERE name='{self.name}'""") + WHERE name=%(name)s""", {"name": self.name}) delete_contact_and_address('Supplier', self.name) diff --git a/erpnext/public/js/utils/supplier_quick_entry.js b/erpnext/public/js/utils/supplier_quick_entry.js index e4a3812cf4..8d591a9651 100644 --- a/erpnext/public/js/utils/supplier_quick_entry.js +++ b/erpnext/public/js/utils/supplier_quick_entry.js @@ -13,63 +13,64 @@ frappe.ui.form.SupplierQuickEntryForm = class SupplierQuickEntryForm extends fra get_variant_fields() { var variant_fields = [ - { - fieldtype: "Section Break", - label: __("Primary Contact Details"), - collapsible: 1 - }, - { - label: __("Email Id"), - fieldname: "email_id", - fieldtype: "Data" - }, - { - fieldtype: "Column Break" - }, - { - label: __("Mobile Number"), - fieldname: "mobile_no", - fieldtype: "Data" - }, - { - fieldtype: "Section Break", - label: __("Primary Address Details"), - collapsible: 1 - }, - { - label: __("Address Line 1"), - fieldname: "address_line1", - fieldtype: "Data" - }, - { - label: __("Address Line 2"), - fieldname: "address_line2", - fieldtype: "Data" - }, - { - label: __("ZIP Code"), - fieldname: "pincode", - fieldtype: "Data" - }, - { - fieldtype: "Column Break" - }, - { - label: __("City"), - fieldname: "city", - fieldtype: "Data" - }, - { - label: __("State"), - fieldname: "state", - fieldtype: "Data" - }, - { - label: __("Country"), - fieldname: "country", - fieldtype: "Link", - options: "Country" - }]; + { + fieldtype: "Section Break", + label: __("Primary Contact Details"), + collapsible: 1 + }, + { + label: __("Email Id"), + fieldname: "email_id", + fieldtype: "Data" + }, + { + fieldtype: "Column Break" + }, + { + label: __("Mobile Number"), + fieldname: "mobile_no", + fieldtype: "Data" + }, + { + fieldtype: "Section Break", + label: __("Primary Address Details"), + collapsible: 1 + }, + { + label: __("Address Line 1"), + fieldname: "address_line1", + fieldtype: "Data" + }, + { + label: __("Address Line 2"), + fieldname: "address_line2", + fieldtype: "Data" + }, + { + label: __("ZIP Code"), + fieldname: "pincode", + fieldtype: "Data" + }, + { + fieldtype: "Column Break" + }, + { + label: __("City"), + fieldname: "city", + fieldtype: "Data" + }, + { + label: __("State"), + fieldname: "state", + fieldtype: "Data" + }, + { + label: __("Country"), + fieldname: "country", + fieldtype: "Link", + options: "Country" + } + ]; return variant_fields; } diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py index 05cabcbbe2..1164f40237 100644 --- a/erpnext/selling/doctype/customer/customer.py +++ b/erpnext/selling/doctype/customer/customer.py @@ -252,7 +252,7 @@ class Customer(TransactionBase): def on_trash(self): if self.customer_primary_contact: - frappe.db.sql(f""" + frappe.db.sql(""" UPDATE `tabCustomer` SET customer_primary_contact=null, @@ -260,7 +260,7 @@ class Customer(TransactionBase): mobile_no=null, email_id=null, primary_address=null - WHERE name='{self.name}'""") + WHERE name=%(name)s""", {"name": self.name}) delete_contact_and_address('Customer', self.name) if self.lead_name: From 9de0f7538f87d95dc1af4cbba2d9560145014efd Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Mon, 30 Aug 2021 14:07:13 +0530 Subject: [PATCH 049/121] ci: concurrency control for CI jobs (#27230) similar to https://github.com/frappe/frappe/pull/14061 This will ensure that only one instance of the following tests run per PR and cancel previous running/queued jobs when new commits are pushed. - Server / unit tests - UI tests - Patch test --- .github/workflows/patch.yml | 3 +++ .github/workflows/server-tests.yml | 4 ++++ .github/workflows/ui-tests.yml | 4 ++++ 3 files changed, 11 insertions(+) diff --git a/.github/workflows/patch.yml b/.github/workflows/patch.yml index f65b0001fe..7bba4b2e9c 100644 --- a/.github/workflows/patch.yml +++ b/.github/workflows/patch.yml @@ -7,6 +7,9 @@ on: - '**.md' workflow_dispatch: +concurrency: + group: patch-develop-${{ github.event.number }} + cancel-in-progress: true jobs: test: diff --git a/.github/workflows/server-tests.yml b/.github/workflows/server-tests.yml index 0a73d74d6b..511a292ee9 100644 --- a/.github/workflows/server-tests.yml +++ b/.github/workflows/server-tests.yml @@ -12,6 +12,10 @@ on: - '**.js' - '**.md' +concurrency: + group: server-develop-${{ github.event.number }} + cancel-in-progress: true + jobs: test: runs-on: ubuntu-18.04 diff --git a/.github/workflows/ui-tests.yml b/.github/workflows/ui-tests.yml index 0ece0d8ee6..06067ff416 100644 --- a/.github/workflows/ui-tests.yml +++ b/.github/workflows/ui-tests.yml @@ -6,6 +6,10 @@ on: - '**.md' workflow_dispatch: +concurrency: + group: ui-develop-${{ github.event.number }} + cancel-in-progress: true + jobs: test: runs-on: ubuntu-18.04 From fd467e6d326fc6abb7820efc458e6106c38e307f Mon Sep 17 00:00:00 2001 From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com> Date: Mon, 30 Aug 2021 17:53:59 +0530 Subject: [PATCH 050/121] fix: Correct company address not getting copied from Purchase Order to Invoice (#27217) * fix: Correct company adderess not getting copied from Purchase Order to Invoice * fix: Linting issues --- erpnext/public/js/controllers/transaction.js | 26 +++++++++++--------- erpnext/public/js/utils/party.js | 4 +-- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index 2538852bfa..5f8966f88a 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -866,21 +866,25 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe if (frappe.meta.get_docfield(this.frm.doctype, "shipping_address") && in_list(['Purchase Order', 'Purchase Receipt', 'Purchase Invoice'], this.frm.doctype)) { - erpnext.utils.get_shipping_address(this.frm, function(){ + erpnext.utils.get_shipping_address(this.frm, function() { set_party_account(set_pricing); }); // Get default company billing address in Purchase Invoice, Order and Receipt - frappe.call({ - 'method': 'frappe.contacts.doctype.address.address.get_default_address', - 'args': { - 'doctype': 'Company', - 'name': this.frm.doc.company - }, - 'callback': function(r) { - me.frm.set_value('billing_address', r.message); - } - }); + if (this.frm.doc.company && frappe.meta.get_docfield(this.frm.doctype, "billing_address")) { + frappe.call({ + method: "erpnext.setup.doctype.company.company.get_default_company_address", + args: {name: this.frm.doc.company, existing_address: this.frm.doc.billing_address || ""}, + debounce: 2000, + callback: function(r) { + if (r.message) { + me.frm.set_value("billing_address", r.message); + } else { + me.frm.set_value("company_address", ""); + } + } + }); + } } else { set_party_account(set_pricing); diff --git a/erpnext/public/js/utils/party.js b/erpnext/public/js/utils/party.js index 4d432e3d5c..a492b32a9f 100644 --- a/erpnext/public/js/utils/party.js +++ b/erpnext/public/js/utils/party.js @@ -289,8 +289,8 @@ erpnext.utils.get_shipping_address = function(frm, callback) { company: frm.doc.company, address: frm.doc.shipping_address }, - callback: function(r){ - if (r.message){ + callback: function(r) { + if (r.message) { frm.set_value("shipping_address", r.message[0]) //Address title or name frm.set_value("shipping_address_display", r.message[1]) //Address to be displayed on the page } From 5fd04101d4e79dead5e023e68ba24f4149d90426 Mon Sep 17 00:00:00 2001 From: Dany Robert Date: Mon, 30 Aug 2021 18:11:33 +0530 Subject: [PATCH 051/121] fix: Stock Ageing report issues for serialized items (#27228) * fix: incorrect calculation in get_range_age * fix: remove serial numbers not in stock from fifo_queue * refactor: make serial_no condition explicit * refactor: reduce code duplication Co-authored-by: Ankush Menat --- .../stock/report/stock_ageing/stock_ageing.py | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/erpnext/stock/report/stock_ageing/stock_ageing.py b/erpnext/stock/report/stock_ageing/stock_ageing.py index 623dc2ffd9..8a9f0a5e58 100644 --- a/erpnext/stock/report/stock_ageing/stock_ageing.py +++ b/erpnext/stock/report/stock_ageing/stock_ageing.py @@ -26,7 +26,7 @@ def execute(filters=None): average_age = get_average_age(fifo_queue, to_date) earliest_age = date_diff(to_date, fifo_queue[0][1]) latest_age = date_diff(to_date, fifo_queue[-1][1]) - range1, range2, range3, above_range3 = get_range_age(filters, fifo_queue, to_date) + range1, range2, range3, above_range3 = get_range_age(filters, fifo_queue, to_date, item_dict) row = [details.name, details.item_name, details.description, details.item_group, details.brand] @@ -58,19 +58,21 @@ def get_average_age(fifo_queue, to_date): return flt(age_qty / total_qty, 2) if total_qty else 0.0 -def get_range_age(filters, fifo_queue, to_date): +def get_range_age(filters, fifo_queue, to_date, item_dict): range1 = range2 = range3 = above_range3 = 0.0 + for item in fifo_queue: age = date_diff(to_date, item[1]) + qty = flt(item[0]) if not item_dict["has_serial_no"] else 1.0 if age <= filters.range1: - range1 += flt(item[0]) + range1 += qty elif age <= filters.range2: - range2 += flt(item[0]) + range2 += qty elif age <= filters.range3: - range3 += flt(item[0]) + range3 += qty else: - above_range3 += flt(item[0]) + above_range3 += qty return range1, range2, range3, above_range3 @@ -197,9 +199,7 @@ def get_fifo_queue(filters, sle=None): fifo_queue.append([d.actual_qty, d.posting_date]) else: if serial_no_list: - for serial_no in fifo_queue: - if serial_no[0] in serial_no_list: - fifo_queue.remove(serial_no) + fifo_queue[:] = [serial_no for serial_no in fifo_queue if serial_no[0] not in serial_no_list] else: qty_to_pop = abs(d.actual_qty) while qty_to_pop: @@ -222,14 +222,16 @@ def get_fifo_queue(filters, sle=None): else: item_details[key]["total_qty"] += d.actual_qty + item_details[key]["has_serial_no"] = d.has_serial_no + return item_details def get_stock_ledger_entries(filters): return frappe.db.sql("""select - item.name, item.item_name, item_group, brand, description, item.stock_uom, + item.name, item.item_name, item_group, brand, description, item.stock_uom, item.has_serial_no, actual_qty, posting_date, voucher_type, voucher_no, serial_no, batch_no, qty_after_transaction, warehouse from `tabStock Ledger Entry` sle, - (select name, item_name, description, stock_uom, brand, item_group + (select name, item_name, description, stock_uom, brand, item_group, has_serial_no from `tabItem` {item_conditions}) item where item_code = item.name and company = %(company)s and From 1682402a9ff157cf31b8871bc4addddefbf4ae12 Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Mon, 30 Aug 2021 18:26:56 +0530 Subject: [PATCH 052/121] refactor: Healthcare Redesign Changes (#27236) --- .../clinical_procedures.json | 6 +- .../clinical_procedures_status.json | 6 +- .../dashboard_chart/diagnoses/diagnoses.json | 7 +- .../dashboard_chart/lab_tests/lab_tests.json | 6 +- .../dashboard_chart/symptoms/symptoms.json | 6 +- .../healthcare/doctype/lab_test/lab_test.py | 8 +- .../test_patient_appointment.py | 14 +- .../patient_history_settings.py | 6 +- .../test_patient_history_settings.py | 3 +- .../healthcare/healthcare.json | 2 +- .../create_healthcare_practitioner.json | 4 +- .../create_patient/create_patient.json | 6 +- .../create_practitioner_schedule.json | 6 +- .../explore_clinical_procedure_templates.json | 4 +- .../explore_healthcare_settings.json | 4 +- ...troduction_to_healthcare_practitioner.json | 6 +- .../page/patient_history/patient_history.css | 42 +- .../page/patient_history/patient_history.html | 38 +- .../page/patient_history/patient_history.js | 774 ++++++++++-------- .../patient_history_sidebar.html | 21 + .../patient_progress/patient_progress.css | 8 +- .../patient_progress/patient_progress.html | 13 +- .../page/patient_progress/patient_progress.js | 65 +- .../report/lab_test_report/lab_test_report.py | 2 +- erpnext/healthcare/utils.py | 165 ++-- .../workspace/healthcare/healthcare.json | 254 +++--- 26 files changed, 825 insertions(+), 651 deletions(-) create mode 100644 erpnext/healthcare/page/patient_history/patient_history_sidebar.html diff --git a/erpnext/healthcare/dashboard_chart/clinical_procedures/clinical_procedures.json b/erpnext/healthcare/dashboard_chart/clinical_procedures/clinical_procedures.json index a59f149ee5..6803528156 100644 --- a/erpnext/healthcare/dashboard_chart/clinical_procedures/clinical_procedures.json +++ b/erpnext/healthcare/dashboard_chart/clinical_procedures/clinical_procedures.json @@ -12,15 +12,15 @@ "idx": 0, "is_public": 1, "is_standard": 1, - "last_synced_on": "2020-07-22 13:22:47.008622", - "modified": "2020-07-22 13:36:48.114479", + "last_synced_on": "2021-01-30 21:03:30.086891", + "modified": "2021-02-01 13:36:04.469863", "modified_by": "Administrator", "module": "Healthcare", "name": "Clinical Procedures", "number_of_groups": 0, "owner": "Administrator", "timeseries": 0, - "type": "Percentage", + "type": "Bar", "use_report_chart": 0, "y_axis": [] } \ No newline at end of file diff --git a/erpnext/healthcare/dashboard_chart/clinical_procedures_status/clinical_procedures_status.json b/erpnext/healthcare/dashboard_chart/clinical_procedures_status/clinical_procedures_status.json index 6d560f74bf..dae9db19b8 100644 --- a/erpnext/healthcare/dashboard_chart/clinical_procedures_status/clinical_procedures_status.json +++ b/erpnext/healthcare/dashboard_chart/clinical_procedures_status/clinical_procedures_status.json @@ -12,15 +12,15 @@ "idx": 0, "is_public": 1, "is_standard": 1, - "last_synced_on": "2020-07-22 13:22:46.691764", - "modified": "2020-07-22 13:40:17.215775", + "last_synced_on": "2021-02-01 13:36:38.787783", + "modified": "2021-02-01 13:37:18.718275", "modified_by": "Administrator", "module": "Healthcare", "name": "Clinical Procedures Status", "number_of_groups": 0, "owner": "Administrator", "timeseries": 0, - "type": "Pie", + "type": "Bar", "use_report_chart": 0, "y_axis": [] } \ No newline at end of file diff --git a/erpnext/healthcare/dashboard_chart/diagnoses/diagnoses.json b/erpnext/healthcare/dashboard_chart/diagnoses/diagnoses.json index 0195aac8b7..82145d6024 100644 --- a/erpnext/healthcare/dashboard_chart/diagnoses/diagnoses.json +++ b/erpnext/healthcare/dashboard_chart/diagnoses/diagnoses.json @@ -5,21 +5,22 @@ "docstatus": 0, "doctype": "Dashboard Chart", "document_type": "Patient Encounter Diagnosis", + "dynamic_filters_json": "", "filters_json": "[]", "group_by_based_on": "diagnosis", "group_by_type": "Count", "idx": 0, "is_public": 1, "is_standard": 1, - "last_synced_on": "2020-07-22 13:22:47.895521", - "modified": "2020-07-22 13:43:32.369481", + "last_synced_on": "2021-01-30 21:03:33.729487", + "modified": "2021-02-01 13:34:57.385335", "modified_by": "Administrator", "module": "Healthcare", "name": "Diagnoses", "number_of_groups": 0, "owner": "Administrator", "timeseries": 0, - "type": "Percentage", + "type": "Bar", "use_report_chart": 0, "y_axis": [] } \ No newline at end of file diff --git a/erpnext/healthcare/dashboard_chart/lab_tests/lab_tests.json b/erpnext/healthcare/dashboard_chart/lab_tests/lab_tests.json index 052483533e..70293b158e 100644 --- a/erpnext/healthcare/dashboard_chart/lab_tests/lab_tests.json +++ b/erpnext/healthcare/dashboard_chart/lab_tests/lab_tests.json @@ -12,15 +12,15 @@ "idx": 0, "is_public": 1, "is_standard": 1, - "last_synced_on": "2020-07-22 13:22:47.344055", - "modified": "2020-07-22 13:37:34.490129", + "last_synced_on": "2021-01-30 21:03:28.272914", + "modified": "2021-02-01 13:36:08.391433", "modified_by": "Administrator", "module": "Healthcare", "name": "Lab Tests", "number_of_groups": 0, "owner": "Administrator", "timeseries": 0, - "type": "Percentage", + "type": "Bar", "use_report_chart": 0, "y_axis": [] } \ No newline at end of file diff --git a/erpnext/healthcare/dashboard_chart/symptoms/symptoms.json b/erpnext/healthcare/dashboard_chart/symptoms/symptoms.json index 8fc86a1c59..65e5472aa1 100644 --- a/erpnext/healthcare/dashboard_chart/symptoms/symptoms.json +++ b/erpnext/healthcare/dashboard_chart/symptoms/symptoms.json @@ -12,15 +12,15 @@ "idx": 0, "is_public": 1, "is_standard": 1, - "last_synced_on": "2020-07-22 13:22:47.296748", - "modified": "2020-07-22 13:40:59.655129", + "last_synced_on": "2021-01-30 21:03:32.067473", + "modified": "2021-02-01 13:35:30.953718", "modified_by": "Administrator", "module": "Healthcare", "name": "Symptoms", "number_of_groups": 0, "owner": "Administrator", "timeseries": 0, - "type": "Percentage", + "type": "Bar", "use_report_chart": 0, "y_axis": [] } \ No newline at end of file diff --git a/erpnext/healthcare/doctype/lab_test/lab_test.py b/erpnext/healthcare/doctype/lab_test/lab_test.py index 4b57cd073d..74495a8591 100644 --- a/erpnext/healthcare/doctype/lab_test/lab_test.py +++ b/erpnext/healthcare/doctype/lab_test/lab_test.py @@ -34,7 +34,7 @@ class LabTest(Document): frappe.db.set_value('Lab Prescription', self.prescription, 'lab_test_created', 1) if frappe.db.get_value('Lab Prescription', self.prescription, 'invoiced'): self.invoiced = True - if not self.lab_test_name and self.template: + if self.template: self.load_test_from_template() self.reload() @@ -50,7 +50,7 @@ class LabTest(Document): item.secondary_uom_result = float(item.result_value) * float(item.conversion_factor) except: item.secondary_uom_result = '' - frappe.msgprint(_('Row #{0}: Result for Secondary UOM not calculated'.format(item.idx)), title = _('Warning')) + frappe.msgprint(_('Row #{0}: Result for Secondary UOM not calculated').format(item.idx), title = _('Warning')) def validate_result_values(self): if self.normal_test_items: @@ -229,9 +229,9 @@ def create_sample_doc(template, patient, invoice, company = None): sample_collection = frappe.get_doc('Sample Collection', sample_exists[0][0]) quantity = int(sample_collection.sample_qty) + int(template.sample_qty) if template.sample_details: - sample_details = sample_collection.sample_details + '\n-\n' + _('Test: ') + sample_details = sample_collection.sample_details + '\n-\n' + _('Test :') sample_details += (template.get('lab_test_name') or template.get('template')) + '\n' - sample_details += _('Collection Details: ') + '\n\t' + template.sample_details + sample_details += _('Collection Details:') + '\n\t' + template.sample_details frappe.db.set_value('Sample Collection', sample_collection.name, 'sample_details', sample_details) frappe.db.set_value('Sample Collection', sample_collection.name, 'sample_qty', quantity) diff --git a/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.py b/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.py index f5477c096a..36ef2d1623 100644 --- a/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.py +++ b/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.py @@ -66,7 +66,7 @@ class TestPatientAppointment(unittest.TestCase): medical_department = create_medical_department() frappe.db.set_value('Healthcare Settings', None, 'enable_free_follow_ups', 0) frappe.db.set_value('Healthcare Settings', None, 'automate_appointment_invoicing', 1) - appointment_type = create_appointment_type() + appointment_type = create_appointment_type({'medical_department': medical_department}) appointment = create_appointment(patient, practitioner, add_days(nowdate(), 2), invoice=1, appointment_type=appointment_type.name, department=medical_department) @@ -91,9 +91,9 @@ class TestPatientAppointment(unittest.TestCase): 'op_consulting_charge': 300 }] appointment_type = create_appointment_type(args={ - 'name': 'Generic Appointment Type charge', - 'items': items - }) + 'name': 'Generic Appointment Type charge', + 'items': items + }) appointment = create_appointment(patient, practitioner, add_days(nowdate(), 2), invoice=1, appointment_type=appointment_type.name) @@ -408,9 +408,9 @@ def create_appointment_type(args=None): else: item = create_healthcare_service_items() items = [{ - 'medical_department': '_Test Medical Department', - 'op_consulting_charge_item': item, - 'op_consulting_charge': 200 + 'medical_department': args.get('medical_department') or '_Test Medical Department', + 'op_consulting_charge_item': item, + 'op_consulting_charge': 200 }] return frappe.get_doc({ 'doctype': 'Appointment Type', diff --git a/erpnext/healthcare/doctype/patient_history_settings/patient_history_settings.py b/erpnext/healthcare/doctype/patient_history_settings/patient_history_settings.py index 63b00859d7..9e0d3c3e27 100644 --- a/erpnext/healthcare/doctype/patient_history_settings/patient_history_settings.py +++ b/erpnext/healthcare/doctype/patient_history_settings/patient_history_settings.py @@ -18,7 +18,7 @@ class PatientHistorySettings(Document): def validate_submittable_doctypes(self): for entry in self.custom_doctypes: if not cint(frappe.db.get_value('DocType', entry.document_type, 'is_submittable')): - msg = _('Row #{0}: Document Type {1} is not submittable. ').format( + msg = _('Row #{0}: Document Type {1} is not submittable.').format( entry.idx, frappe.bold(entry.document_type)) msg += _('Patient Medical Record can only be created for submittable document types.') frappe.throw(msg) @@ -116,12 +116,12 @@ def set_subject_field(doc): fieldname = entry.get('fieldname') if entry.get('fieldtype') == 'Table' and doc.get(fieldname): formatted_value = get_formatted_value_for_table_field(doc.get(fieldname), meta.get_field(fieldname)) - subject += frappe.bold(_(entry.get('label')) + ': ') + '
' + cstr(formatted_value) + '
' + subject += frappe.bold(_(entry.get('label')) + ':') + '
' + cstr(formatted_value) + '
' else: if doc.get(fieldname): formatted_value = format_value(doc.get(fieldname), meta.get_field(fieldname), doc) - subject += frappe.bold(_(entry.get('label')) + ': ') + cstr(formatted_value) + '
' + subject += frappe.bold(_(entry.get('label')) + ':') + cstr(formatted_value) + '
' return subject diff --git a/erpnext/healthcare/doctype/patient_history_settings/test_patient_history_settings.py b/erpnext/healthcare/doctype/patient_history_settings/test_patient_history_settings.py index 33119d8185..9169ea642b 100644 --- a/erpnext/healthcare/doctype/patient_history_settings/test_patient_history_settings.py +++ b/erpnext/healthcare/doctype/patient_history_settings/test_patient_history_settings.py @@ -38,13 +38,12 @@ class TestPatientHistorySettings(unittest.TestCase): # tests for medical record creation of standard doctypes in test_patient_medical_record.py patient = create_patient() doc = create_doc(patient) - # check for medical record medical_rec = frappe.db.exists("Patient Medical Record", {"status": "Open", "reference_name": doc.name}) self.assertTrue(medical_rec) medical_rec = frappe.get_doc("Patient Medical Record", medical_rec) - expected_subject = "Date: {0}Rating: 3Feedback: Test Patient History Settings".format( + expected_subject = "Date:{0}Rating:3Feedback:Test Patient History Settings".format( frappe.utils.format_date(getdate())) self.assertEqual(strip_html(medical_rec.subject), expected_subject) self.assertEqual(medical_rec.patient, patient) diff --git a/erpnext/healthcare/module_onboarding/healthcare/healthcare.json b/erpnext/healthcare/module_onboarding/healthcare/healthcare.json index 56c3c13559..0aa8f9a027 100644 --- a/erpnext/healthcare/module_onboarding/healthcare/healthcare.json +++ b/erpnext/healthcare/module_onboarding/healthcare/healthcare.json @@ -10,7 +10,7 @@ "documentation_url": "https://docs.erpnext.com/docs/user/manual/en/healthcare", "idx": 0, "is_complete": 0, - "modified": "2020-07-08 14:06:19.512946", + "modified": "2021-01-30 19:22:20.273766", "modified_by": "Administrator", "module": "Healthcare", "name": "Healthcare", diff --git a/erpnext/healthcare/onboarding_step/create_healthcare_practitioner/create_healthcare_practitioner.json b/erpnext/healthcare/onboarding_step/create_healthcare_practitioner/create_healthcare_practitioner.json index c45a347080..3f25a9d676 100644 --- a/erpnext/healthcare/onboarding_step/create_healthcare_practitioner/create_healthcare_practitioner.json +++ b/erpnext/healthcare/onboarding_step/create_healthcare_practitioner/create_healthcare_practitioner.json @@ -5,14 +5,14 @@ "doctype": "Onboarding Step", "idx": 0, "is_complete": 0, - "is_mandatory": 1, "is_single": 0, "is_skipped": 0, - "modified": "2020-05-26 23:16:31.965521", + "modified": "2021-01-30 12:02:22.849260", "modified_by": "Administrator", "name": "Create Healthcare Practitioner", "owner": "Administrator", "reference_document": "Healthcare Practitioner", + "show_form_tour": 0, "show_full_form": 1, "title": "Create Healthcare Practitioner", "validate_action": 1 diff --git a/erpnext/healthcare/onboarding_step/create_patient/create_patient.json b/erpnext/healthcare/onboarding_step/create_patient/create_patient.json index 77bc5bd7ad..b46bb15b48 100644 --- a/erpnext/healthcare/onboarding_step/create_patient/create_patient.json +++ b/erpnext/healthcare/onboarding_step/create_patient/create_patient.json @@ -5,14 +5,14 @@ "doctype": "Onboarding Step", "idx": 0, "is_complete": 0, - "is_mandatory": 1, "is_single": 0, "is_skipped": 0, - "modified": "2020-05-19 12:26:24.023418", - "modified_by": "Administrator", + "modified": "2021-01-30 00:09:28.786428", + "modified_by": "ruchamahabal2@gmail.com", "name": "Create Patient", "owner": "Administrator", "reference_document": "Patient", + "show_form_tour": 0, "show_full_form": 1, "title": "Create Patient", "validate_action": 1 diff --git a/erpnext/healthcare/onboarding_step/create_practitioner_schedule/create_practitioner_schedule.json b/erpnext/healthcare/onboarding_step/create_practitioner_schedule/create_practitioner_schedule.json index 65980ef668..7ce122d5c0 100644 --- a/erpnext/healthcare/onboarding_step/create_practitioner_schedule/create_practitioner_schedule.json +++ b/erpnext/healthcare/onboarding_step/create_practitioner_schedule/create_practitioner_schedule.json @@ -5,14 +5,14 @@ "doctype": "Onboarding Step", "idx": 0, "is_complete": 0, - "is_mandatory": 1, "is_single": 0, "is_skipped": 0, - "modified": "2020-05-19 12:27:09.437825", - "modified_by": "Administrator", + "modified": "2021-01-30 00:09:28.794602", + "modified_by": "ruchamahabal2@gmail.com", "name": "Create Practitioner Schedule", "owner": "Administrator", "reference_document": "Practitioner Schedule", + "show_form_tour": 0, "show_full_form": 1, "title": "Create Practitioner Schedule", "validate_action": 1 diff --git a/erpnext/healthcare/onboarding_step/explore_clinical_procedure_templates/explore_clinical_procedure_templates.json b/erpnext/healthcare/onboarding_step/explore_clinical_procedure_templates/explore_clinical_procedure_templates.json index 697b761e52..dfe9f71a76 100644 --- a/erpnext/healthcare/onboarding_step/explore_clinical_procedure_templates/explore_clinical_procedure_templates.json +++ b/erpnext/healthcare/onboarding_step/explore_clinical_procedure_templates/explore_clinical_procedure_templates.json @@ -5,14 +5,14 @@ "doctype": "Onboarding Step", "idx": 0, "is_complete": 0, - "is_mandatory": 0, "is_single": 0, "is_skipped": 0, - "modified": "2020-05-26 23:10:24.504030", + "modified": "2021-01-30 19:22:08.257160", "modified_by": "Administrator", "name": "Explore Clinical Procedure Templates", "owner": "Administrator", "reference_document": "Clinical Procedure Template", + "show_form_tour": 0, "show_full_form": 0, "title": "Explore Clinical Procedure Templates", "validate_action": 1 diff --git a/erpnext/healthcare/onboarding_step/explore_healthcare_settings/explore_healthcare_settings.json b/erpnext/healthcare/onboarding_step/explore_healthcare_settings/explore_healthcare_settings.json index b2d5aef431..2d952f3093 100644 --- a/erpnext/healthcare/onboarding_step/explore_healthcare_settings/explore_healthcare_settings.json +++ b/erpnext/healthcare/onboarding_step/explore_healthcare_settings/explore_healthcare_settings.json @@ -5,14 +5,14 @@ "doctype": "Onboarding Step", "idx": 0, "is_complete": 0, - "is_mandatory": 1, "is_single": 1, "is_skipped": 0, - "modified": "2020-05-26 23:10:24.507648", + "modified": "2021-01-30 19:22:07.275735", "modified_by": "Administrator", "name": "Explore Healthcare Settings", "owner": "Administrator", "reference_document": "Healthcare Settings", + "show_form_tour": 0, "show_full_form": 0, "title": "Explore Healthcare Settings", "validate_action": 1 diff --git a/erpnext/healthcare/onboarding_step/introduction_to_healthcare_practitioner/introduction_to_healthcare_practitioner.json b/erpnext/healthcare/onboarding_step/introduction_to_healthcare_practitioner/introduction_to_healthcare_practitioner.json index fa4c9036d7..baa8358c06 100644 --- a/erpnext/healthcare/onboarding_step/introduction_to_healthcare_practitioner/introduction_to_healthcare_practitioner.json +++ b/erpnext/healthcare/onboarding_step/introduction_to_healthcare_practitioner/introduction_to_healthcare_practitioner.json @@ -6,14 +6,14 @@ "field": "schedule", "idx": 0, "is_complete": 0, - "is_mandatory": 1, "is_single": 0, "is_skipped": 0, - "modified": "2020-05-26 22:07:07.482530", - "modified_by": "Administrator", + "modified": "2021-01-30 00:09:28.807129", + "modified_by": "ruchamahabal2@gmail.com", "name": "Introduction to Healthcare Practitioner", "owner": "Administrator", "reference_document": "Healthcare Practitioner", + "show_form_tour": 0, "show_full_form": 0, "title": "Introduction to Healthcare Practitioner", "validate_action": 0 diff --git a/erpnext/healthcare/page/patient_history/patient_history.css b/erpnext/healthcare/page/patient_history/patient_history.css index 1bb589164e..74b5e7eb91 100644 --- a/erpnext/healthcare/page/patient_history/patient_history.css +++ b/erpnext/healthcare/page/patient_history/patient_history.css @@ -9,6 +9,26 @@ cursor: pointer; } +.patient-image-container { + margin-top: 17px; + } + +.patient-image { + display: inline-block; + width: 100%; + height: 0; + padding: 50% 0px; + background-size: cover; + background-repeat: no-repeat; + background-position: center center; + border-radius: 4px; +} + +.patient-name { + font-size: 20px; + margin-top: 25px; +} + .medical_record-label { max-width: 100px; margin-bottom: -4px; @@ -19,19 +39,19 @@ } .date-indicator { - background:none; - font-size:12px; - vertical-align:middle; - font-weight:bold; - color:#6c7680; + background:none; + font-size:12px; + vertical-align:middle; + font-weight:bold; + color:#6c7680; } .date-indicator::after { - margin:0 -4px 0 12px; - content:''; - display:inline-block; - height:8px; - width:8px; - border-radius:8px; + margin:0 -4px 0 12px; + content:''; + display:inline-block; + height:8px; + width:8px; + border-radius:8px; background: #d1d8dd; } diff --git a/erpnext/healthcare/page/patient_history/patient_history.html b/erpnext/healthcare/page/patient_history/patient_history.html index f1706557f4..d16b38637c 100644 --- a/erpnext/healthcare/page/patient_history/patient_history.html +++ b/erpnext/healthcare/page/patient_history/patient_history.html @@ -1,26 +1,18 @@ -
-
-

-
+
+
+
+
+
+
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
- -
+ +
+
+
+
+
+
+
+
diff --git a/erpnext/healthcare/page/patient_history/patient_history.js b/erpnext/healthcare/page/patient_history/patient_history.js index 54343aae44..bf947cac21 100644 --- a/erpnext/healthcare/page/patient_history/patient_history.js +++ b/erpnext/healthcare/page/patient_history/patient_history.js @@ -1,403 +1,455 @@ frappe.provide('frappe.patient_history'); frappe.pages['patient_history'].on_page_load = function(wrapper) { - let me = this; - let page = frappe.ui.make_app_page({ + frappe.ui.make_app_page({ parent: wrapper, - title: 'Patient History', - single_column: true + title: __('Patient History') }); - frappe.breadcrumbs.add('Healthcare'); - let pid = ''; - page.main.html(frappe.render_template('patient_history', {})); - page.main.find('.header-separator').hide(); - - let patient = frappe.ui.form.make_control({ - parent: page.main.find('.patient'), - df: { - fieldtype: 'Link', - options: 'Patient', - fieldname: 'patient', - placeholder: __('Select Patient'), - only_select: true, - change: function() { - let patient_id = patient.get_value(); - if (pid != patient_id && patient_id) { - me.start = 0; - me.page.main.find('.patient_documents_list').html(''); - setup_filters(patient_id, me); - get_documents(patient_id, me); - show_patient_info(patient_id, me); - show_patient_vital_charts(patient_id, me, 'bp', 'mmHg', 'Blood Pressure'); - } - pid = patient_id; - } - }, - }); - patient.refresh(); - - if (frappe.route_options) { - patient.set_value(frappe.route_options.patient); - } - - this.page.main.on('click', '.btn-show-chart', function() { - let btn_show_id = $(this).attr('data-show-chart-id'), pts = $(this).attr('data-pts'); - let title = $(this).attr('data-title'); - show_patient_vital_charts(patient.get_value(), me, btn_show_id, pts, title); - }); - - this.page.main.on('click', '.btn-more', function() { - let doctype = $(this).attr('data-doctype'), docname = $(this).attr('data-docname'); - if (me.page.main.find('.'+docname).parent().find('.document-html').attr('data-fetched') == '1') { - me.page.main.find('.'+docname).hide(); - me.page.main.find('.'+docname).parent().find('.document-html').show(); - } else { - if (doctype && docname) { - let exclude = ['patient', 'patient_name', 'patient_sex', 'encounter_date']; - frappe.call({ - method: 'erpnext.healthcare.utils.render_doc_as_html', - args:{ - doctype: doctype, - docname: docname, - exclude_fields: exclude - }, - freeze: true, - callback: function(r) { - if (r.message) { - me.page.main.find('.' + docname).hide(); - - me.page.main.find('.' + docname).parent().find('.document-html').html( - `${r.message.html} -
- - -
- `); - - me.page.main.find('.' + docname).parent().find('.document-html').show(); - me.page.main.find('.' + docname).parent().find('.document-html').attr('data-fetched', '1'); - } - } - }); - } - } - }); - - this.page.main.on('click', '.btn-less', function() { - let docname = $(this).attr('data-docname'); - me.page.main.find('.' + docname).parent().find('.document-id').show(); - me.page.main.find('.' + docname).parent().find('.document-html').hide(); - }); - me.start = 0; - me.page.main.on('click', '.btn-get-records', function() { - get_documents(patient.get_value(), me); + let patient_history = new PatientHistory(wrapper); + $(wrapper).bind('show', ()=> { + patient_history.show(); }); }; -let setup_filters = function(patient, me) { - $('.doctype-filter').empty(); - frappe.xcall( - 'erpnext.healthcare.page.patient_history.patient_history.get_patient_history_doctypes' - ).then(document_types => { - let doctype_filter = frappe.ui.form.make_control({ - parent: $('.doctype-filter'), +class PatientHistory { + constructor(wrapper) { + this.wrapper = $(wrapper); + this.page = wrapper.page; + this.sidebar = this.wrapper.find('.layout-side-section'); + this.main_section = this.wrapper.find('.layout-main-section'); + this.start = 0; + } + + show() { + frappe.breadcrumbs.add('Healthcare'); + this.sidebar.empty(); + + let me = this; + let patient = frappe.ui.form.make_control({ + parent: me.sidebar, df: { - fieldtype: 'MultiSelectList', - fieldname: 'document_type', - placeholder: __('Select Document Type'), - input_class: 'input-xs', + fieldtype: 'Link', + options: 'Patient', + fieldname: 'patient', + placeholder: __('Select Patient'), + only_select: true, change: () => { - me.start = 0; - me.page.main.find('.patient_documents_list').html(''); - get_documents(patient, me, doctype_filter.get_value(), date_range_field.get_value()); - }, - get_data: () => { - return document_types.map(document_type => { - return { - description: document_type, - value: document_type - }; - }); - }, + me.patient_id = ''; + if (me.patient_id != patient.get_value() && patient.get_value()) { + me.start = 0; + me.patient_id = patient.get_value(); + me.make_patient_profile(); + } + } } }); - doctype_filter.refresh(); + patient.refresh(); - $('.date-filter').empty(); - let date_range_field = frappe.ui.form.make_control({ - df: { - fieldtype: 'DateRange', - fieldname: 'date_range', - placeholder: __('Date Range'), - input_class: 'input-xs', - change: () => { - let selected_date_range = date_range_field.get_value(); - if (selected_date_range && selected_date_range.length === 2) { + if (frappe.route_options && !this.patient_id) { + patient.set_value(frappe.route_options.patient); + this.patient_id = frappe.route_options.patient; + } + + this.sidebar.find('[data-fieldname="patient"]').append('
'); + } + + make_patient_profile() { + this.page.set_title(__('Patient History')); + this.main_section.empty().append(frappe.render_template('patient_history')); + this.setup_filters(); + this.setup_documents(); + this.show_patient_info(); + this.setup_buttons(); + this.show_patient_vital_charts('bp', 'mmHg', 'Blood Pressure'); + } + + setup_filters() { + $('.doctype-filter').empty(); + let me = this; + + frappe.xcall( + 'erpnext.healthcare.page.patient_history.patient_history.get_patient_history_doctypes' + ).then(document_types => { + let doctype_filter = frappe.ui.form.make_control({ + parent: $('.doctype-filter'), + df: { + fieldtype: 'MultiSelectList', + fieldname: 'document_type', + placeholder: __('Select Document Type'), + change: () => { me.start = 0; me.page.main.find('.patient_documents_list').html(''); - get_documents(patient, me, doctype_filter.get_value(), selected_date_range); - } + this.setup_documents(doctype_filter.get_value(), date_range_field.get_value()); + }, + get_data: () => { + return document_types.map(document_type => { + return { + description: document_type, + value: document_type + }; + }); + }, } - }, - parent: $('.date-filter') + }); + doctype_filter.refresh(); + + $('.date-filter').empty(); + let date_range_field = frappe.ui.form.make_control({ + df: { + fieldtype: 'DateRange', + fieldname: 'date_range', + placeholder: __('Date Range'), + input_class: 'input-xs', + change: () => { + let selected_date_range = date_range_field.get_value(); + if (selected_date_range && selected_date_range.length === 2) { + me.start = 0; + me.page.main.find('.patient_documents_list').html(''); + this.setup_documents(doctype_filter.get_value(), date_range_field.get_value()); + } + } + }, + parent: $('.date-filter') + }); + date_range_field.refresh(); }); - date_range_field.refresh(); - }); -}; + } -let get_documents = function(patient, me, document_types="", selected_date_range="") { - let filters = { - name: patient, - start: me.start, - page_length: 20 - }; - if (document_types) - filters['document_types'] = document_types; - if (selected_date_range) - filters['date_range'] = selected_date_range; + setup_documents(document_types="", selected_date_range="") { + let filters = { + name: this.patient_id, + start: this.start, + page_length: 20 + }; + if (document_types) + filters['document_types'] = document_types; + if (selected_date_range) + filters['date_range'] = selected_date_range; - frappe.call({ - 'method': 'erpnext.healthcare.page.patient_history.patient_history.get_feed', - args: filters, - callback: function(r) { - let data = r.message; - if (data.length) { - add_to_records(me, data); - } else { - me.page.main.find('.patient_documents_list').append(` -
-

${__('No more records..')}

-
`); - me.page.main.find('.btn-get-records').hide(); + let me = this; + frappe.call({ + 'method': 'erpnext.healthcare.page.patient_history.patient_history.get_feed', + args: filters, + callback: function(r) { + let data = r.message; + if (data.length) { + me.add_to_records(data); + } else { + me.page.main.find('.patient_documents_list').append(` +
+

${__('No more records..')}

+
`); + me.page.main.find('.btn-get-records').hide(); + } } - } - }); -}; + }); + } -let add_to_records = function(me, data) { - let details = "
`; + } + } + + this.page.main.find('.patient_documents_list').append(details); + this.start += data.length; + + if (data.length === 20) { + this.page.main.find(".btn-get-records").show(); + } else { + this.page.main.find(".btn-get-records").hide(); + this.page.main.find(".patient_documents_list").append(` +
+

${__('No more records..')}

+
`); } } - details += ''; - me.page.main.find('.patient_documents_list').append(details); - me.start += data.length; + add_date_separator(data) { + let date = frappe.datetime.str_to_obj(data.communication_date); + let pdate = ''; + let diff = frappe.datetime.get_day_diff(frappe.datetime.get_today(), + frappe.datetime.obj_to_str(date)); - if (data.length === 20) { - me.page.main.find(".btn-get-records").show(); - } else { - me.page.main.find(".btn-get-records").hide(); - me.page.main.find(".patient_documents_list").append(` -
-

${__('No more records..')}

-
`); - } -}; - -let add_date_separator = function(data) { - let date = frappe.datetime.str_to_obj(data.communication_date); - let pdate = ''; - let diff = frappe.datetime.get_day_diff(frappe.datetime.get_today(), frappe.datetime.obj_to_str(date)); - - if (diff < 1) { - pdate = __('Today'); - } else if (diff < 2) { - pdate = __('Yesterday'); - } else { - pdate = __('on ') + frappe.datetime.global_date_format(date); - } - data.date_sep = pdate; - return data; -}; - -let show_patient_info = function(patient, me) { - frappe.call({ - 'method': 'erpnext.healthcare.doctype.patient.patient.get_patient_detail', - args: { - patient: patient - }, - callback: function(r) { - let data = r.message; - let details = ''; - if (data.image) { - details += `
`; - } - - details += ` ${data.patient_name}
${data.sex}`; - if (data.email) details += `
${data.email}`; - if (data.mobile) details += `
${data.mobile}`; - if (data.occupation) details += `

${__('Occupation')} : ${data.occupation}`; - if (data.blood_group) details += `
${__('Blood Group')} : ${data.blood_group}`; - if (data.allergies) details += `

${__('Allerigies')} : ${data.allergies.replace("\n", ", ")}`; - if (data.medication) details += `
${__('Medication')} : ${data.medication.replace("\n", ", ")}`; - if (data.alcohol_current_use) details += `

${__('Alcohol use')} : ${data.alcohol_current_use}`; - if (data.alcohol_past_use) details += `
${__('Alcohol past use')} : ${data.alcohol_past_use}`; - if (data.tobacco_current_use) details += `
${__('Tobacco use')} : ${data.tobacco_current_use}`; - if (data.tobacco_past_use) details += `
${__('Tobacco past use')} : ${data.tobacco_past_use}`; - if (data.medical_history) details += `

${__('Medical history')} : ${data.medical_history.replace("\n", ", ")}`; - if (data.surgical_history) details += `
${__('Surgical history')} : ${data.surgical_history.replace("\n", ", ")}`; - if (data.surrounding_factors) details += `

${__('Occupational hazards')} : ${data.surrounding_factors.replace("\n", ", ")}`; - if (data.other_risk_factors) details += `
${__('Other risk factors')} : ${data.other_risk_factors.replace("\n", ", ")}`; - if (data.patient_details) details += `

${__('More info')} : ${data.patient_details.replace("\n", ", ")}`; - - if (details) { - details = `
` + details + `
`; - } - me.page.main.find('.patient_details').html(details); + if (diff < 1) { + pdate = __('Today'); + } else if (diff < 2) { + pdate = __('Yesterday'); + } else { + pdate = __('on {0}', [frappe.datetime.global_date_format(date)]); } - }); -}; + data.date_sep = pdate; + return data; + } -let show_patient_vital_charts = function(patient, me, btn_show_id, pts, title) { - frappe.call({ - method: 'erpnext.healthcare.utils.get_patient_vitals', - args:{ - patient: patient - }, - callback: function(r) { - if (r.message) { - let show_chart_btns_html = ` - `; + show_patient_info() { + this.get_patient_info().then(() => { + $('.patient-info').empty().append(frappe.render_template('patient_history_sidebar', { + patient_image: this.patient.image, + patient_name: this.patient.patient_name, + patient_gender: this.patient.sex, + patient_mobile: this.patient.mobile + })); + this.show_patient_details(); + }); + } - me.page.main.find('.show_chart_btns').html(show_chart_btns_html); + show_patient_details() { + let me = this; + frappe.call({ + 'method': 'erpnext.healthcare.doctype.patient.patient.get_patient_detail', + args: { + patient: me.patient_id + }, + callback: function(r) { let data = r.message; - let labels = [], datasets = []; - let bp_systolic = [], bp_diastolic = [], temperature = []; - let pulse = [], respiratory_rate = [], bmi = [], height = [], weight = []; + let details = ``; - for (let i=0; i
${__('Occupation')} : ${data.occupation}`; + if (data.blood_group) details += `
${__('Blood Group')} : ${data.blood_group}`; + if (data.allergies) details += `

${__('Allerigies')} : ${data.allergies.replace("\n", ", ")}`; + if (data.medication) details += `
${__('Medication')} : ${data.medication.replace("\n", ", ")}`; + if (data.alcohol_current_use) details += `

${__('Alcohol use')} : ${data.alcohol_current_use}`; + if (data.alcohol_past_use) details += `
${__('Alcohol past use')} : ${data.alcohol_past_use}`; + if (data.tobacco_current_use) details += `
${__('Tobacco use')} : ${data.tobacco_current_use}`; + if (data.tobacco_past_use) details += `
${__('Tobacco past use')} : ${data.tobacco_past_use}`; + if (data.medical_history) details += `

${__('Medical history')} : ${data.medical_history.replace("\n", ", ")}`; + if (data.surgical_history) details += `
${__('Surgical history')} : ${data.surgical_history.replace("\n", ", ")}`; + if (data.surrounding_factors) details += `

${__('Occupational hazards')} : ${data.surrounding_factors.replace("\n", ", ")}`; + if (data.other_risk_factors) details += `
${__('Other risk factors')} : ${data.other_risk_factors.replace("\n", ", ")}`; + if (data.patient_details) details += `

${__('More info')} : ${data.patient_details.replace("\n", ", ")}`; - if (btn_show_id === 'bp') { - bp_systolic.push(data[i].bp_systolic); - bp_diastolic.push(data[i].bp_diastolic); - } - if (btn_show_id === 'temperature') { - temperature.push(data[i].temperature); - } - if (btn_show_id === 'pulse_rate') { - pulse.push(data[i].pulse); - respiratory_rate.push(data[i].respiratory_rate); - } - if (btn_show_id === 'bmi') { - bmi.push(data[i].bmi); - height.push(data[i].height); - weight.push(data[i].weight); - } + if (details) { + details = `
` + details + `
`; } - if (btn_show_id === 'temperature') { - datasets.push({name: 'Temperature', values: temperature, chartType: 'line'}); - } - if (btn_show_id === 'bmi') { - datasets.push({name: 'BMI', values: bmi, chartType: 'line'}); - datasets.push({name: 'Height', values: height, chartType: 'line'}); - datasets.push({name: 'Weight', values: weight, chartType: 'line'}); - } - if (btn_show_id === 'bp') { - datasets.push({name: 'BP Systolic', values: bp_systolic, chartType: 'line'}); - datasets.push({name: 'BP Diastolic', values: bp_diastolic, chartType: 'line'}); - } - if (btn_show_id === 'pulse_rate') { - datasets.push({name: 'Heart Rate / Pulse', values: pulse, chartType: 'line'}); - datasets.push({name: 'Respiratory Rate', values: respiratory_rate, chartType: 'line'}); - } - new frappe.Chart('.patient_vital_charts', { - data: { - labels: labels, - datasets: datasets - }, - title: title, - type: 'axis-mixed', - height: 200, - colors: ['purple', '#ffa3ef', 'light-blue'], - - tooltipOptions: { - formatTooltipX: d => (d + '').toUpperCase(), - formatTooltipY: d => d + ' ' + pts, - } - }); - me.page.main.find('.header-separator').show(); - } else { - me.page.main.find('.patient_vital_charts').html(''); - me.page.main.find('.show_chart_btns').html(''); - me.page.main.find('.header-separator').hide(); + me.sidebar.find('.patient-details').html(details); } - } - }); -}; + }); + } + + get_patient_info() { + return frappe.xcall('frappe.client.get', { + doctype: 'Patient', + name: this.patient_id, + }).then((patient) => { + if (patient) { + this.patient = patient; + } + }); + } + + setup_buttons() { + let me = this; + this.page.main.on("click", ".btn-show-chart", function() { + let btn_id = $(this).attr("data-show-chart-id"), scale_unit = $(this).attr("data-pts"); + let title = $(this).attr("data-title"); + me.show_patient_vital_charts(btn_id, scale_unit, title); + }); + + this.page.main.on('click', '.btn-more', function() { + let doctype = $(this).attr('data-doctype'), docname = $(this).attr('data-docname'); + if (me.page.main.find('.'+docname).parent().find('.document-html').attr('data-fetched') == '1') { + me.page.main.find('.'+docname).hide(); + me.page.main.find('.'+docname).parent().find('.document-html').show(); + } else { + if (doctype && docname) { + let exclude = ['patient', 'patient_name', 'patient_sex', 'encounter_date', 'naming_series']; + frappe.call({ + method: 'erpnext.healthcare.utils.render_doc_as_html', + args: { + doctype: doctype, + docname: docname, + exclude_fields: exclude + }, + freeze: true, + callback: function(r) { + if (r.message) { + me.page.main.find('.' + docname).hide(); + + me.page.main.find('.' + docname).parent().find('.document-html').html( + `${r.message.html} +
+
+ + +
+ `); + + me.page.main.find('.' + docname).parent().find('.document-html').attr('hidden', false); + me.page.main.find('.' + docname).parent().find('.document-html').attr('data-fetched', '1'); + } + } + }); + } + } + }); + + this.page.main.on('click', '.btn-less', function() { + let docname = $(this).attr('data-docname'); + me.page.main.find('.' + docname).parent().find('.document-id').show(); + me.page.main.find('.' + docname).parent().find('.document-html').hide(); + }); + + me.page.main.on('click', '.btn-get-records', function() { + this.setup_documents(); + }); + } + + show_patient_vital_charts(btn_id, scale_unit, title) { + let me = this; + + frappe.call({ + method: 'erpnext.healthcare.utils.get_patient_vitals', + args: { + patient: me.patient_id + }, + callback: function(r) { + if (r.message) { + let show_chart_btns_html = ` + `; + + me.page.main.find('.show_chart_btns').html(show_chart_btns_html); + let data = r.message; + let labels = [], datasets = []; + let bp_systolic = [], bp_diastolic = [], temperature = []; + let pulse = [], respiratory_rate = [], bmi = [], height = [], weight = []; + + for (let i=0; i (d + '').toUpperCase(), + formatTooltipY: d => d + ' ' + scale_unit, + } + }); + me.page.main.find('.header-separator').show(); + } else { + me.page.main.find('.patient_vital_charts').html(''); + me.page.main.find('.show_chart_btns').html(''); + me.page.main.find('.header-separator').hide(); + } + } + }); + } +} \ No newline at end of file diff --git a/erpnext/healthcare/page/patient_history/patient_history_sidebar.html b/erpnext/healthcare/page/patient_history/patient_history_sidebar.html new file mode 100644 index 0000000000..4560e7e125 --- /dev/null +++ b/erpnext/healthcare/page/patient_history/patient_history_sidebar.html @@ -0,0 +1,21 @@ +
+
+ {% if patient_image %} +
+ {% endif %} +
+
+ {% if patient_name %} +

{{patient_name}}

+ {% endif %} + {% if patient_gender %} +

{%=__("Gender: ") %} {{patient_gender}}

+ {% endif %} + {% if patient_mobile %} +

{%=__("Contact: ") %} {{patient_mobile}}

+ {% endif %} +
+
+
+
+ diff --git a/erpnext/healthcare/page/patient_progress/patient_progress.css b/erpnext/healthcare/page/patient_progress/patient_progress.css index 5d85a7487f..737b2e0ea2 100644 --- a/erpnext/healthcare/page/patient_progress/patient_progress.css +++ b/erpnext/healthcare/page/patient_progress/patient_progress.css @@ -29,6 +29,7 @@ .patient-name { font-size: 20px; + margin-top: 25px; } /* heatmap */ @@ -55,6 +56,7 @@ } .heatmap-container .chart-filter { + z-index: 1; position: relative; top: 5px; margin-right: 10px; @@ -111,10 +113,13 @@ text.title { } .chart-column-container { - border-bottom: 1px solid #d1d8dd; margin: 5px 0; } +.progress-graphs .progress-container { + margin-bottom: var(--margin-xl); +} + .line-chart-container .frappe-chart { margin-top: -20px; } @@ -146,6 +151,7 @@ text.title { } .percentage-chart-container .chart-filter { + z-index: 1; position: relative; top: 12px; margin-right: 10px; diff --git a/erpnext/healthcare/page/patient_progress/patient_progress.html b/erpnext/healthcare/page/patient_progress/patient_progress.html index 30064bd165..ee60065618 100644 --- a/erpnext/healthcare/page/patient_progress/patient_progress.html +++ b/erpnext/healthcare/page/patient_progress/patient_progress.html @@ -1,14 +1,15 @@
-