Create asset with stock conditionally
In this example, we will define a post function to create asset and set it to "Assets" asset custom field.
Post function performs following operations:
- Checks if the asset custom field is empty, if it is not empty, does nothing
- Checks if "In Stock" is not Yes
- Creates asset with
- "Asset Name" field value will be name of asset
- Order Amount will be "Number of items in stock" asset value if asset has this attribute
- Sets new asset to "Assets" custom field
Fields of Screen and Asset
- Assets - Asset custom field
- maps to assetCustomFieldId in groovy script
Other Fields
- Asset Type - ListBox - Values are "Asset Type Name - ID".
- maps to assetTypeCustomFieldId in groovy script
- Examples:
- Laptop - 3
- Keyboard - 2
- Computer - 27
- Asset Name - Text Field: Name of the asset. If asset names are set to unique and asset name is not unique for assets, it will not be created.
- maps to assetNameCustomFieldId in groovy script
- Order Amount - Number Field - number of items to be purchased
- maps to orderAmountCustomFieldId in groovy script
- In Stock - Radio (Yes / No) - This must be No for this operation as we will create new asset.
- maps to inStockCustomFieldId in groovy script
Asset Attribute
- Number of items in stock - Number - This will hold inventory of assets
Add Post Function
Add "[AIP] - Asset generic groovy script" to a specific transition. Put the post function after issue updates and before "Update change history for an issue and store the issue in the database", GenerateChangeHistoryFunction and Re-index post functions.
Post function parameters
"Asset custom fields (with values) to inject as script parameter": Select the target asset custom field
"Groovy script":
import com.atlassian.jira.component.ComponentAccessor import com.atlassian.jira.issue.CustomFieldManager import com.atlassian.jira.issue.ModifiedValue import com.atlassian.jira.issue.customfields.option.Option import com.atlassian.jira.issue.util.DefaultIssueChangeHolder import groovy.json.JsonSlurper import org.apache.commons.lang3.StringUtils import org.apache.http.client.methods.CloseableHttpResponse import org.apache.http.client.methods.HttpGet import org.apache.http.client.methods.HttpPost import org.apache.http.entity.StringEntity import org.apache.http.impl.client.CloseableHttpClient import org.apache.http.impl.client.HttpClients import org.apache.http.util.EntityUtils import org.apache.log4j.Level import org.apache.log4j.Logger // To test with script runner //import com.atlassian.jira.issue.Issue //def issueManager = ComponentAccessor.getIssueManager() //def Issue issue = issueManager.getIssueObject("KTP-25") Logger logger = Logger.getLogger("inventoryplugin.groovy.script") logger.setLevel(Level.DEBUG) /*** variables to configure **************************/ def assetCustomFieldId = 'customfield_10227'; def assetTypeCustomFieldId = 'customfield_10314'; def inStockCustomFieldId = 'customfield_10317'; def orderAmountCustomFieldId = 'customfield_10316'; def assetNameCustomFieldId = 'customfield_10318'; def inStockNoValue = 'No' def AUTH_HASH = 'Basic YWRtaW46YWRtaW4='; // auth hash for authorization. this sample is for user=admin, and password=admin def stockAttributeId = 67; // asset "Number of items in stock" attribute id /*****************************************************/ boolean isNotInStockCase(issueObj, inStockCustomFieldId, inStockNoValue) { def customFieldManager = ComponentAccessor.getCustomFieldManager() def cField = customFieldManager.getCustomFieldObject(inStockCustomFieldId) def option = (Option) issueObj.getCustomFieldValue(cField); return option != null && option.getValue() != null && option.getValue().equals(inStockNoValue) } def updateAssetCustomFieldOfTheIssue(issueObj, assetCustomFieldId, issueKey, assetCustomFieldValue) { // get issue def issueToUpdate = ComponentAccessor.getIssueManager().getIssueObject(issueKey); // get asset custom field CustomFieldManager customFieldManager = ComponentAccessor.getCustomFieldManager() def assetCf = customFieldManager.getCustomFieldObject(assetCustomFieldId) // asset cf id // execute update assetCf.updateValue(null, issueToUpdate, new ModifiedValue(issueToUpdate.getCustomFieldValue(assetCf), assetCustomFieldValue), new DefaultIssueChangeHolder()) } int getAssetTypeId(issueObj, assetTypeCustomFieldId) { def customFieldManager = ComponentAccessor.getCustomFieldManager() def cField = customFieldManager.getCustomFieldObject(assetTypeCustomFieldId) def assetTypeValue = issueObj.getCustomFieldValue(cField).getValue() as String return StringUtils.trim(StringUtils.substring(assetTypeValue, StringUtils.lastIndexOf(assetTypeValue, "- ") + 2)) as Integer; } /** * Checks if Asset custom field value is empty */ boolean isCustomFieldEmpty(issueObj, assetCustomFieldId) { def customFieldManager = ComponentAccessor.getCustomFieldManager() def cField = customFieldManager.getCustomFieldObject(assetCustomFieldId) return StringUtils.isBlank(issueObj.getCustomFieldValue(cField)); } /** * converts stream to json */ def streamToJson(stream) { BufferedReader br = new BufferedReader(new InputStreamReader(stream)); StringBuilder sb = new StringBuilder(); String line; while ((line = br.readLine()) != null) { sb.append(line + "\n"); } br.close(); def jsonSlurper = new JsonSlurper() return jsonSlurper.parseText(sb.toString()) } /** * Calls GET service */ def callGetRestServiceAndReturnJson(serviceUrl, authHash) { Logger logger = Logger.getLogger("inventoryplugin.groovy.script") try { // get asset ID(s) def baseurl = ComponentAccessor.getApplicationProperties().getString("jira.baseurl") CloseableHttpClient httpclient = HttpClients.createDefault(); def httpGet = new HttpGet(baseurl + serviceUrl); httpGet.setHeader("Accept", "application/json"); httpGet.setHeader("Content-type", "application/json"); httpGet.setHeader("Authorization", authHash); CloseableHttpResponse response = httpclient.execute(httpGet); try { if (response.getStatusLine().getStatusCode() == 200) { return streamToJson(response.getEntity().getContent()); } else { return null; } } finally { EntityUtils.consume(response.getEntity()); httpclient.close(); } } catch (Exception e) { logger.error("Error while calling service: " + e.getMessage() + serviceUrl); return null; } } /** * Calls POST service */ def callPostRestServiceAndReturnJson(serviceUrl, queryToPostJson, authHash) { Logger logger = Logger.getLogger("inventoryplugin.groovy.script") try { // get asset ID(s) def baseurl = ComponentAccessor.getApplicationProperties().getString("jira.baseurl") CloseableHttpClient httpclient = HttpClients.createDefault(); def httpPost = new HttpPost(baseurl + serviceUrl); httpPost.setHeader("Accept", "application/json"); httpPost.setHeader("Content-type", "application/json"); httpPost.setHeader("Authorization", authHash); def entity = new StringEntity(queryToPostJson); httpPost.setEntity(entity); CloseableHttpResponse response = httpclient.execute(httpPost); try { if (response.getStatusLine().getStatusCode() == 200) { return streamToJson(response.getEntity().getContent()) } else { return null; } } finally { EntityUtils.consume(response.getEntity()); httpclient.close(); } } catch (Exception e) { logger.error("Error while calling service:" + serviceUrl, e); return null; } } String getAssetName(issueObj, assetNameCustomFieldId) { def customFieldManager = ComponentAccessor.getCustomFieldManager() def cField = customFieldManager.getCustomFieldObject(assetNameCustomFieldId) return issueObj.getCustomFieldValue(cField); } int getOrderAmount(issueObj, orderAmountCustomFieldId) { def customFieldManager = ComponentAccessor.getCustomFieldManager() def cField = customFieldManager.getCustomFieldObject(orderAmountCustomFieldId) def orderAmount = issueObj.getCustomFieldValue(cField); return (orderAmount == null) ? 0 : orderAmount as Integer; } def createAsset(issueObj, assetTypeCustomFieldId, assetNameCustomFieldId, stockAttributeId, orderAmountCustomFieldId, authHash) { Logger logger = Logger.getLogger("inventoryplugin.groovy.script") int assetTypeId = getAssetTypeId(issueObj, assetTypeCustomFieldId); if (assetTypeId > 0) { def addStockAttr = false; def assetTypeJson = callGetRestServiceAndReturnJson("/rest/jip-api/1.0/form/" + assetTypeId + ".json", authHash); logger.debug('assetTypeJson') logger.debug(assetTypeJson) if (assetTypeJson == null || assetTypeJson.attributes == null) { return null; } // loop JsonSlurper assetTypeJson.attributes.each { if (it.attribute.id == stockAttributeId) { addStockAttr = true; } } // get asset ID(s) def assetName = getAssetName(issueObj, assetNameCustomFieldId) // this is the search query parameters. When you search assets on Asset Navigator, // same parameters appear on Developer tools-> Network Tab. You can make different searches and get the parameters from there when you need. def queryToPostJson = "{\n" + " \"formId\": " + assetTypeId + ",\n" + " \"name\": \"" + assetName + "\",\n"; // if asset type has stock attribute set it if (addStockAttr) { queryToPostJson += " \"attributes\": [ {\"attributeId\": " + stockAttributeId + ", \"attributeValue\": \"" + getOrderAmount(issueObj, orderAmountCustomFieldId) + "\"}] "; } else { queryToPostJson += " \"attributes\": [ ] "; } queryToPostJson += " }" logger.debug(queryToPostJson); def assetJson = callPostRestServiceAndReturnJson("/rest/jip-api/1.0/inventory.json", queryToPostJson, authHash) if (assetJson != null) { return assetJson.id; } else { return null; } } } if (isCustomFieldEmpty(issue, assetCustomFieldId)) { if (isNotInStockCase(issue, inStockCustomFieldId, inStockNoValue)) { Integer assetId = createAsset(issue, assetTypeCustomFieldId, assetNameCustomFieldId, stockAttributeId, orderAmountCustomFieldId, AUTH_HASH); if (assetId != null && assetId > 0) { updateAssetCustomFieldOfTheIssue(issue, assetCustomFieldId, issue.getKey(), "," + assetId + ",") return true; } } } return false;
Variables to Set
Inspect issue edit screen and located the Ids of the fields and then update the script.
def assetCustomFieldId = 'customfield_10227'; def assetTypeCustomFieldId = 'customfield_10314'; def inStockCustomFieldId = 'customfield_10317'; def orderAmountCustomFieldId = 'customfield_10316'; def assetNameCustomFieldId = 'customfield_10318'; def inStockNoValue = 'No' def AUTH_HASH = 'Basic YWRtaW46YWRtaW4='; // auth hash for authorization. this sample is for user=admin, and password=admin def stockAttributeId = 67; // asset "Number of items in stock" attribute id
Example of Post function location
Test
After Done transition, new asset created with inventory and assigned to Issue.
Before | After |
---|---|