merge
diff --git a/patches/january_2013/update_closed_on.py b/patches/january_2013/update_closed_on.py
new file mode 100644
index 0000000..138549a
--- /dev/null
+++ b/patches/january_2013/update_closed_on.py
@@ -0,0 +1,32 @@
+import webnotes
+
+def execute():
+ webnotes.reload_doc("core", "doctype", "docfield")
+ webnotes.reload_doc("support", "doctype", "support_ticket")
+
+ # customer issue resolved_by should be Profile
+ if webnotes.conn.sql("""select count(*) from `tabCustomer Issue`
+ where ifnull(resolved_by,"")!="" """)[0][0]:
+ webnotes.make_property_setter({
+ "doctype":"Customer Issue",
+ "fieldname": "resolved_by",
+ "property": "options",
+ "value": "Sales Person"
+ })
+
+ def get_communication_time(support_ticket, sort_order = 'asc'):
+ tmp = webnotes.conn.sql("""select creation from tabCommunication where
+ support_ticket=%s order by creation %s limit 1""" % ("%s", sort_order),
+ support_ticket)
+ return tmp and tmp[0][0] or None
+
+ # update in support ticket
+ webnotes.conn.auto_commit_on_many_writes = True
+ for st in webnotes.conn.sql("""select name, modified, status from
+ `tabSupport Ticket`""", as_dict=1):
+
+ webnotes.conn.sql("""update `tabSupport Ticket` set first_responded_on=%s where
+ name=%s""", (get_communication_time(st.name) or st.modified, st.name))
+ if st.status=="Closed":
+ webnotes.conn.sql("""update `tabSupport Ticket` set resolution_date=%s where
+ name=%s""", (get_communication_time(st.name, 'desc') or st.modified, st.name))
diff --git a/projects/doctype/task/task.py b/projects/doctype/task/task.py
index 83f8995..79fca9a 100644
--- a/projects/doctype/task/task.py
+++ b/projects/doctype/task/task.py
@@ -17,7 +17,7 @@
from __future__ import unicode_literals
import webnotes
-from webnotes.utils import getdate
+from webnotes.utils import getdate, today
from webnotes.model import db_exists
from webnotes.model.wrapper import copy_doclist
from webnotes import msgprint
@@ -40,7 +40,7 @@
if cust:
ret = {'customer_name': cust and cust[0][0] or ''}
return ret
-
+
def validate(self):
if self.doc.exp_start_date and self.doc.exp_end_date and getdate(self.doc.exp_start_date) > getdate(self.doc.exp_end_date):
msgprint("'Expected Start Date' can not be greater than 'Expected End Date'")
@@ -49,4 +49,14 @@
if self.doc.act_start_date and self.doc.act_end_date and getdate(self.doc.act_start_date) > getdate(self.doc.act_end_date):
msgprint("'Actual Start Date' can not be greater than 'Actual End Date'")
raise Exception
+
+ self.update_status()
+ def update_status(self):
+ status = webnotes.conn.get_value("Task", self.doc.name, "status")
+ if self.doc.status=="Working" and status !="Working" and not self.doc.act_start_date:
+ self.doc.act_start_date = today()
+
+ if self.doc.status=="Closed" and status != "Closed" and not self.doc.act_end_date:
+ self.doc.act_end_date = today()
+
\ No newline at end of file
diff --git a/projects/doctype/task/task.txt b/projects/doctype/task/task.txt
index 9b8c2eb..e95c456 100644
--- a/projects/doctype/task/task.txt
+++ b/projects/doctype/task/task.txt
@@ -2,9 +2,9 @@
{
"owner": "Administrator",
"docstatus": 0,
- "creation": "2012-10-29 14:30:00",
+ "creation": "2013-01-10 16:34:17",
"modified_by": "Administrator",
- "modified": "2013-01-02 12:40:26"
+ "modified": "2013-01-14 14:03:52"
},
{
"autoname": "TASK.#####",
@@ -28,6 +28,8 @@
"parent": "Task",
"read": 1,
"doctype": "DocPerm",
+ "submit": 0,
+ "report": 1,
"parenttype": "DocType",
"role": "Projects User",
"parentfield": "permissions"
@@ -192,14 +194,6 @@
"fieldtype": "Date"
},
{
- "oldfieldtype": "Data",
- "doctype": "DocField",
- "label": "Total Hours (Actual)",
- "oldfieldname": "act_total_hrs",
- "fieldname": "act_total_hrs",
- "fieldtype": "Data"
- },
- {
"oldfieldtype": "Currency",
"doctype": "DocField",
"label": "Actual Budget",
@@ -253,7 +247,6 @@
"amend": 0,
"create": 0,
"doctype": "DocPerm",
- "submit": 0,
"cancel": 0,
"permlevel": 1
}
diff --git a/public/js/utils.js b/public/js/utils.js
index 805f578..436c532 100644
--- a/public/js/utils.js
+++ b/public/js/utils.js
@@ -34,6 +34,7 @@
var defaults = {
posting_date: wn.datetime.get_today(),
+ posting_time: wn.datetime.now_time()
}
$.each(defaults, function(k, v) {
diff --git a/startup/report_data_map.py b/startup/report_data_map.py
index 41d6cb8..228a8ae 100644
--- a/startup/report_data_map.py
+++ b/startup/report_data_map.py
@@ -219,7 +219,7 @@
# Support
"Support Ticket": {
- "columns": ["name","status","creation","modified"],
+ "columns": ["name","status","creation","resolution_date","first_responded_on"],
"conditions": ["docstatus < 2"],
"order_by": "creation"
}
diff --git a/stock/doctype/stock_ledger_entry/stock_ledger_entry.py b/stock/doctype/stock_ledger_entry/stock_ledger_entry.py
index 9b73c6b..2b1af33 100644
--- a/stock/doctype/stock_ledger_entry/stock_ledger_entry.py
+++ b/stock/doctype/stock_ledger_entry/stock_ledger_entry.py
@@ -102,6 +102,4 @@
def scrub_posting_time(self):
if not self.doc.posting_time or self.doc.posting_time == '00:0':
self.doc.posting_time = '00:00'
- if len(self.doc.posting_time.split(':')) > 2:
- self.doc.posting_time = '00:00'
\ No newline at end of file
diff --git a/support/doctype/customer_issue/customer_issue.js b/support/doctype/customer_issue/customer_issue.js
index 835509f..523b240 100644
--- a/support/doctype/customer_issue/customer_issue.js
+++ b/support/doctype/customer_issue/customer_issue.js
@@ -15,15 +15,17 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
cur_frm.cscript.onload = function(doc,cdt,cdn){
- if(!doc.status) set_multiple(dt,dn,{status:'Open'});
+ if(!doc.status)
+ set_multiple(dt,dn,{status:'Open'});
if(doc.__islocal){
hide_field(['customer_address','contact_person']);
- }
+ }
}
cur_frm.cscript.refresh = function(doc,ct,cdn){
if(doc.docstatus == 1 && (doc.status == 'Open' || doc.status == 'Work In Progress'))
- cur_frm.add_custom_button('Make Maintenance Visit', cur_frm.cscript['Make Maintenance Visit']);
+ cur_frm.add_custom_button('Make Maintenance Visit',
+ cur_frm.cscript['Make Maintenance Visit']);
}
@@ -109,11 +111,9 @@
cur_frm.add_fetch('serial_no', 'maintenance_status', 'warranty_amc_status');
cur_frm.add_fetch('serial_no', 'warranty_expiry_date', 'warranty_expiry_date');
cur_frm.add_fetch('serial_no', 'amc_expiry_date', 'amc_expiry_date');
-if (cstr(doc.customer) == '') {
- cur_frm.add_fetch('serial_no', 'customer', 'customer');
- cur_frm.add_fetch('serial_no', 'customer_name', 'customer_name');
- cur_frm.add_fetch('serial_no', 'delivery_address', 'customer_address');
-}
+cur_frm.add_fetch('serial_no', 'customer', 'customer');
+cur_frm.add_fetch('serial_no', 'customer_name', 'customer_name');
+cur_frm.add_fetch('serial_no', 'delivery_address', 'customer_address');
// ----------
// item code
diff --git a/support/doctype/customer_issue/customer_issue.py b/support/doctype/customer_issue/customer_issue.py
index 0a08d82..af93f33 100644
--- a/support/doctype/customer_issue/customer_issue.py
+++ b/support/doctype/customer_issue/customer_issue.py
@@ -21,6 +21,7 @@
from webnotes.model import db_exists
from webnotes.model.wrapper import copy_doclist
from webnotes import session, msgprint
+from webnotes.utils import today
sql = webnotes.conn.sql
@@ -43,6 +44,11 @@
if session['user'] != 'Guest' and not self.doc.customer:
msgprint("Please select Customer from whom issue is raised",
raise_exception=True)
+
+ if self.doc.status=="Closed" and \
+ webnotes.conn.get_value("Customer Issue", self.doc.name, "status")!="Closed":
+ self.doc.resolution_date = today()
+ self.doc.resolved_by = webnotes.session.user
def on_cancel(self):
lst = sql("select t1.name from `tabMaintenance Visit` t1, `tabMaintenance Visit Purpose` t2 where t2.parent = t1.name and t2.prevdoc_docname = '%s' and t1.docstatus!=2"%(self.doc.name))
diff --git a/support/doctype/customer_issue/customer_issue.txt b/support/doctype/customer_issue/customer_issue.txt
index 9225eb3..1b01803 100644
--- a/support/doctype/customer_issue/customer_issue.txt
+++ b/support/doctype/customer_issue/customer_issue.txt
@@ -2,9 +2,9 @@
{
"owner": "harshada@webnotestech.com",
"docstatus": 0,
- "creation": "2012-11-28 11:26:23",
+ "creation": "2013-01-10 16:34:30",
"modified_by": "Administrator",
- "modified": "2012-12-03 17:10:41"
+ "modified": "2013-01-14 12:41:48"
},
{
"is_submittable": 1,
@@ -27,6 +27,7 @@
"read": 1,
"doctype": "DocPerm",
"parenttype": "DocType",
+ "report": 1,
"parentfield": "permissions"
},
{
@@ -51,7 +52,6 @@
"permlevel": 0,
"no_copy": 1,
"oldfieldtype": "Select",
- "colour": "White:FFF",
"doctype": "DocField",
"label": "Status",
"oldfieldname": "status",
@@ -87,12 +87,10 @@
{
"print_hide": 1,
"oldfieldtype": "Link",
- "colour": "White:FFF",
"doctype": "DocField",
"label": "Customer",
"oldfieldname": "customer",
"permlevel": 0,
- "trigger": "Client",
"fieldname": "customer",
"fieldtype": "Link",
"search_index": 1,
@@ -140,28 +138,24 @@
},
{
"description": "Item, Warranty, AMC (Annual Maintenance Contract) details will be automatically fetched when Serial Number is selected.",
- "colour": "White:FFF",
"doctype": "DocField",
"label": "Serial No",
- "trigger": "Client",
+ "options": "Serial No",
"fieldname": "serial_no",
"fieldtype": "Link",
- "options": "Serial No",
"permlevel": 0
},
{
"oldfieldtype": "Link",
- "colour": "White:FFF",
"doctype": "DocField",
"label": "Item Code",
"oldfieldname": "item_code",
- "permlevel": 0,
- "trigger": "Client",
+ "options": "Item",
"fieldname": "item_code",
"fieldtype": "Link",
"search_index": 1,
"reqd": 0,
- "options": "Item",
+ "permlevel": 0,
"in_filter": 1
},
{
@@ -174,7 +168,6 @@
},
{
"oldfieldtype": "Data",
- "colour": "White:FFF",
"doctype": "DocField",
"label": "Item Name",
"oldfieldname": "item_name",
@@ -185,7 +178,6 @@
},
{
"oldfieldtype": "Small Text",
- "colour": "White:FFF",
"doctype": "DocField",
"label": "Description",
"oldfieldname": "description",
@@ -196,7 +188,6 @@
"permlevel": 1
},
{
- "colour": "White:FFF",
"doctype": "DocField",
"label": "Warranty / AMC Status",
"options": "\nUnder Warranty\nOut of Warranty\nUnder AMC\nOut of AMC",
@@ -223,7 +214,6 @@
{
"description": "To assign this issue, use the \"Assign\" button in the sidebar.",
"oldfieldtype": "Section Break",
- "colour": "White:FFF",
"doctype": "DocField",
"label": "Resolution",
"options": "Simple",
@@ -238,7 +228,7 @@
"label": "Resolution Date",
"oldfieldname": "resolution_date",
"fieldname": "resolution_date",
- "fieldtype": "Date",
+ "fieldtype": "Datetime",
"search_index": 1,
"permlevel": 0,
"in_filter": 1
@@ -249,7 +239,7 @@
"doctype": "DocField",
"label": "Resolved By",
"oldfieldname": "resolved_by",
- "options": "Sales Person",
+ "options": "Profile",
"fieldname": "resolved_by",
"fieldtype": "Link",
"search_index": 1,
@@ -300,7 +290,6 @@
{
"print_hide": 1,
"oldfieldtype": "Link",
- "colour": "White:FFF",
"doctype": "DocField",
"label": "Territory",
"oldfieldname": "territory",
@@ -373,12 +362,10 @@
{
"print_hide": 1,
"oldfieldtype": "Link",
- "colour": "White:FFF",
"doctype": "DocField",
"label": "Company",
"oldfieldname": "company",
"permlevel": 0,
- "trigger": "Client",
"fieldname": "company",
"fieldtype": "Link",
"search_index": 1,
diff --git a/support/doctype/support_ticket/support_ticket.js b/support/doctype/support_ticket/support_ticket.js
index 3484bf3..159dddd 100644
--- a/support/doctype/support_ticket/support_ticket.js
+++ b/support/doctype/support_ticket/support_ticket.js
@@ -85,25 +85,26 @@
},
'Close Ticket': function() {
- var doc = cur_frm.doc
- if(doc.name)
- $c_obj(make_doclist(doc.doctype, doc.name),'close_ticket','',function(r,rt) {
- if(!r.exc) {
- cur_frm.refresh();
- }
- });
+ cur_frm.cscript.set_status("Closed");
},
'Re-Open Ticket': function() {
- var doc = cur_frm.doc
- if(doc.name)
- $c_obj(make_doclist(doc.doctype, doc.name),'reopen_ticket','',function(r,rt) {
- if(!r.exc) {
- cur_frm.refresh();
- }
- });
- }
+ cur_frm.cscript.set_status("Open");
+ },
+ set_status: function(status) {
+ wn.call({
+ method:"support.doctype.support_ticket.support_ticket.set_status",
+ args: {
+ name: cur_frm.doc.name,
+ status: status
+ },
+ callback: function(r) {
+ if(!r.exc) cur_frm.reload_doc();
+ }
+ })
+
+ }
})
diff --git a/support/doctype/support_ticket/support_ticket.py b/support/doctype/support_ticket/support_ticket.py
index 0f4a25e..43b8283 100644
--- a/support/doctype/support_ticket/support_ticket.py
+++ b/support/doctype/support_ticket/support_ticket.py
@@ -19,6 +19,7 @@
from utilities.transaction_base import TransactionBase
from home import update_feed
+from webnotes.utils import now
class DocType(TransactionBase):
def __init__(self, doc, doclist=[]):
@@ -40,6 +41,9 @@
if signature:
content += '<p>' + signature + '</p>'
return content
+
+ def validate(self):
+ self.update_status()
def on_communication_sent(self, comm):
webnotes.conn.set(self.doc, 'status', 'Waiting for Customer')
@@ -47,15 +51,23 @@
webnotes.conn.set(self.doc, 'lead', comm.lead)
if comm.contact and not self.doc.contact:
webnotes.conn.set(self.doc, 'contact', comm.contact)
-
- def close_ticket(self):
- webnotes.conn.set(self.doc,'status','Closed')
- update_feed(self)
-
- def reopen_ticket(self):
- webnotes.conn.set(self.doc,'status','Open')
- update_feed(self)
-
+
def on_trash(self):
webnotes.conn.sql("""update `tabCommunication` set support_ticket=NULL
where support_ticket=%s""", (self.doc.name,))
+
+ def update_status(self):
+ status = webnotes.conn.get_value("Support Ticket", self.doc.name, "status")
+ if self.doc.status!="Open" and status =="Open":
+ self.doc.first_responded_on = now()
+ if self.doc.status=="Closed" and status !="Closed":
+ self.doc.resolution_date = now()
+ if self.doc.status=="Open" and status !="Open":
+ self.doc.resolution_date = ""
+
+@webnotes.whitelist()
+def set_status(name, status):
+ st = webnotes.model_wrapper("Support Ticket", name)
+ st.doc.status = status
+ st.save()
+
diff --git a/support/doctype/support_ticket/support_ticket.txt b/support/doctype/support_ticket/support_ticket.txt
index b2bdadb..b475db5 100644
--- a/support/doctype/support_ticket/support_ticket.txt
+++ b/support/doctype/support_ticket/support_ticket.txt
@@ -2,9 +2,9 @@
{
"owner": "Administrator",
"docstatus": 0,
- "creation": "2012-11-02 17:17:05",
+ "creation": "2013-01-10 16:34:31",
"modified_by": "Administrator",
- "modified": "2012-11-28 10:45:19"
+ "modified": "2013-01-14 14:15:37"
},
{
"autoname": "naming_series:",
@@ -25,10 +25,11 @@
"name": "__common__",
"parent": "Support Ticket",
"amend": 0,
- "submit": 0,
"doctype": "DocPerm",
+ "submit": 0,
"read": 1,
"parenttype": "DocType",
+ "report": 1,
"parentfield": "permissions"
},
{
@@ -52,7 +53,6 @@
"permlevel": 1,
"no_copy": 1,
"oldfieldtype": "Select",
- "colour": "White:FFF",
"doctype": "DocField",
"label": "Status",
"oldfieldname": "status",
@@ -117,7 +117,6 @@
"permlevel": 1
},
{
- "colour": "White:FFF",
"doctype": "DocField",
"label": "Additional Info",
"fieldname": "additional_info",
@@ -152,12 +151,10 @@
{
"print_hide": 1,
"oldfieldtype": "Link",
- "colour": "White:FFF",
"doctype": "DocField",
"label": "Customer",
"oldfieldname": "customer",
"permlevel": 1,
- "trigger": "Client",
"fieldname": "customer",
"fieldtype": "Link",
"search_index": 1,
@@ -218,31 +215,26 @@
"permlevel": 1
},
{
- "depends_on": "eval:!doc.__islocal",
+ "doctype": "DocField",
+ "label": "First Responded On",
+ "fieldname": "first_responded_on",
+ "fieldtype": "Datetime",
+ "permlevel": 0
+ },
+ {
"no_copy": 1,
- "search_index": 0,
- "colour": "White:FFF",
+ "depends_on": "eval:!doc.__islocal",
"doctype": "DocField",
"label": "Resolution Date",
"oldfieldname": "resolution_date",
"fieldname": "resolution_date",
- "fieldtype": "Date",
+ "fieldtype": "Datetime",
+ "search_index": 0,
"oldfieldtype": "Date",
"permlevel": 1,
"in_filter": 0
},
{
- "oldfieldtype": "Time",
- "doctype": "DocField",
- "label": "Resolution Time",
- "oldfieldname": "resolution_time",
- "fieldname": "resolution_time",
- "fieldtype": "Time",
- "depends_on": "eval:!doc.__islocal",
- "permlevel": 1
- },
- {
- "colour": "White:FFF",
"doctype": "DocField",
"label": "Content Type",
"fieldname": "content_type",
diff --git a/support/page/support_analytics/support_analytics.js b/support/page/support_analytics/support_analytics.js
index e310df3..60384bb 100644
--- a/support/page/support_analytics/support_analytics.js
+++ b/support/page/support_analytics/support_analytics.js
@@ -53,8 +53,12 @@
checked:true};
var days_to_close = {status:"Days to Close", "id":"days-to-close",
checked:false};
+ var total_closed = {};
var hours_to_close = {status:"Hours to Close", "id":"hours-to-close",
checked:false};
+ var hours_to_respond = {status:"Hours to Respond", "id":"hours-to-respond",
+ checked:false};
+ var total_responded = {};
$.each(wn.report_dump.data["Support Ticket"], function(i, d) {
@@ -62,25 +66,40 @@
var date = d.creation.split(" ")[0];
var col = me.column_map[date];
if(col) {
- // just count
- var day_diff = dateutil.get_diff(d.modified, d.creation);
- var hour_diff = dateutil.get_hour_diff(d.modified, d.creation);
-
total_tickets[col.field] = flt(total_tickets[col.field]) + 1;
- days_to_close[col.field] = flt(days_to_close[col.field]) + day_diff;
- hours_to_close[col.field] = flt(hours_to_close[col.field]) + hour_diff;
+ if(d.status=="Closed") {
+ // just count
+ total_closed[col.field] = flt(total_closed[col.field]) + 1;
+
+ days_to_close[col.field] = flt(days_to_close[col.field])
+ + dateutil.get_diff(d.resolution_date, d.creation);
+
+ hours_to_close[col.field] = flt(hours_to_close[col.field])
+ + dateutil.get_hour_diff(d.resolution_date, d.creation);
+
+ }
+ if (d.first_responded_on) {
+ total_responded[col.field] = flt(total_responded[col.field]) + 1;
+
+ hours_to_respond[col.field] = flt(hours_to_respond[col.field])
+ + dateutil.get_hour_diff(d.first_responded_on, d.creation);
+ }
}
});
// make averages
$.each(this.columns, function(i, col) {
if(col.formatter==me.currency_formatter && total_tickets[col.field]) {
- days_to_close[col.field] = flt(days_to_close[col.field]) / flt(total_tickets[col.field]);
- hours_to_close[col.field] = flt(hours_to_close[col.field]) / flt(total_tickets[col.field]);
+ days_to_close[col.field] = flt(days_to_close[col.field]) /
+ flt(total_closed[col.field]);
+ hours_to_close[col.field] = flt(hours_to_close[col.field]) /
+ flt(total_closed[col.field]);
+ hours_to_respond[col.field] = flt(hours_to_respond[col.field]) /
+ flt(total_responded[col.field]);
}
})
- this.data = [total_tickets, days_to_close, hours_to_close];
+ this.data = [total_tickets, days_to_close, hours_to_close, hours_to_respond];
},
get_plot_points: function(item, col, idx) {