[website] [minor] moving to framework
diff --git a/accounts/doctype/sales_invoice/templates/pages/invoice.py b/accounts/doctype/sales_invoice/templates/pages/invoice.py
index 7196a30..200727c 100644
--- a/accounts/doctype/sales_invoice/templates/pages/invoice.py
+++ b/accounts/doctype/sales_invoice/templates/pages/invoice.py
@@ -7,7 +7,7 @@
 no_cache = True
 
 def get_context():
-	from portal.website_transactions import get_transaction_context
+	from portal.utils import get_transaction_context
 	context = get_transaction_context("Sales Invoice", webnotes.form_dict.name)
 	context.update({
 		"parent_link": "invoices",
diff --git a/accounts/doctype/sales_invoice/templates/pages/invoices.py b/accounts/doctype/sales_invoice/templates/pages/invoices.py
index c72903b..ec957f3 100644
--- a/accounts/doctype/sales_invoice/templates/pages/invoices.py
+++ b/accounts/doctype/sales_invoice/templates/pages/invoices.py
@@ -7,7 +7,7 @@
 no_cache = True
 
 def get_context():
-	from portal.website_transactions import get_currency_context
+	from portal.utils import get_currency_context
 	context = get_currency_context()
 	context.update({
 		"title": "Invoices",
@@ -20,5 +20,5 @@
 	
 @webnotes.whitelist()
 def get_invoices(start=0):
-	from portal.website_transactions import get_transaction_list
+	from portal.utils import get_transaction_list
 	return get_transaction_list("Sales Invoice", start)
\ No newline at end of file
diff --git a/portal/templates/includes/transactions.html b/portal/templates/includes/transactions.html
index 65651ca..036a77c 100644
--- a/portal/templates/includes/transactions.html
+++ b/portal/templates/includes/transactions.html
@@ -6,6 +6,8 @@
     	<li><a href="index">Home</a></li>
     	<li class="active"><i class="{{ icon }} icon-fixed-width"></i> {{ title }}</li>
     </ul>
+	<p id="msgprint-alert" class="alert alert-danger" 
+		style="display: none;">&nbsp;</p>
 	<div class="list-group transaction-list">
 		<div class="progress progress-striped active">
 			<div class="progress-bar progress-bar-info" style="width: 100%;"></div>
@@ -35,7 +37,6 @@
 		callback: function(r) {
 			$list.find(".progress").remove();
 			$show_more.toggleClass("hide", !(r.message && r.message.length===20));
-		
 			if(!(r.message && r.message.length)) {
 				console.log("empty");
 				if(!$list.html().trim()) {
diff --git a/portal/website_transactions.py b/portal/utils.py
similarity index 75%
rename from portal/website_transactions.py
rename to portal/utils.py
index 21e9111..25da39c 100644
--- a/portal/website_transactions.py
+++ b/portal/utils.py
@@ -47,4 +47,17 @@
 			"doclist": bean.doclist,
 			"webnotes": webnotes,
 			"utils": webnotes.utils
-		}
\ No newline at end of file
+		}
+
+@webnotes.whitelist(allow_guest=True)
+def send_message(subject="Website Query", message="", sender="", status="Open"):
+	from website.doctype.contact_us_settings.templates.pages.contact \
+		import send_message as website_send_message
+	
+	if not website_send_message(subject, message, sender):
+		return
+	
+	# make lead / communication
+	from selling.doctype.lead.get_leads import add_sales_communication
+	add_sales_communication(subject or "Website Query", message, sender, sender, 
+		mail=None, status=status)
\ No newline at end of file
diff --git a/public/js/website_utils.js b/public/js/website_utils.js
index b42a986..fceb8f6 100644
--- a/public/js/website_utils.js
+++ b/public/js/website_utils.js
@@ -5,14 +5,18 @@
 
 // Add / update a new Lead / Communication
 // subject, sender, description
-erpnext.send_message = function(opts) {
+wn.send_message = function(opts, btn) {
 	return wn.call({
 		type: "POST",
-		method: "selling.utils.contact.send_message",
+		method: "portal.utils.send_message",
+		btn: btn,
 		args: opts,
 		callback: opts.callback
 	});
-}
+};
+
+// for backward compatibility
+erpnext.send_message = wn.send_message;
 
 // Setup the user tools
 //
diff --git a/selling/doctype/sales_order/templates/pages/order.py b/selling/doctype/sales_order/templates/pages/order.py
index f25a521..6152e17 100644
--- a/selling/doctype/sales_order/templates/pages/order.py
+++ b/selling/doctype/sales_order/templates/pages/order.py
@@ -7,7 +7,7 @@
 no_cache = True
 
 def get_context():
-	from portal.website_transactions import get_transaction_context
+	from portal.utils import get_transaction_context
 	context = get_transaction_context("Sales Order", webnotes.form_dict.name)
 	context.update({
 		"parent_link": "orders",
diff --git a/selling/doctype/sales_order/templates/pages/orders.py b/selling/doctype/sales_order/templates/pages/orders.py
index 204e3f7..aea81a9 100644
--- a/selling/doctype/sales_order/templates/pages/orders.py
+++ b/selling/doctype/sales_order/templates/pages/orders.py
@@ -7,7 +7,7 @@
 no_cache = True
 
 def get_context():
-	from portal.website_transactions import get_currency_context
+	from portal.utils import get_currency_context
 	context = get_currency_context()
 	context.update({
 		"title": "My Orders",
@@ -20,6 +20,6 @@
 	
 @webnotes.whitelist()
 def get_orders(start=0):
-	from portal.website_transactions import get_transaction_list
+	from portal.utils import get_transaction_list
 	return get_transaction_list("Sales Order", start)
 	
\ No newline at end of file
diff --git a/selling/utils/contact.py b/selling/utils/contact.py
deleted file mode 100644
index 35446a3..0000000
--- a/selling/utils/contact.py
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
-# License: GNU General Public License v3. See license.txt
-
-from __future__ import unicode_literals
-
-import webnotes
-from webnotes.utils import now
-
-max_communications_per_hour = 300
-
-@webnotes.whitelist(allow_guest=True)
-def send_message(subject="Website Query", message="", sender="", status="Open"):
-	if not message:
-		webnotes.response["message"] = 'Please write something'
-		return
-		
-	if not sender:
-		webnotes.response["message"] = 'Email Id Required'
-		return
-
-	# make lead / communication
-	from selling.doctype.lead.get_leads import add_sales_communication
-	message = add_sales_communication(subject or "Website Query", message, sender, sender, 
-		mail=None, status=status)
-	
-	# guest method, cap max writes per hour
-	if webnotes.conn.sql("""select count(*) from `tabCommunication`
-		where TIMEDIFF(%s, modified) < '01:00:00'""", now())[0][0] > max_communications_per_hour:
-		webnotes.response["message"] = "Sorry: we believe we have received an unreasonably high number of requests of this kind. Please try later"
-		return
-	
-	webnotes.response.status = "okay"
diff --git a/stock/doctype/delivery_note/templates/pages/shipment.py b/stock/doctype/delivery_note/templates/pages/shipment.py
index 60dc9d8..a33203b 100644
--- a/stock/doctype/delivery_note/templates/pages/shipment.py
+++ b/stock/doctype/delivery_note/templates/pages/shipment.py
@@ -7,7 +7,7 @@
 no_cache = True
 
 def get_context():
-	from portal.website_transactions import get_transaction_context
+	from portal.utils import get_transaction_context
 	context = get_transaction_context("Delivery Note", webnotes.form_dict.name)
 	context.update({
 		"parent_link": "shipments",
diff --git a/stock/doctype/delivery_note/templates/pages/shipments.py b/stock/doctype/delivery_note/templates/pages/shipments.py
index 48c636d..8b29149 100644
--- a/stock/doctype/delivery_note/templates/pages/shipments.py
+++ b/stock/doctype/delivery_note/templates/pages/shipments.py
@@ -7,7 +7,7 @@
 no_cache = True
 
 def get_context():
-	from portal.website_transactions import get_currency_context
+	from portal.utils import get_currency_context
 	context = get_currency_context()
 	context.update({
 		"title": "Shipments",
@@ -20,5 +20,5 @@
 	
 @webnotes.whitelist()
 def get_shipments(start=0):
-	from portal.website_transactions import get_transaction_list
+	from portal.utils import get_transaction_list
 	return get_transaction_list("Delivery Note", start)
diff --git a/support/doctype/support_ticket/get_support_mails.py b/support/doctype/support_ticket/get_support_mails.py
index fa4f304..02f7ea8 100644
--- a/support/doctype/support_ticket/get_support_mails.py
+++ b/support/doctype/support_ticket/get_support_mails.py
@@ -3,7 +3,7 @@
 
 from __future__ import unicode_literals
 import webnotes
-from webnotes.utils import cstr, cint, decode_dict
+from webnotes.utils import cstr, cint, decode_dict, today
 from webnotes.utils.email_lib import sendmail		
 from webnotes.utils.email_lib.receive import POP3Mailbox
 from core.doctype.communication.communication import make
@@ -22,32 +22,13 @@
 		if mail.from_email == self.email_settings.fields.get('support_email'):
 			return
 		thread_id = mail.get_thread_id()
-		ticket = None
 		new_ticket = False
 
-		if thread_id and webnotes.conn.exists("Support Ticket", thread_id):
-			ticket = webnotes.bean("Support Ticket", thread_id)
-			ticket.doc.status = 'Open'
-			ticket.doc.save()
-				
-		else:
-			ticket = webnotes.bean([decode_dict({
-				"doctype":"Support Ticket",
-				"description": mail.content,
-				"subject": mail.subject,
-				"raised_by": mail.from_email,
-				"content_type": mail.content_type,
-				"status": "Open",
-			})])
-						
-			ticket.insert()
+		if not (thread_id and webnotes.conn.exists("Support Ticket", thread_id)):
 			new_ticket = True
-
-		mail.save_attachments_in_doc(ticket.doc)
-				
-		make(content=mail.content, sender=mail.from_email, subject = ticket.doc.subject,
-			doctype="Support Ticket", name=ticket.doc.name,
-			date=mail.date)
+		
+		ticket = add_support_communication(mail.subject, mail.content, mail.from_email,
+			docname=thread_id if new_ticket else None, mail=mail)
 			
 		if new_ticket and cint(self.email_settings.send_autoreply) and \
 			"mailer-daemon" not in mail.from_email.lower():
@@ -78,4 +59,31 @@
 
 def get_support_mails():
 	if cint(webnotes.conn.get_value('Email Settings', None, 'sync_support_mails')):
-		SupportMailbox()
\ No newline at end of file
+		SupportMailbox()
+		
+def add_support_communication(subject, content, sender, docname=None, mail=None):
+	if docname:
+		ticket = webnotes.bean("Support Ticket", docname)
+		ticket.doc.status = 'Open'
+		ticket.ignore_permissions = True
+		ticket.doc.save()
+	else:
+		ticket = webnotes.bean([decode_dict({
+			"doctype":"Support Ticket",
+			"description": content,
+			"subject": subject,
+			"raised_by": sender,
+			"content_type": mail.content_type if mail else None,
+			"status": "Open",
+		})])
+		ticket.ignore_permissions = True
+		ticket.insert()
+	
+	make(content=content, sender=sender, subject = subject,
+		doctype="Support Ticket", name=ticket.doc.name,
+		date=mail.date if mail else today())
+
+	if mail:
+		mail.save_attachments_in_doc(ticket.doc)
+		
+	return ticket
\ No newline at end of file
diff --git a/support/doctype/support_ticket/templates/pages/ticket.html b/support/doctype/support_ticket/templates/pages/ticket.html
index 1cfab9b..3584d7b 100644
--- a/support/doctype/support_ticket/templates/pages/ticket.html
+++ b/support/doctype/support_ticket/templates/pages/ticket.html
@@ -38,17 +38,27 @@
 			<span class="text-muted">{{ utils.formatdate(doc.creation) }}</span>
 		</div>
 	</div>
-	<br>
-	<h4>Messages</h4>
+	<div class="row">
+		<h4 class="col-xs-6">Messages</h4>
+		<div class="col-xs-6">
+			 <button class="btn btn-sm btn-primary pull-right" id="ticket-reply">
+				  <i class="icon-envelope icon-fixed-width"></i> Reply</button>
+			 <button class="btn btn-sm btn-success pull-right hide" id="ticket-reply-send">
+				  <i class="icon-arrow-right icon-fixed-width"></i> Send</button>
+		</div>
+	</div>
+	<p id="ticket-alert" class="alert alert-danger" 
+		style="display: none;">&nbsp;</p>
 	{%- if doclist.get({"doctype":"Communication"}) -%}
 	<div>
-		<table class="table table-bordered table-striped">
+		<table class="table table-bordered table-striped" id="ticket-thread">
 			<tbody>
-				{%- for comm in doclist.get({"doctype":"Communication"}) %}
+				{%- for comm in 
+					(doclist.get({"doctype":"Communication"})|sort(reverse=True, attribute="creation")) %}
 				<tr>
 					<td>
 					<h5 style="text-transform: none">
-						{{ comm.sender }} on {{ utils.formatdate(doc.modified) }}</h5>
+						{{ comm.sender }} on {{ utils.formatdate(comm.creation) }}</h5>
 					<hr>
 					<p>{{ webnotes.utils.is_html(comm.content) and comm.content or
 						comm.content.replace("\n", "<br>")}}</p>
@@ -64,4 +74,49 @@
 	{%- endif -%}
 	{% endif -%}
 </div>
+{% endblock %}
+
+{% block javascript %}
+<script>
+$(document).ready(function() {
+	$("#ticket-reply").on("click", function() {
+		if(!$("#ticket-reply-editor").length) {
+			$('<tr id="ticket-reply-editor"><td>\
+				<h5 style="text-transform: none">Reply</h5>\
+				<hr>\
+				<textarea rows=10 class="form-control" style="resize: vertical;"></textarea>\
+			</td></tr>').prependTo($("#ticket-thread").find("tbody"));
+			$("#ticket-reply").addClass("hide");
+			$("#ticket-reply-send").removeClass("hide");
+		}
+	});
+	
+	$("#ticket-reply-send").on("click", function() {
+		var reply = $("#ticket-reply-editor").find("textarea").val().trim();
+		if(!reply) {
+			msgprint("Please write something in reply!");
+		} else {
+			wn.call({
+				type: "POST",
+				method: "support.doctype.support_ticket.templates.pages.ticket.add_reply",
+				btn: this,
+				args: { ticket: "{{ doc.name }}", message: reply },
+				callback: function(r) {
+					if(r.exc) {
+						msgprint(r._server_messages 
+							? JSON.parse(r._server_messages).join("<br>")
+							: "Something went wrong!");
+					} else {
+						window.location.reload();
+					}
+				}
+			})
+		}
+	});
+});
+
+var msgprint = function(txt) {
+	if(txt) $("#ticket-alert").html(txt).toggle(true);
+}
+</script>
 {% endblock %}
\ No newline at end of file
diff --git a/support/doctype/support_ticket/templates/pages/ticket.py b/support/doctype/support_ticket/templates/pages/ticket.py
index 999f69f..ce3100f 100644
--- a/support/doctype/support_ticket/templates/pages/ticket.py
+++ b/support/doctype/support_ticket/templates/pages/ticket.py
@@ -3,6 +3,8 @@
 
 from __future__ import unicode_literals
 import webnotes
+from webnotes import _
+from webnotes.utils import today
 
 no_cache = True
 
@@ -19,3 +21,17 @@
 			"webnotes": webnotes,
 			"utils": webnotes.utils
 		}
+
+@webnotes.whitelist()
+def add_reply(ticket, message):
+	if not message:
+		raise webnotes.throw(_("Please write something"))
+	
+	bean = webnotes.bean("Support Ticket", ticket)
+	if bean.doc.raised_by != webnotes.session.user:
+		raise webnotes.throw(_("You are not allowed to reply to this ticket."), webnotes.PermissionError)
+	
+	from core.doctype.communication.communication import make
+	make(content=message, sender=bean.doc.raised_by, subject = bean.doc.subject,
+		doctype="Support Ticket", name=bean.doc.name,
+		date=today())
\ No newline at end of file
diff --git a/support/doctype/support_ticket/templates/pages/tickets.html b/support/doctype/support_ticket/templates/pages/tickets.html
index d3e316c..d99e614 100644
--- a/support/doctype/support_ticket/templates/pages/tickets.html
+++ b/support/doctype/support_ticket/templates/pages/tickets.html
@@ -29,5 +29,59 @@
 				</div>\
 			</a>', doc)).appendTo($list);
 	};
+	
+	$(document).ready(function() {
+		if(!window.$new_ticket) {
+			window.$new_ticket = $('<div>\
+					<button class="btn btn-primary" style="margin-bottom: 15px;" id="new-ticket">\
+						<i class="icon-tag icon-fixed-width"></i> New Ticket\
+					</button>\
+					<button class="btn btn-success hide" style="margin-bottom: 15px;" id="new-ticket-send">\
+						<i class="icon-arrow-right icon-fixed-width"></i> Send\
+					</button>\
+				</div>').insertBefore(".transaction-list");
+		}
+		
+		window.$new_ticket.find("#new-ticket").on("click", function() {
+			$(this).addClass("hide");
+			$(window.$new_ticket).find("#new-ticket-send").removeClass("hide");
+			$('<div class="well" id="ticket-editor">\
+					<div class="form-group"><input class="form-control" type="data"\
+						 placeholder="Subject" data-fieldname="subject"></div>\
+					<div class="form-group"><textarea rows=10 class="form-control" \
+						 style="resize: vertical;" placeholder="Message" \
+						 data-fieldname="message"></textarea></div>\
+				</div>')
+				.insertAfter(window.$new_ticket);
+		});
+		
+		window.$new_ticket.find("#new-ticket-send").on("click", function() {
+			var subject = $("#ticket-editor").find('[data-fieldname="subject"]').val().trim();
+			var message = $("#ticket-editor").find('[data-fieldname="message"]').val().trim();
+			if(!(subject && message)) {
+				msgprint("Please write something in subject and message!");
+			} else {
+				wn.call({
+					type: "POST",
+					method: "support.doctype.support_ticket.templates.pages.tickets.make_new_ticket",
+					btn: this,
+					args: { subject: subject, message: message },
+					callback: function(r) {
+						if(r.exc) {
+							msgprint(r._server_messages 
+								? JSON.parse(r._server_messages).join("<br>")
+								: "Something went wrong!");
+						} else {
+							window.location.href = "ticket?name=" + encodeURIComponent(r.message);
+						}
+					}
+				})
+			}
+		});
+	});
+	
+	var msgprint = function(txt) {
+		if(txt) $("#msgprint-alert").html(txt).toggle(true);
+	}
 </script>
 {%- endblock %}
\ No newline at end of file
diff --git a/support/doctype/support_ticket/templates/pages/tickets.py b/support/doctype/support_ticket/templates/pages/tickets.py
index f434746..dd2e52e 100644
--- a/support/doctype/support_ticket/templates/pages/tickets.py
+++ b/support/doctype/support_ticket/templates/pages/tickets.py
@@ -25,4 +25,14 @@
 	for t in tickets:
 		t.creation = formatdate(t.creation)
 	
-	return tickets
\ No newline at end of file
+	return tickets
+	
+@webnotes.whitelist()
+def make_new_ticket(subject, message):
+	if not (subject and message):
+		raise webnotes.throw(_("Please write something in subject and message!"))
+		
+	from support.doctype.support_ticket.get_support_mails import add_support_communication
+	ticket = add_support_communication(subject, message, webnotes.session.user)
+	
+	return ticket.doc.name
\ No newline at end of file
diff --git a/support/doctype/support_ticket/templates/ticket.html b/support/doctype/support_ticket/templates/ticket.html
deleted file mode 100644
index b7d2f2b..0000000
--- a/support/doctype/support_ticket/templates/ticket.html
+++ /dev/null
@@ -1,66 +0,0 @@
-{% extends base_template %}
-
-{% set title=doc.name %}
-
-{% set status_label = {
-	"Open": "label-success",
-	"To Reply": "label-danger",
-	"Closed": "label-default"
-} %}
-
-{% block content %}
-<div class="col-md-12">
-    <ul class="breadcrumb">
-    	<li><a href="index">Home</a></li>
-    	<li><a href="tickets">My Tickets</a></li>
-    	<li class="active"><i class="icon-ticket icon-fixed-width"></i> {{ doc.name }}</li>
-    </ul>
-	<h3><i class="icon-ticket icon-fixed-width"></i> {{ doc.name }}</h3>
-	{% if doc.name == "Not Allowed" -%}
-		<script>ask_to_login();</script>
-	{% else %}
-	<hr>
-	{%- if doc.status -%}
-	{% if doc.status == "Waiting for Customer" -%}
-		{% set status = "To Reply" %}
-	{% else %}
-		{% set status = doc.status %}
-	{%- endif -%}
-	<div class="row">
-		<div class="col-md-2" style="margin-bottom: 7px;">
-			<span class="label {{ status_label.get(status) or 'label-default' }}">{{ status }}</span>
-		</div>
-		<div class="col-md-8">
-			<div class="row col-md-12">{{ doc.subject }}</div>
-		</div>
-		<div class="col-md-2 pull-right">
-			<span class="text-muted">{{ utils.formatdate(doc.creation) }}</span>
-		</div>
-	</div>
-	<br>
-	<h4>Messages</h4>
-	{%- if doclist.get({"doctype":"Communication"}) -%}
-	<div>
-		<table class="table table-bordered table-striped">
-			<tbody>
-				{%- for comm in doclist.get({"doctype":"Communication"}) %}
-				<tr>
-					<td>
-					<h5 style="text-transform: none">
-						{{ comm.sender }} on {{ utils.formatdate(doc.modified) }}</h5>
-					<hr>
-					<p>{{ webnotes.utils.is_html(comm.content) and comm.content or
-						comm.content.replace("\n", "<br>")}}</p>
-					</td>
-				</tr>
-				{% endfor -%}
-			</tbody>
-		</table>
-	</div>
-	{%- else -%}
-	<div class="alert">No messages</div>
-	{%- endif -%}
-	{%- endif -%}
-	{% endif -%}
-</div>
-{% endblock %}
\ No newline at end of file