EntitlementCalculator.java

package uk.gov.dhsc.htbhf.claimant.entitlement;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import uk.gov.dhsc.htbhf.dwp.model.QualifyingReason;

import java.time.LocalDate;
import java.util.List;
import java.util.Optional;

import static uk.gov.dhsc.htbhf.claimant.message.processor.ChildDateOfBirthCalculator.getNumberOfChildrenUnderFour;
import static uk.gov.dhsc.htbhf.claimant.message.processor.ChildDateOfBirthCalculator.getNumberOfChildrenUnderOne;

/**
 * Responsible for calculating how many 'vouchers' an eligible claimant is entitled to.
 * The number of vouchers is based on:
 * (2) vouchers per child under one, plus
 * (1) voucher per child between one and four, plus
 * (1) voucher per pregnancy
 * (numbers in brackets are configurable).
 */
@Component
@Slf4j
public class EntitlementCalculator {

    private final PregnancyEntitlementCalculator pregnancyEntitlementCalculator;
    private final int vouchersPerChildUnderOne;
    private final int vouchersPerChildBetweenOneAndFour;
    private final int vouchersPerPregnancy;
    private final int voucherValueInPence;

    public EntitlementCalculator(
            PregnancyEntitlementCalculator pregnancyEntitlementCalculator,
            @Value("${entitlement.number-of-vouchers-per-child-under-one}") int vouchersPerChildUnderOne,
            @Value("${entitlement.number-of-vouchers-per-child-between-one-and-four}") int vouchersPerChildBetweenOneAndFour,
            @Value("${entitlement.number-of-vouchers-per-pregnancy}") int vouchersPerPregnancy,
            @Value("${entitlement.voucher-value-in-pence}") int voucherValueInPence) {
        this.pregnancyEntitlementCalculator = pregnancyEntitlementCalculator;
        this.vouchersPerChildUnderOne = vouchersPerChildUnderOne;
        this.vouchersPerChildBetweenOneAndFour = vouchersPerChildBetweenOneAndFour;
        this.vouchersPerPregnancy = vouchersPerPregnancy;
        this.voucherValueInPence = voucherValueInPence;
    }

    /**
     * Calculates the {@link VoucherEntitlement} a claimant is entitled to for a given date. The number of children under one and
     * the number between one and four is calculated for the given date.
     *
     * @param expectedDueDate       the expected due date of the claimant. Use Empty.optional() if the claimant is not pregnant
     * @param dateOfBirthOfChildren the date of birth of the claimant's children
     * @param entitlementDate       the date to check entitlement for
     * @param qualifyingReason      overrides the reason that this applicant qualifies for Healthy Start
     * @return the voucher entitlement calculated for the claimant
     */
    public VoucherEntitlement calculateVoucherEntitlement(Optional<LocalDate> expectedDueDate,
                                                          List<LocalDate> dateOfBirthOfChildren,
                                                          LocalDate entitlementDate,
                                                          QualifyingReason qualifyingReason) {
        int numberOfChildrenUnderFour = getNumberOfChildrenUnderFour(dateOfBirthOfChildren, entitlementDate);
        int numberOfChildrenUnderOne = getNumberOfChildrenUnderOne(dateOfBirthOfChildren, entitlementDate);

        if (numberOfChildrenUnderFour < numberOfChildrenUnderOne) {
            log.error("Number of children under four ({}) must not be less than number of children under one ({})",
                    numberOfChildrenUnderFour, numberOfChildrenUnderOne);
            throw new IllegalArgumentException("Number of children under four must not be less than number of children under one");
        }

        // call pregnancyEntitlementCalculator if the expectedDueDate exists
        boolean isEntitledToPregnancyVoucher = expectedDueDate
                .map(dueDate -> pregnancyEntitlementCalculator.isEntitledToVoucher(dueDate, entitlementDate, qualifyingReason)).orElse(false);

        return createVoucherEntitlement(isEntitledToPregnancyVoucher, numberOfChildrenUnderFour, numberOfChildrenUnderOne, entitlementDate);
    }

    private VoucherEntitlement createVoucherEntitlement(boolean isEntitledToPregnancyVoucher,
                                                        int numberOfChildrenUnderFour,
                                                        int numberOfChildrenUnderOne,
                                                        LocalDate entitlementDate) {
        int numberOfChildrenBetweenOneAndFour = numberOfChildrenUnderFour - numberOfChildrenUnderOne;

        int vouchersForPregnancy = calculateVouchersForPregnancy(isEntitledToPregnancyVoucher);
        int vouchersForChildrenUnderOne = calculateVouchersForChildrenUnderOne(numberOfChildrenUnderOne);
        int vouchersForChildrenBetweenOneAndFour = calculateVouchersForChildrenBetweenOneAndFour(numberOfChildrenBetweenOneAndFour);

        return VoucherEntitlement.builder()
                .vouchersForPregnancy(vouchersForPregnancy)
                .vouchersForChildrenUnderOne(vouchersForChildrenUnderOne)
                .vouchersForChildrenBetweenOneAndFour(vouchersForChildrenBetweenOneAndFour)
                .singleVoucherValueInPence(voucherValueInPence)
                .entitlementDate(entitlementDate)
                .build();
    }

    private int calculateVouchersForPregnancy(boolean isEntitledToPregnancyVoucher) {
        return isEntitledToPregnancyVoucher ? vouchersPerPregnancy : 0;
    }

    private int calculateVouchersForChildrenUnderOne(int numberOfChildrenUnderOne) {
        return numberOfChildrenUnderOne * vouchersPerChildUnderOne;
    }

    private int calculateVouchersForChildrenBetweenOneAndFour(int numberOfChildrenBetweenOneAndFour) {
        return numberOfChildrenBetweenOneAndFour * vouchersPerChildBetweenOneAndFour;
    }

}