diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py index 0c8d999a98..244d39e1b6 100644 --- a/erpnext/accounts/party.py +++ b/erpnext/accounts/party.py @@ -16,7 +16,7 @@ class DuplicatePartyAccountError(frappe.ValidationError): pass @frappe.whitelist() def get_party_details(party=None, account=None, party_type="Customer", company=None, - posting_date=None, price_list=None, currency=None, doctype=None): + posting_date=None, price_list=None, currency=None, doctype=None, ignore_permissions=False): if not party: return {} @@ -25,7 +25,7 @@ def get_party_details(party=None, account=None, party_type="Customer", company=N frappe.throw(_("{0}: {1} does not exists").format(party_type, party)) return _get_party_details(party, account, party_type, - company, posting_date, price_list, currency, doctype) + company, posting_date, price_list, currency, doctype, ignore_permissions) def _get_party_details(party=None, account=None, party_type="Customer", company=None, posting_date=None, price_list=None, currency=None, doctype=None, ignore_permissions=False): diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js index 617befff29..78924e9233 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.js +++ b/erpnext/buying/doctype/purchase_order/purchase_order.js @@ -47,7 +47,7 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend( if(is_drop_ship && doc.status!="Delivered"){ cur_frm.add_custom_button(__('Delivered'), - this.delivered_by_supplier, __("Status")); + this.delivered_by_supplier, __("Status")); cur_frm.page.set_inner_btn_group_as_primary(__("Status")); } diff --git a/erpnext/buying/doctype/request_for_quotation/__init__.py b/erpnext/buying/doctype/request_for_quotation/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js new file mode 100644 index 0000000000..0d509e2498 --- /dev/null +++ b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js @@ -0,0 +1,87 @@ +// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors +// License: GNU General Public License v3. See license.txt + + +{% include 'buying/doctype/purchase_common/purchase_common.js' %}; + +frappe.require("assets/erpnext/js/utils.js"); + +frappe.ui.form.on("Request for Quotation",{ + setup: function(frm){ + frm.fields_dict["suppliers"].grid.get_field("contact_person").get_query = function(doc, cdt, cdn){ + var d =locals[cdt][cdn]; + return { + filters: {'supplier': d.supplier} + } + } + }, + + onload: function(frm){ + frm.add_fetch('standard_reply', 'response', 'response'); + }, + + refresh: function(frm, cdt, cdn){ + if (frm.doc.docstatus === 1) { + frm.add_custom_button(__("Supplier Quotation"), function(){ frm.trigger("make_suppplier_quotation") }, + __("Make")); + frm.page.set_inner_btn_group_as_primary(__("Make")); + } + }, + + make_suppplier_quotation: function(frm){ + var doc = frm.doc; + var dialog = new frappe.ui.Dialog({ + title: __("For Supplier"), + fields: [ + {"fieldtype": "Link", "label": __("Supplier"), "fieldname": "supplier", "options":"Supplier", + "get_query": function () { + return { + query:"erpnext.buying.doctype.request_for_quotation.request_for_quotation.get_supplier", + filters: {'parent': doc.name} + } + }, "reqd": 1 }, + {"fieldtype": "Button", "label": __("Make Supplier Quotation"), "fieldname": "make_supplier_quotation", "cssClass": "btn-primary"}, + ] + }); + + dialog.fields_dict.make_supplier_quotation.$input.click(function(){ + args = dialog.get_values(); + if(!args) return; + dialog.hide(); + return frappe.call({ + type: "GET", + method: "erpnext.buying.doctype.request_for_quotation.request_for_quotation.make_supplier_quotation", + args: { + "source_name": doc.name, + "for_supplier": args.supplier + }, + freeze: true, + callback: function(r) { + if(!r.exc) { + var doc = frappe.model.sync(r.message); + frappe.set_route("Form", r.message.doctype, r.message.name); + } + } + }); + }); + dialog.show() + } +}) + +erpnext.buying.RequestforQuotationController = erpnext.buying.BuyingController.extend({ + refresh: function() { + this._super(); + }, + + calculate_taxes_and_totals: function() { + return; + }, + + tc_name: function() { + this.get_terms(); + } +}); + + +// for backward compatibility: combine new and previous states +$.extend(cur_frm.cscript, new erpnext.buying.RequestforQuotationController({frm: cur_frm})); diff --git a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.json b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.json new file mode 100644 index 0000000000..88a91a0a37 --- /dev/null +++ b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.json @@ -0,0 +1,767 @@ +{ + "allow_copy": 0, + "allow_import": 1, + "allow_rename": 0, + "autoname": "naming_series:", + "creation": "2016-02-25 01:24:07.224790", + "custom": 0, + "docstatus": 0, + "doctype": "DocType", + "document_type": "Document", + "fields": [ + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "naming_series", + "fieldtype": "Select", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Series", + "length": 0, + "no_copy": 1, + "oldfieldname": "naming_series", + "oldfieldtype": "Select", + "options": "RFQ-", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "description": "", + "fieldname": "company", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 1, + "in_list_view": 0, + "label": "Company", + "length": 0, + "no_copy": 0, + "oldfieldname": "company", + "oldfieldtype": "Link", + "options": "Company", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 1, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "column_break1", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "length": 0, + "no_copy": 0, + "oldfieldtype": "Column Break", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "print_width": "50%", + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0, + "width": "50%" + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "transaction_date", + "fieldtype": "Date", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 1, + "in_list_view": 0, + "label": "Date", + "length": 0, + "no_copy": 0, + "oldfieldname": "transaction_date", + "oldfieldtype": "Date", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 1, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "suppliers_section", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "suppliers", + "fieldtype": "Table", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Supplier Detail", + "length": 0, + "no_copy": 0, + "options": "RFQ Supplier", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "items_section", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "", + "length": 0, + "no_copy": 0, + "oldfieldtype": "Section Break", + "options": "icon-shopping-cart", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "items", + "fieldtype": "Table", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Items", + "length": 0, + "no_copy": 0, + "oldfieldname": "po_details", + "oldfieldtype": "Table", + "options": "Request for Quotation Item", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "supplier_response_section", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "standard_reply", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Standard Reply", + "length": 0, + "no_copy": 0, + "options": "Standard Reply", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "response", + "fieldtype": "Text Editor", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Message for Supplier", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 1, + "collapsible_depends_on": "terms", + "fieldname": "terms_section_break", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Terms and Conditions", + "length": 0, + "no_copy": 0, + "oldfieldtype": "Section Break", + "options": "icon-legal", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "tc_name", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Terms", + "length": 0, + "no_copy": 0, + "oldfieldname": "tc_name", + "oldfieldtype": "Link", + "options": "Terms and Conditions", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "terms", + "fieldtype": "Text Editor", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Terms and Conditions", + "length": 0, + "no_copy": 0, + "oldfieldname": "terms", + "oldfieldtype": "Text Editor", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 1, + "fieldname": "printing_settings", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Printing Settings", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 1, + "bold": 0, + "collapsible": 0, + "fieldname": "select_print_heading", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Print Heading", + "length": 0, + "no_copy": 1, + "oldfieldname": "select_print_heading", + "oldfieldtype": "Link", + "options": "Print Heading", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 1, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 1, + "bold": 0, + "collapsible": 0, + "fieldname": "letter_head", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Letter Head", + "length": 0, + "no_copy": 0, + "oldfieldname": "letter_head", + "oldfieldtype": "Select", + "options": "Letter Head", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 1, + "fieldname": "more_info", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "More Information", + "length": 0, + "no_copy": 0, + "oldfieldtype": "Section Break", + "options": "icon-file-text", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "status", + "fieldtype": "Select", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 1, + "in_list_view": 0, + "label": "Status", + "length": 0, + "no_copy": 1, + "oldfieldname": "status", + "oldfieldtype": "Select", + "options": "\nDraft\nSubmitted\nCancelled", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 1, + "report_hide": 0, + "reqd": 1, + "search_index": 1, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "fiscal_year", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 1, + "in_list_view": 0, + "label": "Fiscal Year", + "length": 0, + "no_copy": 0, + "oldfieldname": "fiscal_year", + "oldfieldtype": "Select", + "options": "Fiscal Year", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 1, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "column_break3", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "amended_from", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Amended From", + "length": 0, + "no_copy": 1, + "options": "Request for Quotation", + "permlevel": 0, + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + } + ], + "hide_heading": 0, + "hide_toolbar": 0, + "icon": "icon-shopping-cart", + "idx": 0, + "in_create": 0, + "in_dialog": 0, + "is_submittable": 1, + "issingle": 0, + "istable": 0, + "max_attachments": 0, + "modified": "2016-03-25 01:14:01.194848", + "modified_by": "Administrator", + "module": "Buying", + "name": "Request for Quotation", + "name_case": "", + "owner": "Administrator", + "permissions": [ + { + "amend": 1, + "apply_user_permissions": 0, + "cancel": 1, + "create": 1, + "delete": 1, + "email": 1, + "export": 0, + "if_owner": 0, + "import": 0, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "Manufacturing Manager", + "set_user_permissions": 0, + "share": 1, + "submit": 1, + "write": 1 + }, + { + "amend": 1, + "apply_user_permissions": 0, + "cancel": 1, + "create": 1, + "delete": 1, + "email": 1, + "export": 0, + "if_owner": 0, + "import": 0, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "Purchase Manager", + "set_user_permissions": 0, + "share": 1, + "submit": 1, + "write": 1 + }, + { + "amend": 1, + "apply_user_permissions": 0, + "cancel": 0, + "create": 1, + "delete": 0, + "email": 1, + "export": 0, + "if_owner": 0, + "import": 0, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "Purchase User", + "set_user_permissions": 0, + "share": 1, + "submit": 0, + "write": 1 + }, + { + "amend": 0, + "apply_user_permissions": 0, + "cancel": 0, + "create": 0, + "delete": 0, + "email": 1, + "export": 0, + "if_owner": 0, + "import": 0, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "Stock User", + "set_user_permissions": 0, + "share": 0, + "submit": 0, + "write": 0 + }, + { + "amend": 0, + "apply_user_permissions": 0, + "cancel": 0, + "create": 0, + "delete": 0, + "email": 1, + "export": 0, + "if_owner": 0, + "import": 0, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "Supplier", + "set_user_permissions": 0, + "share": 0, + "submit": 0, + "write": 0 + }, + { + "amend": 0, + "apply_user_permissions": 0, + "cancel": 0, + "create": 0, + "delete": 0, + "email": 0, + "export": 0, + "if_owner": 0, + "import": 0, + "permlevel": 1, + "print": 0, + "read": 1, + "report": 0, + "role": "Purchase Manager", + "set_user_permissions": 0, + "share": 0, + "submit": 0, + "write": 1 + }, + { + "amend": 0, + "apply_user_permissions": 0, + "cancel": 0, + "create": 0, + "delete": 0, + "email": 0, + "export": 0, + "if_owner": 0, + "import": 0, + "permlevel": 1, + "print": 0, + "read": 1, + "report": 0, + "role": "All", + "set_user_permissions": 0, + "share": 0, + "submit": 0, + "write": 0 + } + ], + "read_only": 0, + "read_only_onload": 1, + "search_fields": "status, transaction_date", + "sort_field": "modified", + "sort_order": "DESC", + "timeline_field": "", + "title_field": "" +} \ No newline at end of file diff --git a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py new file mode 100644 index 0000000000..92089e4a16 --- /dev/null +++ b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py @@ -0,0 +1,177 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +import frappe, json +from frappe import _ +from frappe.utils import get_url, cint +from frappe.utils.user import get_user_fullname +from frappe.model.mapper import get_mapped_doc +from erpnext.stock.doctype.material_request.material_request import set_missing_values +from erpnext.controllers.buying_controller import BuyingController + +STANDARD_USERS = ("Guest", "Administrator") + +class RequestforQuotation(BuyingController): + def validate(self): + self.validate_duplicate_supplier() + self.validate_common() + + def validate_duplicate_supplier(self): + supplier_list = [d.supplier for d in self.suppliers] + if len(supplier_list) != len(set(supplier_list)): + frappe.throw(_("Same supplier has been entered multiple times")) + + def validate_common(self): + pc = frappe.get_doc('Purchase Common') + pc.validate_for_items(self) + + def on_submit(self): + frappe.db.set(self, 'status', 'Submitted') + self.send_to_supplier() + + def on_cancel(self): + frappe.db.set(self, 'status', 'Cancelled') + + def send_to_supplier(self): + link = get_url("/rfq/" + self.name) + for supplier_data in self.suppliers: + if supplier_data.email_id and cint(supplier_data.sent_email_to_supplier)==1: + update_password_link = self.create_supplier_user(supplier_data, link) + self.supplier_rfq_mail(supplier_data, update_password_link, link) + + def create_supplier_user(self, supplier_data, link): + from frappe.utils import random_string, get_url + + update_password_link = '' + if not supplier_data.user_id: + user = self.create_user(supplier_data) + key = random_string(32) + user.reset_password_key = key + user.redirect_url = link + user.save(ignore_permissions=True) + + update_password_link = get_url("/update-password?key=" + key) + frappe.get_doc('Contact', supplier_data.contact_person).save() + + return update_password_link + + def create_user(self, supplier_data): + user = frappe.get_doc({ + 'doctype': 'User', + 'send_welcome_email': 0, + 'email': supplier_data.email_id, + 'first_name': supplier_data.supplier_name, + 'user_type': 'Website User' + }) + + return user + + def supplier_rfq_mail(self, data, update_password_link, rfq_link): + full_name = get_user_fullname(frappe.session['user']) + if full_name == "Guest": + full_name = "Administrator" + + args = { + 'update_password_link': update_password_link, + 'message': frappe.render_template(self.response, data.as_dict()), + 'rfq_link': rfq_link, + 'user_fullname': full_name + } + + subject = _("Request for Quotation") + template = "templates/emails/request_for_quotation.html" + sender = frappe.session.user not in STANDARD_USERS and frappe.session.user or None + + frappe.sendmail(recipients=data.email_id, sender=sender, subject=subject, + message=frappe.get_template(template).render(args), + attachments = [frappe.attach_print('Request for Quotation', self.name)],as_bulk=True) + + frappe.msgprint(_("Email sent to supplier {0}").format(data.supplier)) + +def get_list_context(context=None): + from erpnext.controllers.website_list_for_contact import get_list_context + list_context = get_list_context(context) + return list_context + +@frappe.whitelist() +def get_supplier(doctype, txt, searchfield, start, page_len, filters): + query = """Select supplier from `tabRFQ Supplier` where parent = %(parent)s and supplier like %(txt)s + limit %(start)s, %(page_len)s """ + + return frappe.db.sql(query, {'parent': filters.get('parent'), + 'start': start, 'page_len': page_len, 'txt': "%%%s%%" % frappe.db.escape(txt)}) + +# 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 postprocess(source, target_doc): + target_doc.supplier = for_supplier + set_missing_values(source, target_doc) + + doclist = get_mapped_doc("Request for Quotation", source_name, { + "Request for Quotation": { + "doctype": "Supplier Quotation", + "validation": { + "docstatus": ["=", 1] + } + }, + "Request for Quotation Item": { + "doctype": "Supplier Quotation Item", + "field_map": [ + ["name", "request_for_quotation_item"], + ["parent", "request_for_quotation"], + ["uom", "uom"] + ], + } + }, target_doc, postprocess) + + return doclist + +# This method is used to make supplier quotation from supplier's portal. +@frappe.whitelist() +def create_supplier_quotation(doc): + if isinstance(doc, basestring): + doc = json.loads(doc) + + supplier = frappe.get_doc('Supplier', doc.get('supplier')) + + try: + sq_doc = frappe.get_doc({ + "doctype": "Supplier Quotation", + "supplier": supplier.name, + "terms": doc.get("terms"), + "company": doc.get("company"), + "currency": supplier.default_currency, + "buying_price_list": supplier.default_price_list or frappe.db.get_value('Buying Settings', None, 'buying_price_list') + }) + add_items(sq_doc, supplier, doc.get('items')) + sq_doc.flags.ignore_permissions = True + sq_doc.run_method("set_missing_values") + sq_doc.save() + frappe.msgprint(_("Supplier Quotation {0} created").format(sq_doc.name)) + return sq_doc.name + except Exception: + return + +def add_items(sq_doc, supplier, items): + for data in items: + if data.get("qty") > 0: + if isinstance(data, dict): + data = frappe._dict(data) + + create_rfq_items(sq_doc, supplier, data) + +def create_rfq_items(sq_doc, supplier, data): + sq_doc.append('items', { + "item_code": data.item_code, + "item_name": data.item_name, + "description": data.description, + "qty": data.qty, + "rate": data.rate, + "supplier_part_no": frappe.db.get_value("Item Supplier", {'parent': data.item_code, 'supplier': supplier}, "supplier_part_no"), + "warehouse": data.warehouse or '', + "request_for_quotation_item": data.name, + "request_for_quotation": data.parent + }) diff --git a/erpnext/buying/doctype/request_for_quotation/test_request_for_quotation.py b/erpnext/buying/doctype/request_for_quotation/test_request_for_quotation.py new file mode 100644 index 0000000000..d643a051ba --- /dev/null +++ b/erpnext/buying/doctype/request_for_quotation/test_request_for_quotation.py @@ -0,0 +1,79 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors +# See license.txt +from __future__ import unicode_literals + +import frappe +import unittest +from frappe.utils import nowdate + +class TestRequestforQuotation(unittest.TestCase): + def test_make_supplier_quotation(self): + from erpnext.buying.doctype.request_for_quotation.request_for_quotation import make_supplier_quotation + rfq = make_request_for_quotation() + + sq = make_supplier_quotation(rfq.name, rfq.get('suppliers')[0].supplier) + sq.submit() + + sq1 = make_supplier_quotation(rfq.name, rfq.get('suppliers')[1].supplier) + sq1.submit() + + self.assertEquals(sq.supplier, rfq.get('suppliers')[0].supplier) + self.assertEquals(sq.get('items')[0].request_for_quotation, rfq.name) + self.assertEquals(sq.get('items')[0].item_code, "_Test Item") + self.assertEquals(sq.get('items')[0].qty, 5) + + self.assertEquals(sq1.supplier, rfq.get('suppliers')[1].supplier) + self.assertEquals(sq1.get('items')[0].request_for_quotation, rfq.name) + self.assertEquals(sq1.get('items')[0].item_code, "_Test Item") + self.assertEquals(sq1.get('items')[0].qty, 5) + + def test_make_supplier_quotation_from_portal(self): + from erpnext.buying.doctype.request_for_quotation.request_for_quotation import create_supplier_quotation + rfq = make_request_for_quotation() + rfq.get('items')[0].rate = 100 + rfq.supplier = rfq.suppliers[0].supplier + supplier_quotation_name = create_supplier_quotation(rfq) + + supplier_quotation_doc = frappe.get_doc('Supplier Quotation', supplier_quotation_name) + + self.assertEquals(supplier_quotation_doc.supplier, rfq.get('suppliers')[0].supplier) + self.assertEquals(supplier_quotation_doc.get('items')[0].request_for_quotation, rfq.name) + self.assertEquals(supplier_quotation_doc.get('items')[0].item_code, "_Test Item") + self.assertEquals(supplier_quotation_doc.get('items')[0].qty, 5) + self.assertEquals(supplier_quotation_doc.get('items')[0].amount, 500) + + +def make_request_for_quotation(): + supplier_data = get_supplier_data() + rfq = frappe.new_doc('Request for Quotation') + rfq.transaction_date = nowdate() + rfq.status = 'Draft' + rfq.company = '_Test Company' + rfq.response = 'Test Data' + + for data in supplier_data: + rfq.append('suppliers', data) + + rfq.append("items", { + "item_code": "_Test Item", + "description": "_Test Item", + "uom": "_Test UOM", + "qty": 5, + "warehouse": "_Test Warehouse - _TC", + "schedule_date": nowdate() + }) + + rfq.submit() + + return rfq + +def get_supplier_data(): + return [{ + "supplier": "_Test Supplier", + "supplier_name": "_Test Supplier" + }, + { + "supplier": "_Test Supplier 1", + "supplier_name": "_Test Supplier 1" + }] \ No newline at end of file diff --git a/erpnext/buying/doctype/request_for_quotation_item/__init__.py b/erpnext/buying/doctype/request_for_quotation_item/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/buying/doctype/request_for_quotation_item/request_for_quotation_item.json b/erpnext/buying/doctype/request_for_quotation_item/request_for_quotation_item.json new file mode 100644 index 0000000000..305253c193 --- /dev/null +++ b/erpnext/buying/doctype/request_for_quotation_item/request_for_quotation_item.json @@ -0,0 +1,612 @@ +{ + "allow_copy": 0, + "allow_import": 0, + "allow_rename": 0, + "autoname": "hash", + "creation": "2016-02-25 08:04:02.452958", + "custom": 0, + "docstatus": 0, + "doctype": "DocType", + "document_type": "", + "fields": [ + { + "allow_on_submit": 0, + "bold": 1, + "collapsible": 0, + "fieldname": "item_code", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 1, + "in_list_view": 1, + "label": "Item Code", + "length": 0, + "no_copy": 0, + "oldfieldname": "item_code", + "oldfieldtype": "Link", + "options": "Item", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 1, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "column_break_3", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "item_name", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 1, + "in_list_view": 1, + "label": "Item Name", + "length": 0, + "no_copy": 0, + "oldfieldname": "item_name", + "oldfieldtype": "Data", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 1, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 1, + "fieldname": "section_break_5", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Description", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "description", + "fieldtype": "Text Editor", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Description", + "length": 0, + "no_copy": 0, + "oldfieldname": "description", + "oldfieldtype": "Small Text", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "print_width": "300px", + "read_only": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0, + "width": "300px" + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "col_break1", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "image", + "fieldtype": "Attach", + "hidden": 1, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Image", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "image_view", + "fieldtype": "Image", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Image View", + "length": 0, + "no_copy": 0, + "options": "image", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "quantity", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Quantity", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 1, + "collapsible": 0, + "fieldname": "qty", + "fieldtype": "Float", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 1, + "label": "Quantity", + "length": 0, + "no_copy": 0, + "oldfieldname": "qty", + "oldfieldtype": "Currency", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "print_width": "60px", + "read_only": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0, + "width": "60px" + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "col_break2", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "schedule_date", + "fieldtype": "Date", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Required Date", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "uom", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 1, + "label": "UOM", + "length": 0, + "no_copy": 0, + "oldfieldname": "uom", + "oldfieldtype": "Link", + "options": "UOM", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "print_width": "100px", + "read_only": 1, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0, + "width": "100px" + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "warehouse_and_reference", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Warehouse and Reference", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "warehouse", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 1, + "label": "Warehouse", + "length": 0, + "no_copy": 0, + "oldfieldname": "warehouse", + "oldfieldtype": "Link", + "options": "Warehouse", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "project_name", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 1, + "in_list_view": 0, + "label": "Project Name", + "length": 0, + "no_copy": 0, + "options": "Project", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "material_request", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Material Request", + "length": 0, + "no_copy": 1, + "options": "Material Request", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "col_break4", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "material_request_item", + "fieldtype": "Data", + "hidden": 1, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Material Request Item", + "length": 0, + "no_copy": 1, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "brand", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Brand", + "length": 0, + "no_copy": 0, + "oldfieldname": "brand", + "oldfieldtype": "Link", + "options": "Brand", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "description": "", + "fieldname": "item_group", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 1, + "in_list_view": 0, + "label": "Item Group", + "length": 0, + "no_copy": 0, + "oldfieldname": "item_group", + "oldfieldtype": "Link", + "options": "Item Group", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 1, + "bold": 0, + "collapsible": 0, + "fieldname": "page_break", + "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Page Break", + "length": 0, + "no_copy": 1, + "oldfieldname": "page_break", + "oldfieldtype": "Check", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + } + ], + "hide_heading": 0, + "hide_toolbar": 0, + "idx": 0, + "in_create": 0, + "in_dialog": 0, + "is_submittable": 0, + "issingle": 0, + "istable": 1, + "max_attachments": 0, + "modified": "2016-03-25 01:14:38.490488", + "modified_by": "Administrator", + "module": "Buying", + "name": "Request for Quotation Item", + "name_case": "", + "owner": "Administrator", + "permissions": [], + "read_only": 0, + "read_only_onload": 0, + "sort_field": "modified", + "sort_order": "DESC" +} \ No newline at end of file diff --git a/erpnext/buying/doctype/request_for_quotation_item/request_for_quotation_item.py b/erpnext/buying/doctype/request_for_quotation_item/request_for_quotation_item.py new file mode 100644 index 0000000000..cc897af944 --- /dev/null +++ b/erpnext/buying/doctype/request_for_quotation_item/request_for_quotation_item.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +import frappe +from frappe.model.document import Document + +class RequestforQuotationItem(Document): + pass diff --git a/erpnext/buying/doctype/rfq_supplier/__init__.py b/erpnext/buying/doctype/rfq_supplier/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/buying/doctype/rfq_supplier/rfq_supplier.json b/erpnext/buying/doctype/rfq_supplier/rfq_supplier.json new file mode 100644 index 0000000000..02a6f0ba33 --- /dev/null +++ b/erpnext/buying/doctype/rfq_supplier/rfq_supplier.json @@ -0,0 +1,213 @@ +{ + "allow_copy": 0, + "allow_import": 0, + "allow_rename": 0, + "creation": "2016-02-29 17:31:02.993221", + "custom": 0, + "docstatus": 0, + "doctype": "DocType", + "document_type": "", + "fields": [ + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "supplier", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 1, + "label": "Supplier", + "length": 0, + "no_copy": 0, + "options": "Supplier", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "contact_person", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 1, + "label": "Contact Person", + "length": 0, + "no_copy": 1, + "options": "Contact", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "default": "1", + "description": "Send Request for Quotation to Supplier", + "fieldname": "sent_email_to_supplier", + "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Sent Email to Supplier", + "length": 0, + "no_copy": 1, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "column_break_3", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "supplier_name", + "fieldtype": "Read Only", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 1, + "label": "Supplier Name", + "length": 0, + "no_copy": 0, + "options": "supplier.supplier_name", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "email_id", + "fieldtype": "Read Only", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Email Id", + "length": 0, + "no_copy": 1, + "options": "contact_person.email_id", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 1, + "bold": 0, + "collapsible": 0, + "fieldname": "user_id", + "fieldtype": "Read Only", + "hidden": 1, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "User Id", + "length": 0, + "no_copy": 1, + "options": "contact_person.user", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + } + ], + "hide_heading": 0, + "hide_toolbar": 0, + "idx": 0, + "in_create": 0, + "in_dialog": 0, + "is_submittable": 0, + "issingle": 0, + "istable": 1, + "max_attachments": 0, + "modified": "2016-03-25 13:18:11.017660", + "modified_by": "Administrator", + "module": "Buying", + "name": "RFQ Supplier", + "name_case": "", + "owner": "Administrator", + "permissions": [], + "read_only": 0, + "read_only_onload": 0, + "sort_field": "modified", + "sort_order": "DESC" +} \ No newline at end of file diff --git a/erpnext/buying/doctype/rfq_supplier/rfq_supplier.py b/erpnext/buying/doctype/rfq_supplier/rfq_supplier.py new file mode 100644 index 0000000000..a7ba65c673 --- /dev/null +++ b/erpnext/buying/doctype/rfq_supplier/rfq_supplier.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +import frappe +from frappe.model.document import Document + +class RFQSupplier(Document): + pass diff --git a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json index e12c9fff6f..c9bcc46214 100644 --- a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json +++ b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json @@ -1885,6 +1885,26 @@ "share": 0, "submit": 0, "write": 1 + }, + { + "amend": 0, + "apply_user_permissions": 0, + "cancel": 0, + "create": 0, + "delete": 0, + "email": 0, + "export": 0, + "if_owner": 0, + "import": 0, + "permlevel": 1, + "print": 0, + "read": 1, + "report": 0, + "role": "All", + "set_user_permissions": 0, + "share": 0, + "submit": 0, + "write": 0 } ], "read_only": 0, 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 b09667ba96..1275fcdf31 100644 --- a/erpnext/buying/doctype/supplier_quotation_item/supplier_quotation_item.json +++ b/erpnext/buying/doctype/supplier_quotation_item/supplier_quotation_item.json @@ -879,6 +879,32 @@ "unique": 0, "width": "120px" }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "request_for_quotation", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Request for Quotation", + "length": 0, + "no_copy": 1, + "options": "Request for Quotation", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_on_submit": 0, "bold": 0, @@ -928,6 +954,31 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "request_for_quotation_item", + "fieldtype": "Data", + "hidden": 1, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Request for Quotation Item", + "length": 0, + "no_copy": 1, + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_on_submit": 0, "bold": 0, @@ -1046,7 +1097,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2016-03-18 05:15:03.936587", + "modified": "2016-03-25 17:01:59.632826", "modified_by": "Administrator", "module": "Buying", "name": "Supplier Quotation Item", diff --git a/erpnext/config/buying.py b/erpnext/config/buying.py index c259f06428..0dc51f6df0 100644 --- a/erpnext/config/buying.py +++ b/erpnext/config/buying.py @@ -12,6 +12,11 @@ def get_data(): "name": "Material Request", "description": _("Request for purchase."), }, + { + "type": "doctype", + "name": "Request for Quotation", + "description": _("Request for quotation."), + }, { "type": "doctype", "name": "Supplier Quotation", diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py index c9b660db4c..536112662d 100644 --- a/erpnext/controllers/buying_controller.py +++ b/erpnext/controllers/buying_controller.py @@ -20,8 +20,9 @@ class BuyingController(StockController): } def get_feed(self): - return _("From {0} | {1} {2}").format(self.supplier_name, self.currency, - self.grand_total) + if self.get("supplier_name"): + return _("From {0} | {1} {2}").format(self.supplier_name, self.currency, + self.grand_total) def validate(self): super(BuyingController, self).validate() @@ -40,7 +41,7 @@ class BuyingController(StockController): # set contact and address details for supplier, if they are not mentioned if getattr(self, "supplier", None): - self.update_if_missing(get_party_details(self.supplier, party_type="Supplier")) + self.update_if_missing(get_party_details(self.supplier, party_type="Supplier", ignore_permissions=self.flags.ignore_permissions)) self.set_missing_item_details() diff --git a/erpnext/controllers/website_list_for_contact.py b/erpnext/controllers/website_list_for_contact.py index ae6e9e4362..588257828f 100644 --- a/erpnext/controllers/website_list_for_contact.py +++ b/erpnext/controllers/website_list_for_contact.py @@ -28,15 +28,14 @@ def get_transaction_list(doctype, txt=None, filters=None, limit_start=0, limit_p filters.append((doctype, "docstatus", "=", 1)) if user != "Guest" and is_website_user(): + parties_doctype = 'RFQ Supplier' if doctype == 'Request for Quotation' else doctype # find party for this contact - customers, suppliers = get_customers_suppliers(doctype, user) + customers, suppliers = get_customers_suppliers(parties_doctype, user) + key, parties = get_party_details(customers, suppliers) - if customers: - key, parties = "customer", customers - elif suppliers: - key, parties = "supplier", suppliers - else: - key, parties = "customer", [] + if doctype == 'Request for Quotation': + if key == 'customer': frappe.throw(_("Not Permitted"), frappe.PermissionError) + return rfq_transaction_list(parties_doctype, doctype, parties, limit_start, limit_page_length) filters.append((doctype, key, "in", parties)) @@ -52,6 +51,23 @@ def get_transaction_list(doctype, txt=None, filters=None, limit_start=0, limit_p return post_process(doctype, get_list(doctype, txt, filters, limit_start, limit_page_length, fields="name", order_by = "modified desc")) +def get_party_details(customers, suppliers): + if customers: + key, parties = "customer", customers + elif suppliers: + key, parties = "supplier", suppliers + else: + key, parties = "customer", [] + + return key, parties + +def rfq_transaction_list(parties_doctype, doctype, parties, limit_start, limit_page_length): + data = frappe.db.sql("""select distinct parent as name, supplier from `tab{doctype}` + where supplier = '{supplier}' and docstatus=1 order by modified desc limit {start}, {len}""". + format(doctype=parties_doctype, supplier=parties[0], start=limit_start, len = limit_page_length), as_dict=1) + + return post_process(doctype, data) + def post_process(doctype, data): result = [] for d in data: diff --git a/erpnext/docs/assets/img/buying/make-supplier-quotation-from-rfq.png b/erpnext/docs/assets/img/buying/make-supplier-quotation-from-rfq.png new file mode 100644 index 0000000000..135e9fc62d Binary files /dev/null and b/erpnext/docs/assets/img/buying/make-supplier-quotation-from-rfq.png differ diff --git a/erpnext/docs/assets/img/buying/request-for-quotation.png b/erpnext/docs/assets/img/buying/request-for-quotation.png new file mode 100644 index 0000000000..b8b1ec2ded Binary files /dev/null and b/erpnext/docs/assets/img/buying/request-for-quotation.png differ diff --git a/erpnext/docs/user/manual/en/buying/index.txt b/erpnext/docs/user/manual/en/buying/index.txt index a12bb06462..25c8797e18 100644 --- a/erpnext/docs/user/manual/en/buying/index.txt +++ b/erpnext/docs/user/manual/en/buying/index.txt @@ -1,4 +1,5 @@ supplier +request-for-quotation supplier-quotation purchase-order setup diff --git a/erpnext/docs/user/manual/en/buying/request-for-quotation.md b/erpnext/docs/user/manual/en/buying/request-for-quotation.md new file mode 100644 index 0000000000..379cdb543e --- /dev/null +++ b/erpnext/docs/user/manual/en/buying/request-for-quotation.md @@ -0,0 +1,14 @@ +A Request for Quotation is a document that an organization submits to one or more suppliers eliciting quotation for items. + +In ERPNext, You can create request for quotation directly by going to: + +`Buying > Documents > Request for Quotation > New Request for Quotation` + +Create Request for Quotation: + +![Request For Quotation]({{docs_base_url}}/assets/img/buying/request-for-quotation.png) + +Create Supplier Quotation from Request for Quotation form: + +![Request For Quotation]({{docs_base_url}}/assets/img/buying/make-supplier-quotation-from-rfq.png) + \ No newline at end of file diff --git a/erpnext/hooks.py b/erpnext/hooks.py index f44daf37aa..0ccc82a0db 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -71,6 +71,13 @@ website_route_rules = [ "parents": [{"title": _("Shipments"), "name": "shipments"}] } }, + {"from_route": "/rfq", "to_route": "Request for Quotation"}, + {"from_route": "/rfq/", "to_route": "rfq", + "defaults": { + "doctype": "Request for Quotation", + "parents": [{"title": _("Request for Quotation"), "name": "rfq"}] + } + }, {"from_route": "/jobs", "to_route": "Job Opening"}, ] diff --git a/erpnext/shopping_cart/utils.py b/erpnext/shopping_cart/utils.py index 3e1afe27fa..7cd269d0ce 100644 --- a/erpnext/shopping_cart/utils.py +++ b/erpnext/shopping_cart/utils.py @@ -16,6 +16,8 @@ def show_cart_count(): return False def set_cart_count(login_manager): + role, parties = check_customer_or_supplier() + if role == 'Supplier': return if show_cart_count(): from erpnext.shopping_cart.cart import set_cart_count set_cart_count() @@ -29,6 +31,19 @@ def update_website_context(context): context["shopping_cart_enabled"] = cart_enabled def update_my_account_context(context): + check_user_role, parties = check_customer_or_supplier() + + if check_user_role == 'Supplier': + get_supplier_context(context) + else: + get_customer_context(context) + +def get_supplier_context(context): + context["my_account_list"].extend([ + {"label": _("Request for Quotations"), "url": "rfq"}, + ]) + +def get_customer_context(context): context["my_account_list"].extend([ {"label": _("Projects"), "url": "project"}, {"label": _("Orders"), "url": "orders"}, @@ -37,3 +52,15 @@ def update_my_account_context(context): {"label": _("Issues"), "url": "issues"}, {"label": _("Addresses"), "url": "addresses"} ]) + +def check_customer_or_supplier(): + if frappe.session.user: + contacts = frappe.get_all("Contact", fields=["customer", "supplier", "email_id"], + filters={"email_id": frappe.session.user}) + + customer = [d.customer for d in contacts if d.customer] or None + supplier = [d.supplier for d in contacts if d.supplier] or None + + if customer: return 'Customer', customer + if supplier : return 'Supplier', supplier + return 'Customer', None \ No newline at end of file diff --git a/erpnext/startup/notifications.py b/erpnext/startup/notifications.py index 75553122c8..75e55b51f6 100644 --- a/erpnext/startup/notifications.py +++ b/erpnext/startup/notifications.py @@ -32,6 +32,9 @@ def get_notification_config(): "status": ("not in", ("Stopped",)), "per_ordered": ("<", 100) }, + "Request for Quotation": { + "docstatus": 0 + }, "Purchase Order": { "status": ("not in", ("Completed", "Closed")), "docstatus": ("<", 2) diff --git a/erpnext/stock/doctype/material_request/material_request.js b/erpnext/stock/doctype/material_request/material_request.js index c4b4b0e7ed..982534de6b 100644 --- a/erpnext/stock/doctype/material_request/material_request.js +++ b/erpnext/stock/doctype/material_request/material_request.js @@ -49,6 +49,10 @@ erpnext.buying.MaterialRequestController = erpnext.buying.BuyingController.exten cur_frm.add_custom_button(__('Purchase Order'), this.make_purchase_order, __("Make")); + if(doc.material_request_type === "Purchase") + cur_frm.add_custom_button(__("Request for Quotation"), + this.make_request_for_quotation, __("Make")); + if(doc.material_request_type === "Purchase") cur_frm.add_custom_button(__("Supplier Quotation"), this.make_supplier_quotation, __("Make")); @@ -158,6 +162,14 @@ erpnext.buying.MaterialRequestController = erpnext.buying.BuyingController.exten run_link_triggers: true }); }, + + make_request_for_quotation: function(){ + frappe.model.open_mapped_doc({ + method: "erpnext.stock.doctype.material_request.material_request.make_request_for_quotation", + frm: cur_frm, + run_link_triggers: true + }); + }, make_supplier_quotation: function() { frappe.model.open_mapped_doc({ diff --git a/erpnext/stock/doctype/material_request/material_request.py b/erpnext/stock/doctype/material_request/material_request.py index 679bd2d89d..6456d03342 100644 --- a/erpnext/stock/doctype/material_request/material_request.py +++ b/erpnext/stock/doctype/material_request/material_request.py @@ -212,6 +212,28 @@ def make_purchase_order(source_name, target_doc=None): }, target_doc, postprocess) return doclist + +@frappe.whitelist() +def make_request_for_quotation(source_name, target_doc=None): + doclist = get_mapped_doc("Material Request", source_name, { + "Material Request": { + "doctype": "Request for Quotation", + "validation": { + "docstatus": ["=", 1], + "material_request_type": ["=", "Purchase"] + } + }, + "Material Request Item": { + "doctype": "Request for Quotation Item", + "field_map": [ + ["name", "material_request_item"], + ["parent", "material_request"], + ["uom", "uom"] + ] + } + }, target_doc) + + return doclist @frappe.whitelist() def make_purchase_order_based_on_supplier(source_name, target_doc=None): diff --git a/erpnext/templates/emails/request_for_quotation.html b/erpnext/templates/emails/request_for_quotation.html new file mode 100644 index 0000000000..91bdd6b782 --- /dev/null +++ b/erpnext/templates/emails/request_for_quotation.html @@ -0,0 +1,12 @@ +

