Different issue type and customer request type based on custom field value

Originally asked by Peter Pesta on 26 October 2021 (original question)


Dear community,

We´re trying to sync issues between two server instances (Jira core to JSM), where the Jira Core is the master system sending data to JSM.
Within Jira core we have a dedicated custom field where we declare which issue type (and corresponding customer request type) should be created on the JSM side.

However, no matter what we try to do, we end up having issues and the sync doesn´t work.

The logic:

If customfield value = A, create an incident and set the customer request type = A
If customfield value = B, create an change request and set the customer request type = B

If customfield value = C, create an problem and set the customer request type = C

If customfield value = D, create an task and set the customer request type = D

Currently we´re trying to send values from the sender side and have the decision in the incoming script of the recipient Jira instance.

if(replica.customFields."type of issue" == "Problem") {
  issue.projectKey   = "SYNC"
  issue.typeName     = "Fault"
  issue.customFields."Customer Request Type" = "Problem"
}
else if (replica.customFields."type of issue" == "Request") {
  issue.projectKey   = "SYNC"
  issue.typeName     = "Request"
  issue.customFields."Customer Request Type" = "Request"
}
else if (replica.customFields."type of issue" == "Change") {
  issue.projectKey   = "SYNC"
  issue.typeName     = "Change"
  issue.customFields."Customer Request Type" = "Change request"
}
else (replica.customFields."type of issue" == "Task") {
  issue.projectKey   = "SYNC"
  issue.typeName     = "Project issue"
  issue.customFields."Customer Request Type" = "Ordinary task"
}

Can anyone tell me how the incoming script of the recipient side should look like?

Thank you in advance,
Kind regards,
Peter


Answer by Francis Martens (Exalate) on 30 March 2022

Another variation on the question

The problem is, if we have an issue with issue type corrective and customer request type corrective, and we move, on Jira Software, the sync issue to a unplaned support issue type, we need exalate to update the customer request type to unplaned support.

Actually, this doesn’t update that field, if we do a JQL we can find an Unplaned Support with Corrective customer request type. Which is impossible due to the configuration.

Actually, the only solution we found is creating an automation which detects issue type field had changed, and changes the customer request type.


Comments:

Francis Martens (Exalate) commented on 30 March 2022

Regarding the customer request type - it can always be set as part of the logic which changes the issue.type

issue.type = replica.type

def requestName = [
       // typename is mapped to request type

       "Bug" : "IT Help",
       "Improvement" : "Change request",

       
]
// custom field 'request type' can have another name
issue."Request Type".value = requestName[replica.type.name] ?: "Default Request"


Answer by Serhiy Onyshchenko on 26 October 2021

Hello, Peter Pesta
Thanks for raising this on community!
Have you tried either using the .value after customfield name in the full notation:

if(replica.customFields."type of issue".value == "Problem") {
  issue.projectKey   = "SYNC"
  issue.typeName     = "Fault"
  issue.customFields."Customer Request Type".value = "Problem"
}
else if (replica.customFields."type of issue".value == "Request") {
  issue.projectKey   = "SYNC"
  issue.typeName     = "Request"
  issue.customFields."Customer Request Type".value = "Request"
}
else if (replica.customFields."type of issue".value == "Change") {
  issue.projectKey   = "SYNC"
  issue.typeName     = "Change"
  issue.customFields."Customer Request Type".value = "Change request"
}
else (replica.customFields."type of issue".value == "Task") {
  issue.projectKey   = "SYNC"
  issue.typeName     = "Project issue"
  issue.customFields."Customer Request Type".value = "Ordinary task"
}

Or using the shorthand customfield notation:

if(replica."type of issue" == "Problem") {
  issue.projectKey   = "SYNC"
  issue.typeName     = "Fault"
  issue."Customer Request Type" = "Problem"
}
else if (replica."type of issue" == "Request") {
  issue.projectKey   = "SYNC"
  issue.typeName     = "Request"
  issue."Customer Request Type" = "Request"
}
else if (replica."type of issue" == "Change") {
  issue.projectKey   = "SYNC"
  issue.typeName     = "Change"
  issue."Customer Request Type" = "Change request"
}
else (replica."type of issue" == "Task") {
  issue.projectKey   = "SYNC"
  issue.typeName     = "Project issue"
  issue."Customer Request Type" = "Ordinary task"
}

