PaymentCycleService.java

package uk.gov.dhsc.htbhf.claimant.service.payments;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import uk.gov.dhsc.htbhf.claimant.entitlement.PregnancyEntitlementCalculator;
import uk.gov.dhsc.htbhf.claimant.entity.Claim;
import uk.gov.dhsc.htbhf.claimant.entity.PaymentCycle;
import uk.gov.dhsc.htbhf.claimant.entity.PaymentCycleStatus;
import uk.gov.dhsc.htbhf.claimant.model.eligibility.EligibilityAndEntitlementDecision;
import uk.gov.dhsc.htbhf.claimant.repository.PaymentCycleRepository;

import java.time.LocalDate;

import static uk.gov.dhsc.htbhf.claimant.entity.PaymentCycleStatus.NEW;
import static uk.gov.dhsc.htbhf.eligibility.model.EligibilityStatus.ELIGIBLE;

@Service
public class PaymentCycleService {

    private final PaymentCycleRepository paymentCycleRepository;
    private final Integer cycleDurationInDays;
    private final PregnancyEntitlementCalculator pregnancyEntitlementCalculator;
    private final Integer pendingExpiryCycleDurationInDays;

    public PaymentCycleService(PaymentCycleRepository paymentCycleRepository,
                               @Value("${payment-cycle.cycle-duration-in-days}") Integer cycleDurationInDays,
                               @Value("${payment-cycle.pending-expiry-cycle-duration-in-days}") Integer pendingExpiryCycleDurationInDays,
                               PregnancyEntitlementCalculator pregnancyEntitlementCalculator) {
        this.paymentCycleRepository = paymentCycleRepository;
        this.cycleDurationInDays = cycleDurationInDays;
        this.pendingExpiryCycleDurationInDays = pendingExpiryCycleDurationInDays;
        this.pregnancyEntitlementCalculator = pregnancyEntitlementCalculator;
    }

    /**
     * Creates a new payment cycle for the given claim and cycle start date, saving it in the database.
     * The cycle end date is set to the start date plus the payment cycle duration time.
     *
     * @param claim          claim to create a payment cycle for
     * @param cycleStartDate the start date of the new payment cycle
     * @return the new payment cycle.
     */
    public PaymentCycle createAndSavePaymentCycle(Claim claim, LocalDate cycleStartDate) {
        PaymentCycle paymentCycle = PaymentCycle.builder()
                .claim(claim)
                .paymentCycleStatus(NEW)
                .cycleStartDate(cycleStartDate)
                .cycleEndDate(cycleStartDate.plusDays(cycleDurationInDays - 1))
                .build();
        paymentCycleRepository.save(paymentCycle);
        return paymentCycle;
    }

    /**
     * Creates a new payment cycle, saving it in the database.
     * The cycle end date is set to the start date plus the payment cycle duration time.
     * The expected due date is set only if the voucher entitlement contains pregnancy vouchers.
     * EligibilityStatus is set to ELIGIBLE.
     *
     * @param claim                             claim to create a payment cycle for
     * @param cycleStartDate                    the start date of the new payment cycle
     * @param eligibilityAndEntitlementDecision the eligibility and entitlement decision
     * @return the new payment cycle.
     */
    public PaymentCycle createAndSavePaymentCycleForEligibleClaim(Claim claim,
                                                                  LocalDate cycleStartDate,
                                                                  EligibilityAndEntitlementDecision eligibilityAndEntitlementDecision) {
        PaymentCycle paymentCycle = PaymentCycle.builder()
                .claim(claim)
                .paymentCycleStatus(NEW)
                .cycleStartDate(cycleStartDate)
                .cycleEndDate(cycleStartDate.plusDays(cycleDurationInDays - 1))
                .eligibilityStatus(ELIGIBLE)
                .identityAndEligibilityResponse(eligibilityAndEntitlementDecision.getIdentityAndEligibilityResponse())
                .expectedDeliveryDate(getExpectedDeliveryDateIfRelevant(claim, cycleStartDate))
                .build();

        paymentCycle.applyVoucherEntitlement(eligibilityAndEntitlementDecision.getVoucherEntitlement());
        paymentCycleRepository.save(paymentCycle);
        return paymentCycle;
    }

    private LocalDate getExpectedDeliveryDateIfRelevant(Claim claim, LocalDate cycleStartDate) {
        if (pregnancyEntitlementCalculator.isEntitledToVoucher(
                claim.getClaimant().getExpectedDeliveryDate(),
                cycleStartDate,
                claim.getCurrentIdentityAndEligibilityResponse().getQualifyingReason())) {
            return claim.getClaimant().getExpectedDeliveryDate();
        }
        return null;
    }

    /**
     * Save the PaymentCycle to the database.
     *
     * @param paymentCycle The {@link PaymentCycle} to save
     */
    public void savePaymentCycle(PaymentCycle paymentCycle) {
        paymentCycleRepository.save(paymentCycle);
    }

    /**
     * Update and saves the payment cycle with values from the decision.
     *
     * @param paymentCycle payment cycle to update
     * @param decision     decision to update the payment cycle with
     */
    public void updatePaymentCycleFromDecision(PaymentCycle paymentCycle, EligibilityAndEntitlementDecision decision) {
        paymentCycle.setEligibilityStatus(decision.getEligibilityStatus());
        paymentCycle.setIdentityAndEligibilityResponse(decision.getIdentityAndEligibilityResponse());
        paymentCycle.applyVoucherEntitlement(decision.getVoucherEntitlement());
        PaymentCycleStatus paymentCycleStatus = PaymentCycleStatus.getStatusForEligibilityDecision(decision.getEligibilityStatus());
        paymentCycle.setPaymentCycleStatus(paymentCycleStatus);
        LocalDate expectedDeliveryDate = getExpectedDeliveryDateIfRelevant(paymentCycle.getClaim(), paymentCycle.getCycleStartDate());
        paymentCycle.setExpectedDeliveryDate(expectedDeliveryDate);
        paymentCycleRepository.save(paymentCycle);
    }

    /**
     * Update and saves the payment cycle with status and card balance from the given calculation.
     *
     * @param paymentCycle       payment cycle to update
     * @param paymentCalculation the calculation of how much of the entitlement should be paid this cycle
     */
    public void updatePaymentCycleFromCalculation(PaymentCycle paymentCycle, PaymentCalculation paymentCalculation) {
        paymentCycle.setPaymentCycleStatus(paymentCalculation.getPaymentCycleStatus());
        paymentCycle.setCardBalanceInPence(paymentCalculation.getAvailableBalanceInPence());
        paymentCycle.setCardBalanceTimestamp(paymentCalculation.getBalanceTimestamp());
        paymentCycleRepository.save(paymentCycle);
    }

    /**
     * Sets the paymentCycle's end date to the start date plus the pending expiry cycle duration time.
     * @param paymentCycle payment cycle to update.
     */
    public void updateEndDateForClaimBecomingPendingExpiry(PaymentCycle paymentCycle) {
        paymentCycle.setCycleEndDate(paymentCycle.getCycleStartDate().plusDays(pendingExpiryCycleDurationInDays - 1));
        paymentCycleRepository.save(paymentCycle);
    }
}