RequestPaymentMessageProcessor.java

package uk.gov.dhsc.htbhf.claimant.message.processor;

import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import uk.gov.dhsc.htbhf.claimant.entity.Message;
import uk.gov.dhsc.htbhf.claimant.entity.PaymentCycle;
import uk.gov.dhsc.htbhf.claimant.message.MessageQueueClient;
import uk.gov.dhsc.htbhf.claimant.message.MessageStatus;
import uk.gov.dhsc.htbhf.claimant.message.MessageType;
import uk.gov.dhsc.htbhf.claimant.message.MessageTypeProcessor;
import uk.gov.dhsc.htbhf.claimant.message.context.MessageContextLoader;
import uk.gov.dhsc.htbhf.claimant.message.context.RequestPaymentMessageContext;
import uk.gov.dhsc.htbhf.claimant.message.payload.CompletePaymentMessagePayload;
import uk.gov.dhsc.htbhf.claimant.message.payload.PaymentType;
import uk.gov.dhsc.htbhf.claimant.reporting.PaymentAction;
import uk.gov.dhsc.htbhf.claimant.service.audit.EventAuditor;
import uk.gov.dhsc.htbhf.claimant.service.payments.PaymentCalculation;
import uk.gov.dhsc.htbhf.claimant.service.payments.PaymentCycleService;
import uk.gov.dhsc.htbhf.claimant.service.payments.PaymentResult;
import uk.gov.dhsc.htbhf.claimant.service.payments.PaymentService;
import uk.gov.dhsc.htbhf.logging.event.FailureEvent;

import javax.transaction.Transactional;

import static uk.gov.dhsc.htbhf.claimant.entity.PaymentCycleStatus.BALANCE_TOO_HIGH_FOR_PAYMENT;
import static uk.gov.dhsc.htbhf.claimant.message.MessageStatus.COMPLETED;
import static uk.gov.dhsc.htbhf.claimant.message.MessageType.COMPLETE_PAYMENT;
import static uk.gov.dhsc.htbhf.claimant.message.MessageType.REQUEST_PAYMENT;
import static uk.gov.dhsc.htbhf.claimant.reporting.PaymentAction.INITIAL_PAYMENT;
import static uk.gov.dhsc.htbhf.claimant.reporting.PaymentAction.SCHEDULED_PAYMENT;
import static uk.gov.dhsc.htbhf.claimant.service.payments.PaymentCalculation.aFullPaymentCalculationWithZeroBalance;

/**
 * Processes REQUEST_PAYMENT messages by calling the PaymentService.
 */
@Component
@AllArgsConstructor
@Slf4j
public class RequestPaymentMessageProcessor implements MessageTypeProcessor {

    private PaymentService paymentService;
    private MessageContextLoader messageContextLoader;
    private MessageQueueClient messageQueueClient;
    private PaymentCycleService paymentCycleService;
    private EventAuditor eventAuditor;

    @Override
    @Transactional(Transactional.TxType.REQUIRES_NEW)
    public MessageStatus processMessage(Message message) {
        RequestPaymentMessageContext messageContext = messageContextLoader.loadRequestPaymentMessageContext(message);
        PaymentCycle paymentCycle = messageContext.getPaymentCycle();
        PaymentType paymentType = messageContext.getPaymentType();

        // TODO AFHS-788 Handle payments with balance check overrides.
        if (paymentType == PaymentType.FIRST_PAYMENT) {
            PaymentCalculation paymentCalculation = aFullPaymentCalculationWithZeroBalance(paymentCycle.getTotalEntitlementAmountInPence());
            makePayment(paymentCycle, INITIAL_PAYMENT, paymentCalculation, paymentType);
        } else {
            PaymentCalculation paymentCalculation = paymentService.calculatePaymentAmount(paymentCycle);
            if (paymentCalculation.getPaymentCycleStatus() == BALANCE_TOO_HIGH_FOR_PAYMENT) {
                paymentCycleService.updatePaymentCycleFromCalculation(paymentCycle, paymentCalculation);
                log.debug("No payment will be made as the existing balance on the card is too high for PaymentCycle {}", paymentCycle.getId());
                eventAuditor.auditBalanceTooHighForPayment(paymentCycle);
                return COMPLETED;
            }
            makePayment(paymentCycle, SCHEDULED_PAYMENT, paymentCalculation, paymentType);
        }

        return COMPLETED;
    }

    private void makePayment(PaymentCycle paymentCycle, PaymentAction paymentAction, PaymentCalculation paymentCalculation, PaymentType paymentType) {
        PaymentResult paymentResult = paymentService.makePayment(paymentCycle, paymentCalculation.getPaymentAmount(), paymentAction);
        CompletePaymentMessagePayload payload = CompletePaymentMessagePayload.builder()
                .paymentType(paymentType)
                .paymentResult(paymentResult)
                .paymentCalculation(paymentCalculation)
                .paymentCycleId(paymentCycle.getId())
                .claimId(paymentCycle.getClaim().getId())
                .build();
        messageQueueClient.sendMessage(payload, COMPLETE_PAYMENT);
    }

    @Override
    public MessageType supportsMessageType() {
        return REQUEST_PAYMENT;
    }

    @Override
    @Transactional(Transactional.TxType.REQUIRES_NEW)
    public void processFailedMessage(Message message, FailureEvent failureEvent) {
        RequestPaymentMessageContext messageContext = messageContextLoader.loadRequestPaymentMessageContext(message);
        paymentService.saveFailedPayment(messageContext.getPaymentCycle(), failureEvent);
    }
}