Regards, Serhiy.


Comments:

Peter Pesta commented on 27 October 2021

Hi Serhiy Onyshchenko ,

Yes, we tried this but didn´t manage to get it working.
Even tried .value.value as advised by Andrii.

Regards,
Peter

Serhiy Onyshchenko commented on 27 October 2021

Hello, Peter Pesta , did you get any errors?
Have you tried placing a debug.error(“special message”) into either of the if blocks to check if the “if” blocks were working?

Peter Pesta commented on 03 November 2021

Hi Serhiy Onyshchenko,

I do apologize for the delay, here´s the output:

  • Impact: ISSUE
  • Local entity: TESMOSD-562
  • Remote entity: SD-11636
  • Connection: mssr_to_icz2
  • Error type: Issue Tracker Error
  • Error Creation Time: 2021-10-14 14:20:41.0
  • Error Detail Message: Cannot set the Customer request type. You can assign only string value to a custom field. The assigned value was com.exalate.basic.domain.hubobject.v1.BasicHubOption
  • Error Stack Trace: com.exalate.api.exception.IssueTrackerException: Cannot set the Customer request type. You can assign only string value to a custom field. The assigned value was com.exalate.basic.domain.hubobject.v1.BasicHubOption at com.exalate.node.hubobject.v1_3.NodeHubObjectConversionService.getNodeVpOrigin(NodeHubObjectConversionService.java:1928) at com.exalate.node.hubobject.v1_3.NodeHubObjectConversionService.getNodeCustomFieldValue(NodeHubObjectConversionService.java:1434) at com.exalate.node.hubobject.v1_4.NodeHubIssueHelper.updateCustomFieldWith(NodeHubIssueHelper.java:1407) at com.exalate.node.hubobject.v1_4.NodeHubIssueHelper.updateCustomFieldsWith(NodeHubIssueHelper.java:1386) at com.exalate.node.hubobject.v1_4.NodeHubIssueHelper.applyFields(NodeHubIssueHelper.java:1240) at com.exalate.node.hubobject.v1_4.NodeHubIssueHelper.updateIssueWith(NodeHubIssueHelper.java:883) at com.exalate.node.hubobject.v1_4.NodeHubIssueHelper.updateIssueWith(NodeHubIssueHelper.java:780) at com.exalate.compatibility.HubObjectHelperAdapter.updateNodeIssueWith(HubObjectHelperAdapter.java:61) at com.exalate.hubobject.v1_2.HubObjectHelper.updateNodeIssueWith(HubObjectHelper.java:352) at com.exalate.processor.jira.JiraChangeIssueProcessor.applyProcessorResult(JiraChangeIssueProcessor.java:311) at com.exalate.processor.jira.JiraChangeIssueProcessor.changeIssue(JiraChangeIssueProcessor.java:201) at com.exalate.replication.request.UpdateIssueSyncRequestState.transition(UpdateIssueSyncRequestState.java:118) at com.exalate.replication.request.UpdateIssueSyncRequestState.transition(UpdateIssueSyncRequestState.java:36) at com.exalate.replication.in.RequestProcessorService.processSyncRequest(RequestProcessorService.java:320) at com.exalate.replication.in.RequestProcessorService.processSyncRequestsForIssue(RequestProcessorService.java:190) at com.exalate.replication.in.RequestProcessorService.processSyncRequests(RequestProcessorService.java:127) at com.exalate.replication.in.RequestWorker$1.run(RequestWorker.java:83) at com.exalate.node.util.concurrent.ClusteredSensitiveExecutorService.lambda$executeHandlingLocks$0(ClusteredSensitiveExecutorService.java:31) at com.exalate.node.util.concurrent.ClusteredSensitiveExecutorService.executeHandlingLocks(ClusteredSensitiveExecutorService.java:52) at com.exalate.node.util.concurrent.ClusteredSensitiveExecutorService.executeHandlingLocks(ClusteredSensitiveExecutorService.java:29) at com.exalate.replication.in.RequestWorker.run(RequestWorker.java:72) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748)
  • Incoming sync data:

