Jira for bug tracking and customer support?

We are thinking of using Jira to track bugs and integrate it with Git to fix bugs in version handling.

Do you recommend Jira also for customer support or should we find another system, for example, Zendesk for this purpose? I know that you can somehow integrate, for example, Hipchat with Jira to enable chat features with customers, but is Jira too complicated for customer service? What is your experience?

+6
source share
1 answer

We use Jira to support customers, but we found that Jira lacks many of the required features that are required for this. why we make a lot of changes.

Everyone and everyone, we are very happy with our choice, and we managed to save a lot of money using Jira instead of other solutions.

Here are the main changes that we made, it will show you what is missing, and on the other hand I will show you that with a little programming Jira can do everything :)

Note. The scenarios below should be attached to a workflow transition. Scripts are written using Jython , so you need to install it to use it.

Create Email Issues

Jira sends emails only to Jira users. Since we don’t want to create a user for each person who accessed this support, we used anonymous users and used scripts to send them email.

First install Jira in create problems from emails . Then use Script Launch Player to save the email and customer names in a custom field., Code:

 from com.atlassian.jira import ComponentManager import re cfm = ComponentManager.getInstance().getCustomFieldManager() # read issue description description = issue.getDescription() if (description is not None) and ('Created via e-mail received from' in description): # extract email and name: if ('<' in description) and ('>' in description): # pattern [Created via e-mail received from: name < email@company.com >] # split it to a list description_list = re.split('<|>|:',description) list_length = len(description_list) for index in range(list_length-1, -1, -1): if '@' in description_list[index]: customer_email = description_list[index] customer_name = description_list[index - 1] break else: # pattern [Created via e-mail received from: email@company.com ] customer_name = "Sir or Madam" # split it to a list description_list = re.split(': |]',description) list_length = len(description_list) for index in range(list_length-1, -1, -1): if '@' in description_list[index]: customer_email = description_list[index] break # if the name isn't in the right form, switch it places: if (customer_name[0] == '"') and (customer_name[-1] == '"') and (',' in customer_name): customer_name = customer_name[1:-1] i = customer_name.index(',') customer_name = customer_name[i+2:]+" "+customer_name[:i] # insert data to issue fields issue.setCustomFieldValue(cfm.getCustomFieldObject("customfield_10401"),customer_email) issue.setCustomFieldValue(cfm.getCustomFieldObject("customfield_10108"),customer_name) 

Send client notification issue created

Send a message using the following script:

 import smtplib,email from smtplib import SMTP from email.MIMEMultipart import MIMEMultipart from email.MIMEBase import MIMEBase from email.MIMEText import MIMEText from email import Encoders import os import re from com.atlassian.jira import ComponentManager customFieldManager = ComponentManager.getInstance().getCustomFieldManager() cfm = ComponentManager.getInstance().getCustomFieldManager() # read needed fields from the issue key = issue.getKey() #status = issue.getStatusObject().name summary = issue.getSummary() project = issue.getProjectObject().name # read customer email address toAddr = issue.getCustomFieldValue(cfm.getCustomFieldObject("customfield_10401")) # send mail only if a valid email was entered if (toAddr is not None) and (re.match('[A-Za-z0-9._%+-] +@ (?:[A-Za-z0-9-]+\.)+[A-Za-z]{2,4}',toAddr)): # read customer name customerName = issue.getCustomFieldValue(cfm.getCustomFieldObject("customfield_10108")) # read template from the disk template_file = 'new_case.template' f = open(template_file, 'r') htmlBody = "" for line in f: line = line.replace('$$CUSTOMER_NAME',customerName) line = line.replace('$$KEY',key) line = line.replace('$$PROJECT',project) line = line.replace('$$SUMMARY',summary) htmlBody += line + '<BR>' smtpserver = 'smtpserver.com' to = [toAddr] fromAddr = ' jira@email.com ' subject = "["+key+"] Thank You for Contacting Support team" mail_user = ' jira@email.com ' mail_password = 'password' # create html email html = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" ' html +='"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml">' html +='<body style="font-size:12px;font-family:Verdana">' html +='<p align="center"><img src="http://path/to/company_logo.jpg" alt="logo"></p> ' html +='<p>'+htmlBody+'</p>' html +='</body></html>' emailMsg = email.MIMEMultipart.MIMEMultipart('alternative') emailMsg['Subject'] = subject emailMsg['From'] = fromAddr emailMsg['To'] = ', '.join(to) emailMsg.attach(email.mime.text.MIMEText(html,'html')) # Send the email s = SMTP(smtpserver) # ip or domain name of smtp server s.login(mail_user, mail_password) s.sendmail(fromAddr, [to], emailMsg.as_string()) s.quit() # add sent mail to comments cm = ComponentManager.getInstance().getCommentManager() email_body = htmlBody.replace('<BR>','\n') cm.create(issue,'anonymous','Email was sent to the customer ; Subject: '+subject+'\n'+email_body,False) 

