Documentation for a newer release is available. View Latest

Scheduler de pagos

El objetivo principal es gestionar comandos automáticos de programación de FDP (Future-Dated Payment) bajo demanda (crear, actualizar, eliminar). Esos comandos están relacionados con el propio scheduler, NO con pagos, y se basan en Domain Functions externas de MPS. Además, este concepto utiliza el Persistent Scheduler para almacenarlo en la base de datos.

El esquema general se representa aquí:

payment scheduler flow

Función de programación (Schedule)

Esta función sirve para la creación del scheduler y, en MPS, la solicitud se ve de la siguiente manera:

Nombre Descripción Datos de negocio Respuestas

Schedule Request

Programar FDP con el tiempo de antelación adecuado para activar correctamente la transferencia de crédito en la fecha de ejecución.

Hora programada

Nombre: Schedule Response Descripción: Respuesta a la solicitud Datos de negocio: ninguno Códigos de respuesta: AcceptOrReject Códigos de motivo: <no reasonCodeSet> Completa: true

Dentro del flujo de MPS, esta es la parte donde sucede:

scheduling flow mps

Ahora, veamos el código. La primera parte es un action port de MPS generado, que debe implementarse:

public interface PaymentSchedulerActionPort {

  CompletionStage<Void> execute(ScheduleRequestAction scheduleRequest);

}

La implementación es una parte clave aquí:

@Slf4j
@AllArgsConstructor
public class SamplePaymentSchedulerAdapter implements PaymentSchedulerActionPort {

    SchedulingModuleInterface schedulingModuleInterface;

    @Override
    public CompletionStage<Void> execute(ScheduleRequestAction scheduleRequest) {
        var cron = CronExpressionHelper.calendarToCron(scheduleRequest.getScheduledTime());
        var jobSpecification = JobSpecificationDto.builder()
                .jobSpecificationKey(new JobSpecificationKeyDto("DEBTOR_CT_JOB_ID"))
                .schedulingSpecification(cron)
                .jobRequestor(scheduleRequest.getId())
                .triggerCommand(new PaymentSchedulerCommand(scheduleRequest.getId()))
                .triggerIdentifier("triggerIdentifier")
                .build();
        return schedulingModuleInterface.scheduleJob(jobSpecification);
    }
}

Puedes notar que hemos instanciado nuestro comando dentro del parámetro triggerCommand. Ese comando se presenta a continuación:

@Data
@AllArgsConstructor
public class PaymentSchedulerCommand implements SchedulingCommand {
    private String id;
}

Parece bastante básico; como podemos ver, solo contiene un parámetro ID. Implementa la interfaz SchedulingCommand de la biblioteca shared-scheduling. Hablando de esa biblioteca, hay otra interfaz que debe usarse para que funcione:

public interface SchedulingHelper {

    CompletionStage<Void> execute(String id, final SchedulingCommand request);

    boolean supports(SchedulingCommand request);
}

Nuestra implementación está aquí:

@Slf4j
@RequiredArgsConstructor
public class PaymentSchedulerHelper implements SchedulingHelper {

    @Override
    public CompletionStage<Void> execute(String s, SchedulingCommand schedulingCommand) {
        PaymentSchedulerCommand paymentSchedulerCommand = (PaymentSchedulerCommand) schedulingCommand;
        return CredittransferDomain.paymentScheduler()
                .handle(new ScheduleResponseInput.Builder(paymentSchedulerCommand.getId(), AcceptOrRejectCodes.Accepted).build())
                .thenAccept(it -> log.debug("Scheduled"));
    }

    @Override
    public boolean supports(SchedulingCommand schedulingCommand) {
        return schedulingCommand instanceof PaymentSchedulerCommand;
    }
}

Por último, pero no menos importante, debemos definir un bean que devuelva una instancia de nuestro SchedulingHelper implementado:

@Bean
public PaymentSchedulerHelper paymentSchedulerHelper() {
    return new PaymentSchedulerHelper();
}