{{_("Request for Quotation")}}

+
+

{{ message }}

+{% if update_password_link %} +

{{_("Please click on the following link to set your new password")}}:

+

{{ update_password_link }}

+{% else %} +

{{_("Request for quotation can be access by clicking following link")}}:

+

{{ rfq_link }}

+{% endif %} +

{{_("Thank you")}},
+{{ user_fullname }}

\ No newline at end of file diff --git a/erpnext/templates/includes/rfq.js b/erpnext/templates/includes/rfq.js new file mode 100644 index 0000000000..3623d77932 --- /dev/null +++ b/erpnext/templates/includes/rfq.js @@ -0,0 +1,84 @@ +// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors +// License: GNU General Public License v3. See license.txt + +window.doc={{ doc.as_json() }}; + +$(document).ready(function() { + new rfq(); + doc.supplier = "{{ doc.supplier }}" +}); + +rfq = Class.extend({ + init: function(){ + this.onfocus_select_all(); + this.change_qty(); + this.change_rate(); + this.terms(); + this.submit_rfq(); + }, + + onfocus_select_all: function(){ + $("input").click(function(){ + $(this).select(); + }) + }, + + change_qty: function(){ + var me = this; + $('.rfq-items').on("change", ".rfq-qty", function(){ + me.idx = parseFloat($(this).attr('data-idx')); + me.qty = parseFloat($(this).val()); + me.rate = parseFloat($(repl('.rfq-rate[data-idx=%(idx)s]',{'idx': me.idx})).val()); + me.update_qty_rate(); + }) + }, + + change_rate: function(){ + var me = this; + $(".rfq-items").on("change", ".rfq-rate", function(){ + me.idx = parseFloat($(this).attr('data-idx')); + me.rate = parseFloat($(this).val()); + me.qty = parseFloat($(repl('.rfq-qty[data-idx=%(idx)s]',{'idx': me.idx})).val()); + me.update_qty_rate(); + }) + }, + + terms: function(){ + $(".terms").on("change", ".terms-feedback", function(){ + doc.terms = $(this).val(); + }) + }, + + update_qty_rate: function(){ + var me = this; + doc.grand_total = 0.0; + $.each(doc.items, function(idx, data){ + if(data.idx == me.idx){ + data.qty = me.qty; + data.rate = me.rate; + data.amount = (me.rate * me.qty) || 0.0; + $(repl('.rfq-amount[data-idx=%(idx)s]',{'idx': me.idx})).text(data.amount.toFixed(2)); + } + + doc.grand_total += flt(data.amount); + $('.tax-grand-total').text(doc.grand_total.toFixed(2)); + }) + }, + + submit_rfq: function(){ + $('.btn-sm').click(function(){ + frappe.freeze(); + frappe.call({ + type: "POST", + method: "erpnext.buying.doctype.request_for_quotation.request_for_quotation.create_supplier_quotation", + args: { + doc: doc + }, + btn: this, + callback: function(r){ + frappe.unfreeze(); + } + }) + }) + } +}) diff --git a/erpnext/templates/includes/rfq/rfq_items.html b/erpnext/templates/includes/rfq/rfq_items.html new file mode 100644 index 0000000000..de9a95fdaa --- /dev/null +++ b/erpnext/templates/includes/rfq/rfq_items.html @@ -0,0 +1,30 @@ +{% from "erpnext/templates/includes/rfq/rfq_macros.html" import item_name_and_description %} + +{% for d in doc.items %} +
+
+
+ {{ item_name_and_description(d, doc) }} +
+ +
+ +

