added users
diff --git a/erpnext/utilities/page/messages/messages.js b/erpnext/utilities/page/messages/messages.js
index 39f7974..43adce4 100644
--- a/erpnext/utilities/page/messages/messages.js
+++ b/erpnext/utilities/page/messages/messages.js
@@ -1,3 +1,19 @@
+// ERPNext - web based ERP (http://erpnext.com)
+// Copyright (C) 2012 Web Notes Technologies Pvt Ltd
+// 
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
 wn.provide('erpnext.messages');
 
 wn.pages.messages.onload = function(wrapper) {
diff --git a/erpnext/utilities/page/messages/messages.py b/erpnext/utilities/page/messages/messages.py
index d7c6026..8e92ff9 100644
--- a/erpnext/utilities/page/messages/messages.py
+++ b/erpnext/utilities/page/messages/messages.py
@@ -1,3 +1,19 @@
+# ERPNext - web based ERP (http://erpnext.com)
+# Copyright (C) 2012 Web Notes Technologies Pvt Ltd
+# 
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
 import webnotes
 
 @webnotes.whitelist()
diff --git a/erpnext/utilities/page/todo/todo.js b/erpnext/utilities/page/todo/todo.js
index 77e4625..4350023 100644
--- a/erpnext/utilities/page/todo/todo.js
+++ b/erpnext/utilities/page/todo/todo.js
@@ -1,3 +1,19 @@
+// ERPNext - web based ERP (http://erpnext.com)
+// Copyright (C) 2012 Web Notes Technologies Pvt Ltd
+// 
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
 wn.provide('erpnext.todo');
 
 erpnext.todo.refresh = function() {
diff --git a/erpnext/utilities/page/todo/todo.py b/erpnext/utilities/page/todo/todo.py
index c10809e..05d55fe 100644
--- a/erpnext/utilities/page/todo/todo.py
+++ b/erpnext/utilities/page/todo/todo.py
@@ -1,3 +1,19 @@
+# ERPNext - web based ERP (http://erpnext.com)
+# Copyright (C) 2012 Web Notes Technologies Pvt Ltd
+# 
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
 import webnotes
 from webnotes.model.doc import Document
 
diff --git a/erpnext/utilities/page/users/__init__.py b/erpnext/utilities/page/users/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/utilities/page/users/__init__.py
diff --git a/erpnext/utilities/page/users/users.css b/erpnext/utilities/page/users/users.css
new file mode 100644
index 0000000..1a85d15
--- /dev/null
+++ b/erpnext/utilities/page/users/users.css
@@ -0,0 +1,35 @@
+.user-card {
+	border-radius: 5px;
+	width: 200px;
+	margin: 11px;
+	padding: 11px;
+	background-color: #FFEDBD;
+	box-shadow: 3px 3px 5px #888;
+	float: left;
+	overflow: hidden;
+}
+
+.user-card.disabled {
+	background-color: #eee;
+}
+
+.user-card img {
+	height: 60px;
+}
+
+.user-role {
+	padding: 5px;
+	width: 45%;
+	float: left;
+}
+
+table.user-perm {
+	border-collapse: collapse;
+}
+
+table.user-perm td, table.user-perm th {
+	padding: 5px;
+	text-align: center;
+	border-bottom: 1px solid #aaa;
+	min-width: 30px;
+}
\ No newline at end of file
diff --git a/erpnext/utilities/page/users/users.html b/erpnext/utilities/page/users/users.html
new file mode 100644
index 0000000..fe2f000
--- /dev/null
+++ b/erpnext/utilities/page/users/users.html
@@ -0,0 +1,13 @@
+<div class="layout-wrapper">
+	<a class="close" onclick="window.history.back();">&times;</a>		
+	<h1>Users</h1>
+	<hr>
+	<div class="help" style="margin-bottom: 20px">Add, disable, delete users and change their roles, passwords and security settings</div>
+	<div style="margin: 11px">
+		<button class="btn btn-small add-user" onclick="wn.pages.users.add_user()"
+			><i class="icon-plus"></i> Add User</button>
+	</div>
+	<div class="users-area">
+	</div>
+	<div style="clear: both"></div>
+</div>
\ No newline at end of file
diff --git a/erpnext/utilities/page/users/users.js b/erpnext/utilities/page/users/users.js
new file mode 100644
index 0000000..21519b8
--- /dev/null
+++ b/erpnext/utilities/page/users/users.js
@@ -0,0 +1,377 @@
+// ERPNext - web based ERP (http://erpnext.com)
+// Copyright (C) 2012 Web Notes Technologies Pvt Ltd
+// 
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+$.extend(wn.pages.users, {
+	onload: function(wrapper) {
+		wn.pages.users.profiles = {};
+		wn.pages.users.refresh();
+		wn.pages.users.setup();
+		wn.pages.users.role_editor = new erpnext.RoleEditor();
+	},
+	setup: function() {
+		// set roles
+		$('.users-area').on('click', '.btn.user-roles', function() {
+			var uid = $(this).parent().parent().attr('data-name');
+			wn.pages.users.role_editor.show(uid);
+		});
+
+		// settings
+		$('.users-area').on('click', '.btn.user-settings', function() {
+			var uid = $(this).parent().parent().attr('data-name');
+			wn.pages.users.show_settings(uid);
+		});
+		
+		// delete
+		$('.users-area').on('click', 'a.close', function() {
+			$card = $(this).parent();
+			var uid = $card.attr('data-name');
+			$card.css('opacity', 0.6);
+			wn.call({
+				method: 'utilities.page.users.users.delete',
+				args: {'uid': uid},
+				callback: function(r,rt) {
+					if(!r.exc)
+						$card.fadeOut()
+				}
+			});
+		})
+		
+	},
+	refresh: function() {
+		// make the list
+		wn.call({
+			method:'utilities.page.users.users.get',
+			callback: function(r, rt) {
+				$('.users-area').empty();
+				for(var i in r.message) {
+					var p = r.message[i];
+					wn.pages.users.profiles[p.name] = p;
+					wn.pages.users.render(p);
+				}
+			}
+		});
+	},
+	render: function(data) {
+		if(data.file_list) {
+			data.imgsrc = 'files/' + data.files_list.split('\n')[0].split(',')[1];
+		} else {
+			data.imgsrc = 'lib/images/ui/no_img_' + (data.gender=='Female' ? 'f' : 'm');
+		}
+		data.fullname = wn.boot.user_fullnames[data.name];
+		data.delete_html = '';
+		if(!data.enabled) 
+			data.delete_html = '<a class="close" title="delete">&times;</a>';
+		
+		$('.users-area').append(repl('<div class="user-card" data-name="%(name)s">\
+			%(delete_html)s\
+			<img src="%(imgsrc)s">\
+			<div class="user-info">\
+				<b class="user-fullname">%(fullname)s</b><br>\
+				%(name)s<br>\
+				<button class="btn btn-small user-roles"><i class="icon-user"></i> Roles</button>\
+				<button class="btn btn-small user-settings"><i class="icon-cog"></i> Settings</button>\
+			</div>\
+		</div>', data));
+		
+		if(!data.enabled) {
+			$('.users-area .user-card:last')
+				.addClass('disabled')
+				.find('.user-fullname').html('Disabled');
+		}
+	},
+	show_settings: function(uid) {
+		var me = wn.pages.users;
+		if(!me.settings_dialog)
+			me.make_settings_dialog();
+		
+		var p = me.profiles[uid];
+		me.uid = uid;
+		
+		me.settings_dialog.set_values({
+			restrict_ip: p.restrict_ip || '',
+			login_before: p.login_before || '',
+			login_after: p.login_after || '',
+			enabled: p.enabled || 0,
+			new_password: ''
+		});
+		
+		me.settings_dialog.show();
+
+	},
+	make_settings_dialog: function() {
+		var me = wn.pages.users;
+		me.settings_dialog = new wn.widgets.Dialog({
+			title: 'Set User Security',
+			width: 500,
+			fields: [
+				{
+					label:'Enabled',
+					description: 'Uncheck to disable',
+					fieldtype: 'Check', fieldname: 'enabled'
+				},
+				{
+					label:'IP Address', 
+					description: 'Restrict user login by IP address, partial ips (111.111.111), \
+					multiple addresses (separated by commas) allowed', 
+					fieldname:'restrict_ip', fieldtype:'Data'
+				},
+				{
+					label:'Login After',
+					description: 'User can only login after this hour (0-24)',
+					fieldtype: 'Int', fieldname: 'login_after'
+				},
+				{
+					label:'Login Before',
+					description: 'User can only login before this hour (0-24)',
+					fieldtype: 'Int', fieldname: 'login_before'
+				},
+				{
+					label:'New Password',
+					description: 'Update the current user password',
+					fieldtype: 'Data', fieldname: 'new_password'
+				},
+				{
+					label:'Update', fieldtype:'Button', fieldname:'update'
+				}
+			]
+		});
+
+		this.settings_dialog.fields_dict.update.input.onclick = function() {
+			var btn = this;
+			this.set_working();
+			var args = me.settings_dialog.get_values();
+			args.user = me.uid;
+
+			if (args.new_password) {
+				me.get_password(btn, args);
+			} else {
+				btn.set_working();					
+				me.update_security(args);
+			}
+		};
+		
+	},
+	update_security: function(args) {
+		var me = wn.pages.users;
+		$c_page('utilities', 'users', 'update_security', JSON.stringify(args), function(r,rt) {
+			if(r.exc) {
+				msgprint(r.exc);				
+				return;
+			}
+			me.settings_dialog.hide();
+			$.extend(me.profiles[me.uid], me.settings_dialog.get_values());
+			me.refresh();
+		});
+	},
+	get_password: function(btn, args) {
+		var me = wn.pages.users;
+		var pass_d = new wn.widgets.Dialog({
+			title: 'Your Password',
+			width: 300,
+			fields: [
+				{
+					label: 'Please Enter <b style="color: black">Your Password</b>',
+					description: "Your password is required to update the user's password",
+					fieldtype: 'Password', fieldname: 'sys_admin_pwd', reqd: 1		
+				},
+				{
+					label: 'Continue', fieldtype: 'Button', fieldname: 'continue'
+				}
+			]
+		});
+
+		pass_d.fields_dict.continue.input.onclick = function() {
+			btn.pwd_dialog.hide();					
+			args.sys_admin_pwd = btn.pwd_dialog.get_values().sys_admin_pwd;					
+			btn.set_working();					
+			me.update_security(args);
+			btn.done_working();
+		}
+
+		pass_d.show();
+		btn.pwd_dialog = pass_d;
+		btn.done_working();	
+	},
+	add_user: function() {
+		var me = wn.pages.users;
+		var d = new wn.widgets.Dialog({
+			title: 'Add User',
+			width: 400,
+			fields: [{
+					fieldtype: 'Data', fieldname: 'user', reqd: 1, 
+					label: 'Email Id of the user to add'
+				}, {
+					fieldtype: 'Data', fieldname: 'first_name', reqd: 1, label: 'First Name'
+				}, {
+					fieldtype: 'Data', fieldname: 'last_name', label: 'Last Name'
+				}, {
+					fieldtype: 'Data', fieldname: 'password', reqd: 1, label: 'Password'
+				}, {
+					fieldtype: 'Button', label: 'Add', fieldname: 'add'
+				}]
+		});
+		
+		d.make();
+		d.fields_dict.add.input.onclick = function() {
+			v = d.get_values();
+			if(v) {
+				d.fields_dict.add.input.set_working();
+				$c_page('utilities', 'users', 'add_user', v, function(r,rt) {
+					if(r.exc) { msgprint(r.exc); return; }
+					else {
+						d.hide();
+						me.refresh();
+					}
+				})
+			}
+		}
+		d.show();		
+	}
+});
+
+erpnext.RoleEditor = Class.extend({
+	init: function() {
+		this.dialog = new wn.widgets.Dialog({
+			title: 'Set Roles'
+		});
+		var me = this;
+		$(this.dialog.body).html('<div class="help">Loading...</div>')
+		wn.call({
+			method:'utilities.page.users.users.get_roles',
+			callback: function(r) {
+				me.roles = r.message;
+				me.show_roles();
+			}
+		});
+	},
+	show_roles: function() {
+		var me = this;
+		$(this.dialog.body).empty();
+		for(var i in this.roles) {
+			$(this.dialog.body).append(repl('<div class="user-role" \
+				data-user-role="%(role)s">\
+				<input type="checkbox"> \
+				<a href="#"><i class="icon-question-sign"></i></a> %(role)s\
+			</div>', {role: this.roles[i]}));
+		}
+		$(this.dialog.body).append('<div style="clear: both">\
+			<button class="btn btn-small btn-primary">Save</button></div>');
+		$(this.dialog.body).find('button.btn-primary').click(function() {
+			me.save();
+		});
+		$(this.dialog.body).find('.user-role a').click(function() {
+			me.show_permissions($(this).parent().attr('data-user-role'))
+			return false;
+		})
+	},
+	show: function(uid) {
+		var me = this;
+		this.uid = uid;
+		this.dialog.show();
+		// set user roles
+		wn.call({
+			method:'utilities.page.users.users.get_user_roles',
+			args: {uid:uid},
+			callback: function(r, rt) {
+				$(me.dialog.body).find('input[type="checkbox"]').attr('checked', false);
+				for(var i in r.message) {
+					$(me.dialog.body)
+						.find('[data-user-role="'+r.message[i]
+							+'"] input[type="checkbox"]').attr('checked',true);
+				}
+			}
+		})
+	},
+	save: function() {
+		var set_roles = [];
+		var unset_roles = [];
+		$(this.dialog.body).find('[data-user-role]').each(function() {
+			var $check = $(this).find('input[type="checkbox"]');
+			if($check.attr('checked')) {
+				set_roles.push($(this).attr('data-user-role'));
+			} else {
+				unset_roles.push($(this).attr('data-user-role'));
+			}
+		})
+		wn.call({
+			method:'utilities.page.users.users.update_roles',
+			args: {
+				set_roles: JSON.stringify(set_roles),
+				unset_roles: JSON.stringify(unset_roles),
+				uid: this.uid
+			},
+			btn: $(this.dialog.body).find('.btn-primary').get(0),
+			callback: function() {
+				
+			}
+		})
+	},
+	show_permissions: function(role) {
+		// show permissions for a role
+		var me = this;
+		if(!this.perm_dialog)
+			this.make_perm_dialog()
+		$(this.perm_dialog.body).empty();
+		wn.call({
+			method:'utilities.page.users.users.get_perm_info',
+			args: {role: role},
+			callback: function(r) {
+				var $body = $(me.perm_dialog.body);
+				$body.append('<table class="user-perm"><tbody><tr>\
+					<th style="text-align: left">Document Type</th>\
+					<th>Level</th>\
+					<th>Read</th>\
+					<th>Write</th>\
+					<th>Submit</th>\
+					<th>Cancel</th>\
+					<th>Amend</th></tr></tbody></table>');
+				for(var i in r.message) {
+					var perm = r.message[i];
+					
+					// if permission -> icon
+					for(key in perm) {
+						if(key!='parent' && key!='permlevel') {
+							if(perm[key]) {
+								perm[key] = '<i class="icon-ok"></i>';
+							} else {
+								perm[key] = '';
+							}							
+						}
+					}
+					
+					$body.find('tbody').append(repl('<tr>\
+						<td style="text-align: left">%(parent)s</td>\
+						<td>%(permlevel)s</td>\
+						<td>%(read)s</td>\
+						<td>%(write)s</td>\
+						<td>%(submit)s</td>\
+						<td>%(cancel)s</td>\
+						<td>%(amend)s</td>\
+						</tr>', perm))
+				}
+				
+				me.perm_dialog.show();
+			}
+		});
+		
+	},
+	make_perm_dialog: function() {
+		this.perm_dialog = new wn.widgets.Dialog({
+			title:'Role Permissions',
+			width: 500
+		});
+	}
+})
diff --git a/erpnext/utilities/page/users/users.py b/erpnext/utilities/page/users/users.py
new file mode 100644
index 0000000..44e2fb2
--- /dev/null
+++ b/erpnext/utilities/page/users/users.py
@@ -0,0 +1,192 @@
+# ERPNext - web based ERP (http://erpnext.com)
+# Copyright (C) 2012 Web Notes Technologies Pvt Ltd
+# 
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+import webnotes
+import json
+
+from webnotes.model.doc import Document
+from webnotes.utils import cint
+
+@webnotes.whitelist()
+def get(arg=None):
+	"""return all users"""
+	return webnotes.conn.sql("""select name, file_list, enabled, gender,
+	 	restrict_ip, login_before, login_after from tabProfile
+		where docstatus<2 and name not in ('Administrator', 'Guest') order by
+		ifnull(enabled,0) desc, name""", as_dict=1)
+
+@webnotes.whitelist()
+def get_roles(arg=None):
+	"""return all roles"""
+	return [r[0] for r in webnotes.conn.sql("""select name from tabRole
+		where name not in ('Administrator', 'Guest', 'All') order by name""")]
+
+@webnotes.whitelist()
+def get_user_roles(arg=None):
+	"""get roles for a user"""
+	return [r[0] for r in webnotes.conn.sql("""select role from tabUserRole
+		where parent=%s""", webnotes.form_dict['uid'])]
+
+@webnotes.whitelist()
+def get_perm_info(arg=None):
+	"""get permission info"""
+	return webnotes.conn.sql("""select parent, permlevel, `read`, `write`, submit,
+		cancel, amend from tabDocPerm where role=%s 
+		and docstatus<2 order by parent, permlevel""", 
+			webnotes.form_dict['role'], as_dict=1)
+
+@webnotes.whitelist()
+def update_roles(arg=None):
+	"""update set and unset roles"""
+	# remove roles
+	unset = json.loads(webnotes.form_dict['unset_roles'])
+	webnotes.conn.sql("""delete from tabUserRole where parent='%s' 
+		and role in ('%s')""" % (webnotes.form_dict['uid'], "','".join(unset)))
+
+	# check for 1 system manager
+	if not webnotes.conn.sql("""select parent from tabUserRole where role='System Manager'
+		and docstatus<2"""):
+		webnotes.msgprint("Sorry there must be atleast one 'System Manager'")
+		raise webnotes.ValidationError
+
+	# add roles
+	roles = get_user_roles()
+	toset = json.loads(webnotes.form_dict['set_roles'])
+	for role in toset:
+		if not role in roles:
+			d = Document('UserRole')
+			d.role = role
+			d.parent = webnotes.form_dict['uid']
+			d.save()
+	
+	webnotes.msgprint('Roles Updated')
+
+@webnotes.whitelist()
+def update_security(args=''):
+	args = json.loads(args)
+	webnotes.conn.set_value('Profile', args['user'], 'restrict_ip', args.get('restrict_ip'))
+	webnotes.conn.set_value('Profile', args['user'], 'login_after', args.get('login_after'))
+	webnotes.conn.set_value('Profile', args['user'], 'login_before', args.get('login_before'))
+	webnotes.conn.set_value('Profile', args['user'], 'enabled', int(args.get('enabled',0)) or 0)
+
+	if 'new_password' in args:
+		if cint(webnotes.conn.get_value('Control Panel',None,'sync_with_gateway')):
+			import server_tools.gateway_utils
+			res = server_tools.gateway_utils.change_password('', args['new_password'], 
+				args['user'], args['sys_admin_pwd'])
+			if 'Traceback' not in res['message']:
+				webnotes.msgprint(res['message'])
+		webnotes.conn.sql("update tabProfile set password=password(%s) where name=%s", 
+			(args['new_password'], args['user']))
+	else: 
+		webnotes.msgprint('Settings Updated')
+
+
+
+#
+# user addition
+#
+
+@webnotes.whitelist()
+def add_user(args):
+	args = json.loads(args)
+	# erpnext-saas
+	if cint(webnotes.conn.get_value('Control Panel', None, 'sync_with_gateway')):
+		from server_tools.gateway_utils import add_user_gateway
+		add_user_gateway(args['user'])
+	
+	add_profile(args)
+	
+@webnotes.whitelist()
+def add_profile(args):
+	from webnotes.utils import validate_email_add, now
+	email = args['user']
+			
+	sql = webnotes.conn.sql
+	
+	if not email:
+		email = webnotes.form_dict.get('user')
+	if not validate_email_add(email):
+		raise Exception
+		return 'Invalid Email Id'
+	
+	if sql("select name from tabProfile where name = %s", email):
+		# exists, enable it
+		sql("update tabProfile set enabled = 1, docstatus=0 where name = %s", email)
+		webnotes.msgprint('Profile exists, enabled it with new password')
+	else:
+		# does not exist, create it!
+		pr = Document('Profile')
+		pr.name = email
+		pr.email = email
+		pr.first_name = args.get('first_name')
+		pr.last_name = args.get('last_name')
+		pr.enabled = 1
+		pr.user_type = 'System User'
+		pr.save(1)
+
+	if args.get('password'):
+		sql("""
+			UPDATE tabProfile 
+			SET password = PASSWORD(%s), modified = %s
+			WHERE name = %s""", (args.get('password'), now, email))
+
+	send_welcome_mail(email, args)
+
+@webnotes.whitelist()
+def send_welcome_mail(email, args):
+	"""send welcome mail to user with password and login url"""
+	pr = Document('Profile', email)
+	from webnotes.utils.email_lib import sendmail_md
+	args.update({
+		'company': webnotes.conn.get_default('company'),
+		'password': args.get('password'),
+		'account_url': webnotes.conn.get_default('account_url')
+	})
+	if not args.get('last_name'): args['last_name'] = ''
+	sendmail_md(pr.email, subject="Welcome to ERPNext", msg=welcome_txt % args, from_defs=1)
+
+#
+# delete user
+#
+@webnotes.whitelist()
+def delete(arg=None):
+	"""delete user"""
+	webnotes.conn.sql("update tabProfile set enabled=0, docstatus=2 where name=%s", 
+		webnotes.form_dict['uid'])
+	# erpnext-saas
+	if int(webnotes.conn.get_value('Control Panel', None, 'sync_with_gateway')):
+		from server_tools.gateway_utils import remove_user_gateway
+		remove_user_gateway(webnotes.form_dict['uid'])
+
+	webnotes.login_manager.logout(user=webnotes.form_dict['uid'])
+	
+welcome_txt = """
+## %(company)s
+
+Dear %(first_name)s %(last_name)s
+
+Welcome!
+
+A new account has been created for you, here are your details:
+
+login-id: %(user)s
+password: %(password)s
+
+To login to your new ERPNext account, please go to:
+
+%(account_url)s
+"""
\ No newline at end of file
diff --git a/erpnext/utilities/page/users/users.txt b/erpnext/utilities/page/users/users.txt
new file mode 100644
index 0000000..165cc16
--- /dev/null
+++ b/erpnext/utilities/page/users/users.txt
@@ -0,0 +1,28 @@
+# Page, users
+[
+
+	# These values are common in all dictionaries
+	{
+		'creation': '2012-02-28 10:29:39',
+		'docstatus': 0,
+		'modified': '2012-02-28 10:29:39',
+		'modified_by': u'Administrator',
+		'owner': u'Administrator'
+	},
+
+	# These values are common for all Page
+	{
+		'doctype': 'Page',
+		'module': u'Utilities',
+		'name': '__common__',
+		'page_name': u'users',
+		'standard': u'Yes',
+		'title': u'Users'
+	},
+
+	# Page, users
+	{
+		'doctype': 'Page',
+		'name': u'users'
+	}
+]
\ No newline at end of file