Merge pull request #1756 from rmehta/develop

removed sms control and related cleanup, fixes frappe/erpnext#462
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index 21b42a5..034880a 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -11,7 +11,6 @@
 
 {% include 'selling/sales_common.js' %};
 {% include 'accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.js' %}
-{% include 'utilities/doctype/sms_control/sms_control.js' %}
 {% include 'accounts/doctype/sales_invoice/pos.js' %}
 
 frappe.provide("erpnext.accounts");
@@ -426,3 +425,9 @@
 		}
 	}
 }
+
+cur_frm.cscript.send_sms = function() {
+	frappe.require("assets/erpnext/js/sms_manager.js");
+	var sms_man = new SMSManager(cur_frm.doc);
+}
+
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js
index 8e759f7..6474446 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.js
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.js
@@ -9,53 +9,52 @@
 
 {% include 'buying/doctype/purchase_common/purchase_common.js' %};
 {% include 'accounts/doctype/purchase_taxes_and_charges_master/purchase_taxes_and_charges_master.js' %}
-{% include 'utilities/doctype/sms_control/sms_control.js' %}
 {% include 'accounts/doctype/sales_invoice/pos.js' %}
 
 erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend({
 	refresh: function(doc, cdt, cdn) {
 		this._super();
 		this.frm.dashboard.reset();
-		
+
 		if(doc.docstatus == 1 && doc.status != 'Stopped'){
-			cur_frm.dashboard.add_progress(cint(doc.per_received) + __("% Received"), 
+			cur_frm.dashboard.add_progress(cint(doc.per_received) + __("% Received"),
 				doc.per_received);
-			cur_frm.dashboard.add_progress(cint(doc.per_billed) + __("% Billed"), 
+			cur_frm.dashboard.add_progress(cint(doc.per_billed) + __("% Billed"),
 				doc.per_billed);
 
 			cur_frm.add_custom_button('Send SMS', cur_frm.cscript.send_sms);
 
-			if(flt(doc.per_received, 2) < 100) 
-				cur_frm.add_custom_button(__('Make Purchase Receipt'), this.make_purchase_receipt);	
-			if(flt(doc.per_billed, 2) < 100) 
+			if(flt(doc.per_received, 2) < 100)
+				cur_frm.add_custom_button(__('Make Purchase Receipt'), this.make_purchase_receipt);
+			if(flt(doc.per_billed, 2) < 100)
 				cur_frm.add_custom_button(__('Make Invoice'), this.make_purchase_invoice);
-			if(flt(doc.per_billed, 2) < 100 || doc.per_received < 100) 
+			if(flt(doc.per_billed, 2) < 100 || doc.per_received < 100)
 				cur_frm.add_custom_button(__('Stop'), cur_frm.cscript['Stop Purchase Order'], "icon-exclamation");
 		} else if(doc.docstatus===0) {
 			cur_frm.cscript.add_from_mappers();
 		}
 
 		if(doc.docstatus == 1 && doc.status == 'Stopped')
-			cur_frm.add_custom_button(__('Unstop Purchase Order'), 
+			cur_frm.add_custom_button(__('Unstop Purchase Order'),
 				cur_frm.cscript['Unstop Purchase Order'], "icon-check");
 	},
-		
+
 	make_purchase_receipt: function() {
 		frappe.model.open_mapped_doc({
 			method: "erpnext.buying.doctype.purchase_order.purchase_order.make_purchase_receipt",
 			frm: cur_frm
 		})
 	},
-	
+
 	make_purchase_invoice: function() {
 		frappe.model.open_mapped_doc({
 			method: "erpnext.buying.doctype.purchase_order.purchase_order.make_purchase_invoice",
 			frm: cur_frm
 		})
 	},
-	
+
 	add_from_mappers: function() {
-		cur_frm.add_custom_button(__('From Material Request'), 
+		cur_frm.add_custom_button(__('From Material Request'),
 			function() {
 				frappe.model.map_current_doc({
 					method: "erpnext.stock.doctype.material_request.material_request.make_purchase_order",
@@ -71,7 +70,7 @@
 			}
 		);
 
-		cur_frm.add_custom_button(__('From Supplier Quotation'), 
+		cur_frm.add_custom_button(__('From Supplier Quotation'),
 			function() {
 				frappe.model.map_current_doc({
 					method: "erpnext.buying.doctype.supplier_quotation.supplier_quotation.make_purchase_order",
@@ -83,9 +82,9 @@
 					}
 				})
 			}
-		);	
-			
-		cur_frm.add_custom_button(__('For Supplier'), 
+		);
+
+		cur_frm.add_custom_button(__('For Supplier'),
 			function() {
 				frappe.model.map_current_doc({
 					method: "erpnext.stock.doctype.material_request.material_request.make_purchase_order_based_on_supplier",
@@ -128,7 +127,7 @@
 }
 
 cur_frm.cscript.get_last_purchase_rate = function(doc, cdt, cdn){
-	return $c_obj(doc, 'get_last_purchase_rate', '', function(r, rt) { 
+	return $c_obj(doc, 'get_last_purchase_rate', '', function(r, rt) {
 		refresh_field(cur_frm.cscript.fname);
 		var doc = locals[cdt][cdn];
 		cur_frm.cscript.calc_amount( doc, 2);
@@ -142,7 +141,7 @@
 	if (check) {
 		return $c('runserverobj', args={'method':'update_status', 'arg': 'Stopped', 'docs':doc}, function(r,rt) {
 			cur_frm.refresh();
-		});	
+		});
 	}
 }
 
@@ -153,13 +152,13 @@
 	if (check) {
 		return $c('runserverobj', args={'method':'update_status', 'arg': 'Submitted', 'docs':doc}, function(r,rt) {
 			cur_frm.refresh();
-		});	
+		});
 	}
 }
 
 cur_frm.pformat.indent_no = function(doc, cdt, cdn){
 	//function to make row of table
-	
+
 	var make_row = function(title,val1, val2, bold){
 		var bstart = '<b>'; var bend = '</b>';
 
@@ -169,12 +168,12 @@
 	}
 
 	out ='';
-	
+
 	var cl = doc.po_details || [];
 
-	// outer table	
+	// outer table
 	var out='<div><table class="noborder" style="width:100%"><tr><td style="width: 50%"></td><td>';
-	
+
 	// main table
 	out +='<table class="noborder" style="width:100%">';
 
@@ -202,3 +201,9 @@
 		cur_frm.email_doc(frappe.boot.notification_settings.purchase_order_message);
 	}
 }
+
+cur_frm.cscript.send_sms = function() {
+	frappe.require("assets/erpnext/js/sms_manager.js");
+	var sms_man = new SMSManager(cur_frm.doc);
+}
+
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index a5a7ae4..f68af6a 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -46,3 +46,4 @@
 erpnext.patches.v4_0.update_account_root_type
 execute:frappe.delete_doc("Report", "Purchase In Transit")
 erpnext.patches.v4_0.new_address_template
+execute:frappe.delete_doc("DocType", "SMS Control")
diff --git a/erpnext/public/js/sms_manager.js b/erpnext/public/js/sms_manager.js
new file mode 100644
index 0000000..489096f
--- /dev/null
+++ b/erpnext/public/js/sms_manager.js
@@ -0,0 +1,104 @@
+// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
+// License: GNU General Public License v3. See license.txt
+
+function SMSManager(doc) {
+	var me = this;
+	this.setup = function() {
+		var default_msg = {
+			'Lead'				: '',
+			'Opportunity'			: 'Your enquiry has been logged into the system. Ref No: ' + doc.name,
+			'Quotation'			: 'Quotation ' + doc.name + ' has been sent via email. Thanks!',
+			'Sales Order'		: 'Sales Order ' + doc.name + ' has been created against '
+						+ (doc.quotation_no ? ('Quote No:' + doc.quotation_no) : '')
+						+ (doc.po_no ? (' for your PO: ' + doc.po_no) : ''),
+			'Delivery Note'		: 'Items has been delivered against delivery note: ' + doc.name
+						+ (doc.po_no ? (' for your PO: ' + doc.po_no) : ''),
+			'Sales Invoice': 'Invoice ' + doc.name + ' has been sent via email '
+						+ (doc.po_no ? (' for your PO: ' + doc.po_no) : ''),
+			'Material Request'			: 'Material Request ' + doc.name + ' has been raised in the system',
+			'Purchase Order'	: 'Purchase Order ' + doc.name + ' has been sent via email',
+			'Purchase Receipt'	: 'Items has been received against purchase receipt: ' + doc.name
+		}
+
+		if (in_list(['Quotation', 'Sales Order', 'Delivery Note', 'Sales Invoice'], doc.doctype))
+			this.show(doc.contact_person, 'customer', doc.customer, '', default_msg[doc.doctype]);
+		else if (in_list(['Purchase Order', 'Purchase Receipt'], doc.doctype))
+			this.show(doc.contact_person, 'supplier', doc.supplier, '', default_msg[doc.doctype]);
+		else if (doc.doctype == 'Lead')
+			this.show('', '', '', doc.mobile_no, default_msg[doc.doctype]);
+		else if (doc.doctype == 'Opportunity')
+			this.show('', '', '', doc.contact_no, default_msg[doc.doctype]);
+		else if (doc.doctype == 'Material Request')
+			this.show('', '', '', '', default_msg[doc.doctype]);
+
+	};
+
+	this.get_contact_number = function(contact, key, value) {
+		frappe.call({
+			method: "erpnext.setup.doctype.sms_settings.sms_settings.get_contact_number",
+			args: {
+				contact_name:contact,
+				value:value,
+				key:key
+			},
+			callback: function(r) {
+				if(r.exc) { msgprint(r.exc); return; }
+				me.number = r.message;
+				me.show_dialog();
+			}
+		});
+	};
+
+	this.show = function(contact, key, value, mobile_nos, message) {
+		this.message = message;
+		if (mobile_nos) {
+			me.number = mobile_nos;
+			me.show_dialog();
+		} else if (contact){
+			this.get_contact_number(contact, key, value)
+		} else {
+			me.show_dialog();
+		}
+	}
+	this.show_dialog = function() {
+		if(!me.dialog)
+			me.make_dialog();
+		me.dialog.set_values({
+			'message': me.message,
+			'number': me.number
+		})
+		me.dialog.show();
+	}
+	this.make_dialog = function() {
+		var d = new frappe.ui.Dialog({
+			title: 'Send SMS',
+			width: 400,
+			fields: [
+				{fieldname:'number', fieldtype:'Data', label:'Mobile Number', reqd:1},
+				{fieldname:'message', fieldtype:'Text', label:'Message', reqd:1},
+				{fieldname:'send', fieldtype:'Button', label:'Send'}
+			]
+		})
+		d.fields_dict.send.input.onclick = function() {
+			var btn = d.fields_dict.send.input;
+			var v = me.dialog.get_values();
+			if(v) {
+				$(btn).set_working();
+				frappe.call({
+					method: "erpnext.setup.doctype.sms_settings.sms_settings.send_sms",
+					args: {
+						receiver_list: [v.number],
+						msg: v.message
+					},
+					callback: function(r) {
+						$(btn).done_working();
+						if(r.exc) {msgprint(r.exc); return; }
+						me.dialog.hide();
+					}
+				});
+			}
+		}
+		this.dialog = d;
+	}
+	this.setup();
+}
diff --git a/erpnext/public/js/transaction.js b/erpnext/public/js/transaction.js
index a1d9f38..27ee152 100644
--- a/erpnext/public/js/transaction.js
+++ b/erpnext/public/js/transaction.js
@@ -42,7 +42,7 @@
 			this.calculate_taxes_and_totals();
 		}
 		if(frappe.meta.get_docfield(this.tname, "item_code")) {
-			cur_frm.get_field(this.fname).grid.set_multiple_add("item_code");
+			cur_frm.get_field(this.fname).grid.set_multiple_add("item_code", "qty");
 		}
 	},
 
diff --git a/erpnext/selling/doctype/lead/lead.js b/erpnext/selling/doctype/lead/lead.js
index 6172b1e..286ce35 100644
--- a/erpnext/selling/doctype/lead/lead.js
+++ b/erpnext/selling/doctype/lead/lead.js
@@ -2,7 +2,6 @@
 // License: GNU General Public License v3. See license.txt
 
 {% include 'setup/doctype/contact_control/contact_control.js' %};
-{% include 'utilities/doctype/sms_control/sms_control.js' %}
 
 frappe.provide("erpnext");
 erpnext.LeadController = frappe.ui.form.Controller.extend({
@@ -90,3 +89,9 @@
 });
 
 $.extend(cur_frm.cscript, new erpnext.LeadController({frm: cur_frm}));
+
+cur_frm.cscript.send_sms = function() {
+	frappe.require("assets/erpnext/js/sms_manager.js");
+	var sms_man = new SMSManager(cur_frm.doc);
+}
+
diff --git a/erpnext/selling/doctype/opportunity/opportunity.js b/erpnext/selling/doctype/opportunity/opportunity.js
index 8fd4e82..4cc95ad 100644
--- a/erpnext/selling/doctype/opportunity/opportunity.js
+++ b/erpnext/selling/doctype/opportunity/opportunity.js
@@ -1,8 +1,6 @@
 // Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
 // License: GNU General Public License v3. See license.txt
 
-{% include 'utilities/doctype/sms_control/sms_control.js' %};
-
 frappe.ui.form.on_change("Opportunity", "customer", function(frm) {
 	erpnext.utils.get_party_details(frm) });
 frappe.ui.form.on_change("Opportunity", "customer_address", erpnext.utils.get_address_display);
@@ -145,3 +143,9 @@
 	});
 	dialog.show();
 }
+
+cur_frm.cscript.send_sms = function() {
+	frappe.require("assets/erpnext/js/sms_manager.js");
+	var sms_man = new SMSManager(cur_frm.doc);
+}
+
diff --git a/erpnext/selling/doctype/quotation/quotation.js b/erpnext/selling/doctype/quotation/quotation.js
index 022e2e4..e65fcbe 100644
--- a/erpnext/selling/doctype/quotation/quotation.js
+++ b/erpnext/selling/doctype/quotation/quotation.js
@@ -10,7 +10,6 @@
 
 {% include 'selling/sales_common.js' %}
 {% include 'accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.js' %}
-{% include 'utilities/doctype/sms_control/sms_control.js' %}
 {% include 'accounts/doctype/sales_invoice/pos.js' %}
 
 erpnext.selling.QuotationController = erpnext.selling.SellingController.extend({
@@ -175,3 +174,9 @@
 	if(cint(frappe.boot.notification_settings.quotation))
 		cur_frm.email_doc(frappe.boot.notification_settings.quotation_message);
 }
+
+cur_frm.cscript.send_sms = function() {
+	frappe.require("assets/erpnext/js/sms_manager.js");
+	var sms_man = new SMSManager(cur_frm.doc);
+}
+
diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js
index 06eb470..c8ddcf5 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.js
+++ b/erpnext/selling/doctype/sales_order/sales_order.js
@@ -10,7 +10,6 @@
 
 {% include 'selling/sales_common.js' %}
 {% include 'accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.js' %}
-{% include 'utilities/doctype/sms_control/sms_control.js' %}
 {% include 'accounts/doctype/sales_invoice/pos.js' %}
 
 erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend({
@@ -189,3 +188,8 @@
 		cur_frm.email_doc(frappe.boot.notification_settings.sales_order_message);
 	}
 };
+
+cur_frm.cscript.send_sms = function() {
+	frappe.require("assets/erpnext/js/sms_manager.js");
+	var sms_man = new SMSManager(cur_frm.doc);
+};
diff --git a/erpnext/selling/doctype/sms_center/sms_center.py b/erpnext/selling/doctype/sms_center/sms_center.py
index 209d1b4..8193954 100644
--- a/erpnext/selling/doctype/sms_center/sms_center.py
+++ b/erpnext/selling/doctype/sms_center/sms_center.py
@@ -9,6 +9,8 @@
 
 from frappe.model.document import Document
 
+from erpnext.setup.doctype.sms_settings.sms_settings import send_sms
+
 class SMSCenter(Document):
 
 	def create_receiver_list(self):
@@ -26,29 +28,30 @@
 				self.sales_partner.replace("'", "\'") or " and ifnull(sales_partner, '') != ''"
 
 		if self.send_to in ['All Contact', 'All Customer Contact', 'All Supplier Contact', 'All Sales Partner Contact']:
-			rec = frappe.db.sql("""select CONCAT(ifnull(first_name,''), '', ifnull(last_name,'')), 
-				mobile_no from `tabContact` where ifnull(mobile_no,'')!='' and 
-				docstatus != 2 %s""", where_clause)
-		
+			rec = frappe.db.sql("""select CONCAT(ifnull(first_name,''), ' ', ifnull(last_name,'')),
+				mobile_no from `tabContact` where ifnull(mobile_no,'')!='' and
+				docstatus != 2 %s""" % where_clause)
+
 		elif self.send_to == 'All Lead (Open)':
-			rec = frappe.db.sql("""select lead_name, mobile_no from `tabLead` where 
+			rec = frappe.db.sql("""select lead_name, mobile_no from `tabLead` where
 				ifnull(mobile_no,'')!='' and docstatus != 2 and status='Open'""")
-		
+
 		elif self.send_to == 'All Employee (Active)':
 			where_clause = self.department and " and department = '%s'" % \
 				self.department.replace("'", "\'") or ""
 			where_clause += self.branch and " and branch = '%s'" % \
 				self.branch.replace("'", "\'") or ""
-				
-			rec = frappe.db.sql("""select employee_name, cell_number from 
-				`tabEmployee` where status = 'Active' and docstatus < 2 and 
-				ifnull(cell_number,'')!='' %s""", where_clause)
-		
+
+			rec = frappe.db.sql("""select employee_name, cell_number from
+				`tabEmployee` where status = 'Active' and docstatus < 2 and
+				ifnull(cell_number,'')!='' %s""" % where_clause)
+
 		elif self.send_to == 'All Sales Person':
-			rec = frappe.db.sql("""select sales_person_name, mobile_no from 
+			rec = frappe.db.sql("""select sales_person_name, mobile_no from
 				`tabSales Person` where docstatus!=2 and ifnull(mobile_no,'')!=''""")
-			rec_list = ''
-		
+
+		rec_list = ''
+
 		for d in rec:
 			rec_list += d[0] + ' - ' + d[1] + '\n'
 			self.receiver_list = rec_list
@@ -64,7 +67,7 @@
 					receiver_nos.append(cstr(receiver_no).strip())
 		else:
 			msgprint(_("Receiver List is empty. Please create Receiver List"))
-		
+
 		return receiver_nos
 
 	def send_sms(self):
@@ -73,4 +76,5 @@
 		else:
 			receiver_list = self.get_receiver_nos()
 		if receiver_list:
-			msgprint(frappe.get_doc('SMS Control', 'SMS Control').send_sms(receiver_list, cstr(self.message)))
\ No newline at end of file
+			send_sms(receiver_list, cstr(self.message))
+
diff --git a/erpnext/selling/sales_common.js b/erpnext/selling/sales_common.js
index 1cc643e..63ffb36 100644
--- a/erpnext/selling/sales_common.js
+++ b/erpnext/selling/sales_common.js
@@ -22,7 +22,7 @@
 	},
 
 	onload_post_render: function() {
-		cur_frm.get_field(this.fname).grid.set_multiple_add("item_code");
+		cur_frm.get_field(this.fname).grid.set_multiple_add("item_code", "qty");
 	},
 
 	setup_queries: function() {
diff --git a/erpnext/setup/doctype/sms_settings/sms_settings.js b/erpnext/setup/doctype/sms_settings/sms_settings.js
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/setup/doctype/sms_settings/sms_settings.js
diff --git a/erpnext/setup/doctype/sms_settings/sms_settings.py b/erpnext/setup/doctype/sms_settings/sms_settings.py
index 281ae76..a9afacf 100644
--- a/erpnext/setup/doctype/sms_settings/sms_settings.py
+++ b/erpnext/setup/doctype/sms_settings/sms_settings.py
@@ -2,9 +2,111 @@
 # License: GNU General Public License v3. See license.txt
 
 from __future__ import unicode_literals
-import frappe
+import frappe, json
+
+from frappe import _, throw, msgprint
+from frappe.utils import cstr, nowdate
 
 from frappe.model.document import Document
 
 class SMSSettings(Document):
-	pass
\ No newline at end of file
+	pass
+
+def validate_receiver_nos(receiver_list):
+	validated_receiver_list = []
+	for d in receiver_list:
+		# remove invalid character
+		invalid_char_list = [' ', '+', '-', '(', ')']
+		for x in invalid_char_list:
+			d = d.replace(x, '')
+
+		validated_receiver_list.append(d)
+
+	if not validated_receiver_list:
+		throw(_("Please enter valid mobile nos"))
+
+	return validated_receiver_list
+
+
+def get_sender_name():
+	"returns name as SMS sender"
+	sender_name = frappe.db.get_value('Global Defaults', None, 'sms_sender_name') or \
+		'ERPNXT'
+	if len(sender_name) > 6 and \
+			frappe.db.get_default("country") == "India":
+		throw("""As per TRAI rule, sender name must be exactly 6 characters.
+			Kindly change sender name in Setup --> Global Defaults.
+			Note: Hyphen, space, numeric digit, special characters are not allowed.""")
+	return sender_name
+
+@frappe.whitelist()
+def get_contact_number(contact_name, value, key):
+	"returns mobile number of the contact"
+	number = frappe.db.sql("""select mobile_no, phone from tabContact where name=%s and %s=%s""" %
+		('%s', key, '%s'), (contact_name, value))
+	return number and (number[0][0] or number[0][1]) or ''
+
+@frappe.whitelist()
+def send_sms(receiver_list, msg, sender_name = ''):
+	receiver_list = validate_receiver_nos(receiver_list)
+
+	arg = {
+		'receiver_list' : receiver_list,
+		'message'		: msg,
+		'sender_name'	: sender_name or get_sender_name()
+	}
+
+	if frappe.db.get_value('SMS Settings', None, 'sms_gateway_url'):
+		ret = send_via_gateway(arg)
+		msgprint(ret)
+	else:
+		msgprint(_("Please Update SMS Settings"))
+
+def send_via_gateway(arg):
+	ss = frappe.get_doc('SMS Settings', 'SMS Settings')
+	args = {ss.message_parameter : arg.get('message')}
+	for d in ss.get("static_parameter_details"):
+		args[d.parameter] = d.value
+
+	resp = []
+	for d in arg.get('receiver_list'):
+		args[ss.receiver_parameter] = d
+		resp.append(send_request(ss.sms_gateway_url, args))
+
+	return resp
+
+# Send Request
+# =========================================================
+def send_request(gateway_url, args):
+	import httplib, urllib
+	server, api_url = scrub_gateway_url(gateway_url)
+	conn = httplib.HTTPConnection(server)  # open connection
+	headers = {}
+	headers['Accept'] = "text/plain, text/html, */*"
+	conn.request('GET', api_url + urllib.urlencode(args), headers = headers)    # send request
+	resp = conn.getresponse()     # get response
+	resp = resp.read()
+	return resp
+
+# Split gateway url to server and api url
+# =========================================================
+def scrub_gateway_url(url):
+	url = url.replace('http://', '').strip().split('/')
+	server = url.pop(0)
+	api_url = '/' + '/'.join(url)
+	if not api_url.endswith('?'):
+		api_url += '?'
+	return server, api_url
+
+
+# Create SMS Log
+# =========================================================
+def create_sms_log(arg, sent_sms):
+	sl = frappe.get_doc('SMS Log')
+	sl.sender_name = arg['sender_name']
+	sl.sent_on = nowdate()
+	sl.receiver_list = cstr(arg['receiver_list'])
+	sl.message = arg['message']
+	sl.no_of_requested_sms = len(arg['receiver_list'])
+	sl.no_of_sent_sms = sent_sms
+	sl.save()
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.js b/erpnext/stock/doctype/delivery_note/delivery_note.js
index ff551f7..fb94b88 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.js
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.js
@@ -9,7 +9,6 @@
 
 {% include 'selling/sales_common.js' %};
 {% include 'accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.js' %}
-{% include 'utilities/doctype/sms_control/sms_control.js' %}
 {% include 'accounts/doctype/sales_invoice/pos.js' %}
 
 frappe.provide("erpnext.stock");
@@ -245,3 +244,9 @@
 		}
 	}
 }
+
+cur_frm.cscript.send_sms = function() {
+	frappe.require("assets/erpnext/js/sms_manager.js");
+	var sms_man = new SMSManager(cur_frm.doc);
+}
+
diff --git a/erpnext/stock/doctype/material_request/material_request.js b/erpnext/stock/doctype/material_request/material_request.js
index 8dabbd3..e53a92a 100644
--- a/erpnext/stock/doctype/material_request/material_request.js
+++ b/erpnext/stock/doctype/material_request/material_request.js
@@ -5,7 +5,6 @@
 cur_frm.cscript.fname = "indent_details";
 
 {% include 'buying/doctype/purchase_common/purchase_common.js' %};
-{% include 'utilities/doctype/sms_control/sms_control.js' %}
 
 erpnext.buying.MaterialRequestController = erpnext.buying.BuyingController.extend({
 	onload: function(doc) {
@@ -17,46 +16,46 @@
 			}
 		});
 	},
-	
+
 	refresh: function(doc) {
 		this._super();
-		
+
 		// dashboard
 		cur_frm.dashboard.reset();
 		if(doc.docstatus===1) {
 			if(doc.status==="Stopped") {
 				cur_frm.dashboard.set_headline_alert(__("Stopped"), "alert-danger", "icon-stop")
 			}
-			cur_frm.dashboard.add_progress(cint(doc.per_ordered) + "% " 
+			cur_frm.dashboard.add_progress(cint(doc.per_ordered) + "% "
 				+ __("Fulfilled"), cint(doc.per_ordered));
 		}
-		
+
 		if(doc.docstatus==0) {
 			cur_frm.add_custom_button(__("Get Items from BOM"), cur_frm.cscript.get_items_from_bom, "icon-sitemap");
 		}
-		
+
 		if(doc.docstatus == 1 && doc.status != 'Stopped') {
 			if(doc.material_request_type === "Purchase")
-				cur_frm.add_custom_button(__("Make Supplier Quotation"), 
+				cur_frm.add_custom_button(__("Make Supplier Quotation"),
 					this.make_supplier_quotation);
-				
+
 			if(doc.material_request_type === "Transfer" && doc.status === "Submitted")
 				cur_frm.add_custom_button(__("Transfer Material"), this.make_stock_entry);
-			
+
 			if(flt(doc.per_ordered, 2) < 100) {
 				if(doc.material_request_type === "Purchase")
-					cur_frm.add_custom_button(__('Make Purchase Order'), 
+					cur_frm.add_custom_button(__('Make Purchase Order'),
 						this.make_purchase_order);
-				
-				cur_frm.add_custom_button(__('Stop Material Request'), 
+
+				cur_frm.add_custom_button(__('Stop Material Request'),
 					cur_frm.cscript['Stop Material Request'], "icon-exclamation");
 			}
 			cur_frm.add_custom_button(__('Send SMS'), cur_frm.cscript.send_sms, "icon-mobile-phone");
 
-		} 
-		
+		}
+
 		if (this.frm.doc.docstatus===0) {
-			cur_frm.add_custom_button(__('From Sales Order'), 
+			cur_frm.add_custom_button(__('From Sales Order'),
 				function() {
 					frappe.model.map_current_doc({
 						method: "erpnext.selling.doctype.sales_order.sales_order.make_material_request",
@@ -72,11 +71,11 @@
 		}
 
 		if(doc.docstatus == 1 && doc.status == 'Stopped')
-			cur_frm.add_custom_button(__('Unstop Material Request'), 
+			cur_frm.add_custom_button(__('Unstop Material Request'),
 				cur_frm.cscript['Unstop Material Request'], "icon-check");
-		
+
 	},
-	
+
 	schedule_date: function(doc, cdt, cdn) {
 		var val = locals[cdt][cdn].schedule_date;
 		if(val) {
@@ -88,14 +87,14 @@
 			refresh_field("indent_details");
 		}
 	},
-	
+
 	get_items_from_bom: function() {
 		var d = new frappe.ui.Dialog({
 			title: __("Get Items from BOM"),
 			fields: [
-				{"fieldname":"bom", "fieldtype":"Link", "label":__("BOM"), 
+				{"fieldname":"bom", "fieldtype":"Link", "label":__("BOM"),
 					options:"BOM"},
-				{"fieldname":"fetch_exploded", "fieldtype":"Check", 
+				{"fieldname":"fetch_exploded", "fieldtype":"Check",
 					"label":__("Fetch exploded BOM (including sub-assemblies)"), "default":1},
 				{fieldname:"fetch", "label":__("Get Items from BOM"), "fieldtype":"Button"}
 			]
@@ -103,7 +102,7 @@
 		d.get_input("fetch").on("click", function() {
 			var values = d.get_values();
 			if(!values) return;
-			
+
 			frappe.call({
 				method: "erpnext.manufacturing.doctype.bom.bom.get_bom_items",
 				args: values,
@@ -123,19 +122,19 @@
 		});
 		d.show();
 	},
-	
+
 	tc_name: function() {
 		this.get_terms();
 	},
-	
+
 	validate_company_and_party: function(party_field) {
 		return true;
 	},
-	
+
 	calculate_taxes_and_totals: function() {
 		return;
 	},
-		
+
 	make_purchase_order: function() {
 		frappe.model.open_mapped_doc({
 			method: "erpnext.stock.doctype.material_request.material_request.make_purchase_order",
@@ -160,7 +159,7 @@
 
 // for backward compatibility: combine new and previous states
 $.extend(cur_frm.cscript, new erpnext.buying.MaterialRequestController({frm: cur_frm}));
-	
+
 cur_frm.cscript.qty = function(doc, cdt, cdn) {
 	var d = locals[cdt][cdn];
 	if (flt(d.qty) < flt(d.min_order_qty))
@@ -181,10 +180,15 @@
 cur_frm.cscript['Unstop Material Request'] = function(){
 	var doc = cur_frm.doc;
 	var check = confirm(__("Do you really want to UNSTOP this Material Request?"));
-	
+
 	if (check) {
 		return $c('runserverobj', args={'method':'update_status', 'arg': 'Submitted','docs': doc}, function(r,rt) {
 			cur_frm.refresh();
 		});
 	}
-};
\ No newline at end of file
+};
+
+cur_frm.cscript.send_sms = function() {
+	frappe.require("assets/erpnext/js/sms_manager.js");
+	var sms_man = new SMSManager(cur_frm.doc);
+}
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
index 3d1a216..5851709 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
@@ -7,7 +7,6 @@
 
 {% include 'buying/doctype/purchase_common/purchase_common.js' %};
 {% include 'accounts/doctype/purchase_taxes_and_charges_master/purchase_taxes_and_charges_master.js' %}
-{% include 'utilities/doctype/sms_control/sms_control.js' %}
 {% include 'accounts/doctype/sales_invoice/pos.js' %}
 
 frappe.provide("erpnext.stock");
@@ -165,3 +164,9 @@
 	if(cint(frappe.boot.notification_settings.purchase_receipt))
 		cur_frm.email_doc(frappe.boot.notification_settings.purchase_receipt_message);
 }
+
+cur_frm.cscript.send_sms = function() {
+	frappe.require("assets/erpnext/js/sms_manager.js");
+	var sms_man = new SMSManager(cur_frm.doc);
+}
+
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js
index 553b25c..a42a865 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.js
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.js
@@ -56,7 +56,7 @@
 	},
 
 	onload_post_render: function() {
-		cur_frm.get_field(this.fname).grid.set_multiple_add("item_code");
+		cur_frm.get_field(this.fname).grid.set_multiple_add("item_code", "qty");
 		this.set_default_account();
 	},
 
diff --git a/erpnext/utilities/doctype/sms_control/__init__.py b/erpnext/utilities/doctype/sms_control/__init__.py
deleted file mode 100644
index baffc48..0000000
--- a/erpnext/utilities/doctype/sms_control/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-from __future__ import unicode_literals
diff --git a/erpnext/utilities/doctype/sms_control/sms_control.js b/erpnext/utilities/doctype/sms_control/sms_control.js
deleted file mode 100644
index 60f53d9..0000000
--- a/erpnext/utilities/doctype/sms_control/sms_control.js
+++ /dev/null
@@ -1,94 +0,0 @@
-// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
-// License: GNU General Public License v3. See license.txt
-
-function SMSManager() {
-	var me = this;
-	this.get_contact_number = function(contact, key, value) {
-		return $c_obj('SMS Control', 'get_contact_number', {
-				contact_name:contact, 
-				value:value,
-				key:key
-			}, function(r,rt) {
-				if(r.exc) { msgprint(r.exc); return; }
-				me.number = r.message;
-				me.show_dialog();
-			}
-		);
-	}
-	this.show = function(contact, key, value, mobile_nos, message) {
-		this.message = message;
-		if (mobile_nos) {
-			me.number = mobile_nos;
-			me.show_dialog();
-		} else if (contact){
-			this.get_contact_number(contact, key, value)
-		} else {
-			me.show_dialog();
-		}
-	}
-	this.show_dialog = function() {
-		if(!me.dialog) 
-			me.make_dialog();
-		me.dialog.set_values({
-			'message': me.message,
-			'number': me.number
-		})
-		me.dialog.show();
-	}
-	this.make_dialog = function() {
-		var d = new frappe.ui.Dialog({
-			title: 'Send SMS',
-			width: 400,
-			fields: [
-				{fieldname:'number', fieldtype:'Data', label:'Mobile Number', reqd:1},
-				{fieldname:'message', fieldtype:'Text', label:'Message', reqd:1},
-				{fieldname:'send', fieldtype:'Button', label:'Send'}
-			]
-		})
-		d.fields_dict.send.input.onclick = function() {
-			var btn = d.fields_dict.send.input;
-			var v = me.dialog.get_values();
-			if(v) {
-				$(this).set_working();
-				return $c_obj('SMS Control', 'send_form_sms', v, function(r,rt) {
-					$(this).done_working();
-					if(r.exc) {msgprint(r.exc); return; }
-					msgprint(__('Message Sent'));
-					me.dialog.hide();
-				})
-			}
-		}
-		this.dialog = d;
-	}
-}
-
-cur_frm.cscript.send_sms = function(doc,dt,dn) {
-	var doc = cur_frm.doc;
-	var sms_man = new SMSManager();
-	var default_msg = {
-		'Lead'				: '',
-		'Opportunity'			: 'Your enquiry has been logged into the system. Ref No: ' + doc.name,
-		'Quotation'			: 'Quotation ' + doc.name + ' has been sent via email. Thanks!',
-		'Sales Order'		: 'Sales Order ' + doc.name + ' has been created against ' 
-					+ (doc.quotation_no ? ('Quote No:' + doc.quotation_no) : '')
-					+ (doc.po_no ? (' for your PO: ' + doc.po_no) : ''),
-		'Delivery Note'		: 'Items has been delivered against delivery note: ' + doc.name
-					+ (doc.po_no ? (' for your PO: ' + doc.po_no) : ''),		
-		'Sales Invoice': 'Invoice ' + doc.name + ' has been sent via email '
-					+ (doc.po_no ? (' for your PO: ' + doc.po_no) : ''),
-		'Material Request'			: 'Material Request ' + doc.name + ' has been raised in the system',
-		'Purchase Order'	: 'Purchase Order ' + doc.name + ' has been sent via email',
-		'Purchase Receipt'	: 'Items has been received against purchase receipt: ' + doc.name
-	}
-
-	if (in_list(['Quotation', 'Sales Order', 'Delivery Note', 'Sales Invoice'], doc.doctype))
-		sms_man.show(doc.contact_person, 'customer', doc.customer, '', default_msg[doc.doctype]);
-	else if (in_list(['Purchase Order', 'Purchase Receipt'], doc.doctype))
-		sms_man.show(doc.contact_person, 'supplier', doc.supplier, '', default_msg[doc.doctype]);
-	else if (doc.doctype == 'Lead')
-		sms_man.show('', '', '', doc.mobile_no, default_msg[doc.doctype]);
-	else if (doc.doctype == 'Opportunity')
-		sms_man.show('', '', '', doc.contact_no, default_msg[doc.doctype]);
-	else if (doc.doctype == 'Material Request')
-		sms_man.show('', '', '', '', default_msg[doc.doctype]);
-}
diff --git a/erpnext/utilities/doctype/sms_control/sms_control.json b/erpnext/utilities/doctype/sms_control/sms_control.json
deleted file mode 100644
index 1c933f2..0000000
--- a/erpnext/utilities/doctype/sms_control/sms_control.json
+++ /dev/null
@@ -1,29 +0,0 @@
-{
- "creation": "2013-01-10 16:34:32.000000", 
- "docstatus": 0, 
- "doctype": "DocType", 
- "icon": "icon-mobile-phone", 
- "idx": 1, 
- "in_create": 0, 
- "issingle": 1, 
- "modified": "2013-12-20 19:21:47.000000", 
- "modified_by": "Administrator", 
- "module": "Utilities", 
- "name": "SMS Control", 
- "owner": "Administrator", 
- "permissions": [
-  {
-   "create": 1, 
-   "email": 1, 
-   "export": 0, 
-   "import": 0, 
-   "permlevel": 0, 
-   "print": 1, 
-   "read": 1, 
-   "report": 0, 
-   "role": "System Manager", 
-   "submit": 0, 
-   "write": 1
-  }
- ]
-}
\ No newline at end of file
diff --git a/erpnext/utilities/doctype/sms_control/sms_control.py b/erpnext/utilities/doctype/sms_control/sms_control.py
deleted file mode 100644
index e599eea..0000000
--- a/erpnext/utilities/doctype/sms_control/sms_control.py
+++ /dev/null
@@ -1,114 +0,0 @@
-# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
-# License: GNU General Public License v3. See license.txt
-
-from __future__ import unicode_literals
-import frappe, json
-
-from frappe.utils import nowdate, cstr
-from frappe import msgprint, throw, _
-
-
-from frappe.model.document import Document
-
-class SMSControl(Document):
-
-	def validate_receiver_nos(self,receiver_list):
-		validated_receiver_list = []
-		for d in receiver_list:
-			# remove invalid character
-			invalid_char_list = [' ', '+', '-', '(', ')']
-			for x in invalid_char_list:
-				d = d.replace(x, '')
-
-			validated_receiver_list.append(d)
-
-		if not validated_receiver_list:
-			throw(_("Please enter valid mobile nos"))
-
-		return validated_receiver_list
-
-
-	def get_sender_name(self):
-		"returns name as SMS sender"
-		sender_name = frappe.db.get_value('Global Defaults', None, 'sms_sender_name') or \
-			'ERPNXT'
-		if len(sender_name) > 6 and \
-				frappe.db.get_default("country") == "India":
-			throw("""As per TRAI rule, sender name must be exactly 6 characters.
-				Kindly change sender name in Setup --> Global Defaults.
-				Note: Hyphen, space, numeric digit, special characters are not allowed.""")
-		return sender_name
-
-	def get_contact_number(self, arg):
-		"returns mobile number of the contact"
-		args = json.loads(arg)
-		number = frappe.db.sql("""select mobile_no, phone from tabContact where name=%s and %s=%s""" %
-			('%s', args['key'], '%s'), (args['contact_name'], args['value']))
-		return number and (number[0][0] or number[0][1]) or ''
-
-	def send_form_sms(self, arg):
-		"called from client side"
-		args = json.loads(arg)
-		self.send_sms([cstr(args['number'])], cstr(args['message']))
-
-	def send_sms(self, receiver_list, msg, sender_name = ''):
-		receiver_list = self.validate_receiver_nos(receiver_list)
-
-		arg = {
-			'receiver_list' : receiver_list,
-			'message'		: msg,
-			'sender_name'	: sender_name or self.get_sender_name()
-		}
-
-		if frappe.db.get_value('SMS Settings', None, 'sms_gateway_url'):
-			ret = self.send_via_gateway(arg)
-			msgprint(ret)
-
-	def send_via_gateway(self, arg):
-		ss = frappe.get_doc('SMS Settings', 'SMS Settings')
-		args = {ss.message_parameter : arg.get('message')}
-		for d in ss.get("static_parameter_details"):
-			args[d.parameter] = d.value
-
-		resp = []
-		for d in arg.get('receiver_list'):
-			args[ss.receiver_parameter] = d
-			resp.append(self.send_request(ss.sms_gateway_url, args))
-
-		return resp
-
-	# Send Request
-	# =========================================================
-	def send_request(self, gateway_url, args):
-		import httplib, urllib
-		server, api_url = self.scrub_gateway_url(gateway_url)
-		conn = httplib.HTTPConnection(server)  # open connection
-		headers = {}
-		headers['Accept'] = "text/plain, text/html, */*"
-		conn.request('GET', api_url + urllib.urlencode(args), headers = headers)    # send request
-		resp = conn.getresponse()     # get response
-		resp = resp.read()
-		return resp
-
-	# Split gateway url to server and api url
-	# =========================================================
-	def scrub_gateway_url(self, url):
-		url = url.replace('http://', '').strip().split('/')
-		server = url.pop(0)
-		api_url = '/' + '/'.join(url)
-		if not api_url.endswith('?'):
-			api_url += '?'
-		return server, api_url
-
-
-	# Create SMS Log
-	# =========================================================
-	def create_sms_log(self, arg, sent_sms):
-		sl = frappe.get_doc('SMS Log')
-		sl.sender_name = arg['sender_name']
-		sl.sent_on = nowdate()
-		sl.receiver_list = cstr(arg['receiver_list'])
-		sl.message = arg['message']
-		sl.no_of_requested_sms = len(arg['receiver_list'])
-		sl.no_of_sent_sms = sent_sms
-		sl.save()