the contents of new_case.template :

 Dear $$CUSTOMER_NAME, Thank you for contacting support team. We will address your case as soon as possible and respond with a solution very quickly. Issue key $$KEY has been created as a reference for future correspondence. If you need urgent support please refer to our Frequently Asked Questions page at http://www.example.com/faq. Thank you, Support Team Issue key: $$KEY Issue subject: $$PROJECT Issue summary: $$SUMMARY 

Problem Reminder - Open for notifications 24/36/48 hours

  • Created a custom field called "Open With" - the "Date Time" field to save the time when the problem was opened.
  • Created a custom field called "Notification" - a read-only text field.
  • Using Script Runner pluging , I created a post-function and placed it with each transition to the "Open" state of affairs. This should provide a time to open the problem.

code:

 from com.atlassian.jira import ComponentManager from datetime import datetime opend_since_field = "customfield_10001" # get opened since custom field: cfm = ComponentManager.getInstance().getCustomFieldManager() # get current time currentTime = datetime.today() # save current time issue.setCustomFieldValue(cfm.getCustomFieldObject(opend_since_field),currentTime) 
  • I created a new filter to get a list of issues that have been open for more than 24 hours:

JQL:

 project = XXX AND status= Open ORDER BY updated ASC, key DESC 
  • Finally, I used the Jira remote API - XML-RPC to write a python script that is scheduled to run every 5 minutes. The script reads all released from the filter, pulls out all of them that have the Open status for more than 24 hours 36 hours 48 hours, send an email with a reminder and mark it as a notification, so only one reminder of each type will be sent.

Python code:

 #!/usr/bin/python # Refer to the XML-RPC Javadoc to see what calls are available: # http://docs.atlassian.com/software/jira/docs/api/rpc-jira-plugin/latest/com/atlassian/jira/rpc/xmlrpc/XmlRpcService.html # /home/issues_reminder.py import xmlrpclib import time from time import mktime from datetime import datetime from datetime import timedelta import smtplib,email from smtplib import SMTP from email.MIMEMultipart import MIMEMultipart from email.MIMEBase import MIMEBase from email.MIMEText import MIMEText from email import Encoders # Jira connction info server = 'https://your.jira.com/rpc/xmlrpc' user = 'user' password = 'password' filter = '10302' # Filter ID # Email definitions smtpserver = 'mail.server.com' fromAddr = ' support@your.jira.com ' mail_user = ' jira_admin@your.domain.com ' mail_password = 'password' toAddr = ' support@your.domain.com ' mysubject = "hrs Issue notification!!!" opend_since_field = "customfield_10101" COMMASPACE = ', ' def email_issue(issue,esc_time): # create html email subject = '['+issue+'] '+esc_time+mysubject html = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" ' html +='"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml">' html +='<body style="font-size:12px;font-family:Verdana">' html +='<p align="center"><img src="your_logo.jpg" alt="logo" height="43" width="198"></p> ' html +='<p> The issue ['+issue+'] is open for over '+esc_time+' hours.</p>' html +='<p> A link to view the issue: https://your.jira.com/browse/'+issue+'.</p>' html +='<BR><p> This is an automated email sent from Jira.</p>' html +='</body></html>' emailMsg = email.MIMEMultipart.MIMEMultipart('alternative') emailMsg['Subject'] = subject emailMsg['From'] = fromAddr emailMsg['To'] = toAddr emailMsg.attach(MIMEText(html, 'html')) # Send the email emailserver = SMTP(smtpserver) # ip or domain name of smtp server emailserver.login(mail_user, mail_password) emailserver.sendmail(fromAddr, [toAddr], emailMsg.as_string()) emailserver.quit() return s = xmlrpclib.ServerProxy(server) auth = s.jira1.login(user, password) esc12List = [] esc24List = [] esc48List = [] issues = s.jira1.getIssuesFromFilter(auth, filter) print "Modifying issue..." for issue in issues: creation = 0; # get open since time for customFields in issue['customFieldValues']: if customFields['customfieldId'] == opend_since_field : print "found field!"+ customFields['values'] creation = customFields['values'] if (creation == 0): creation = issue['created'] print "field not found" creationTime = datetime.fromtimestamp(mktime(time.strptime(creation, '%d/%b/%y %I:%M %p'))) currentTime = datetime.fromtimestamp(mktime(time.gmtime())) delta = currentTime - creationTime esc12 = timedelta(hours=12) esc24 = timedelta(hours=24) esc48 = timedelta(hours=48) print "\nchecking issue "+issue['key'] if (delta < esc12): print "less than 12 hours" print "not updating" continue if (delta < esc24): print "less than 24 hours" for customFields in issue['customFieldValues']: if customFields['customfieldId'] == 'customfield_10412': if customFields['values'] == '12h': print "not updating" break else: print "updating !!!" s.jira1.updateIssue(auth, issue['key'], {"customfield_10412": ["12h"]}) esc12List.append(issue['key']) break continue if (delta < esc48): print "less than 48 hours" for customFields in issue['customFieldValues']: if customFields['customfieldId'] == 'customfield_10412': if customFields['values'] == '24h': print "not updating" break else: print "updating !!!" s.jira1.updateIssue(auth, issue['key'], {"customfield_10412": ["24h"]}) esc24List.append(issue['key']) break continue print "more than 48 hours" for customFields in issue['customFieldValues']: if customFields['customfieldId'] == 'customfield_10412': if customFields['values'] == '48h': print "not updating" break else: print "updating !!!" s.jira1.updateIssue(auth, issue['key'], {"customfield_10412": ["48h"]}) esc48List.append(issue['key']) break for key in esc12List: email_issue(key,'12') for key in esc24List: email_issue(key,'24') for key in esc48List: email_issue(key,'48') 

