major(manufacturing): fixes to ux, material requests to purchase order based on default supplier etc (#15267)
* major(manufacturing): fixes to ux, material requests to purchase order based on default supplier etc
* fix: remove debug
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index 194c364..5fefd6e 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -497,15 +497,15 @@
}
cur_frm.cscript.income_account = function(doc, cdt, cdn) {
- erpnext.utils.copy_value_in_all_row(doc, cdt, cdn, "items", "income_account");
+ erpnext.utils.copy_value_in_all_rows(doc, cdt, cdn, "items", "income_account");
}
cur_frm.cscript.expense_account = function(doc, cdt, cdn) {
- erpnext.utils.copy_value_in_all_row(doc, cdt, cdn, "items", "expense_account");
+ erpnext.utils.copy_value_in_all_rows(doc, cdt, cdn, "items", "expense_account");
}
cur_frm.cscript.cost_center = function(doc, cdt, cdn) {
- erpnext.utils.copy_value_in_all_row(doc, cdt, cdn, "items", "cost_center");
+ erpnext.utils.copy_value_in_all_rows(doc, cdt, cdn, "items", "cost_center");
}
cur_frm.set_query("debit_to", function(doc) {
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js
index d7ffe04..74af4ce 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.js
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.js
@@ -64,7 +64,7 @@
var row = locals[cdt][cdn];
if (row.schedule_date) {
if(!frm.doc.schedule_date) {
- erpnext.utils.copy_value_in_all_row(frm.doc, cdt, cdn, "items", "schedule_date");
+ erpnext.utils.copy_value_in_all_rows(frm.doc, cdt, cdn, "items", "schedule_date");
} else {
set_schedule_date(frm);
}
@@ -309,6 +309,7 @@
method: "erpnext.stock.doctype.material_request.material_request.make_purchase_order",
source_doctype: "Material Request",
target: me.frm,
+ args: args,
setters: {
company: me.frm.doc.company
},
@@ -319,7 +320,7 @@
per_ordered: ["<", 99.99],
}
})
- }, __("Add items from"));
+ }, __("Get items from"));
this.frm.add_custom_button(__('Supplier Quotation'),
function() {
@@ -335,7 +336,7 @@
status: ["!=", "Stopped"],
}
})
- }, __("Add items from"));
+ }, __("Get items from"));
this.frm.add_custom_button(__('Update rate as per last purchase'),
function() {
@@ -364,7 +365,7 @@
},
callback: function(r) {
if(r.exc) return;
-
+
var i = 0;
var item_length = me.frm.doc.items.length;
while (i < item_length) {
@@ -379,17 +380,17 @@
d.qty = d.qty - my_qty;
me.frm.doc.items[i].stock_qty = my_qty * me.frm.doc.items[i].conversion_factor;
me.frm.doc.items[i].qty = my_qty;
-
+
frappe.msgprint("Assigning " + d.mr_name + " to " + d.item_code + " (row " + me.frm.doc.items[i].idx + ")");
if (qty > 0) {
frappe.msgprint("Splitting " + qty + " units of " + d.item_code);
var new_row = frappe.model.add_child(me.frm.doc, me.frm.doc.items[i].doctype, "items");
item_length++;
-
+
for (var key in me.frm.doc.items[i]) {
new_row[key] = me.frm.doc.items[i][key];
}
-
+
new_row.idx = item_length;
new_row["stock_qty"] = new_row.conversion_factor * qty;
new_row["qty"] = qty;
@@ -477,7 +478,7 @@
function set_schedule_date(frm) {
if(frm.doc.schedule_date){
- erpnext.utils.copy_value_in_all_row(frm.doc, frm.doc.doctype, frm.doc.name, "items", "schedule_date");
+ erpnext.utils.copy_value_in_all_rows(frm.doc, frm.doc.doctype, frm.doc.name, "items", "schedule_date");
}
}
diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py
index e2e9209..77df650 100644
--- a/erpnext/manufacturing/doctype/bom/bom.py
+++ b/erpnext/manufacturing/doctype/bom/bom.py
@@ -173,7 +173,7 @@
if not rate:
frappe.msgprint(_("{0} not found for Item {1}")
- .format(self.rm_cost_as_per, arg["item_code"]))
+ .format(self.rm_cost_as_per, arg["item_code"]), alert=True)
return flt(rate)
@@ -561,7 +561,6 @@
where
bom_item.docstatus < 2
and bom.name = %(bom)s
- and is_stock_item = 1
{where_conditions}
group by item_code, stock_uom
order by idx"""
diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.py b/erpnext/manufacturing/doctype/production_plan/production_plan.py
index 46fdb85..12f2f04 100644
--- a/erpnext/manufacturing/doctype/production_plan/production_plan.py
+++ b/erpnext/manufacturing/doctype/production_plan/production_plan.py
@@ -280,7 +280,7 @@
item_dict[(d.item_code, d.sales_order, d.warehouse)] = item_details
return item_dict
-
+
def get_items_for_material_requests(self):
self.mr_items = []
@@ -295,15 +295,15 @@
bei.description, bei.stock_uom, item.min_order_qty, bei.source_warehouse,
item.default_material_request_type, item.min_order_qty, item_default.default_warehouse
from
- `tabBOM Explosion Item` bei
+ `tabBOM Explosion Item` bei
JOIN `tabBOM` bom ON bom.name = bei.parent
JOIN `tabItem` item ON item.name = bei.item_code
LEFT JOIN `tabItem Default` item_default
ON item_default.parent = item.name and item_default.company=%s
where
- bei.docstatus < 2
+ bei.docstatus < 2
and bom.name=%s and item.is_stock_item in (1, {0})
- group by bei.item_code, bei.stock_uom""".format(self.include_non_stock_items),
+ group by bei.item_code, bei.stock_uom""".format(0 if self.include_non_stock_items else 1),
(self.company, data.bom_no), as_dict=1):
bom_wise_item_details.setdefault(d.item_code, d)
else:
@@ -332,7 +332,7 @@
bom.name = %(bom)s
and bom_item.docstatus < 2
and item.is_stock_item in (1, {0})
- group by bom_item.item_code""".format(self.include_non_stock_items),{
+ group by bom_item.item_code""".format(0 if self.include_non_stock_items else 1),{
'bom': bom_no,
'parent_qty': parent_qty,
'company': self.company
@@ -412,61 +412,60 @@
pass
def make_material_request(self):
+ '''Create Material Requests grouped by Sales Order and Material Request Type'''
material_request_list = []
+ material_request_map = {}
- item_details = self.get_itemwise_qty()
- for item_code, rows in item_details.items():
- item_doc = frappe.get_doc("Item", item_code)
+ for item in self.mr_items:
+ item_doc = frappe.get_cached_doc('Item', item.item_code)
+
+ # key for Sales Order:Material Request Type
+ key = '{}:{}'.format(item.sales_order, item_doc.default_material_request_type)
schedule_date = add_days(nowdate(), cint(item_doc.lead_time_days))
- material_request = frappe.new_doc("Material Request")
- material_request.update({
- "transaction_date": nowdate(),
- "status": "Draft",
- "company": self.company,
- "requested_by": frappe.session.user,
+ if not key in material_request_map:
+ # make a new MR for the combination
+ material_request_map[key] = frappe.new_doc("Material Request")
+ material_request = material_request_map[key]
+ material_request.update({
+ "transaction_date": nowdate(),
+ "status": "Draft",
+ "company": self.company,
+ "requested_by": frappe.session.user,
+ 'material_request_type': item_doc.default_material_request_type
+ })
+ material_request_list.append(material_request)
+ else:
+ material_request = material_request_map[key]
+
+ # add item
+ material_request.append("items", {
+ "item_code": item.item_code,
+ "qty": item.quantity,
"schedule_date": schedule_date,
- 'material_request_type': item_doc.default_material_request_type
+ "warehouse": item.warehouse,
+ "sales_order": item.sales_order,
+ 'production_plan': self.name,
+ 'material_request_plan_item': item.name,
+ "project": frappe.db.get_value("Sales Order", item.sales_order, "project") \
+ if item.sales_order else None
})
- for idx in rows:
- child = self.mr_items[cint(idx)-1]
- material_request.append("items", {
- "item_code": item_code,
- "qty": child.quantity,
- "schedule_date": schedule_date,
- "warehouse": child.warehouse,
- "sales_order": child.sales_order,
- 'production_plan': self.name,
- 'material_request_plan_item': child.name,
- "project": frappe.db.get_value("Sales Order", child.sales_order, "project") \
- if child.sales_order else None
- })
-
+ for material_request in material_request_list:
+ # submit
material_request.flags.ignore_permissions = 1
material_request.run_method("set_missing_values")
material_request.submit()
- material_request_list.append(material_request.name)
-
+
frappe.flags.mute_messages = False
if material_request_list:
- material_request_list = ["""<a href="#Form/Material Request/%s" target="_blank">%s</a>""" % \
- (p, p) for p in material_request_list]
+ material_request_list = ["""<a href="#Form/Material Request/{0}">{1}</a>""".format(m.name, m.name) \
+ for m in material_request_list]
msgprint(_("{0} created").format(comma_and(material_request_list)))
else :
msgprint(_("No material request created"))
- def get_itemwise_qty(self):
- item_details = {}
- for data in self.get('mr_items'):
- if data.item_code in item_details:
- item_details[data.item_code].append(data.idx)
- else:
- item_details.setdefault(data.item_code, [data.idx])
-
- return item_details
-
def get_sales_orders(self):
so_filter = item_filter = ""
if self.from_date:
@@ -516,7 +515,7 @@
conditions = " and warehouse='{0}'".format(frappe.db.escape(warehouse))
item_projected_qty = frappe.db.sql(""" select ifnull(sum(projected_qty),0) as projected_qty,
- ifnull(sum(actual_qty),0) as actual_qty from `tabBin`
+ ifnull(sum(actual_qty),0) as actual_qty from `tabBin`
where item_code = %(item_code)s {conditions}
""".format(conditions=conditions), { "item_code": row.item_code }, as_list=1)
diff --git a/erpnext/public/js/utils.js b/erpnext/public/js/utils.js
index e4c1d53..682577b 100644
--- a/erpnext/public/js/utils.js
+++ b/erpnext/public/js/utils.js
@@ -118,7 +118,7 @@
return dict[party_type];
},
- copy_value_in_all_row: function(doc, dt, dn, table_fieldname, fieldname) {
+ copy_value_in_all_rows: function(doc, dt, dn, table_fieldname, fieldname) {
var d = locals[dt][dn];
if(d[fieldname]){
var cl = doc[table_fieldname] || [];
@@ -487,6 +487,7 @@
"method": opts.method,
"source_names": opts.source_name,
"target_doc": cur_frm.doc,
+ 'args': opts.args
},
callback: function(r) {
if(!r.exc) {
diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js
index 9de9c6b..e8698f1 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.js
+++ b/erpnext/selling/doctype/sales_order/sales_order.js
@@ -82,7 +82,7 @@
},
delivery_date: function(frm, cdt, cdn) {
if(!frm.doc.delivery_date) {
- erpnext.utils.copy_value_in_all_row(frm.doc, cdt, cdn, "items", "delivery_date");
+ erpnext.utils.copy_value_in_all_rows(frm.doc, cdt, cdn, "items", "delivery_date");
}
}
});
diff --git a/erpnext/setup/doctype/company/company_dashboard.py b/erpnext/setup/doctype/company/company_dashboard.py
index 7526dd6..868284a 100644
--- a/erpnext/setup/doctype/company/company_dashboard.py
+++ b/erpnext/setup/doctype/company/company_dashboard.py
@@ -2,9 +2,6 @@
def get_data():
return {
- 'heatmap': True,
- 'heatmap_message': _('This is based on transactions against this Company. See timeline below for details'),
-
'graph': True,
'graph_method': "frappe.utils.goal.get_monthly_goal_graph_data",
'graph_method_args': {
diff --git a/erpnext/stock/doctype/item/item.json b/erpnext/stock/doctype/item/item.json
index 9161f2d..2851537 100644
--- a/erpnext/stock/doctype/item/item.json
+++ b/erpnext/stock/doctype/item/item.json
@@ -1841,7 +1841,7 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
- "label": "Defaults",
+ "label": "Sales, Purchase, Accounting Defaults",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@@ -3951,7 +3951,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 1,
- "modified": "2018-08-29 06:27:10.198002",
+ "modified": "2018-08-30 05:28:12.312880",
"modified_by": "Administrator",
"module": "Stock",
"name": "Item",
diff --git a/erpnext/stock/doctype/material_request/material_request.js b/erpnext/stock/doctype/material_request/material_request.js
index 9a80a9a..5fd7a6a 100644
--- a/erpnext/stock/doctype/material_request/material_request.js
+++ b/erpnext/stock/doctype/material_request/material_request.js
@@ -1,6 +1,7 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
+// eslint-disable-next-line
{% include 'erpnext/public/js/controllers/buying.js' %};
frappe.ui.form.on('Material Request', {
@@ -11,24 +12,122 @@
'Request for Quotation': 'Request for Quotation',
'Supplier Quotation': 'Supplier Quotation',
'Work Order': 'Work Order'
- }
+ };
// formatter for material request item
frm.set_indicator_formatter('item_code',
- function(doc) { return (doc.qty<=doc.ordered_qty) ? "green" : "orange" })
+ function(doc) { return (doc.qty<=doc.ordered_qty) ? "green" : "orange"; });
+
+ frm.set_query("item_code", "items", function() {
+ return {
+ query: "erpnext.controllers.queries.item_query"
+ };
+ });
},
+
onload: function(frm) {
// add item, if previous view was item
erpnext.utils.add_item(frm);
- //set schedule_date
+ // set schedule_date
set_schedule_date(frm);
- frm.fields_dict["items"].grid.get_field("warehouse").get_query = function(doc, cdt, cdn){
- return{
+ frm.fields_dict["items"].grid.get_field("warehouse").get_query = function(doc) {
+ return {
filters: {'company': doc.company}
+ };
+ };
+ },
+
+ refresh: function(frm) {
+ frm.events.make_custom_buttons(frm);
+ },
+
+ make_custom_buttons: function(frm) {
+ if (frm.doc.docstatus==0) {
+ frm.add_custom_button(__("Bill of Materials"),
+ () => frm.events.get_items_from_bom(frm), __("Get items from"));
+ }
+
+ if (frm.doc.docstatus == 1 && frm.doc.status != 'Stopped') {
+ if (flt(frm.doc.per_ordered, 2) < 100) {
+ // make
+ if (frm.doc.material_request_type === "Material Transfer") {
+ frm.add_custom_button(__("Transfer Material"),
+ () => frm.events.make_stock_entry(frm), __("Make"));
+ }
+
+ if (frm.doc.material_request_type === "Material Issue") {
+ frm.add_custom_button(__("Issue Material"),
+ () => frm.events.make_stock_entry(frm), __("Make"));
+ }
+
+ if (frm.doc.material_request_type === "Purchase") {
+ frm.add_custom_button(__('Purchase Order'),
+ () => frm.events.make_purchase_order(frm), __("Make"));
+ }
+
+ if (frm.doc.material_request_type === "Purchase") {
+ frm.add_custom_button(__("Request for Quotation"),
+ () => frm.events.make_request_for_quotation(frm), __("Make"));
+ }
+
+ if (frm.doc.material_request_type === "Purchase") {
+ frm.add_custom_button(__("Supplier Quotation"),
+ () => frm.events.make_supplier_quotation(frm), __("Make"));
+ }
+
+ if (frm.doc.material_request_type === "Manufacture") {
+ frm.add_custom_button(__("Work Order"),
+ () => frm.events.raise_work_orders(frm), __("Make"));
+ }
+
+ frm.page.set_inner_btn_group_as_primary(__("Make"));
+
+ // stop
+ frm.add_custom_button(__('Stop'),
+ () => frm.events.update_status(frm, 'Stop'));
+
}
}
+
+ if (frm.doc.docstatus===0) {
+ frm.add_custom_button(__('Sales Order'), () => frm.events.get_items_from_sales_order(frm),
+ __("Get items from"));
+ }
+
+ if (frm.doc.docstatus == 1 && frm.doc.status == 'Stopped') {
+ frm.add_custom_button(__('Re-open'), () => frm.events.update_status(frm, 'Submitted'));
+ }
},
+
+ update_status: function(frm, stop_status) {
+ frappe.call({
+ method: 'erpnext.stock.material_request.material_request.update_status',
+ args: { name: frm.doc.name, status: stop_status },
+ callback(r) {
+ if (!r.exc) {
+ frm.reload_doc();
+ }
+ }
+ });
+ },
+
+ get_items_from_sales_order: function(frm) {
+ erpnext.utils.map_current_doc({
+ method: "erpnext.selling.doctype.sales_order.sales_order.make_material_request",
+ source_doctype: "Sales Order",
+ target: frm,
+ setters: {
+ company: frm.doc.company
+ },
+ get_query_filters: {
+ docstatus: 1,
+ status: ["!=", "Closed"],
+ per_delivered: ["<", 99.99],
+ }
+ });
+ },
+
get_item_data: function(frm, item) {
frm.call({
method: "erpnext.stock.get_item_details.get_item_details",
@@ -45,7 +144,6 @@
stock_qty: item.stock_qty,
company: frm.doc.company,
conversion_rate: 1,
- name: frm.doc.name,
material_request_type: frm.doc.material_request_type,
plc_conversion_rate: 1,
rate: item.rate,
@@ -62,133 +160,19 @@
}
});
},
-});
-frappe.ui.form.on("Material Request Item", {
- qty: function (frm, doctype, name) {
- var d = locals[doctype][name];
- if (flt(d.qty) < flt(d.min_order_qty)) {
- frappe.msgprint(__("Warning: Material Requested Qty is less than Minimum Order Qty"));
- }
-
- const item = locals[doctype][name];
- frm.events.get_item_data(frm, item);
- },
-
- rate: function(frm, doctype, name) {
- const item = locals[doctype][name];
- frm.events.get_item_data(frm, item);
- },
-
- item_code: function(frm, doctype, name) {
- const item = locals[doctype][name];
- item.rate = 0
- set_schedule_date(frm);
- frm.events.get_item_data(frm, item);
- },
-
- schedule_date: function(frm, cdt, cdn) {
- var row = locals[cdt][cdn];
- if (row.schedule_date) {
- if(!frm.doc.schedule_date) {
- erpnext.utils.copy_value_in_all_row(frm.doc, cdt, cdn, "items", "schedule_date");
- } else {
- set_schedule_date(frm);
- }
- }
- }
-});
-
-erpnext.buying.MaterialRequestController = erpnext.buying.BuyingController.extend({
- onload: function(doc) {
- this._super();
- this.frm.set_query("item_code", "items", function() {
- return {
- query: "erpnext.controllers.queries.item_query"
- }
- });
- },
-
- refresh: function(doc) {
- var me = this;
- this._super();
-
- if(doc.docstatus==0) {
- cur_frm.add_custom_button(__("Get Items from BOM"),
- cur_frm.cscript.get_items_from_bom, "fa fa-sitemap", "btn-default");
- }
-
- if(doc.docstatus == 1 && doc.status != 'Stopped') {
- if(flt(doc.per_ordered, 2) < 100) {
- // make
- if(doc.material_request_type === "Material Transfer")
- cur_frm.add_custom_button(__("Transfer Material"),
- this.make_stock_entry, __("Make"));
-
- if(doc.material_request_type === "Material Issue")
- cur_frm.add_custom_button(__("Issue Material"),
- this.make_stock_entry, __("Make"));
-
- if(doc.material_request_type === "Purchase")
- 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"));
-
- if(doc.material_request_type === "Manufacture")
- cur_frm.add_custom_button(__("Work Order"),
- function() { me.raise_work_orders() }, __("Make"));
-
- cur_frm.page.set_inner_btn_group_as_primary(__("Make"));
-
- // stop
- me.frm.add_custom_button(__('Stop'),
- me.frm.cscript['Stop Material Request']);
-
- }
- }
-
- if (this.frm.doc.docstatus===0) {
- this.frm.add_custom_button(__('Sales Order'),
- function() {
- erpnext.utils.map_current_doc({
- method: "erpnext.selling.doctype.sales_order.sales_order.make_material_request",
- source_doctype: "Sales Order",
- target: me.frm,
- setters: {
- company: me.frm.doc.company
- },
- get_query_filters: {
- docstatus: 1,
- status: ["!=", "Closed"],
- per_delivered: ["<", 99.99],
- }
- })
- }, __("Get items from"));
- }
-
- if(doc.docstatus == 1 && doc.status == 'Stopped')
- me.frm.add_custom_button(__('Re-open'),
- me.frm.cscript['Unstop Material Request']);
-
- },
-
- get_items_from_bom: function() {
+ get_items_from_bom: function(frm) {
var d = new frappe.ui.Dialog({
title: __("Get Items from BOM"),
fields: [
{"fieldname":"bom", "fieldtype":"Link", "label":__("BOM"),
- options:"BOM", reqd: 1, get_query: function(){
- return {filters: { docstatus:1 }}
+ options:"BOM", reqd: 1, get_query: function() {
+ return {filters: { docstatus:1 }};
}},
{"fieldname":"warehouse", "fieldtype":"Link", "label":__("Warehouse"),
options:"Warehouse", reqd: 1},
+ {"fieldname":"qty", "fieldtype":"Float", "label":__("Quantity"),
+ reqd: 1, "default": 1},
{"fieldname":"fetch_exploded", "fieldtype":"Check",
"label":__("Fetch exploded BOM (including sub-assemblies)"), "default":1},
{fieldname:"fetch", "label":__("Get Items from BOM"), "fieldtype":"Button"}
@@ -197,15 +181,15 @@
d.get_input("fetch").on("click", function() {
var values = d.get_values();
if(!values) return;
- values["company"] = cur_frm.doc.company;
+ values["company"] = frm.doc.company;
frappe.call({
method: "erpnext.manufacturing.doctype.bom.bom.get_bom_items",
args: values,
callback: function(r) {
- if(!r.message) {
- frappe.throw(__("BOM does not contain any stock item"))
+ if (!r.message) {
+ frappe.throw(__("BOM does not contain any stock item"));
} else {
- erpnext.utils.remove_empty_first_row(cur_frm, "items");
+ erpnext.utils.remove_empty_first_row(frm, "items");
$.each(r.message, function(i, item) {
var d = frappe.model.add_child(cur_frm.doc, "Material Request Item", "items");
d.item_code = item.item_code;
@@ -226,6 +210,94 @@
d.show();
},
+ make_purchase_order: function(frm) {
+ frappe.prompt(
+ {fieldname:'default_supplier', label: __('For Default Supplier (optional)'), fieldtype: 'Link', options: 'Supplier'},
+ (values) => {
+ frappe.model.open_mapped_doc({
+ method: "erpnext.stock.doctype.material_request.material_request.make_purchase_order",
+ frm: frm,
+ args: { default_supplier: values.default_supplier },
+ run_link_triggers: true
+ });
+ }
+ )
+ },
+
+ make_request_for_quotation: function(frm) {
+ frappe.model.open_mapped_doc({
+ method: "erpnext.stock.doctype.material_request.material_request.make_request_for_quotation",
+ frm: frm,
+ run_link_triggers: true
+ });
+ },
+
+ make_supplier_quotation: function(frm) {
+ frappe.model.open_mapped_doc({
+ method: "erpnext.stock.doctype.material_request.material_request.make_supplier_quotation",
+ frm: frm
+ });
+ },
+
+ make_stock_entry: function(frm) {
+ frappe.model.open_mapped_doc({
+ method: "erpnext.stock.doctype.material_request.material_request.make_stock_entry",
+ frm: frm
+ });
+ },
+
+ raise_work_orders: function(frm) {
+ frappe.call({
+ method:"erpnext.stock.doctype.material_request.material_request.raise_work_orders",
+ args: {
+ "material_request": frm.doc.name
+ },
+ callback: function(r) {
+ if(r.message.length) {
+ frm.reload_doc();
+ }
+ }
+ });
+ },
+
+});
+
+frappe.ui.form.on("Material Request Item", {
+ qty: function (frm, doctype, name) {
+ var d = locals[doctype][name];
+ if (flt(d.qty) < flt(d.min_order_qty)) {
+ frappe.msgprint(__("Warning: Material Requested Qty is less than Minimum Order Qty"));
+ }
+
+ const item = locals[doctype][name];
+ frm.events.get_item_data(frm, item);
+ },
+
+ rate: function(frm, doctype, name) {
+ const item = locals[doctype][name];
+ frm.events.get_item_data(frm, item);
+ },
+
+ item_code: function(frm, doctype, name) {
+ const item = locals[doctype][name];
+ item.rate = 0;
+ set_schedule_date(frm);
+ frm.events.get_item_data(frm, item);
+ },
+
+ schedule_date: function(frm, cdt, cdn) {
+ var row = locals[cdt][cdn];
+ if (row.schedule_date) {
+ if(!frm.doc.schedule_date) {
+ erpnext.utils.copy_value_in_all_rows(frm.doc, cdt, cdn, "items", "schedule_date");
+ } else {
+ set_schedule_date(frm);
+ }
+ }
+ }
+});
+
+erpnext.buying.MaterialRequestController = erpnext.buying.BuyingController.extend({
tc_name: function() {
this.get_terms();
},
@@ -234,7 +306,7 @@
// to override item code trigger from transaction.js
},
- validate_company_and_party: function(party_field) {
+ validate_company_and_party: function() {
return true;
},
@@ -242,51 +314,6 @@
return;
},
- make_purchase_order: function() {
- frappe.model.open_mapped_doc({
- method: "erpnext.stock.doctype.material_request.material_request.make_purchase_order",
- frm: cur_frm,
- 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({
- method: "erpnext.stock.doctype.material_request.material_request.make_supplier_quotation",
- frm: cur_frm
- });
- },
-
- make_stock_entry: function() {
- frappe.model.open_mapped_doc({
- method: "erpnext.stock.doctype.material_request.material_request.make_stock_entry",
- frm: cur_frm
- });
- },
-
- raise_work_orders: function() {
- var me = this;
- frappe.call({
- method:"erpnext.stock.doctype.material_request.material_request.raise_work_orders",
- args: {
- "material_request": me.frm.doc.name
- },
- callback: function(r) {
- if(r.message.length) {
- me.frm.reload_doc();
- }
- }
- });
- },
-
validate: function() {
set_schedule_date(this.frm);
},
@@ -313,22 +340,8 @@
// for backward compatibility: combine new and previous states
$.extend(cur_frm.cscript, new erpnext.buying.MaterialRequestController({frm: cur_frm}));
-cur_frm.cscript['Stop Material Request'] = function() {
- var doc = cur_frm.doc;
- $c('runserverobj', {'method':'update_status', 'arg': 'Stopped', 'docs': doc}, function(r,rt) {
- cur_frm.refresh();
- });
-};
-
-cur_frm.cscript['Unstop Material Request'] = function(){
- var doc = cur_frm.doc;
- $c('runserverobj', {'method':'update_status', 'arg': 'Submitted','docs': doc}, function(r,rt) {
- cur_frm.refresh();
- });
-};
-
function set_schedule_date(frm) {
if(frm.doc.schedule_date){
- erpnext.utils.copy_value_in_all_row(frm.doc, frm.doc.doctype, frm.doc.name, "items", "schedule_date");
+ erpnext.utils.copy_value_in_all_rows(frm.doc, frm.doc.doctype, frm.doc.name, "items", "schedule_date");
}
}
diff --git a/erpnext/stock/doctype/material_request/material_request.json b/erpnext/stock/doctype/material_request/material_request.json
index 14e7955..9927265 100644
--- a/erpnext/stock/doctype/material_request/material_request.json
+++ b/erpnext/stock/doctype/material_request/material_request.json
@@ -59,7 +59,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
- "in_list_view": 1,
+ "in_list_view": 0,
"in_standard_filter": 0,
"label": "Series",
"length": 0,
@@ -793,7 +793,7 @@
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
- "modified": "2018-08-29 06:28:35.129352",
+ "modified": "2018-08-30 07:28:01.070112",
"modified_by": "Administrator",
"module": "Stock",
"name": "Material Request",
diff --git a/erpnext/stock/doctype/material_request/material_request.py b/erpnext/stock/doctype/material_request/material_request.py
index df40654..730ec3e 100644
--- a/erpnext/stock/doctype/material_request/material_request.py
+++ b/erpnext/stock/doctype/material_request/material_request.py
@@ -14,6 +14,7 @@
from erpnext.controllers.buying_controller import BuyingController
from erpnext.manufacturing.doctype.work_order.work_order import get_item_details
from erpnext.buying.utils import check_for_closed_status, validate_for_items
+from erpnext.stock.doctype.item.item import get_item_defaults
from six import string_types
@@ -73,21 +74,16 @@
validate_for_items(self)
- # self.set_title()
+ self.set_title()
# self.validate_qty_against_so()
# NOTE: Since Item BOM and FG quantities are combined, using current data, it cannot be validated
# Though the creation of Material Request from a Production Plan can be rethought to fix this
def set_title(self):
'''Set title as comma separated list of items'''
- items = []
- for d in self.items:
- if d.item_code not in items:
- items.append(d.item_code)
- if(len(items)==4):
- break
+ items = ', '.join([d.item_name for d in self.items][:4])
- self.title = ', '.join(items)
+ self.title = _('{0} for {1}'.format(self.material_request_type, items))[:100]
def on_submit(self):
# frappe.db.set(self, 'status', 'Submitted')
@@ -244,10 +240,29 @@
target.stock_qty = (target.qty * target.conversion_factor)
@frappe.whitelist()
+def update_status(name, status):
+ material_request = frappe.get_doc('Material Request', name)
+ material_request.check_permission('write')
+ material_request.update_status(status)
+
+@frappe.whitelist()
def make_purchase_order(source_name, target_doc=None):
+
def postprocess(source, target_doc):
+ if frappe.flags.args and frappe.flags.args.default_supplier:
+ # items only for given default supplier
+ supplier_items = []
+ for d in target_doc.items:
+ default_supplier = get_item_defaults(d.item_code, target_doc.company).get('default_supplier')
+ if frappe.flags.args.default_supplier == default_supplier:
+ supplier_items.append(d)
+ target_doc.items = supplier_items
+
set_missing_values(source, target_doc)
+ def select_item(d):
+ return d.ordered_qty < d.stock_qty
+
doclist = get_mapped_doc("Material Request", source_name, {
"Material Request": {
"doctype": "Purchase Order",
@@ -267,7 +282,7 @@
["sales_order_item", "sales_order_item"]
],
"postprocess": update_item,
- "condition": lambda doc: doc.ordered_qty < doc.stock_qty
+ "condition": select_item
}
}, target_doc, postprocess)
@@ -334,8 +349,8 @@
return target_doc
def get_material_requests_based_on_supplier(supplier):
- supplier_items = [d[0] for d in frappe.db.get_values("Item",
- {"default_supplier": supplier})]
+ supplier_items = [d.parent for d in frappe.db.get_all("Item Default",
+ {"default_supplier": supplier}, 'parent')]
if supplier_items:
material_requests = frappe.db.sql_list("""select distinct mr.name
from `tabMaterial Request` mr, `tabMaterial Request Item` mr_item
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js
index e468533..fa3501a 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.js
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.js
@@ -472,10 +472,10 @@
}
},
expense_account: function(frm, cdt, cdn) {
- erpnext.utils.copy_value_in_all_row(frm.doc, cdt, cdn, "items", "expense_account");
+ erpnext.utils.copy_value_in_all_rows(frm.doc, cdt, cdn, "items", "expense_account");
},
cost_center: function(frm, cdt, cdn) {
- erpnext.utils.copy_value_in_all_row(frm.doc, cdt, cdn, "items", "cost_center");
+ erpnext.utils.copy_value_in_all_rows(frm.doc, cdt, cdn, "items", "cost_center");
},
sample_quantity: function(frm, cdt, cdn) {
validate_sample_quantity(frm, cdt, cdn);
diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py
index 420d9d8..cbf8217 100644
--- a/erpnext/stock/get_item_details.py
+++ b/erpnext/stock/get_item_details.py
@@ -333,13 +333,13 @@
cost_center = None
if args.get('project'):
cost_center = frappe.db.get_value("Project", args.get("project"), "cost_center", cache=True)
-
+
if not cost_center:
if args.get('customer'):
cost_center = item.get('selling_cost_center') or item_group.get('selling_cost_center')
else:
cost_center = item.get('buying_cost_center') or item_group.get('buying_cost_center')
-
+
return cost_center or args.get("cost_center")
def get_default_supplier(args, item, item_group):
@@ -401,7 +401,7 @@
})
item_price.insert()
frappe.msgprint(_("Item Price added for {0} in Price List {1}").format(args.item_code,
- args.price_list))
+ args.price_list), alert=True)
def get_item_price(args, item_code):
"""
@@ -658,7 +658,7 @@
def get_bin_details_and_serial_nos(item_code, warehouse, has_batch_no, stock_qty=None, serial_no=None):
bin_details_and_serial_nos = {}
bin_details_and_serial_nos.update(get_bin_details(item_code, warehouse))
- if stock_qty > 0:
+ if flt(stock_qty) > 0:
if has_batch_no:
args = frappe._dict({"item_code":item_code, "warehouse":warehouse, "stock_qty":stock_qty})
serial_no = get_serial_no(args)