Tags:
not added yet
The requirement: Synchronizing various trackers on a Workflow transitionThe Sales Template project contains the following trackers:
The goal is that when a Lead finalizes, i.e. it changes to the "SQL" workflow state then we should create appropriate items in the Accounts, Opportunities, Contants trackers. This diagram illustrates how these trackers relate to each other
Synchronization mapping between trackersHere is the required mapping of fields. The Workflow should copy these fields from the "Leads" tracker to the fields of the other tracker as described here.
The script codeHere is the Groovy script, which contains the logic for the Workflow-action. For that you should create a new file as $CB_HOME/CB/tomcat/webapps/cb/WEB-INF/classes/synchronizeLeads.groovy. Paste this Groovy script below to that file, and save it. // Groovy script implements a Workflow state-transition action as requested here: https://codebeamer.com/cb/issue/326159 // registered in my-applicationContext.xml on cb.com only import com.intland.codebeamer.persistence.dto.*; import com.intland.codebeamer.persistence.dto.base.*; import com.intland.codebeamer.persistence.dao.*; import com.intland.codebeamer.manager.*; import com.intland.codebeamer.controller.importexport.*; import org.apache.commons.lang3.*; if (!beforeEvent) { return; // do NOTHING on after-event, everything is already handled in the before-event! } logger.info("-------------------------------------"); logger.info("Synchronizing Lead issue:" + subject); trackerDao = applicationContext.getBean(TrackerDao.class); trackerItemManager = applicationContext.getBean(TrackerItemManager.class); projectId = subject.tracker.project.id // read custom fields in "Leads" tracker // using a helper class to access fields by name fieldAccessor = new com.intland.codebeamer.text.excel.FieldAccessor(applicationContext); fieldAccessor.setUser(user); def getByLabel = { fieldName -> fieldAccessor.getByLabel(subject, fieldName) }; // set a field on contact by finding the field using its label def setField(issue, fieldName, value) { field = fieldAccessor.getFieldByName(issue, fieldName); if (field != null) { field.setValue(issue, value); } else { logger.warn("Can not find field <" + fieldName +"> on " + issue); } }; def copyField(toIssue, fieldName, toFieldName=null, defaultValue=null) { value = fieldAccessor.getByLabel(subject, fieldName); if (value == null && defaultValue != null) { value = defaultValue; } if (toFieldName == null) { toFieldName = fieldName; } setField(toIssue, toFieldName, value); } def updateOriginal(fieldName, value) { setField(subject, fieldName, value); } def getOrCreateChoice(issue, fieldName, value) { if (StringUtils.isBlank(value)) { return null; } choicesProvider = new ChoicesProvider(applicationContext); choiceField = choicesProvider.getFieldByName(user, issue, fieldName); if (choiceField == null) { return null; } asChoice = choicesProvider.getOrCreateChoiceByName(user, issue.tracker, choiceField, value, null); return asChoice; } // first check/create account if does not exist, because this is required by contact account = getByLabel("Account"); if (account == null) { try { account = new TrackerItemDto(); accounts = trackerDao.findByNameAndProjectId("Accounts", projectId); account.tracker = accounts; // use the trackerItemManager to copy of the source issue, because this copies comments and attachments too request = event.getRequest(); fieldMapping = new HashMap(); Map<TrackerItemDto,TrackerItemDto> copied = trackerItemManager.copy(request, user, Collections.singletonList(subject), null, account, null, fieldMapping); account = copied.get(subject); logger.info("copied account's id:" + account.id); // required fields copyField(account, "Company", "Account Name"); copyField(account, "Description", "Company Profile"); // must fill with something, this is a required field copyField(account, "Street"); copyField(account, "Post code"); copyField(account, "City"); copyField(account, "Country"); copyField(account, "Employees"); copyField(account, "Website", "Company website"); copyField(account, "Comment"); copyField(account, "Phone"); // industry is a choice field in the target, creating a new choice if necessary industry = getByLabel("Industry"); logger.warn("Creating industry:" + industry) industryAsChoice = getOrCreateChoice(account, "Industry", industry); logger.warn("industryAsChoice:" + industryAsChoice); if (industryAsChoice != null) { setField(account, "Industry", Arrays.asList(industryAsChoice)); } logger.info("Created Account:" + account); // trackerItemManager.create(user, account, event.getData()); trackerItemManager.update(user, account, event.getData()); updateOriginal("Account", Arrays.asList(account)); } catch (Throwable th) { logger.warn("Failed to create Account for " + subject, th); } } // only create a new contact if that does not exist yet!, this also avoids infinite event loops ! contact = getByLabel("contact"); if (contact == null) { try { // create a new Contact contact = new TrackerItemDto(); contacts = trackerDao.findByNameAndProjectId("Contacts", projectId); contact.tracker = contacts; copyField(contact, "First Name"); copyField(contact, "Last Name"); copyField(contact, "Title"); // TODO: there is NO such field here copyField(contact, "Department"); // TODO: there is NO such field here copyField(contact,"Phone"); copyField(contact,"E-mail", "Email"); copyField(contact,"Street"); copyField(contact,"Post code", "Zip/Postal code"); copyField(contact,"City"); copyField(contact,"Country"); copyField(contact, "Geolocation"); // TODO: no such field! // fill the Mandatory Account field setField(contact, "Account", Arrays.asList(account)); trackerItemManager.create(user, contact, event.getData()); logger.info("Created Contact:" + contact); updateOriginal("Contact", Arrays.asList(contact)); } catch (Throwable th) { logger.warn("Failed to create Contact for " + subject, th); } } try { // Account - Main Contact field should have a default value for Contact person created upon conversion mainContact = fieldAccessor.getByLabel(account, "Main Contact"); if (mainContact == null || mainContact.isEmpty()) { setField(account, "Main Contact", Arrays.asList(contact)); trackerItemManager.update(user, account, event.getData()); } } catch (Throwable th) { logger.warn("Failed to set Main Contanct field", th); } opportunity = getByLabel("opportunity"); if (opportunity == null) { try { opportunities = trackerDao.findByNameAndProjectId("Opportunities", projectId); // create a new opportunity opportunity = new TrackerItemDto(); opportunity.tracker = opportunities; defaultVal = getByLabel("Account"); // use this as default value if the "opportunity" field would be empty, because this is a required field opportunity.name = account.name; // REQUIRED field opportunity.description = "--"; // REQUIRED field // copyField(opportunity, "Lead Source", "Opportunity", defaultVal); // REQUIRED field // copyField(opportunity, "Lead Source", "Description", defaultVal); // REQUIRED field copyField(opportunity, "Lead Source"); setField(opportunity, "Account", Arrays.asList(account)); // store the "Account" to the "Contacts" table opportunityTables = new com.intland.codebeamer.manager.trackeritems.TableFields(user, opportunity, applicationContext); contactsTable = opportunityTables.getTableByName("Contacts"); contactColumn = contactsTable.getTableColumnByName("Contact"); contactColumn.setReferenceValues(0, Arrays.asList(contact)); trackerItemManager.create(user, opportunity, event.getData()); logger.info("Created Opportunity:" + opportunity); updateOriginal("opportunity", Arrays.asList(opportunity)); } catch (Throwable th) { logger.warn("Failed to create Opportunity for " + subject, th); } } logger.info("-------------------------------------"); |
Fast Links
codebeamer Overview codebeamer Knowledge Base Services by Intland Software |
This website stores cookies on your computer. These cookies are used to improve your browsing experience, constantly optimize the functionality and content of our website, furthermore helps us to understand your interests and provide more personalized services to you, both on this website and through other media. With your permission we and our partners may use precise geolocation data and identification through device scanning. You may click accept to consent to our and our partners’ processing as described above. Please be aware that some processing of your personal data may not require your consent, but you have a right to object to such processing. By using our website, you acknowledge this notice of our cookie practices. By accepting and continuing to browse this site, you agree to this use. For more information about the cookies we use, please visit our Privacy Policy.Your preferences will apply to this website only.
Note that user-behavior analytics are being captured on this server for the purpose of improving the Codebeamer user experience.