Summary: customer request type test v4Entity Key: SD-11636(id: 25605)Encoded payload: {“version”:{“major”:1,“minor”:15,“patch”:0},“hubIssue”:{“components”:,“attachments”:,“voters”:,“customFields”:{“Typ požiadavky”:{“id”:11901.0,“name”:“Typ požiadavky”,“uid”:“11901”,“type”:“OPTION”,“value”:{“id”:“11607”,“sequence”:1.0,“value”:“Žiadosť o školenie a metodiku”,“disabled”:false,“childOptions”:}},“E-mail”:{“id”:11200.0,“name”:“E-mail”,“uid”:“11200”,“description”:“”,“type”:“STRING”},“Úroveň problému”:{“id”:11806.0,“name”:“Úroveň problému”,“uid”:“11806”,“type”:“OPTION”,“value”:{“id”:“11515”,“sequence”:2.0,“value”:“Nekritický problém”,“disabled”:false,“childOptions”:}},“Prostredie”:{“id”:11805.0,“name”:“Prostredie”,“uid”:“11805”,“type”:“OPTION”,“value”:{“id”:“11516”,“sequence”:2.0,“value”:“Integračné”,“disabled”:false,“childOptions”:}}},“project”:{“idStr”:“10200”,“key”:“SD”,“name”:“Service Desk”,“lead”:{“key”:“helpdesk”,“active”:true,“email”:“domena@xxxxx.sk”,“displayName”:“Systém JIRA”,“username”:“system.jira”},“versions”:,“components”:},“watchers”:,“fixVersions”:,“key”:“SD-11636”,“summary”:“customer request type test v4”,“comments”:,“internalMap”:{},“priority”:{“id”:“10100”,“name”:“Nie je určená”,“description”:“”},“labels”:,“customKeys”:{},“workLogs”:,“affectedVersions”:,“entityProperties”:{}},“issueUrl”:“https://jirat.xxxxxx.sk/browse/SD-11636”}

Peter Pesta commented on 03 November 2021

Hi Serhiy Onyshchenko,

Here´s the incoming script on the receivers side:

if(firstSync){

issue.projectKey = “TESMOSD”

// Set type name from source issue, if not found set a default

//issue.typeName = nodeHelper.getIssueType(replica.typeName)?.name ?: “Fault”

issue.typeName = nodeHelper.getIssueType(replica.type?.name, issue.projectKey)?.name ?: “Fault”

}

issue.summary = replica.summary

issue.description = replica.description

issue.labels = replica.labels

issue.comments = commentHelper.mergeComments(issue, replica)

issue.attachments = attachmentHelper.mergeAttachments(issue, replica)

//issue.customFields.“Úroveň problému”.value = “Závažný problém”

issue.customFields.“Zadávateľ”.value = “Zakaznik”

//issue.customFields.“e-mail”?.value = replica.customFields.“E-mail”?.value

issue.customFields.“Úroveň problému”.value = replica.customFields.“Úroveň problému”.value

issue.customFields.“Prostredie”.value = replica.customFields.“Prostredie”.value

//issue.customFields.“Customer Request Type”.value = replica.customFields.“Typ požiadavky”?.value ?: “Problém”

if(replica.customFields.“Typ požiadavky”.value == “Problém”) {

issue.customFields.“Customer Request Type”.value = replica.customFields.“Typ požiadavky”?.value

issue.projectKey = “TESMOSD”

issue.typeName = “Fault”

}

else if (replica.customFields.“Typ požiadavky”.value == “Žiadosť o školenie a metodiku”) {

issue.customFields.“Customer Request Type”.value = replica.customFields.“Typ požiadavky”?.value

issue.projectKey = “TESMOD”

issue.typeName = “Task”

}

else if (replica.customFields.“Typ požiadavky”.value == “Žiadosť o zmenu (RFC)”) {

issue.customFields.“Customer Request Type”.value = replica.customFields.“Typ požiadavky”?.value

issue.projectKey = “TESMOD”

issue.typeName = “Change”

}

else if (replica.customFields.“Typ požiadavky”.value == “Úloha z pracovného stretnutia”) {

issue.customFields.“Customer Request Type”.value = replica.customFields.“Typ požiadavky”?.value

issue.projectKey = “TESMOD”

issue.typeName = “Project issue”

}

//issue.customFields.“Telefonický kontakt (new)”?.value = replica.customFields.“Telefónne číslo”.value

//issue.customFields.“e-mail”?.value = replica.customFields.“E-mail”.value

/*

User Synchronization (Assignee/Reporter)

Set a Reporter/Assignee from the source side, if the user can’t be found set a default user

You can use this approach for custom fields of type User

def defaultUser = nodeHelper.getUserByEmail(“default@idalko.com”)

issue.reporter = nodeHelper.getUserByEmail(replica.reporter?.email) ?: defaultUser

issue.assignee = nodeHelper.getUserByEmail(replica.assignee?.email) ?: defaultUser

*/

/*

Comment Synchronization

Sync comments with the original author if the user exists in the local instance

Remove original Comments sync line if you are using this approach

issue.comments = commentHelper.mergeComments(issue, replica){ it.executor = nodeHelper.getUserByEmail(it.author?.email) }

*/

/*

Status Synchronization

Sync status according to the mapping [remote issue status: local issue status]

If statuses are the same on both sides don’t include them in the mapping

def statusMapping = [“Open”:“New”, “To Do”:“Backlog”]

def remoteStatusName = replica.status.name

issue.setStatus(statusMapping[remoteStatusName] ?: remoteStatusName)

*/

/*

Custom Fields

This line will sync Text, Option(s), Number, Date, Organization, and Labels CFs

For other types of CF check documentation

issue.customFields.“CF Name”.value = replica.customFields.“CF Name”.value

*/

Serhiy Onyshchenko commented on 03 November 2021

Hello, Peter Pesta , please try:

if(replica.customFields."Typ požiadavky".value.value == "Problém") {

  issue.customFields."Customer Request Type".value = replica.customFields."Typ požiadavky"?.value.value

  issue.projectKey   = "TESMOSD"

  issue.typeName     = "Fault"

}

else if (replica.customFields."Typ požiadavky".value.value == "Žiadosť o školenie a metodiku") {

 issue.customFields."Customer Request Type".value = replica.customFields."Typ požiadavky"?.value.value

  issue.projectKey   = "TESMOD"

  issue.typeName     = "Task"

}

else if (replica.customFields."Typ požiadavky".value.value == "Žiadosť o zmenu (RFC)") {

  issue.customFields."Customer Request Type".value = replica.customFields."Typ požiadavky"?.value.value

  issue.projectKey   = "TESMOD"

  issue.typeName     = "Change"

}

else if (replica.customFields."Typ požiadavky".value.value == "Úloha z pracovného stretnutia") {

  issue.customFields."Customer Request Type".value = replica.customFields."Typ požiadavky"?.value.value

  issue.projectKey   = "TESMOD"

  issue.typeName     = "Project issue"

}

The problem is that Typ požiadavky is a select list, which has both option id and option text (value).
Regards, Serhiy.

Peter Pesta commented on 02 December 2021

Hi Serhiy Onyshchenko ,

Thank you very much, this helped a lot and it´s working fine on the testing environment. However, once I´ve staged the settings to the production env, it´s malfunctioning and the behaviour is strange.

If I enter the value A into the custom field “Typ poziadavky” then the sync works fine, if I enter value B into the same custom field, the data are not being sent (checked the payload, the values are not within the sent file).
Have to admit that the custom field “typ poziadavky” was created shortly before I´ve set up the synchronization, but it´s working fine for one value, not for the other. Also, I´ve performed an background re-index with no success.

Guess an deeper analysis would be necessary, I also have the support.zip files ready.

Regards,
Peter