Integration with Workflow service

e) Integration with workflow - Integration with workflow service requires the following steps -

i) Add a workflow object to VoterRegistrationApplication POJO -

@Valid @JsonProperty("workflow") private Workflow workflow = null;

Create ProcessInstance, State, Action, ProcessInstanceRequest, ProcessInstanceResponse , BusinessService , BusinessServiceResponse POJOs -

@Getter @Setter @AllArgsConstructor @NoArgsConstructor @Builder @EqualsAndHashCode(of = { "id" }) @ToString public class ProcessInstance { @Size(max = 64) @JsonProperty("id") private String id; @NotNull @Size(max = 128) @JsonProperty("tenantId") private String tenantId; @NotNull @Size(max = 128) @JsonProperty("businessService") private String businessService; @NotNull @Size(max = 128) @JsonProperty("businessId") private String businessId; @NotNull @Size(max = 128) @JsonProperty("action") private String action; @NotNull @Size(max = 64) @JsonProperty("moduleName") private String moduleName; @JsonProperty("state") private State state; @JsonProperty("comment") private String comment; @JsonProperty("documents") @Valid private List<Document> documents; @JsonProperty("assignes") private List<User> assignes; public ProcessInstance addDocumentsItem(Document documentsItem) { if (this.documents == null) { this.documents = new ArrayList<>(); } if (!this.documents.contains(documentsItem)) this.documents.add(documentsItem); return this; } } @Getter @Setter @AllArgsConstructor @NoArgsConstructor @Builder @ToString @EqualsAndHashCode(of = {"tenantId","businessServiceId","state"}) public class State { @Size(max=256) @JsonProperty("uuid") private String uuid; @Size(max=256) @JsonProperty("tenantId") private String tenantId; @Size(max=256) @JsonProperty("businessServiceId") private String businessServiceId; @JsonProperty("sla") private Long sla; @Size(max=256) @JsonProperty("state") private String state; @Size(max=256) @JsonProperty("applicationStatus") private String applicationStatus; @JsonProperty("docUploadRequired") private Boolean docUploadRequired; @JsonProperty("isStartState") private Boolean isStartState; @JsonProperty("isTerminateState") private Boolean isTerminateState; @JsonProperty("isStateUpdatable") private Boolean isStateUpdatable; @JsonProperty("actions") @Valid private List<Action> actions; private AuditDetails auditDetails; public State addActionsItem(Action actionsItem) { if (this.actions == null) { this.actions = new ArrayList<>(); } this.actions.add(actionsItem); return this; } } @Getter @Setter @AllArgsConstructor @NoArgsConstructor @Builder @ToString @EqualsAndHashCode(of = {"tenantId","currentState","action"}) public class Action { @Size(max=256) @JsonProperty("uuid") private String uuid; @Size(max=256) @JsonProperty("tenantId") private String tenantId; @Size(max=256) @JsonProperty("currentState") private String currentState; @Size(max=256) @JsonProperty("action") private String action; @Size(max=256) @JsonProperty("nextState") private String nextState; @Size(max=1024) @JsonProperty("roles") @Valid private List<String> roles; private AuditDetails auditDetails; public Action addRolesItem(String rolesItem) { if (this.roles == null) { this.roles = new ArrayList<>(); } this.roles.add(rolesItem); return this; } } @Getter @Setter @AllArgsConstructor @NoArgsConstructor @Builder @ToString public class ProcessInstanceRequest { @JsonProperty("RequestInfo") private RequestInfo requestInfo; @JsonProperty("ProcessInstances") @Valid @NotNull private List<ProcessInstance> processInstances; public ProcessInstanceRequest addProcessInstanceItem(ProcessInstance processInstanceItem) { if (this.processInstances == null) { this.processInstances = new ArrayList<>(); } this.processInstances.add(processInstanceItem); return this; } } @Getter @Setter @AllArgsConstructor @NoArgsConstructor @Builder public class ProcessInstanceResponse { @JsonProperty("ResponseInfo") private ResponseInfo responseInfo; @JsonProperty("ProcessInstances") @Valid private List<ProcessInstance> processInstances; public ProcessInstanceResponse addProceInstanceItem(ProcessInstance proceInstanceItem) { if (this.processInstances == null) { this.processInstances = new ArrayList<>(); } this.processInstances.add(proceInstanceItem); return this; } } @Getter @Setter @AllArgsConstructor @NoArgsConstructor @Builder @ToString @EqualsAndHashCode(of = {"tenantId","businessService"}) @JsonInclude(JsonInclude.Include.NON_NULL) public class BusinessService { @Size(max=256) @JsonProperty("tenantId") private String tenantId = null; @Size(max=256) @JsonProperty("uuid") private String uuid = null; @Size(max=256) @JsonProperty("businessService") private String businessService = null; @Size(max=256) @JsonProperty("business") private String business = null; @Size(max=1024) @JsonProperty("getUri") private String getUri = null; @Size(max=1024) @JsonProperty("postUri") private String postUri = null; @JsonProperty("businessServiceSla") private Long businessServiceSla = null; @NotNull @Valid @JsonProperty("states") private List<State> states = null; @JsonProperty("auditDetails") private AuditDetails auditDetails = null; public BusinessService addStatesItem(State statesItem) { if (this.states == null) { this.states = new ArrayList<>(); } this.states.add(statesItem); return this; } /** * Returns the currentState with the given uuid if not present returns null * @param uuid the uuid of the currentState to be returned * @return */ public State getStateFromUuid(String uuid) { State state = null; if(this.states!=null){ for(State s : this.states){ if(s.getUuid().equalsIgnoreCase(uuid)){ state = s; break; } } } return state; } } @Data @NoArgsConstructor @AllArgsConstructor @Builder @ToString public class BusinessServiceResponse { @JsonProperty("ResponseInfo") private ResponseInfo responseInfo; @JsonProperty("BusinessServices") @Valid @NotNull private List<BusinessService> businessServices; public BusinessServiceResponse addBusinessServiceItem(BusinessService businessServiceItem) { if (this.businessServices == null) { this.businessServices = new ArrayList<>(); } this.businessServices.add(businessServiceItem); return this; } }

