From 4993ef19d6fe4280ea7b95c2e8ee7e1905a90c5d Mon Sep 17 00:00:00 2001 From: marination Date: Thu, 1 Oct 2020 16:35:09 +0530 Subject: [PATCH 1/4] feat: Supplier Quotation UX fixes --- .../request_for_quotation.js | 2 +- .../request_for_quotation.py | 12 ++-- .../supplier_quotation/supplier_quotation.js | 28 +++++--- .../supplier_quotation_item.json | 69 +++++++++++++------ 4 files changed, 75 insertions(+), 36 deletions(-) diff --git a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js index 4a937f7f0d..cf5d7cd4c5 100644 --- a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js +++ b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js @@ -179,7 +179,7 @@ frappe.ui.form.on("Request for Quotation",{ dialog.hide(); return frappe.call({ type: "GET", - method: "erpnext.buying.doctype.request_for_quotation.request_for_quotation.make_supplier_quotation", + method: "erpnext.buying.doctype.request_for_quotation.request_for_quotation.make_supplier_quotation_from_rfq", args: { "source_name": doc.name, "for_supplier": args.supplier diff --git a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py index b54a585b97..fd04b0d2a6 100644 --- a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py +++ b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py @@ -214,14 +214,14 @@ def get_supplier_contacts(doctype, txt, searchfield, start, page_len, filters): and `tabDynamic Link`.link_name like %(txt)s) and `tabContact`.name = `tabDynamic Link`.parent limit %(start)s, %(page_len)s""", {"start": start, "page_len":page_len, "txt": "%%%s%%" % txt, "name": filters.get('supplier')}) -# This method is used to make supplier quotation from material request form. @frappe.whitelist() -def make_supplier_quotation(source_name, for_supplier, target_doc=None): +def make_supplier_quotation_from_rfq(source_name, target_doc=None, for_supplier=None): def postprocess(source, target_doc): - target_doc.supplier = for_supplier - args = get_party_details(for_supplier, party_type="Supplier", ignore_permissions=True) - target_doc.currency = args.currency or get_party_account_currency('Supplier', for_supplier, source.company) - target_doc.buying_price_list = args.buying_price_list or frappe.db.get_value('Buying Settings', None, 'buying_price_list') + if for_supplier: + target_doc.supplier = for_supplier + args = get_party_details(for_supplier, party_type="Supplier", ignore_permissions=True) + target_doc.currency = args.currency or get_party_account_currency('Supplier', for_supplier, source.company) + target_doc.buying_price_list = args.buying_price_list or frappe.db.get_value('Buying Settings', None, 'buying_price_list') set_missing_values(source, target_doc) doclist = get_mapped_doc("Request for Quotation", source_name, { diff --git a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.js b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.js index 1b8b40459f..4a2a0786f3 100644 --- a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.js +++ b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.js @@ -8,8 +8,7 @@ erpnext.buying.SupplierQuotationController = erpnext.buying.BuyingController.ext setup: function() { this.frm.custom_make_buttons = { 'Purchase Order': 'Purchase Order', - 'Quotation': 'Quotation', - 'Subscription': 'Subscription' + 'Quotation': 'Quotation' } this._super(); @@ -28,12 +27,6 @@ erpnext.buying.SupplierQuotationController = erpnext.buying.BuyingController.ext cur_frm.page.set_inner_btn_group_as_primary(__('Create')); cur_frm.add_custom_button(__("Quotation"), this.make_quotation, __('Create')); - - if(!this.frm.doc.auto_repeat) { - cur_frm.add_custom_button(__('Subscription'), function() { - erpnext.utils.make_subscription(me.frm.doc.doctype, me.frm.doc.name) - }, __('Create')) - } } else if (this.frm.doc.docstatus===0) { @@ -54,6 +47,25 @@ erpnext.buying.SupplierQuotationController = erpnext.buying.BuyingController.ext } }) }, __("Get items from")); + + this.frm.add_custom_button(__("Request for Quotation"), + function() { + if (!me.frm.doc.supplier) { + frappe.throw({message:__("Please select a Supplier"), title:__("Mandatory")}) + } + erpnext.utils.map_current_doc({ + method: "erpnext.buying.doctype.request_for_quotation.request_for_quotation.make_supplier_quotation_from_rfq", + source_doctype: "Request for Quotation", + target: me.frm, + setters: { + company: me.frm.doc.company, + transaction_date: null + }, + get_query_filters: { + docstatus: 1, + } + }) + }, __("Get items from")); } }, diff --git a/erpnext/buying/doctype/supplier_quotation_item/supplier_quotation_item.json b/erpnext/buying/doctype/supplier_quotation_item/supplier_quotation_item.json index b50e834ec7..7d624357f3 100644 --- a/erpnext/buying/doctype/supplier_quotation_item/supplier_quotation_item.json +++ b/erpnext/buying/doctype/supplier_quotation_item/supplier_quotation_item.json @@ -12,6 +12,8 @@ "item_name", "column_break_3", "lead_time_days", + "expected_delivery_date", + "is_free_item", "section_break_5", "description", "item_group", @@ -19,20 +21,18 @@ "col_break1", "image", "image_view", - "manufacture_details", - "manufacturer", - "column_break_15", - "manufacturer_part_no", "quantity_and_rate", "qty", "stock_uom", - "price_list_rate", - "discount_percentage", - "discount_amount", "col_break2", "uom", "conversion_factor", "stock_qty", + "sec_break_price_list", + "price_list_rate", + "discount_percentage", + "discount_amount", + "col_break_price_list", "base_price_list_rate", "sec_break1", "rate", @@ -42,7 +42,6 @@ "base_rate", "base_amount", "pricing_rules", - "is_free_item", "section_break_24", "net_rate", "net_amount", @@ -56,7 +55,6 @@ "weight_uom", "warehouse_and_reference", "warehouse", - "project", "prevdoc_doctype", "material_request", "sales_order", @@ -65,13 +63,19 @@ "material_request_item", "request_for_quotation_item", "item_tax_rate", + "manufacture_details", + "manufacturer", + "column_break_15", + "manufacturer_part_no", + "ad_sec_break", + "project", "section_break_44", "page_break" ], "fields": [ { "bold": 1, - "columns": 4, + "columns": 2, "fieldname": "item_code", "fieldtype": "Link", "in_list_view": 1, @@ -107,7 +111,7 @@ { "fieldname": "lead_time_days", "fieldtype": "Int", - "label": "Lead Time in days" + "label": "Supplier Lead Time (days)" }, { "collapsible": 1, @@ -162,7 +166,6 @@ { "fieldname": "stock_uom", "fieldtype": "Link", - "in_list_view": 1, "label": "Stock UOM", "options": "UOM", "print_hide": 1, @@ -196,6 +199,7 @@ { "fieldname": "uom", "fieldtype": "Link", + "in_list_view": 1, "label": "UOM", "options": "UOM", "print_hide": 1, @@ -289,14 +293,6 @@ "print_hide": 1, "read_only": 1 }, - { - "default": "0", - "fieldname": "is_free_item", - "fieldtype": "Check", - "label": "Is Free Item", - "print_hide": 1, - "read_only": 1 - }, { "fieldname": "section_break_24", "fieldtype": "Section Break" @@ -528,12 +524,43 @@ { "fieldname": "column_break_15", "fieldtype": "Column Break" + }, + { + "fieldname": "sec_break_price_list", + "fieldtype": "Section Break" + }, + { + "fieldname": "col_break_price_list", + "fieldtype": "Column Break" + }, + { + "collapsible": 1, + "fieldname": "ad_sec_break", + "fieldtype": "Section Break", + "label": "Accounting Dimensions" + }, + { + "default": "0", + "depends_on": "is_free_item", + "fieldname": "is_free_item", + "fieldtype": "Check", + "label": "Is Free Item", + "print_hide": 1, + "read_only": 1 + }, + { + "allow_on_submit": 1, + "bold": 1, + "fieldname": "expected_delivery_date", + "fieldtype": "Date", + "label": "Expected Delivery Date" } ], "idx": 1, + "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2020-04-07 18:35:51.175947", + "modified": "2020-10-01 16:34:39.703033", "modified_by": "Administrator", "module": "Buying", "name": "Supplier Quotation Item", From 5006345a0a55ff4bb01cf431af6a8b8b900e5428 Mon Sep 17 00:00:00 2001 From: marination Date: Thu, 1 Oct 2020 20:41:05 +0530 Subject: [PATCH 2/4] chore: Fetch RFQs in Get Items from RFQ based on Supplier selected - Rfq will appear only if selected supplier is in the RFQ --- .../request_for_quotation.py | 28 +++++++++++++++++++ .../supplier_quotation/supplier_quotation.js | 6 ++-- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py index fd04b0d2a6..76775343e4 100644 --- a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py +++ b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py @@ -354,3 +354,31 @@ def get_supplier_tag(): frappe.cache().hset("Supplier", "Tags", tags) return frappe.cache().hget("Supplier", "Tags") + +@frappe.whitelist() +@frappe.validate_and_sanitize_search_inputs +def get_rfq_containing_supplier(doctype, txt, searchfield, start, page_len, filters): + conditions = "" + if txt: + conditions += "and rfq.name like '%%"+txt+"%%' " + + if filters.get("transaction_date"): + conditions += "and rfq.transaction_date = '{0}'".format(filters.get("transaction_date")) + + rfq_data = frappe.db.sql(""" + select + distinct rfq.name, rfq.transaction_date, + rfq.company + from + `tabRequest for Quotation` rfq, `tabRequest for Quotation Supplier` rfq_supplier + where + rfq.name = rfq_supplier.parent + and rfq_supplier.supplier = '{0}' + and rfq.docstatus = 1 + and rfq.company = '{1}' + {2} + order by rfq.transaction_date ASC + limit {3} offset {4} """ \ + .format(filters.get("supplier"), filters.get("company"), conditions, page_len, start), as_dict=1) + + return rfq_data \ No newline at end of file diff --git a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.js b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.js index 4a2a0786f3..3376e82956 100644 --- a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.js +++ b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.js @@ -62,8 +62,10 @@ erpnext.buying.SupplierQuotationController = erpnext.buying.BuyingController.ext transaction_date: null }, get_query_filters: { - docstatus: 1, - } + supplier: me.frm.doc.supplier + }, + get_query_method: "erpnext.buying.doctype.request_for_quotation.request_for_quotation.get_rfq_containing_supplier" + }) }, __("Get items from")); } From f57ba86bce5ad0b1ec647f90a8d8d0d42fd21a31 Mon Sep 17 00:00:00 2001 From: marination Date: Thu, 1 Oct 2020 21:10:00 +0530 Subject: [PATCH 3/4] chore: Add Date and Valid Till to List View --- .../buying/doctype/supplier_quotation/supplier_quotation.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json index 660dcff34b..9a092ca5c3 100644 --- a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json +++ b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json @@ -159,6 +159,7 @@ "default": "Today", "fieldname": "transaction_date", "fieldtype": "Date", + "in_list_view": 1, "label": "Date", "oldfieldname": "transaction_date", "oldfieldtype": "Date", @@ -798,6 +799,7 @@ { "fieldname": "valid_till", "fieldtype": "Date", + "in_list_view": 1, "label": "Valid Till" } ], @@ -805,7 +807,7 @@ "idx": 29, "is_submittable": 1, "links": [], - "modified": "2020-07-18 05:10:45.556792", + "modified": "2020-10-01 20:56:17.932007", "modified_by": "Administrator", "module": "Buying", "name": "Supplier Quotation", From b9e2f17f4f427dc8726c348ddc2577c7d8b50f7b Mon Sep 17 00:00:00 2001 From: marination Date: Thu, 1 Oct 2020 21:31:51 +0530 Subject: [PATCH 4/4] fix: More secure query --- .../doctype/request_for_quotation/request_for_quotation.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py index 76775343e4..361ccdf7f3 100644 --- a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py +++ b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py @@ -378,7 +378,8 @@ def get_rfq_containing_supplier(doctype, txt, searchfield, start, page_len, filt and rfq.company = '{1}' {2} order by rfq.transaction_date ASC - limit {3} offset {4} """ \ - .format(filters.get("supplier"), filters.get("company"), conditions, page_len, start), as_dict=1) + limit %(page_len)s offset %(start)s """ \ + .format(filters.get("supplier"), filters.get("company"), conditions), + {"page_len": page_len, "start": start}, as_dict=1) return rfq_data \ No newline at end of file