diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/functions/OnboardingCompletionFunctions.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/functions/OnboardingCompletionFunctions.java deleted file mode 100644 index 0e8fdc7c5..000000000 --- a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/functions/OnboardingCompletionFunctions.java +++ /dev/null @@ -1,123 +0,0 @@ -package it.pagopa.selfcare.onboarding.functions; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.microsoft.azure.functions.ExecutionContext; -import com.microsoft.azure.functions.HttpMethod; -import com.microsoft.azure.functions.HttpRequestMessage; -import com.microsoft.azure.functions.HttpResponseMessage; -import com.microsoft.azure.functions.annotation.AuthorizationLevel; -import com.microsoft.azure.functions.annotation.FunctionName; -import com.microsoft.azure.functions.annotation.HttpTrigger; -import com.microsoft.durabletask.DurableTaskClient; -import com.microsoft.durabletask.RetryPolicy; -import com.microsoft.durabletask.TaskOptions; -import com.microsoft.durabletask.TaskOrchestrationContext; -import com.microsoft.durabletask.azurefunctions.DurableActivityTrigger; -import com.microsoft.durabletask.azurefunctions.DurableClientContext; -import com.microsoft.durabletask.azurefunctions.DurableClientInput; -import com.microsoft.durabletask.azurefunctions.DurableOrchestrationTrigger; -import it.pagopa.selfcare.onboarding.common.OnboardingStatus; -import it.pagopa.selfcare.onboarding.config.RetryPolicyConfig; -import it.pagopa.selfcare.onboarding.entity.Onboarding; -import it.pagopa.selfcare.onboarding.exception.ResourceNotFoundException; -import it.pagopa.selfcare.onboarding.functions.utils.SaveOnboardingStatusInput; -import it.pagopa.selfcare.onboarding.service.CompletionService; -import it.pagopa.selfcare.onboarding.service.OnboardingService; - -import java.time.Duration; -import java.util.Optional; - -import static it.pagopa.selfcare.onboarding.functions.CommonFunctions.FORMAT_LOGGER_ONBOARDING_STRING; -import static it.pagopa.selfcare.onboarding.functions.CommonFunctions.SAVE_ONBOARDING_STATUS_ACTIVITY; -import static it.pagopa.selfcare.onboarding.utils.Utils.getOnboardingString; -import static it.pagopa.selfcare.onboarding.utils.Utils.readOnboardingValue; - -public class OnboardingCompletionFunctions { - - public static final String CREATED_NEW_ONBOARDING_COMPLETION_ORCHESTRATION_WITH_INSTANCE_ID_MSG = "Created new Onboarding completion orchestration with instance ID = "; - - public static final String ONBOARDING_COMPLETION_ACTIVITY = "OnboardingCompletion"; - public static final String CREATE_INSTITUTION_ACTIVITY = "CreateInstitution"; - public static final String CREATE_ONBOARDING_ACTIVITY = "CreateOnboarding"; - public static final String SEND_MAIL_COMPLETION_ACTIVITY = "SendMailCompletion"; - private final OnboardingService service; - - private final CompletionService completionService; - - private final ObjectMapper objectMapper; - private final TaskOptions optionsRetry; - - public OnboardingCompletionFunctions(OnboardingService service, CompletionService completionService, ObjectMapper objectMapper, RetryPolicyConfig retryPolicyConfig) { - this.service = service; - this.completionService = completionService; - this.objectMapper = objectMapper; - - final int maxAttempts = retryPolicyConfig.maxAttempts(); - final Duration firstRetryInterval = Duration.ofSeconds(retryPolicyConfig.firstRetryInterval()); - RetryPolicy retryPolicy = new RetryPolicy(maxAttempts, firstRetryInterval); - retryPolicy.setBackoffCoefficient(retryPolicyConfig.backoffCoefficient()); - optionsRetry = new TaskOptions(retryPolicy); - } - - /** - * This HTTP-triggered function starts the orchestration. - */ - @FunctionName("StartOnboardingCompletionOrchestration") - public HttpResponseMessage startOrchestration( - @HttpTrigger(name = "req", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.FUNCTION) HttpRequestMessage> request, - @DurableClientInput(name = "durableContext") DurableClientContext durableContext, - final ExecutionContext context) { - context.getLogger().info("StartOnboardingCompletionOrchestration trigger processed a request."); - - final String onboardingId = request.getQueryParameters().get("onboardingId"); - - DurableTaskClient client = durableContext.getClient(); - String instanceId = client.scheduleNewOrchestrationInstance(ONBOARDING_COMPLETION_ACTIVITY, onboardingId); - context.getLogger().info(String.format("%s %s", CREATED_NEW_ONBOARDING_COMPLETION_ORCHESTRATION_WITH_INSTANCE_ID_MSG, instanceId)); - - return durableContext.createCheckStatusResponse(request, instanceId); - } - - /** - * This is the orchestrator function, which can schedule activity functions, create durable timers, - * or wait for external events in a way that's completely fault-tolerant. - */ - @FunctionName(ONBOARDING_COMPLETION_ACTIVITY) - public void onboardingCompletionOrchestrator( - @DurableOrchestrationTrigger(name = "taskOrchestrationContext") TaskOrchestrationContext ctx) { - String onboardingId = ctx.getInput(String.class); - Onboarding onboarding = service.getOnboarding(onboardingId) - .orElseThrow(() -> new ResourceNotFoundException(String.format("Onboarding with id %s not found!", onboardingId))); - String onboardingString = getOnboardingString(objectMapper, onboarding); - - //CreateInstitution activity return an institutionId that is used by CreateOnboarding activity - String institutionId = ctx.callActivity(CREATE_INSTITUTION_ACTIVITY, onboardingString, optionsRetry, String.class).await(); - onboarding.getInstitution().setId(institutionId); - onboardingString = getOnboardingString(objectMapper, onboarding); - - ctx.callActivity(CREATE_ONBOARDING_ACTIVITY, onboardingString, optionsRetry, String.class).await(); - ctx.callActivity(SEND_MAIL_COMPLETION_ACTIVITY, onboardingString, optionsRetry, String.class).await(); - - //Last activity consist of saving pending status - String saveOnboardingStatusInput = SaveOnboardingStatusInput.buildAsJsonString(onboardingId, OnboardingStatus.COMPLETED.name()); - ctx.callActivity(SAVE_ONBOARDING_STATUS_ACTIVITY, saveOnboardingStatusInput, optionsRetry, String.class).await(); - } - - @FunctionName(CREATE_INSTITUTION_ACTIVITY) - public String createInstitutionAndPersistInstitutionId(@DurableActivityTrigger(name = "onboardingString") String onboardingString, final ExecutionContext context) { - context.getLogger().info(String.format(FORMAT_LOGGER_ONBOARDING_STRING, CREATE_INSTITUTION_ACTIVITY, onboardingString)); - return completionService.createInstitutionAndPersistInstitutionId(readOnboardingValue(objectMapper, onboardingString)); - } - - @FunctionName(CREATE_ONBOARDING_ACTIVITY) - public void createOnboarding(@DurableActivityTrigger(name = "onboardingString") String onboardingString, final ExecutionContext context) { - context.getLogger().info(String.format(FORMAT_LOGGER_ONBOARDING_STRING, CREATE_ONBOARDING_ACTIVITY, onboardingString)); - completionService.persistOnboarding(readOnboardingValue(objectMapper, onboardingString)); - } - - @FunctionName(SEND_MAIL_COMPLETION_ACTIVITY) - public void sendMailCompletion(@DurableActivityTrigger(name = "onboardingString") String onboardingString, final ExecutionContext context) { - context.getLogger().info(String.format(FORMAT_LOGGER_ONBOARDING_STRING, SEND_MAIL_COMPLETION_ACTIVITY, onboardingString)); - completionService.sendCompletedEmail(readOnboardingValue(objectMapper, onboardingString)); - } -} diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/functions/OnboardingFunctions.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/functions/OnboardingFunctions.java index 4ee7fd659..f16849823 100644 --- a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/functions/OnboardingFunctions.java +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/functions/OnboardingFunctions.java @@ -16,20 +16,18 @@ import com.microsoft.durabletask.azurefunctions.DurableClientContext; import com.microsoft.durabletask.azurefunctions.DurableClientInput; import com.microsoft.durabletask.azurefunctions.DurableOrchestrationTrigger; -import it.pagopa.selfcare.onboarding.common.OnboardingStatus; -import it.pagopa.selfcare.onboarding.common.WorkflowType; import it.pagopa.selfcare.onboarding.config.RetryPolicyConfig; import it.pagopa.selfcare.onboarding.entity.Onboarding; import it.pagopa.selfcare.onboarding.exception.ResourceNotFoundException; -import it.pagopa.selfcare.onboarding.functions.utils.SaveOnboardingStatusInput; +import it.pagopa.selfcare.onboarding.service.CompletionService; import it.pagopa.selfcare.onboarding.service.OnboardingService; +import it.pagopa.selfcare.onboarding.workflow.*; import java.time.Duration; import java.util.Optional; import static it.pagopa.selfcare.onboarding.functions.CommonFunctions.FORMAT_LOGGER_ONBOARDING_STRING; -import static it.pagopa.selfcare.onboarding.functions.CommonFunctions.SAVE_ONBOARDING_STATUS_ACTIVITY; -import static it.pagopa.selfcare.onboarding.utils.Utils.getOnboardingString; +import static it.pagopa.selfcare.onboarding.functions.utils.ActivityName.*; import static it.pagopa.selfcare.onboarding.utils.Utils.readOnboardingValue; /** @@ -37,24 +35,18 @@ */ public class OnboardingFunctions { public static final String CREATED_NEW_ONBOARDING_ORCHESTRATION_WITH_INSTANCE_ID_MSG = "Created new Onboarding orchestration with instance ID = "; - public static final String SAVE_TOKEN_WITH_CONTRACT_ACTIVITY_NAME = "SaveTokenWithContract"; - public static final String BUILD_CONTRACT_ACTIVITY_NAME = "BuildContract"; - public static final String SEND_MAIL_REGISTRATION_WITH_CONTRACT_ACTIVITY = "SendMailRegistrationWithContract"; - public static final String SEND_MAIL_REGISTRATION_WITH_CONTRACT_WHEN_APPROVE_ACTIVITY = "SendMailRegistrationWithContractWhenApprove"; - public static final String SEND_MAIL_REGISTRATION_REQUEST_ACTIVITY = "SendMailRegistrationRequest"; - public static final String SEND_MAIL_REGISTRATION_APPROVE_ACTIVITY = "SendMailRegistrationApprove"; - public static final String SEND_MAIL_ONBOARDING_APPROVE_ACTIVITY = "SendMailOnboardingApprove"; - public static final String SEND_MAIL_CONFIRMATION_ACTIVITY = "SendMailConfirmation"; private final OnboardingService service; + private final CompletionService completionService; private final ObjectMapper objectMapper; private final TaskOptions optionsRetry; - public OnboardingFunctions(OnboardingService service, ObjectMapper objectMapper, RetryPolicyConfig retryPolicyConfig) { + public OnboardingFunctions(OnboardingService service, ObjectMapper objectMapper, RetryPolicyConfig retryPolicyConfig, CompletionService completionService) { this.service = service; this.objectMapper = objectMapper; + this.completionService = completionService; final int maxAttempts = retryPolicyConfig.maxAttempts(); final Duration firstRetryInterval = Duration.ofSeconds(retryPolicyConfig.firstRetryInterval()); @@ -92,45 +84,18 @@ public void onboardingsOrchestrator( String onboardingId = ctx.getInput(String.class); Onboarding onboarding = service.getOnboarding(onboardingId) .orElseThrow(() -> new ResourceNotFoundException(String.format("Onboarding with id %s not found!", onboardingId))); - String onboardingString = getOnboardingString(objectMapper, onboarding); - switch (onboarding.getWorkflowType()) { - case CONTRACT_REGISTRATION -> workflowContractRegistration(ctx, onboardingString); - case FOR_APPROVE -> workflowForApprove(ctx, onboardingString, onboarding.getStatus()); - case FOR_APPROVE_PT -> workflowRegistrationRequestAndApprove(ctx, onboardingString); - case CONFIRMATION -> workflowForConfirmation(ctx, onboardingString); - } - - //Last activity consist of saving pending status - OnboardingStatus nextStatus = nextProcessOnboardingStatus(onboarding.getStatus(), onboarding.getWorkflowType()); - String saveOnboardingStatusInput = SaveOnboardingStatusInput.buildAsJsonString(onboardingId, nextStatus.name()); - - ctx.callActivity(SAVE_ONBOARDING_STATUS_ACTIVITY, saveOnboardingStatusInput, optionsRetry, String.class).await(); - } + WorkflowExecutor workflowExecutor; - private void workflowContractRegistration(TaskOrchestrationContext ctx, String onboardingString){ - ctx.callActivity(BUILD_CONTRACT_ACTIVITY_NAME, onboardingString, optionsRetry, String.class).await(); - ctx.callActivity(SAVE_TOKEN_WITH_CONTRACT_ACTIVITY_NAME, onboardingString, optionsRetry, String.class).await(); - ctx.callActivity(SEND_MAIL_REGISTRATION_WITH_CONTRACT_ACTIVITY, onboardingString, optionsRetry, String.class).await(); - } - - private void workflowForApprove(TaskOrchestrationContext ctx, String onboardingString, OnboardingStatus onboardingStatus){ - if (OnboardingStatus.REQUEST.equals(onboardingStatus)) { - ctx.callActivity(SEND_MAIL_ONBOARDING_APPROVE_ACTIVITY, onboardingString, optionsRetry, String.class).await(); - } else if (OnboardingStatus.TO_BE_VALIDATED.equals(onboardingStatus)) { - ctx.callActivity(BUILD_CONTRACT_ACTIVITY_NAME, onboardingString, optionsRetry, String.class).await(); - ctx.callActivity(SAVE_TOKEN_WITH_CONTRACT_ACTIVITY_NAME, onboardingString, optionsRetry, String.class).await(); - ctx.callActivity(SEND_MAIL_REGISTRATION_WITH_CONTRACT_WHEN_APPROVE_ACTIVITY, onboardingString, optionsRetry, String.class).await(); + switch (onboarding.getWorkflowType()) { + case CONTRACT_REGISTRATION -> workflowExecutor = new WorkflowExecutorContractRegistration(objectMapper, optionsRetry); + case FOR_APPROVE -> workflowExecutor = new WorkflowExecutorForApprove(objectMapper, optionsRetry); + case FOR_APPROVE_PT -> workflowExecutor = new WorkflowExecutorForApprovePt(objectMapper, optionsRetry); + case CONFIRMATION -> workflowExecutor = new WorkflowExecutorConfirmation(objectMapper, optionsRetry); + default -> throw new IllegalArgumentException("Workflow options not found!"); } - } - private void workflowRegistrationRequestAndApprove(TaskOrchestrationContext ctx, String onboardingString){ - ctx.callActivity(SEND_MAIL_REGISTRATION_REQUEST_ACTIVITY, onboardingString, optionsRetry, String.class).await(); - ctx.callActivity(SEND_MAIL_REGISTRATION_APPROVE_ACTIVITY, onboardingString, optionsRetry, String.class).await(); - } - - private void workflowForConfirmation(TaskOrchestrationContext ctx, String onboardingString){ - ctx.callActivity(SEND_MAIL_CONFIRMATION_ACTIVITY, onboardingString, optionsRetry, String.class).await(); + workflowExecutor.execute(ctx, onboarding); } /** @@ -192,12 +157,23 @@ public String sendMailConfirmation(@DurableActivityTrigger(name = "onboardingStr return onboardingString; } - private OnboardingStatus nextProcessOnboardingStatus(OnboardingStatus previous, WorkflowType workflowType) { - if(OnboardingStatus.REQUEST.equals(previous) && - (WorkflowType.FOR_APPROVE.equals(workflowType) || WorkflowType.FOR_APPROVE_PT.equals(workflowType))) { - return OnboardingStatus.TO_BE_VALIDATED; - } - return OnboardingStatus.PENDING; + + @FunctionName(CREATE_INSTITUTION_ACTIVITY) + public String createInstitutionAndPersistInstitutionId(@DurableActivityTrigger(name = "onboardingString") String onboardingString, final ExecutionContext context) { + context.getLogger().info(String.format(FORMAT_LOGGER_ONBOARDING_STRING, CREATE_INSTITUTION_ACTIVITY, onboardingString)); + return completionService.createInstitutionAndPersistInstitutionId(readOnboardingValue(objectMapper, onboardingString)); + } + + @FunctionName(CREATE_ONBOARDING_ACTIVITY) + public void createOnboarding(@DurableActivityTrigger(name = "onboardingString") String onboardingString, final ExecutionContext context) { + context.getLogger().info(String.format(FORMAT_LOGGER_ONBOARDING_STRING, CREATE_ONBOARDING_ACTIVITY, onboardingString)); + completionService.persistOnboarding(readOnboardingValue(objectMapper, onboardingString)); + } + + @FunctionName(SEND_MAIL_COMPLETION_ACTIVITY) + public void sendMailCompletion(@DurableActivityTrigger(name = "onboardingString") String onboardingString, final ExecutionContext context) { + context.getLogger().info(String.format(FORMAT_LOGGER_ONBOARDING_STRING, SEND_MAIL_COMPLETION_ACTIVITY, onboardingString)); + completionService.sendCompletedEmail(readOnboardingValue(objectMapper, onboardingString)); } } diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/functions/utils/ActivityName.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/functions/utils/ActivityName.java new file mode 100644 index 000000000..4181c0611 --- /dev/null +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/functions/utils/ActivityName.java @@ -0,0 +1,20 @@ +package it.pagopa.selfcare.onboarding.functions.utils; + +public class ActivityName { + + public static final String SAVE_TOKEN_WITH_CONTRACT_ACTIVITY_NAME = "SaveTokenWithContract"; + public static final String BUILD_CONTRACT_ACTIVITY_NAME = "BuildContract"; + public static final String SEND_MAIL_REGISTRATION_WITH_CONTRACT_ACTIVITY = "SendMailRegistrationWithContract"; + + public static final String SEND_MAIL_REGISTRATION_WITH_CONTRACT_WHEN_APPROVE_ACTIVITY = "SendMailRegistrationWithContractWhenApprove"; + public static final String SEND_MAIL_REGISTRATION_REQUEST_ACTIVITY = "SendMailRegistrationRequest"; + public static final String SEND_MAIL_REGISTRATION_APPROVE_ACTIVITY = "SendMailRegistrationApprove"; + public static final String SEND_MAIL_ONBOARDING_APPROVE_ACTIVITY = "SendMailOnboardingApprove"; + public static final String SEND_MAIL_CONFIRMATION_ACTIVITY = "SendMailConfirmation"; + + + public static final String ONBOARDING_COMPLETION_ACTIVITY = "OnboardingCompletion"; + public static final String CREATE_INSTITUTION_ACTIVITY = "CreateInstitution"; + public static final String CREATE_ONBOARDING_ACTIVITY = "CreateOnboarding"; + public static final String SEND_MAIL_COMPLETION_ACTIVITY = "SendMailCompletion"; +} diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/workflow/WorkflowExecutor.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/workflow/WorkflowExecutor.java new file mode 100644 index 000000000..4825fea3f --- /dev/null +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/workflow/WorkflowExecutor.java @@ -0,0 +1,46 @@ +package it.pagopa.selfcare.onboarding.workflow; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.microsoft.durabletask.TaskOptions; +import com.microsoft.durabletask.TaskOrchestrationContext; +import it.pagopa.selfcare.onboarding.common.OnboardingStatus; +import it.pagopa.selfcare.onboarding.entity.Onboarding; +import it.pagopa.selfcare.onboarding.functions.utils.SaveOnboardingStatusInput; + +import static it.pagopa.selfcare.onboarding.functions.CommonFunctions.SAVE_ONBOARDING_STATUS_ACTIVITY; +import static it.pagopa.selfcare.onboarding.functions.utils.ActivityName.*; +import static it.pagopa.selfcare.onboarding.utils.Utils.getOnboardingString; + +public interface WorkflowExecutor { + + void executeRequestState(TaskOrchestrationContext ctx, Onboarding onboarding); + void executeToBeValidatedState(TaskOrchestrationContext ctx, Onboarding onboarding); + + ObjectMapper objectMapper(); + + TaskOptions optionsRetry(); + + default void execute(TaskOrchestrationContext ctx, Onboarding onboarding){ + switch (onboarding.getStatus()){ + case REQUEST -> executeRequestState(ctx, onboarding); + case TO_BE_VALIDATED -> executeToBeValidatedState(ctx, onboarding); + case PENDING -> executePendingState(ctx, onboarding); + } + } + + default void executePendingState(TaskOrchestrationContext ctx, Onboarding onboarding) { + String onboardingString = getOnboardingString(objectMapper(), onboarding); + + //CreateInstitution activity return an institutionId that is used by CreateOnboarding activity + String institutionId = ctx.callActivity(CREATE_INSTITUTION_ACTIVITY, onboardingString, optionsRetry(), String.class).await(); + onboarding.getInstitution().setId(institutionId); + onboardingString = getOnboardingString(objectMapper(), onboarding); + + ctx.callActivity(CREATE_ONBOARDING_ACTIVITY, onboardingString, optionsRetry(), String.class).await(); + ctx.callActivity(SEND_MAIL_COMPLETION_ACTIVITY, onboardingString, optionsRetry(), String.class).await(); + + //Last activity consist of saving pending status + String saveOnboardingStatusInput = SaveOnboardingStatusInput.buildAsJsonString(onboarding.getOnboardingId(), OnboardingStatus.COMPLETED.name()); + ctx.callActivity(SAVE_ONBOARDING_STATUS_ACTIVITY, saveOnboardingStatusInput, optionsRetry(), String.class).await(); + } +} diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/workflow/WorkflowExecutorConfirmation.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/workflow/WorkflowExecutorConfirmation.java new file mode 100644 index 000000000..b2f077bb2 --- /dev/null +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/workflow/WorkflowExecutorConfirmation.java @@ -0,0 +1,43 @@ +package it.pagopa.selfcare.onboarding.workflow; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.microsoft.durabletask.TaskOptions; +import com.microsoft.durabletask.TaskOrchestrationContext; +import it.pagopa.selfcare.onboarding.common.OnboardingStatus; +import it.pagopa.selfcare.onboarding.entity.Onboarding; + +import static it.pagopa.selfcare.onboarding.functions.CommonFunctions.SAVE_ONBOARDING_STATUS_ACTIVITY; +import static it.pagopa.selfcare.onboarding.functions.utils.ActivityName.SEND_MAIL_CONFIRMATION_ACTIVITY; +import static it.pagopa.selfcare.onboarding.functions.utils.SaveOnboardingStatusInput.buildAsJsonString; +import static it.pagopa.selfcare.onboarding.utils.Utils.getOnboardingString; + +public class WorkflowExecutorConfirmation implements WorkflowExecutor { + + private final ObjectMapper objectMapper; + private final TaskOptions optionsRetry; + + public WorkflowExecutorConfirmation(ObjectMapper objectMapper, TaskOptions optionsRetry) { + this.objectMapper = objectMapper; + this.optionsRetry = optionsRetry; + } + @Override + public void executeRequestState(TaskOrchestrationContext ctx, Onboarding onboarding) { + String onboardingString = getOnboardingString(objectMapper, onboarding); + ctx.callActivity(SEND_MAIL_CONFIRMATION_ACTIVITY, onboardingString, optionsRetry, String.class).await(); + ctx.callActivity(SAVE_ONBOARDING_STATUS_ACTIVITY, buildAsJsonString(onboarding.getOnboardingId(), OnboardingStatus.PENDING.name()), optionsRetry, String.class).await(); + } + + @Override + public void executeToBeValidatedState(TaskOrchestrationContext ctx, Onboarding onboarding) { + } + + @Override + public ObjectMapper objectMapper() { + return this.objectMapper; + } + + @Override + public TaskOptions optionsRetry() { + return this.optionsRetry; + } +} diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/workflow/WorkflowExecutorContractRegistration.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/workflow/WorkflowExecutorContractRegistration.java new file mode 100644 index 000000000..36fc9b305 --- /dev/null +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/workflow/WorkflowExecutorContractRegistration.java @@ -0,0 +1,45 @@ +package it.pagopa.selfcare.onboarding.workflow; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.microsoft.durabletask.TaskOptions; +import com.microsoft.durabletask.TaskOrchestrationContext; +import it.pagopa.selfcare.onboarding.common.OnboardingStatus; +import it.pagopa.selfcare.onboarding.entity.Onboarding; + +import static it.pagopa.selfcare.onboarding.functions.CommonFunctions.SAVE_ONBOARDING_STATUS_ACTIVITY; +import static it.pagopa.selfcare.onboarding.functions.utils.ActivityName.*; +import static it.pagopa.selfcare.onboarding.functions.utils.SaveOnboardingStatusInput.buildAsJsonString; +import static it.pagopa.selfcare.onboarding.utils.Utils.getOnboardingString; + +public class WorkflowExecutorContractRegistration implements WorkflowExecutor { + + private final ObjectMapper objectMapper; + private final TaskOptions optionsRetry; + + public WorkflowExecutorContractRegistration(ObjectMapper objectMapper, TaskOptions optionsRetry) { + this.objectMapper = objectMapper; + this.optionsRetry = optionsRetry; + } + @Override + public void executeRequestState(TaskOrchestrationContext ctx, Onboarding onboarding) { + String onboardingString = getOnboardingString(objectMapper, onboarding); + ctx.callActivity(BUILD_CONTRACT_ACTIVITY_NAME, onboardingString, optionsRetry, String.class).await(); + ctx.callActivity(SAVE_TOKEN_WITH_CONTRACT_ACTIVITY_NAME, onboardingString, optionsRetry, String.class).await(); + ctx.callActivity(SEND_MAIL_REGISTRATION_WITH_CONTRACT_ACTIVITY, onboardingString, optionsRetry, String.class).await(); + ctx.callActivity(SAVE_ONBOARDING_STATUS_ACTIVITY, buildAsJsonString(onboarding.getOnboardingId(), OnboardingStatus.PENDING.name()), optionsRetry, String.class).await(); + } + + @Override + public void executeToBeValidatedState(TaskOrchestrationContext ctx, Onboarding onboarding) { + } + + @Override + public ObjectMapper objectMapper() { + return this.objectMapper; + } + + @Override + public TaskOptions optionsRetry() { + return this.optionsRetry; + } +} diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/workflow/WorkflowExecutorForApprove.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/workflow/WorkflowExecutorForApprove.java new file mode 100644 index 000000000..8c39513c5 --- /dev/null +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/workflow/WorkflowExecutorForApprove.java @@ -0,0 +1,48 @@ +package it.pagopa.selfcare.onboarding.workflow; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.microsoft.durabletask.TaskOptions; +import com.microsoft.durabletask.TaskOrchestrationContext; +import it.pagopa.selfcare.onboarding.common.OnboardingStatus; +import it.pagopa.selfcare.onboarding.entity.Onboarding; + +import static it.pagopa.selfcare.onboarding.functions.CommonFunctions.SAVE_ONBOARDING_STATUS_ACTIVITY; +import static it.pagopa.selfcare.onboarding.functions.utils.ActivityName.*; +import static it.pagopa.selfcare.onboarding.functions.utils.SaveOnboardingStatusInput.buildAsJsonString; +import static it.pagopa.selfcare.onboarding.utils.Utils.getOnboardingString; + +public class WorkflowExecutorForApprove implements WorkflowExecutor { + + private final ObjectMapper objectMapper; + private final TaskOptions optionsRetry; + + public WorkflowExecutorForApprove(ObjectMapper objectMapper, TaskOptions optionsRetry) { + this.objectMapper = objectMapper; + this.optionsRetry = optionsRetry; + } + @Override + public void executeRequestState(TaskOrchestrationContext ctx, Onboarding onboarding) { + String onboardingString = getOnboardingString(objectMapper, onboarding); + ctx.callActivity(SEND_MAIL_ONBOARDING_APPROVE_ACTIVITY, onboardingString, optionsRetry, String.class).await(); + ctx.callActivity(SAVE_ONBOARDING_STATUS_ACTIVITY, buildAsJsonString(onboarding.getOnboardingId(), OnboardingStatus.TO_BE_VALIDATED.name()), optionsRetry, String.class).await(); + } + + @Override + public void executeToBeValidatedState(TaskOrchestrationContext ctx, Onboarding onboarding) { + String onboardingString = getOnboardingString(objectMapper, onboarding); + ctx.callActivity(BUILD_CONTRACT_ACTIVITY_NAME, onboardingString, optionsRetry, String.class).await(); + ctx.callActivity(SAVE_TOKEN_WITH_CONTRACT_ACTIVITY_NAME, onboardingString, optionsRetry, String.class).await(); + ctx.callActivity(SEND_MAIL_REGISTRATION_WITH_CONTRACT_WHEN_APPROVE_ACTIVITY, onboardingString, optionsRetry, String.class).await(); + ctx.callActivity(SAVE_ONBOARDING_STATUS_ACTIVITY, buildAsJsonString(onboarding.getOnboardingId(), OnboardingStatus.PENDING.name()), optionsRetry, String.class).await(); + } + + @Override + public ObjectMapper objectMapper() { + return this.objectMapper; + } + + @Override + public TaskOptions optionsRetry() { + return this.optionsRetry; + } +} diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/workflow/WorkflowExecutorForApprovePt.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/workflow/WorkflowExecutorForApprovePt.java new file mode 100644 index 000000000..7a810851f --- /dev/null +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/workflow/WorkflowExecutorForApprovePt.java @@ -0,0 +1,50 @@ +package it.pagopa.selfcare.onboarding.workflow; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.microsoft.durabletask.TaskOptions; +import com.microsoft.durabletask.TaskOrchestrationContext; +import it.pagopa.selfcare.onboarding.common.OnboardingStatus; +import it.pagopa.selfcare.onboarding.entity.Onboarding; + +import static it.pagopa.selfcare.onboarding.functions.CommonFunctions.SAVE_ONBOARDING_STATUS_ACTIVITY; +import static it.pagopa.selfcare.onboarding.functions.utils.ActivityName.SEND_MAIL_REGISTRATION_APPROVE_ACTIVITY; +import static it.pagopa.selfcare.onboarding.functions.utils.ActivityName.SEND_MAIL_REGISTRATION_REQUEST_ACTIVITY; +import static it.pagopa.selfcare.onboarding.functions.utils.SaveOnboardingStatusInput.buildAsJsonString; +import static it.pagopa.selfcare.onboarding.utils.Utils.getOnboardingString; + +public class WorkflowExecutorForApprovePt implements WorkflowExecutor { + + private final ObjectMapper objectMapper; + private final TaskOptions optionsRetry; + + public WorkflowExecutorForApprovePt(ObjectMapper objectMapper, TaskOptions optionsRetry) { + this.objectMapper = objectMapper; + this.optionsRetry = optionsRetry; + } + @Override + public void executeRequestState(TaskOrchestrationContext ctx, Onboarding onboarding) { + String onboardingString = getOnboardingString(objectMapper, onboarding); + ctx.callActivity(SEND_MAIL_REGISTRATION_REQUEST_ACTIVITY, onboardingString, optionsRetry, String.class).await(); + ctx.callActivity(SEND_MAIL_REGISTRATION_APPROVE_ACTIVITY, onboardingString, optionsRetry, String.class).await(); + ctx.callActivity(SAVE_ONBOARDING_STATUS_ACTIVITY, buildAsJsonString(onboarding.getOnboardingId(), OnboardingStatus.TO_BE_VALIDATED.name()), optionsRetry, String.class).await(); + } + + @Override + public void executeToBeValidatedState(TaskOrchestrationContext ctx, Onboarding onboarding) { + executePendingState(ctx, onboarding); + } + + @Override + public void executePendingState(TaskOrchestrationContext ctx, Onboarding onboarding) { + } + + @Override + public ObjectMapper objectMapper() { + return this.objectMapper; + } + + @Override + public TaskOptions optionsRetry() { + return this.optionsRetry; + } +} diff --git a/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/OnboardingCompletionFunctionsTest.java b/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/OnboardingCompletionFunctionsTest.java deleted file mode 100644 index e642f9d22..000000000 --- a/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/OnboardingCompletionFunctionsTest.java +++ /dev/null @@ -1,178 +0,0 @@ -package it.pagopa.selfcare.onboarding; - -import com.microsoft.azure.functions.ExecutionContext; -import com.microsoft.azure.functions.HttpRequestMessage; -import com.microsoft.azure.functions.HttpResponseMessage; -import com.microsoft.azure.functions.HttpStatus; -import com.microsoft.durabletask.DurableTaskClient; -import com.microsoft.durabletask.Task; -import com.microsoft.durabletask.TaskOrchestrationContext; -import com.microsoft.durabletask.azurefunctions.DurableClientContext; -import io.quarkus.test.InjectMock; -import io.quarkus.test.junit.QuarkusTest; -import it.pagopa.selfcare.onboarding.entity.Institution; -import it.pagopa.selfcare.onboarding.entity.Onboarding; -import it.pagopa.selfcare.onboarding.exception.ResourceNotFoundException; -import it.pagopa.selfcare.onboarding.functions.OnboardingCompletionFunctions; -import it.pagopa.selfcare.onboarding.service.CompletionService; -import it.pagopa.selfcare.onboarding.service.OnboardingService; -import jakarta.inject.Inject; -import org.junit.jupiter.api.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.Mockito; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; - -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import java.util.logging.Logger; - -import static it.pagopa.selfcare.onboarding.functions.CommonFunctions.SAVE_ONBOARDING_STATUS_ACTIVITY; -import static it.pagopa.selfcare.onboarding.functions.OnboardingCompletionFunctions.*; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.*; - -@QuarkusTest -public class OnboardingCompletionFunctionsTest { - - - @Inject - OnboardingCompletionFunctions function; - - @InjectMock - OnboardingService service; - - @InjectMock - CompletionService completionService; - - final String onboardinString = "{\"onboardingId\":\"onboardingId\"}"; - - /** - * Unit test for HttpTriggerJava method. - */ - @Test - public void testHttpTriggerJava() { - // Setup - @SuppressWarnings("unchecked") - final HttpRequestMessage> req = mock(HttpRequestMessage.class); - final HttpResponseMessage res = mock(HttpResponseMessage.class); - - final Map queryParams = new HashMap<>(); - final String onboardingId = "onboardingId"; - queryParams.put("onboardingId", onboardingId); - doReturn(queryParams).when(req).getQueryParameters(); - - final Optional queryBody = Optional.empty(); - doReturn(queryBody).when(req).getBody(); - - doAnswer(new Answer() { - @Override - public HttpResponseMessage.Builder answer(InvocationOnMock invocation) { - HttpStatus status = (HttpStatus) invocation.getArguments()[0]; - return new HttpResponseMessageMock.HttpResponseMessageBuilderMock().status(status); - } - }).when(req).createResponseBuilder(any(HttpStatus.class)); - - final ExecutionContext context = mock(ExecutionContext.class); - doReturn(Logger.getGlobal()).when(context).getLogger(); - - final DurableClientContext durableContext = mock(DurableClientContext.class); - final DurableTaskClient client = mock(DurableTaskClient.class); - final String scheduleNewOrchestrationInstance = "scheduleNewOrchestrationInstance"; - doReturn(client).when(durableContext).getClient(); - doReturn(scheduleNewOrchestrationInstance).when(client).scheduleNewOrchestrationInstance(ONBOARDING_COMPLETION_ACTIVITY, onboardingId); - doReturn(res).when(durableContext).createCheckStatusResponse(any(), any()); - - // Invoke - function.startOrchestration(req, durableContext, context); - - // Verify - ArgumentCaptor captorInstanceId = ArgumentCaptor.forClass(String.class); - Mockito.verify(durableContext, times(1)) - .createCheckStatusResponse(any(), captorInstanceId.capture()); - assertEquals(scheduleNewOrchestrationInstance, captorInstanceId.getValue()); - } - - - - @Test - void onboardingsOrchestrator_thorwExceptionIfOnboardingNotPresent() { - final String onboardingId = "onboardingId"; - TaskOrchestrationContext orchestrationContext = mock(TaskOrchestrationContext.class); - when(orchestrationContext.getInput(String.class)).thenReturn(onboardingId); - when(service.getOnboarding(onboardingId)).thenReturn(Optional.empty()); - assertThrows(ResourceNotFoundException.class, () -> function.onboardingCompletionOrchestrator(orchestrationContext)); - } - - - @Test - void onboardingCompletionOrchestrator() { - Onboarding onboarding = new Onboarding(); - onboarding.setOnboardingId("onboardingId"); - onboarding.setInstitution(new Institution()); - - TaskOrchestrationContext orchestrationContext = mockTaskOrchestrationContext(onboarding); - - function.onboardingCompletionOrchestrator(orchestrationContext); - - ArgumentCaptor captorActivity = ArgumentCaptor.forClass(String.class); - Mockito.verify(orchestrationContext, times(4)) - .callActivity(captorActivity.capture(), any(), any(),any()); - assertEquals(CREATE_INSTITUTION_ACTIVITY, captorActivity.getAllValues().get(0)); - assertEquals(CREATE_ONBOARDING_ACTIVITY, captorActivity.getAllValues().get(1)); - assertEquals(SEND_MAIL_COMPLETION_ACTIVITY, captorActivity.getAllValues().get(2)); - assertEquals(SAVE_ONBOARDING_STATUS_ACTIVITY, captorActivity.getAllValues().get(3)); - } - - - @Test - void createInstitutionAndPersistInstitutionId() { - ExecutionContext executionContext = mock(ExecutionContext.class); - when(executionContext.getLogger()).thenReturn(Logger.getGlobal()); - when(completionService.createInstitutionAndPersistInstitutionId(any())) - .thenReturn("id"); - - function.createInstitutionAndPersistInstitutionId(onboardinString, executionContext); - - Mockito.verify(completionService, times(1)) - .createInstitutionAndPersistInstitutionId(any()); - } - - @Test - void sendCompletedEmail() { - ExecutionContext executionContext = mock(ExecutionContext.class); - when(executionContext.getLogger()).thenReturn(Logger.getGlobal()); - doNothing().when(completionService).sendCompletedEmail(any()); - - function.sendMailCompletion(onboardinString, executionContext); - - Mockito.verify(completionService, times(1)) - .sendCompletedEmail(any()); - } - - @Test - void createOnboarding() { - ExecutionContext executionContext = mock(ExecutionContext.class); - when(executionContext.getLogger()).thenReturn(Logger.getGlobal()); - doNothing().when(completionService).persistOnboarding(any()); - - function.createOnboarding(onboardinString, executionContext); - - Mockito.verify(completionService, times(1)) - .persistOnboarding(any()); - } - - TaskOrchestrationContext mockTaskOrchestrationContext(Onboarding onboarding) { - TaskOrchestrationContext orchestrationContext = mock(TaskOrchestrationContext.class); - when(orchestrationContext.getInput(String.class)).thenReturn(onboarding.getOnboardingId()); - when(service.getOnboarding(onboarding.getOnboardingId())).thenReturn(Optional.of(onboarding)); - - Task task = mock(Task.class); - when(orchestrationContext.callActivity(any(),any(),any(),any())).thenReturn(task); - when(task.await()).thenReturn(onboardinString); - return orchestrationContext; - } -} diff --git a/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/OnboardingFunctionsTest.java b/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/OnboardingFunctionsTest.java index bef2f9ec2..d5a163af0 100644 --- a/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/OnboardingFunctionsTest.java +++ b/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/OnboardingFunctionsTest.java @@ -12,9 +12,11 @@ import io.quarkus.test.junit.QuarkusTest; import it.pagopa.selfcare.onboarding.common.OnboardingStatus; import it.pagopa.selfcare.onboarding.common.WorkflowType; +import it.pagopa.selfcare.onboarding.entity.Institution; import it.pagopa.selfcare.onboarding.entity.Onboarding; import it.pagopa.selfcare.onboarding.exception.ResourceNotFoundException; import it.pagopa.selfcare.onboarding.functions.OnboardingFunctions; +import it.pagopa.selfcare.onboarding.service.CompletionService; import it.pagopa.selfcare.onboarding.service.OnboardingService; import jakarta.inject.Inject; import org.junit.jupiter.api.Test; @@ -29,7 +31,7 @@ import java.util.logging.Logger; import static it.pagopa.selfcare.onboarding.functions.CommonFunctions.SAVE_ONBOARDING_STATUS_ACTIVITY; -import static it.pagopa.selfcare.onboarding.functions.OnboardingFunctions.*; +import static it.pagopa.selfcare.onboarding.functions.utils.ActivityName.*; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; @@ -48,6 +50,9 @@ public class OnboardingFunctionsTest { @InjectMock OnboardingService service; + @InjectMock + CompletionService completionService; + final String onboardinString = "{\"onboardingId\":\"onboardingId\"}"; /** @@ -109,6 +114,7 @@ void onboardingsOrchestrator_thorwExceptionIfOnboardingNotPresent() { void onboardingsOrchestratorContractRegistration() { Onboarding onboarding = new Onboarding(); onboarding.setOnboardingId("onboardingId"); + onboarding.setStatus(OnboardingStatus.REQUEST); onboarding.setWorkflowType(WorkflowType.CONTRACT_REGISTRATION); TaskOrchestrationContext orchestrationContext = mockTaskOrchestrationContext(onboarding); @@ -169,6 +175,7 @@ void onboardingsOrchestratorForApproveWhenToBeValidated() { void onboardingsOrchestratorConfirmation() { Onboarding onboarding = new Onboarding(); onboarding.setOnboardingId("onboardingId"); + onboarding.setStatus(OnboardingStatus.REQUEST); onboarding.setWorkflowType(WorkflowType.CONFIRMATION); TaskOrchestrationContext orchestrationContext = mockTaskOrchestrationContext(onboarding); @@ -186,6 +193,7 @@ void onboardingsOrchestratorConfirmation() { void onboardingsOrchestratorRegistrationRequestApprove() { Onboarding onboarding = new Onboarding(); onboarding.setOnboardingId("onboardingId"); + onboarding.setStatus(OnboardingStatus.REQUEST); onboarding.setWorkflowType(WorkflowType.FOR_APPROVE_PT); TaskOrchestrationContext orchestrationContext = mockTaskOrchestrationContext(onboarding); @@ -294,4 +302,52 @@ void sendMailRegistrationWithContractWhenApprove() { Mockito.verify(service, times(1)) .sendMailRegistrationWithContractWhenApprove(any()); } + + + @Test + void onboardingCompletionOrchestrator() { + Onboarding onboarding = new Onboarding(); + onboarding.setOnboardingId("onboardingId"); + onboarding.setStatus(OnboardingStatus.PENDING); + onboarding.setWorkflowType(WorkflowType.CONTRACT_REGISTRATION); + onboarding.setInstitution(new Institution()); + + TaskOrchestrationContext orchestrationContext = mockTaskOrchestrationContext(onboarding); + + function.onboardingsOrchestrator(orchestrationContext); + + ArgumentCaptor captorActivity = ArgumentCaptor.forClass(String.class); + Mockito.verify(orchestrationContext, times(4)) + .callActivity(captorActivity.capture(), any(), any(),any()); + assertEquals(CREATE_INSTITUTION_ACTIVITY, captorActivity.getAllValues().get(0)); + assertEquals(CREATE_ONBOARDING_ACTIVITY, captorActivity.getAllValues().get(1)); + assertEquals(SEND_MAIL_COMPLETION_ACTIVITY, captorActivity.getAllValues().get(2)); + assertEquals(SAVE_ONBOARDING_STATUS_ACTIVITY, captorActivity.getAllValues().get(3)); + } + + + @Test + void createInstitutionAndPersistInstitutionId() { + ExecutionContext executionContext = mock(ExecutionContext.class); + when(executionContext.getLogger()).thenReturn(Logger.getGlobal()); + when(completionService.createInstitutionAndPersistInstitutionId(any())) + .thenReturn("id"); + + function.createInstitutionAndPersistInstitutionId(onboardinString, executionContext); + + Mockito.verify(completionService, times(1)) + .createInstitutionAndPersistInstitutionId(any()); + } + + @Test + void sendCompletedEmail() { + ExecutionContext executionContext = mock(ExecutionContext.class); + when(executionContext.getLogger()).thenReturn(Logger.getGlobal()); + doNothing().when(completionService).sendCompletedEmail(any()); + + function.sendMailCompletion(onboardinString, executionContext); + + Mockito.verify(completionService, times(1)) + .sendCompletedEmail(any()); + } }