The main advantages of this method are that it is very customizable, and by storing data in custom areas, it is easy to create filters and reports to display problems that have been open for a long time.

Escalation to the development team

Create a new transition - Escalate . This will create a problem for the development team and link the new problem with the support problem. Add the following message function:

 from com.atlassian.jira.util import ImportUtils from com.atlassian.jira import ManagerFactory from com.atlassian.jira.issue import MutableIssue from com.atlassian.jira import ComponentManager from com.atlassian.jira.issue.link import DefaultIssueLinkManager from org.ofbiz.core.entity import GenericValue; # get issue objects issueManager = ComponentManager.getInstance().getIssueManager() issueFactory = ComponentManager.getInstance().getIssueFactory() authenticationContext = ComponentManager.getInstance().getJiraAuthenticationContext() issueLinkManager = ComponentManager.getInstance().getIssueLinkManager() customFieldManager = ComponentManager.getInstance().getCustomFieldManager() userUtil = ComponentManager.getInstance().getUserUtil() projectMgr = ComponentManager.getInstance().getProjectManager() customer_name = customFieldManager.getCustomFieldObjectByName("Customer Name") customer_email = customFieldManager.getCustomFieldObjectByName("Customer Email") escalate = customFieldManager.getCustomFieldObjectByName("Escalate to Development") if issue.getCustomFieldValue(escalate) is not None: # define issue issueObject = issueFactory.getIssue() issueObject.setProject(projectMgr.getProject(10000)) issueObject.setIssueTypeId("1") # bug # set subtask attributes issueObject.setSummary("[Escalated from support] "+issue.getSummary()) issueObject.setAssignee(userUtil.getUserObject("nadav")) issueObject.setReporter(issue.getAssignee()) issueObject.setDescription(issue.getDescription()) issueObject.setCustomFieldValue(customer_name, issue.getCustomFieldValue(customer_name)+" "+issue.getCustomFieldValue(customer_email)) issueObject.setComponents(issue.getComponents()) # Create subtask subTask = issueManager.createIssue(authenticationContext.getUser(), issueObject) # Link parent issue to subtask issueLinkManager.createIssueLink(issueObject.getId(),issue.getId(),10003,1,authenticationContext.getUser()) # Update search indexes ImportUtils.setIndexIssues(True); ComponentManager.getInstance().getIndexManager().reIndex(subTask) ImportUtils.setIndexIssues(False) 

Go to sales

create a new transition - Move to sales . Many support calls turn out to be a sell call; this will move the problem to the sales team. Add the following message function:

 from com.atlassian.jira.util import ImportUtils from com.atlassian.jira.issue import MutableIssue from com.atlassian.jira import ComponentManager customFieldManager = ComponentManager.getInstance().getCustomFieldManager() userUtil = ComponentManager.getInstance().getUserUtil() issue.setStatusId("1"); issue.setAssignee(userUtil.getUserObject("John")) issue.setSummary("[Moved from support] "+issue.getSummary()) issue.setProjectId(10201); issue.setIssueTypeId("35"); ImportUtils.setIndexIssues(True); ComponentManager.getInstance().getIndexManager().reIndex(issue) ImportUtils.setIndexIssues(False) # add to comments from time import gmtime, strftime time = strftime("%d-%m-%Y %H:%M:%S", gmtime()) cm = ComponentManager.getInstance().getCommentManager() currentUser = ComponentManager.getInstance().getJiraAuthenticationContext().getUser().toString() cm.create(issue,currentUser,'Email was moved to Sales at '+time,False) 
+14
source

All Articles