2013-03-07 5 views
6

Мы думаем использовать Jira для отслеживания ошибок и интегрировать его с Git для исправления ошибок с обработкой версии.Jira для отслеживания ошибок и поддержки клиентов?

Вы рекомендуете Jira также для поддержки клиентов или мы должны найти другую систему, например, Zendesk для этой цели? Я знаю, что можно каким-то образом интегрировать, например, Hipchat с Jira, чтобы включить функции чата с клиентами, но Jira слишком сложна для обслуживания клиентов? Каков ваш опыт?

+0

Отличный вопрос - мне также интересно видеть ответы. – Brandon

ответ

14

Мы используем Jira для поддержки пользователей, но мы обнаружили, что у Jira отсутствуют многие обязательные функции, которые необходимы для этого. поэтому мы делаем много изменений.

Мы все очень довольны нашим выбором, и нам удалось сэкономить много денег, используя Jira вместо других решений.

Вот основные изменения, которые мы сделали, это покажет вам, что не хватает, а с другой стороны, показать вам, что с немного программирования, Jira может сделать что-нибудь :)

Примечание: Сценарии Нижеприведенный сценарий должен быть прикреплен к переходу рабочего процесса. Сценарии написаны с использованием Jython, поэтому его необходимо установить для его использования.

Создать вопросы по электронной почте

Jira только отправляет сообщения пользователей Jira. Поскольку мы не хотели создавать пользователя для каждого человека, который обратился к этой поддержке, мы использовали анонимных пользователей и использовали сценарии для отправки им электронной почты.

Во-первых, установите Jira на create issues from emails. Затем используйте Script Runner pluging, чтобы сохранить электронную почту и имена клиентов в настраиваемом поле. , Код:

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 protected]>] 
     # 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 protected]] 
     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's 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) 

Отправить клиент issue created уведомление

Отправить почту с помощью следующего сценария:

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._%+-][email protected](?:[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 = '[email protected]' 
    subject = "["+key+"] Thank You for Contacting Support team" 
    mail_user = '[email protected]' 
    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) 

Содержание 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 

Iss у.е напоминание - открыто для 24/36/48 часов уведомлений

  • создал пользовательское поле под названием «Open так» - поле «Date Time», чтобы провести время был открыт вопрос.
  • Создал пользовательское поле под названием «Уведомление» - текстовое поле только для чтения.
  • Используя Script Runner pluging, я создал пост-функцию и поместил ее при каждом переходе в состояние «Открыть». Это должно сохранить время открытия проблемы.

код:

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) 
  • Я создал новый фильтр, чтобы получить список вопросов, которые открыты в течение более 24 часов:

JQL:

project = XXX AND status= Open ORDER BY updated ASC, key DESC 
  • Наконец-то я использовал метод Jira remote API - XML-RPC для написания скрипта python, который должен запускаться каждые 5 минут. Сценарий считывает все выданное из фильтра, вытягивает все из них, которые имеют статус «Открыть» более 24 ч/36 ч/48 ч, отправляют электронное письмо с напоминанием и отмечают их как уведомление, поэтому только одно напоминание каждого типа будет послал.

код питона:

#!/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 = '[email protected]' 
mail_user = '[email protected]' 
mail_password = 'password' 
toAddr = '[email protected]' 
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') 

Основные плюсы этого метода является то, что это очень настраиваемый, и сохранять данные в пользовательских полях легко создавать фильтры и отчеты, чтобы показать проблемы, которые были долгое время открывался.

Эскалация команде разработчиков

Создать новый переход - Escalate. Это создаст проблему для команды разработчиков и свяжет новую проблему с проблемой поддержки. Добавьте следующую запись функции:

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) 

Переход к продажам

reate новый переход - Move to sales. Многие вызовы поддержки оказываются в качестве звонка на продажу, это переместит проблему в команду продаж. Добавьте следующую функцию сообщения:

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) 
+0

Спасибо большое! Я так доволен вашим ответом! – user2144454

Смежные вопросы