+ {{_("UOM") + ": "+ d.uom}} +

+
+
+ +
+
+ 0.00 +
+
+
+{% endfor %} \ No newline at end of file diff --git a/erpnext/templates/includes/rfq/rfq_macros.html b/erpnext/templates/includes/rfq/rfq_macros.html new file mode 100644 index 0000000000..95bbcfec3f --- /dev/null +++ b/erpnext/templates/includes/rfq/rfq_macros.html @@ -0,0 +1,21 @@ +{% from "erpnext/templates/includes/macros.html" import product_image_square %} + +{% macro item_name_and_description(d, doc) %} +
+
+
+ {{ product_image_square(d.image) }} +
+
+
+ {{ d.item_code }} +

{{ d.description }}

+ {% set supplier_part_no = frappe.db.get_value("Item Supplier", {'parent': d.item_code, 'supplier': doc.supplier}, "supplier_part_no") %} +

+ {% if supplier_part_no %} + {{_("Supplier Part No") + ": "+ supplier_part_no}} + {% endif %} +

+
+
+{% endmacro %} diff --git a/erpnext/templates/pages/rfq.html b/erpnext/templates/pages/rfq.html new file mode 100644 index 0000000000..5556d26d96 --- /dev/null +++ b/erpnext/templates/pages/rfq.html @@ -0,0 +1,83 @@ +{% extends "templates/web.html" %} + +{% block header %} +