ii) Next, we have to create a class to transition the workflow object across its states. For this, create a class by the name of WorkflowService and annotate it with @Service annotation. Add the following content to this class -

@Component public class WorkflowService { @Autowired private ObjectMapper mapper; @Autowired private ServiceRequestRepository repository; @Autowired private VTRConfiguration config; public void updateWorkflowStatus(VoterRegistrationRequest voterRegistrationRequest) { voterRegistrationRequest.getVoterRegistrationApplications().forEach(application -> { ProcessInstance processInstance = getProcessInstanceForVTR(application, voterRegistrationRequest.getRequestInfo()); ProcessInstanceRequest workflowRequest = new ProcessInstanceRequest(voterRegistrationRequest.getRequestInfo(), Collections.singletonList(processInstance)); callWorkFlow(workflowRequest); }); } public State callWorkFlow(ProcessInstanceRequest workflowReq) { ProcessInstanceResponse response = null; StringBuilder url = new StringBuilder(config.getWfHost().concat(config.getWfTransitionPath())); Object optional = repository.fetchResult(url, workflowReq); response = mapper.convertValue(optional, ProcessInstanceResponse.class); return response.getProcessInstances().get(0).getState(); } private ProcessInstance getProcessInstanceForVTR(VoterRegistrationApplication application, RequestInfo requestInfo) { Workflow workflow = application.getWorkflow(); ProcessInstance processInstance = new ProcessInstance(); processInstance.setBusinessId(application.getApplicationNumber()); processInstance.setAction(workflow.getAction()); processInstance.setModuleName("voter-services"); processInstance.setTenantId(application.getTenantId()); processInstance.setBusinessService("VTR"); processInstance.setDocuments(workflow.getDocuments()); processInstance.setComment(workflow.getComments()); if(!CollectionUtils.isEmpty(workflow.getAssignes())){ List<User> users = new ArrayList<>(); workflow.getAssignes().forEach(uuid -> { digit.web.models.User user = new digit.web.models.User(); user.setUuid(uuid); users.add(user); }); processInstance.setAssignes(users); } return processInstance; } private BusinessService getBusinessService(VoterRegistrationApplication application, RequestInfo requestInfo) { String tenantId = application.getTenantId(); StringBuilder url = getSearchURLWithParams(tenantId, "VTR"); RequestInfoWrapper requestInfoWrapper = RequestInfoWrapper.builder().requestInfo(requestInfo).build(); Object result = repository.fetchResult(url, requestInfoWrapper); BusinessServiceResponse response = null; try { response = mapper.convertValue(result, BusinessServiceResponse.class); } catch (IllegalArgumentException e) { throw new CustomException("PARSING ERROR", "Failed to parse response of workflow business service search"); } if (CollectionUtils.isEmpty(response.getBusinessServices())) throw new CustomException("BUSINESSSERVICE_NOT_FOUND", "The businessService " + "VTR" + " is not found"); return response.getBusinessServices().get(0); } private StringBuilder getSearchURLWithParams(String tenantId, String businessService) { StringBuilder url = new StringBuilder(config.getWfHost()); url.append(config.getWfBusinessServiceSearchPath()); url.append("?tenantId="); url.append(tenantId); url.append("&businessServices="); url.append(businessService); return url; } public ProcessInstanceRequest getProcessInstanceForVoterRegistrationPayment(VoterRegistrationRequest updateRequest) { VoterRegistrationApplication application = updateRequest.getVoterRegistrationApplications().get(0); ProcessInstance process = ProcessInstance.builder() .businessService("VTR") .businessId(application.getApplicationNumber()) .comment("Payment for voter registration processed") .moduleName("voter-services") .tenantId(application.getTenantId()) .action("PAY") .build(); return ProcessInstanceRequest.builder() .requestInfo(updateRequest.getRequestInfo()) .processInstances(Arrays.asList(process)) .build(); } }

iii) Add the following properties to application.properties file -