Merge branch 'develop' of https://github.com/frappe/erpnext into quoted-item-report
diff --git a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.js b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.js
index 16061c6..1b8b404 100644
--- a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.js
+++ b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.js
@@ -18,6 +18,10 @@
refresh: function() {
var me = this;
this._super();
+
+ if (this.frm.doc.__islocal && !this.frm.doc.valid_till) {
+ this.frm.set_value('valid_till', frappe.datetime.add_months(this.frm.doc.transaction_date, 1));
+ }
if (this.frm.doc.docstatus === 1) {
cur_frm.add_custom_button(__("Purchase Order"), this.make_purchase_order,
__('Create'));
diff --git a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json
index 82fc628..6964e78 100644
--- a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json
+++ b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json
@@ -13,9 +13,10 @@
"supplier",
"supplier_name",
"column_break1",
- "transaction_date",
- "amended_from",
"company",
+ "transaction_date",
+ "valid_till",
+ "amended_from",
"address_section",
"supplier_address",
"contact_person",
@@ -791,13 +792,19 @@
"options": "Opportunity",
"print_hide": 1,
"read_only": 1
+ },
+ {
+ "fieldname": "valid_till",
+ "fieldtype": "Date",
+ "label": "Valid Till",
+ "reqd": 1
}
],
"icon": "fa fa-shopping-cart",
"idx": 29,
"is_submittable": 1,
"links": [],
- "modified": "2019-12-30 19:17:28.208693",
+ "modified": "2020-04-14 22:43:32.248415",
"modified_by": "Administrator",
"module": "Buying",
"name": "Supplier Quotation",
diff --git a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.py b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.py
index 5b4356a..baf2457 100644
--- a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.py
+++ b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.py
@@ -4,7 +4,7 @@
from __future__ import unicode_literals
import frappe
from frappe import _
-from frappe.utils import flt, nowdate, add_days
+from frappe.utils import flt, nowdate, add_days, getdate
from frappe.model.mapper import get_mapped_doc
from erpnext.controllers.buying_controller import BuyingController
@@ -28,6 +28,7 @@
validate_for_items(self)
self.validate_with_previous_doc()
self.validate_uom_is_integer("uom", "qty")
+ self.validate_valid_till()
def on_submit(self):
frappe.db.set(self, "status", "Submitted")
@@ -52,6 +53,11 @@
"is_child_table": True
}
})
+
+ 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"))
+
def update_rfq_supplier_status(self, include_me):
rfq_list = set([])
for item in self.items:
@@ -158,3 +164,11 @@
}, target_doc)
return doclist
+
+def set_expired_status():
+ frappe.db.sql("""
+ UPDATE
+ `tabSupplier Quotation` SET `status` = 'Expired'
+ WHERE
+ `status` not in ('Cancelled', 'Stopped') AND `valid_till` < %s
+ """, (nowdate()))
\ No newline at end of file
diff --git a/erpnext/buying/report/quoted_item_comparison/quoted_item_comparison.js b/erpnext/buying/report/quoted_item_comparison/quoted_item_comparison.js
index 3d05612..f331beb 100644
--- a/erpnext/buying/report/quoted_item_comparison/quoted_item_comparison.js
+++ b/erpnext/buying/report/quoted_item_comparison/quoted_item_comparison.js
@@ -5,13 +5,11 @@
filters: [
{
fieldtype: "Link",
- label: __("Supplier Quotation"),
- options: "Supplier Quotation",
- fieldname: "supplier_quotation",
- default: "",
- get_query: () => {
- return { filters: { "docstatus": ["<", 2] } }
- }
+ label: __("Company"),
+ options: "Company",
+ fieldname: "company",
+ default: frappe.defaults.get_user_default("Company"),
+ "reqd": 1
},
{
reqd: 1,
@@ -37,8 +35,83 @@
}
}
}
+ },
+ {
+ fieldtype: "Link",
+ label: __("Supplier Quotation"),
+ options: "Supplier Quotation",
+ fieldname: "supplier_quotation",
+ default: "",
+ get_query: () => {
+ return { filters: { "docstatus": ["<", 2] } }
+ }
+ },
+ {
+ fieldtype: "Link",
+ label: __("Request for Quotation"),
+ options: "Request for Quotation",
+ fieldname: "request_for_quotation",
+ default: "",
+ get_query: () => {
+ return { filters: { "docstatus": ["<", 2] } }
+ }
}
],
+
+ prepare_chart_data: (result) => {
+ let supplier_wise_map = {}, data_points_map = {};
+ let qty_list = result.map(res=> res.qty);
+ qty_list = new Set(qty_list);
+
+ // create supplier wise map like in Report
+ for(let res of result){
+ if(!(res.supplier in supplier_wise_map)){
+ supplier_wise_map[res.supplier]= {};
+ }
+ supplier_wise_map[res.supplier][res.qty] = res.price;
+ }
+
+ // create datapoints for each qty
+ for(let supplier of Object.keys(supplier_wise_map)) {
+ let row = supplier_wise_map[supplier];
+ for(let qty of qty_list){
+ if(!data_points_map[qty]){
+ data_points_map[qty] = []
+ }
+ if(row[qty]){
+ data_points_map[qty].push(row[qty]);
+ }
+ else{
+ data_points_map[qty].push(null);
+ }
+ }
+ }
+
+ let dataset = [];
+ qty_list.forEach((qty) => {
+ let datapoints = {
+ 'name': 'Price for Qty ' + qty,
+ 'values': data_points_map[qty]
+ }
+ dataset.push(datapoints);
+
+ });
+ return dataset;
+ },
+
+ get_chart_data: function (columns, result) {
+ let suppliers = result.filter(d => d.supplier_name).map(res => res.supplier_name);
+ let dataset = frappe.query_reports["Quoted Item Comparison"].prepare_chart_data(result);
+
+ return {
+ data: {
+ labels: suppliers,
+ datasets: dataset
+ },
+ type: 'bar'
+ }
+ },
+
onload: (report) => {
// Create a button for setting the default supplier
report.page.add_inner_button(__("Select Default Supplier"), () => {
@@ -102,6 +175,4 @@
});
dialog.show();
}
-}
-
-
+}
\ No newline at end of file
diff --git a/erpnext/buying/report/quoted_item_comparison/quoted_item_comparison.py b/erpnext/buying/report/quoted_item_comparison/quoted_item_comparison.py
index 5aff6ba..bb1067a 100644
--- a/erpnext/buying/report/quoted_item_comparison/quoted_item_comparison.py
+++ b/erpnext/buying/report/quoted_item_comparison/quoted_item_comparison.py
@@ -2,103 +2,114 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-from erpnext.setup.utils import get_exchange_rate
-from frappe.utils import flt, cint
import frappe
+from frappe.utils import flt, cint
+from collections import defaultdict
+from erpnext.setup.utils import get_exchange_rate
def execute(filters=None):
- qty_list = get_quantity_list(filters.item)
- data = get_quote_list(filters.item, qty_list)
- columns = get_columns(qty_list)
+ conditions = get_conditions(filters)
+ data = get_data(filters, conditions)
+ columns = get_columns()
return columns, data
-
-def get_quote_list(item, qty_list):
- out = []
+
+def get_data(filters, conditions):
+ out, suppliers = [], []
+ item = filters.get("item")
+
if not item:
return []
- suppliers = []
- price_data = []
company_currency = frappe.db.get_default("currency")
- float_precision = cint(frappe.db.get_default("float_precision")) or 2
- # Get the list of suppliers
- for root in frappe.db.sql("""select parent, qty, rate from `tabSupplier Quotation Item`
- where item_code=%s and docstatus < 2""", item, as_dict=1):
- for splr in frappe.db.sql("""select supplier from `tabSupplier Quotation`
- where name =%s and docstatus < 2""", root.parent, as_dict=1):
- ip = frappe._dict({
- "supplier": splr.supplier,
- "qty": root.qty,
- "parent": root.parent,
- "rate": root.rate
- })
- price_data.append(ip)
- suppliers.append(splr.supplier)
+ float_precision = cint(frappe.db.get_default("float_precision")) or 2
- #Add a row for each supplier
- for root in set(suppliers):
- supplier_currency = frappe.db.get_value("Supplier", root, "default_currency")
+ supplier_quotation_data = frappe.db.sql("""SELECT
+ sqi.parent, sqi.qty, sqi.rate, sqi.uom, sqi.request_for_quotation,
+ sq.supplier
+ FROM
+ `tabSupplier Quotation Item` sqi,
+ `tabSupplier Quotation` sq
+ WHERE
+ sqi.item_code = '{0}'
+ AND sqi.parent = sq.name
+ AND sqi.docstatus < 2
+ AND sq.company = '{1}'
+ AND sq.status != 'Expired'
+ {2}""".format(item, filters.get("company"), conditions), as_dict=1)
+
+ supplier_wise_map = defaultdict(list)
+
+ for data in supplier_quotation_data:
+ supplier_currency = frappe.db.get_value("Supplier", data.get("supplier"), "default_currency")
if supplier_currency:
exchange_rate = get_exchange_rate(supplier_currency, company_currency)
else:
exchange_rate = 1
- row = frappe._dict({
- "supplier_name": root
- })
- for col in qty_list:
- # Get the quantity for this row
- for item_price in price_data:
- if str(item_price.qty) == col.key and item_price.supplier == root:
- row[col.key] = flt(item_price.rate * exchange_rate, float_precision)
- row[col.key + "QUOTE"] = item_price.parent
- break
- else:
- row[col.key] = ""
- row[col.key + "QUOTE"] = ""
- out.append(row)
-
- return out
-
-def get_quantity_list(item):
- out = []
-
- if item:
- qty_list = frappe.db.sql("""select distinct qty from `tabSupplier Quotation Item`
- where ifnull(item_code,'')=%s and docstatus < 2 order by qty""", item, as_dict=1)
+ row = {
+ "quotation": data.get("parent"),
+ "qty": data.get("qty"),
+ "price": flt(data.get("rate") * exchange_rate, float_precision),
+ "request_for_quotation": data.get("request_for_quotation"),
+ "supplier": data.get("supplier") # used for chart generation
+ }
- for qt in qty_list:
- col = frappe._dict({
- "key": str(qt.qty),
- "label": "Qty: " + str(int(qt.qty))
- })
- out.append(col)
+ supplier_wise_map[data.supplier].append(row)
+ suppliers.append(data.supplier)
+
+ suppliers = set(suppliers)
+
+ for supplier in suppliers:
+ supplier_wise_map[supplier][0].update({"supplier_name": supplier})
+ for entry in supplier_wise_map[supplier]:
+ out.append(entry)
return out
-
-def get_columns(qty_list):
+
+def get_conditions(filters):
+ conditions = ""
+
+ if filters.get("request_for_quotation"):
+ conditions += " AND sqi.request_for_quotation = '{0}' ".format(filters.get("request_for_quotation"))
+
+ return conditions
+
+
+def get_columns():
columns = [{
"fieldname": "supplier_name",
"label": "Supplier",
"fieldtype": "Link",
"options": "Supplier",
"width": 200
- }]
-
- for qty in qty_list:
- columns.append({
- "fieldname": qty.key,
- "label": qty.label,
- "fieldtype": "Currency",
- "options": "currency",
- "width": 80
- })
- columns.append({
- "fieldname": qty.key + "QUOTE",
- "label": "Quotation",
- "fieldtype": "Link",
- "options": "Supplier Quotation",
- "width": 90
- })
+ },
+ {
+ "fieldname": "quotation",
+ "label": "Supplier Quotation",
+ "fieldtype": "Link",
+ "options": "Supplier Quotation",
+ "width": 200
+ },
+ {
+ "fieldname": "qty",
+ "label": "Quantity",
+ "fieldtype": "Float",
+ "width": 80
+ },
+ {
+ "fieldname": "price",
+ "label": "Price",
+ "fieldtype": "Currency",
+ "options": "Company:company:default_currency",
+ "width": 110
+ },
+ {
+ "fieldname": "request_for_quotation",
+ "label": "Request for Quotation",
+ "fieldtype": "Link",
+ "options": "Request for Quotation",
+ "width": 200
+ }
+ ]
return columns
\ No newline at end of file
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index 6b6d1e2..e661e9c 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -306,7 +306,8 @@
"erpnext.crm.doctype.email_campaign.email_campaign.send_email_to_leads_or_contacts",
"erpnext.crm.doctype.email_campaign.email_campaign.set_email_campaign_status",
"erpnext.selling.doctype.quotation.quotation.set_expired_status",
- "erpnext.healthcare.doctype.patient_appointment.patient_appointment.update_appointment_status"
+ "erpnext.healthcare.doctype.patient_appointment.patient_appointment.update_appointment_status",
+ "erpnext.buying.doctype.supplier_quotation.supplier_quotation.set_expired_status"
],
"daily_long": [
"erpnext.setup.doctype.email_digest.email_digest.send",
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 9ef0b8d..ec84f5f 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -667,3 +667,4 @@
erpnext.patches.v12_0.set_total_batch_quantity
erpnext.patches.v12_0.rename_mws_settings_fields
erpnext.patches.v12_0.set_updated_purpose_in_pick_list
+erpnext.patches.v12_0.set_valid_till_date_in_supplier_quotation
\ No newline at end of file
diff --git a/erpnext/patches/v12_0/set_valid_till_date_in_supplier_quotation.py b/erpnext/patches/v12_0/set_valid_till_date_in_supplier_quotation.py
new file mode 100644
index 0000000..0f24ec6
--- /dev/null
+++ b/erpnext/patches/v12_0/set_valid_till_date_in_supplier_quotation.py
@@ -0,0 +1,8 @@
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+ reload_doc("buying", "doctype", "suppplier_quotation")
+ frappe.db.sql("""UPDATE `tabSupplier Quotation`
+ SET valid_till = DATE_ADD(transaction_date , INTERVAL 1 MONTH)
+ WHERE docstatus < 2""")
\ No newline at end of file