{{ doc.name }}

+{% endblock %} + +{% block script %} + +{% endblock %} + +{% block breadcrumbs %} + {% include "templates/includes/breadcrumbs.html" %} +{% endblock %} + +{% block style %} + +{% endblock %} + +{% block header_actions %} +{% if doc.items %} + +{% endif %} +{% endblock %} + +{% block page_content %} +
+
+
{{ doc.supplier }}
+
+
+ {{ doc.get_formatted("transaction_date") }} +
+
+ +
+
+
+
+
+ Items +
+
+ Qty +
+
+ Rate +
+
+ Amount +
+
+
+ {% if doc.items %} +
+ {% include "templates/includes/rfq/rfq_items.html" %} +
+ {% endif %} +
+ {% if doc.items %} +
+
{{ _("Grand Total") }}
+
+ 0.0 +
+
+ {% endif %} +
+
{{ _("Terms and Conditions: ") }}
+
+
+
+ +
+
+
+
+ + +{% endblock %} diff --git a/erpnext/templates/pages/rfq.py b/erpnext/templates/pages/rfq.py new file mode 100644 index 0000000000..fbdd6dbd96 --- /dev/null +++ b/erpnext/templates/pages/rfq.py @@ -0,0 +1,31 @@ +# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe +from frappe import _ + +def get_context(context): + context.no_cache = 1 + context.doc = frappe.get_doc(frappe.form_dict.doctype, frappe.form_dict.name) + context.parents = frappe.form_dict.parents + context.doc.supplier = get_supplier() + unauthrized_user(context.doc.supplier) + context["title"] = frappe.form_dict.name + +def unauthrized_user(supplier): + status = check_supplier_has_docname_access(supplier) + if status == False: + frappe.throw(_("Not Permitted"), frappe.PermissionError) + +def get_supplier(): + from erpnext.shopping_cart.utils import check_customer_or_supplier + key, parties = check_customer_or_supplier() + return parties[0] if key == 'Supplier' else '' + +def check_supplier_has_docname_access(supplier): + status = True + if frappe.form_dict.name not in frappe.db.sql_list("""select parent from `tabRFQ Supplier` + where supplier = '{supplier}'""".format(supplier=supplier)): + status = False + return status