src/applications/gi/selectors/calculator.js
import { isEmpty } from 'lodash';
import { createSelector } from 'reselect';
import {
formatCurrency,
isCountryUSA,
isCountryInternational,
} from '../utils/helpers';
import { ariaLabels } from '../constants';
const getConstants = state => state.constants.constants;
const getEligibilityDetails = state => state.eligibility;
const getInstitution = state => state.profile.attributes;
const getFormInputs = state => state.calculator;
export const getInstitutionType = institution =>
institution.type
? institution.type.toLowerCase()
: institution.institutionTypeName.toLowerCase();
const getDerivedValues = createSelector(
getConstants,
getEligibilityDetails,
getInstitution,
getFormInputs,
(constant, eligibility, institution, inputs) => {
if (
[constant, eligibility, institution, inputs].some(e => !e || isEmpty(e))
) {
return {};
}
let monthlyRate;
let numberOfTerms;
let ropOld;
let tuitionFeesCap;
let acadYearLength;
let termLength;
let ropOjt;
let kickerBenefit;
let buyUpRate;
let tuitionFeesTerm1;
let tuitionFeesTerm2;
let tuitionFeesTerm3;
let yrBenTerm1;
let yrBenTerm2;
let yrBenTerm3;
let yrBenTotal;
let housingAllowTerm1;
let housingAllowTerm2;
let housingAllowTerm3;
let housingAllowTotal;
let giBillTotalText;
let totalTerm1;
let totalTerm2;
let totalTerm3;
let totalYear;
let monthlyRateDisplay;
let nameOfTerm1;
let nameOfTerm2;
let nameOfTerm3;
let nameOfTerm4;
let bookStipendTerm1;
let bookStipendTerm2;
let bookStipendTerm3;
let bookStipendTotal;
const {
cumulativeService,
eligForPostGiBill,
enlistmentService,
militaryStatus,
onlineClasses,
} = eligibility;
let giBillChapter;
if (
eligibility.giBillChapter === '33a' ||
eligibility.giBillChapter === '33b'
) {
giBillChapter = 33;
} else {
giBillChapter = +eligibility.giBillChapter;
}
const consecutiveService = +eligibility.consecutiveService;
const numberOfDependents = +eligibility.numberOfDependents;
const spouseActiveDuty = eligibility.spouseActiveDuty === 'yes';
const serviceDischarge = cumulativeService === 'service discharge';
const purpleHeart = cumulativeService === 'purple heart';
const institutionType = getInstitutionType(institution);
const isOJT = institutionType === 'ojt';
const isFlight = institutionType === 'flight';
const isCorrespondence = institutionType === 'correspondence';
const isFlightOrCorrespondence = isFlight || isCorrespondence;
const isPublic = institutionType === 'public';
const isChapter33 = giBillChapter === 33;
const isActiveDuty = militaryStatus === 'active duty';
const institutionCountry = institution.country.toLowerCase();
// VRE and post-9/11 eligibility
const vre911Eligible = giBillChapter === 31 && eligForPostGiBill === 'yes';
// VRE-without-post-911 eligibility
const onlyVRE = giBillChapter === 31 && eligForPostGiBill === 'no';
// Determines benefits tier
const tier =
vre911Eligible || serviceDischarge || purpleHeart
? 1
: +cumulativeService;
const oldGiBill =
giBillChapter === 30 || giBillChapter === 1606 || giBillChapter === 35;
// Determines whether monthly benefit can only be spent on tuition/fees
const activeDutyThirty =
militaryStatus === 'active duty' && giBillChapter === 30;
const correspondenceOrFlightUnderOldGiBill =
isFlightOrCorrespondence && oldGiBill;
const ropOldAndChapter =
['less than half', 'quarter'].includes(inputs.enrolledOld) &&
[30, 35].includes(giBillChapter);
const onlyTuitionFees =
activeDutyThirty ||
correspondenceOrFlightUnderOldGiBill ||
ropOldAndChapter;
// The monthly benefit rate for non-chapter 33 benefits
switch (giBillChapter) {
case 30: {
monthlyRate =
(enlistmentService === '3'
? constant.MGIB3YRRATE
: constant.MGIB2YRRATE) * (isOJT ? 0.75 : 1);
break;
}
case 1606: {
monthlyRate = constant.SRRATE * (isOJT ? 0.75 : 1);
break;
}
case 35: {
if (isOJT) {
monthlyRate = constant.DEARATEOJT;
} else if (isFlight) {
monthlyRate = 0;
} else {
monthlyRate = {
full: constant.DEARATEFULLTIME,
'three quarters': constant.DEARATETHREEQUARTERS,
half: constant.DEARATEONEHALF,
'less than half': constant.DEARATEUPTOONEHALF,
quarter: constant.DEARATEUPTOONEQUARTER,
}[inputs.enrolledOld];
}
break;
}
case 31: {
const OJT = isOJT ? 'OJT' : '';
if (numberOfDependents <= 2) {
monthlyRate = constant[`VRE${numberOfDependents}DEPRATE${OJT}`];
} else {
monthlyRate =
constant[`VRE2DEPRATE${OJT}`] +
(numberOfDependents - 2) * constant[`VREINCRATE${OJT}`];
}
break;
}
default:
monthlyRate = 0;
}
// Calculate the total number of academic terms - getNumberOfTerms
if (isOJT || inputs.calendar === 'quarters') {
numberOfTerms = 3;
} else if (inputs.calendar === 'semesters') {
numberOfTerms = 2;
} else if (inputs.calendar === 'nontraditional') {
numberOfTerms = +inputs.numberNontradTerms;
}
// Set the net price (Payer of Last Resort) - getTuitionNetPrice
const tuitionNetPrice = Math.max(
0,
inputs.tuitionFees - inputs.scholarships - inputs.tuitionAssist,
);
// Set the proper tuition/fees cap - getTuitionFeesCap
if (isFlight) {
tuitionFeesCap = constant.FLTTFCAP;
} else if (isCorrespondence) {
tuitionFeesCap = constant.CORRESPONDTFCAP;
} else if (isPublic && isCountryUSA(institutionCountry)) {
tuitionFeesCap =
inputs.inState === 'yes'
? +inputs.tuitionFees
: +inputs.inStateTuitionFees;
} else {
// Default cap for private, foreign, and for-profit institutions
tuitionFeesCap = constant.TFCAP;
}
// Calculate the tuition/fees per term - getTuitionFeesPerTerm
const tuitionFeesPerTerm = +inputs.tuitionFees / numberOfTerms;
// Calculate the length of each term - getTermLength
// and Calculate the length of the academic year - getAcadYearLength
acadYearLength = 9;
if (isOJT) {
termLength = 6;
} else {
switch (inputs.calendar) {
case 'semesters':
termLength = 4.5;
break;
case 'quarters':
termLength = 3;
break;
case 'nontraditional':
termLength = +inputs.lengthNontradTerms;
acadYearLength =
+inputs.numberNontradTerms * +inputs.lengthNontradTerms;
break;
default:
// noop
}
}
// Calculate the rate of pursuit - getRop
const rop = {
full: 1,
'three quarters': 0.8,
'more than half': 0.6,
'half or less': 0,
}[inputs.enrolled];
// Calculate the rate of pursuit for Book Stipend - getRopBook
const ropBook = {
full: 1,
'three quarters': 0.75,
'more than half': 0.5,
'half or less': 0.25,
}[inputs.enrolled];
// Calculate the rate of pursuit for Old GI Bill - getCalcRopOld
// and Calculate the rate of pursuit for OJT - getRopOjt
if (isOJT) {
// eslint-disable-next-line no-multi-assign
ropOjt = ropOld = +inputs.working / 30;
} else if (giBillChapter === 35) {
// only do these calculations for DEA
ropOld = 1;
} else {
ropOld = {
full: 1,
'three quarters': 0.75,
half: 0.5,
'less than half': 0.5,
quarter: 0.25,
}[inputs.enrolledOld];
}
// Determine yellow ribbon eligibility - getYellowRibbonEligibility
const yellowRibbonElig = !(
tier < 1 ||
!institution.yr ||
inputs.yellowRibbonRecipient === 'no' ||
militaryStatus === 'active duty' ||
isOJT ||
isFlightOrCorrespondence
);
// Determine kicker benefit level - getKickerBenefit
if (inputs.kickerEligible !== 'yes') {
kickerBenefit = 0;
} else {
kickerBenefit = +inputs.kickerAmount;
}
// Determine buy up rates - getBuyUpRate
if (inputs.buyUp === 'no' || giBillChapter !== 30) {
buyUpRate = 0;
} else {
buyUpRate = Math.min(+inputs.buyUpAmount, 600) / 4;
}
// Calculate Housing Allowance Rate Final - getMonthlyRateFinal
const monthlyRateFinal = ropOld * (monthlyRate + buyUpRate + kickerBenefit);
// Calculate the names of Terms 1-4
if (isOJT) {
nameOfTerm1 = 'Months 1-6';
nameOfTerm2 = 'Months 7-12';
nameOfTerm3 = 'Months 13-18';
nameOfTerm4 = 'Months 19-24';
} else {
switch (inputs.calendar) {
case 'semesters':
nameOfTerm1 = 'Fall';
nameOfTerm2 = 'Spring';
nameOfTerm3 = '';
break;
case 'quarters':
nameOfTerm1 = 'Fall';
nameOfTerm2 = 'Winter';
nameOfTerm3 = 'Spring';
break;
case 'nontraditional':
nameOfTerm1 = 'Term 1';
nameOfTerm2 = 'Term 2';
nameOfTerm3 = 'Term 3';
break;
default:
// noop
}
nameOfTerm4 = 'Total per year';
}
// Calculate Tuition Fees for Term #1 - getTuitionFeesTerm1
const shouldHaveNoTuitionFeesTerm1 =
isOJT || oldGiBill || (giBillChapter === 31 && isFlightOrCorrespondence);
if (shouldHaveNoTuitionFeesTerm1) {
tuitionFeesTerm1 = 0;
} else if (giBillChapter === 31) {
tuitionFeesTerm1 = tuitionFeesPerTerm;
} else {
tuitionFeesTerm1 = Math.max(
0,
Math.min(
tier * tuitionFeesPerTerm,
tier * tuitionFeesCap,
tier * tuitionNetPrice,
),
);
}
// getTuitionFeesTerm2
const shouldHaveNoTuitionFeesTerm2 =
isOJT ||
oldGiBill ||
(giBillChapter === 31 && isFlightOrCorrespondence) ||
(inputs.calendar === 'nontraditional' && numberOfTerms === 1);
if (shouldHaveNoTuitionFeesTerm2) {
tuitionFeesTerm2 = 0;
} else if (giBillChapter === 31) {
tuitionFeesTerm2 = tuitionFeesPerTerm;
} else {
tuitionFeesTerm2 = Math.max(
0,
Math.min(
tier * tuitionFeesPerTerm,
tier * tuitionFeesCap - tuitionFeesTerm1,
tier * tuitionNetPrice - tuitionFeesTerm1,
),
);
}
// getTuitionFeesTerm3
const shouldHaveNoTuitionFeesTerm3 =
isOJT ||
oldGiBill ||
(giBillChapter === 31 && isFlightOrCorrespondence) ||
(inputs.calendar === 'semesters' ||
(inputs.calendar === 'nontraditional' && numberOfTerms < 3));
if (shouldHaveNoTuitionFeesTerm3) {
tuitionFeesTerm3 = 0;
} else if (giBillChapter === 31) {
tuitionFeesTerm3 = tuitionFeesPerTerm;
} else {
tuitionFeesTerm3 = Math.max(
0,
Math.min(
tier * tuitionFeesPerTerm,
tier * tuitionFeesCap - tuitionFeesTerm1 - tuitionFeesTerm2,
tier * tuitionNetPrice - tuitionFeesTerm1 - tuitionFeesTerm2,
),
);
}
// Calculate the name of Tuition Fees Total - getTuitionFeesTotal
const tuitionFeesTotal =
tuitionFeesTerm1 + tuitionFeesTerm2 + tuitionFeesTerm3;
const yellowRibbonAmount =
inputs.yellowRibbonRecipient === 'yes' ? +inputs.yellowRibbonAmount : 0;
// Calculate Yellow Ribbon for Term #1 - getYrBenTerm1
const shouldHaveNoYrBenTerm1 =
!yellowRibbonElig ||
yellowRibbonAmount === 0 ||
oldGiBill ||
giBillChapter === 31 ||
tuitionFeesPerTerm === tuitionFeesTerm1;
if (shouldHaveNoYrBenTerm1) {
yrBenTerm1 = 0;
} else {
yrBenTerm1 = Math.max(
0,
Math.min(
tuitionFeesPerTerm - tuitionFeesTerm1,
tuitionNetPrice - tuitionFeesTerm1,
yellowRibbonAmount * 2,
),
);
}
// getYrBenTerm2
const shouldHaveNoYrBenTerm2 =
!yellowRibbonElig ||
yellowRibbonAmount === 0 ||
oldGiBill ||
giBillChapter === 31 ||
(inputs.calendar === 'nontraditional' && numberOfTerms === 1) ||
tuitionFeesPerTerm === tuitionFeesTerm2;
if (shouldHaveNoYrBenTerm2) {
yrBenTerm2 = 0;
} else {
yrBenTerm2 = Math.max(
0,
Math.min(
tuitionFeesPerTerm - tuitionFeesTerm2,
tuitionNetPrice - tuitionFeesTerm1 - tuitionFeesTerm2 - yrBenTerm1,
yellowRibbonAmount * 2 - yrBenTerm1,
),
);
}
// getYrBenTerm3
const shouldHaveNoYrBenTerm3 =
!yellowRibbonElig ||
yellowRibbonAmount === 0 ||
oldGiBill ||
giBillChapter === 31 ||
inputs.calendar === 'semesters' ||
(inputs.calendar === 'nontraditional' && numberOfTerms < 3) ||
tuitionFeesPerTerm === tuitionFeesTerm3;
if (shouldHaveNoYrBenTerm3) {
yrBenTerm3 = 0;
} else {
yrBenTerm3 = Math.max(
0,
Math.min(
tuitionFeesPerTerm - tuitionFeesTerm3,
tuitionNetPrice -
tuitionFeesTerm1 -
tuitionFeesTerm2 -
tuitionFeesTerm3 -
yrBenTerm1 -
yrBenTerm1,
yellowRibbonAmount * 2 - yrBenTerm1 - yrBenTerm2,
),
);
}
// Calculate Yellow Ribbon for the Year - getYrBenTotal
if (!yellowRibbonElig || yellowRibbonAmount === 0) {
yrBenTotal = 0;
} else {
yrBenTotal = yrBenTerm1 + yrBenTerm2 + yrBenTerm3;
}
// Calculate Yellow Ribbon by school / VA contributions - getYrBreakdown
const yrBenSchoolTerm1 = yrBenTerm1 / 2;
const yrBenVaTerm1 = yrBenTerm1 / 2;
const yrBenSchoolTerm2 = yrBenTerm2 / 2;
const yrBenVaTerm2 = yrBenTerm2 / 2;
const yrBenSchoolTerm3 = yrBenTerm3 / 2;
const yrBenVaTerm3 = yrBenTerm3 / 2;
const yrBenSchoolTotal = yrBenTotal / 2;
const yrBenVaTotal = yrBenTotal / 2;
// Calculate Total Paid to School - getTotalPaidToSchool
const totalToSchool = tuitionFeesTotal + yrBenTotal;
// Calculate Total Scholarships and Tuition Assistance - getTotalScholarships
const totalScholarshipTa = +inputs.scholarships + +inputs.tuitionAssist;
// Calculate Total Left to Pay - getTotalLeftToPay
const totalLeftToPay = Math.max(
0,
+inputs.tuitionFees - totalToSchool - totalScholarshipTa,
);
const totalHousingAllowance = monthlyRateFinal * termLength;
let bah;
// if beneficiary has indicated they are using a localized rate and beneficiaryLocationBah exists, then a localized rate has been fetched and should be used
const useBeneficiaryLocationRate =
inputs.beneficiaryLocationBah !== null &&
(inputs.beneficiaryLocationQuestion === 'extension' ||
inputs.beneficiaryLocationQuestion === 'other');
// if beneficiary has indicated they are using the grandfathered rate, use it when available;
const useGrandfatheredBeneficiaryLocationRate =
inputs.giBillBenefit === 'yes';
const hasUsedGiBillBenefit = inputs.giBillBenefit === 'yes';
const avgBah = !hasUsedGiBillBenefit
? constant.AVGDODBAH
: constant.AVGVABAH;
if (useBeneficiaryLocationRate) {
// sometimes there's no grandfathered rate for a zip code
bah =
useGrandfatheredBeneficiaryLocationRate &&
inputs.beneficiaryLocationGrandfatheredBah
? inputs.beneficiaryLocationGrandfatheredBah
: inputs.beneficiaryLocationBah;
} else {
// use the DOD rate on staging
bah =
!hasUsedGiBillBenefit && institution.dodBah
? institution.dodBah
: institution.bah;
}
const hasClassesOutsideUS =
(isCountryInternational(institutionCountry) &&
!useBeneficiaryLocationRate) ||
inputs.classesOutsideUS;
const isUSSchool = facilityCode => {
// the last two of the facility code is used to determine if the institution is foreign or domestic
const foreignDomesticInstituteFacilityCode = facilityCode.slice(-2);
const digits = parseInt(foreignDomesticInstituteFacilityCode, 10);
return digits < 52 || (digits > 60 && digits < 67);
};
const isPhilipines = facilityCode => {
const digits = parseInt(facilityCode[6] + facilityCode[7], 10);
return digits === 62;
};
// Calculate Housing Allowance for Term #1 - getHousingAllowTerm1
if (
isOJT &&
(militaryStatus === 'active duty' ||
(giBillChapter === 33 &&
militaryStatus === 'spouse' &&
spouseActiveDuty))
) {
housingAllowTerm1 = 0;
} else if (giBillChapter === 35 && isPhilipines(institution.facilityCode)) {
housingAllowTerm1 = totalHousingAllowance / 2;
} else if (isOJT && (giBillChapter === 35 || oldGiBill || onlyVRE)) {
housingAllowTerm1 = monthlyRateFinal;
} else if (giBillChapter === 31 && isFlightOrCorrespondence) {
housingAllowTerm1 = 0;
} else if (giBillChapter === 1606 && isFlight) {
housingAllowTerm1 = Math.max(
0,
Math.min(totalHousingAllowance, tuitionFeesPerTerm * 0.55),
);
} else if (giBillChapter === 1606 && isCorrespondence) {
housingAllowTerm1 = Math.max(
0,
Math.min(
totalHousingAllowance,
tuitionFeesPerTerm * (consecutiveService * 0.6),
),
);
} else if (onlyTuitionFees) {
housingAllowTerm1 = Math.max(
0,
Math.min(totalHousingAllowance, tuitionFeesPerTerm),
);
} else if (oldGiBill || onlyVRE) {
housingAllowTerm1 = totalHousingAllowance;
} else if (
militaryStatus === 'active duty' ||
(militaryStatus === 'spouse' && spouseActiveDuty)
) {
housingAllowTerm1 = rop * kickerBenefit * termLength;
} else if (isFlightOrCorrespondence) {
housingAllowTerm1 = 0;
} else if (isOJT) {
if (onlineClasses === 'yes') {
housingAllowTerm1 = ropOjt * ((tier * avgBah) / 2 + kickerBenefit);
} else {
housingAllowTerm1 = ropOjt * (tier * bah + kickerBenefit);
}
} else if (
onlineClasses === 'yes' &&
!isUSSchool(institution.facilityCode)
) {
housingAllowTerm1 = 0;
} else if (onlineClasses === 'yes') {
housingAllowTerm1 =
termLength * rop * ((tier * avgBah) / 2 + kickerBenefit);
} else if (hasClassesOutsideUS) {
housingAllowTerm1 = termLength * rop * (tier * avgBah + kickerBenefit);
} else {
housingAllowTerm1 = termLength * rop * (tier * bah + kickerBenefit);
}
// getHousingAllowTerm2
if (
isOJT &&
(militaryStatus === 'active duty' ||
(giBillChapter === 33 &&
militaryStatus === 'spouse' &&
spouseActiveDuty))
) {
housingAllowTerm2 = 0;
} else if (giBillChapter === 35 && isPhilipines(institution.facilityCode)) {
housingAllowTerm2 = totalHousingAllowance / 2;
} else if (giBillChapter === 35 && isOJT) {
housingAllowTerm2 = 0.75 * monthlyRateFinal;
} else if (oldGiBill && isOJT) {
housingAllowTerm2 = (6.6 / 9) * monthlyRateFinal;
} else if (onlyVRE && isOJT) {
housingAllowTerm2 = monthlyRateFinal;
} else if (isOJT) {
housingAllowTerm2 = 0.8 * ropOjt * (tier * bah + kickerBenefit);
} else if (inputs.calendar === 'nontraditional' && numberOfTerms === 1) {
housingAllowTerm2 = 0;
} else if (giBillChapter === 31 && isFlightOrCorrespondence) {
housingAllowTerm2 = 0;
} else if (giBillChapter === 1606 && isFlight) {
housingAllowTerm2 = Math.max(
0,
Math.min(totalHousingAllowance, tuitionFeesPerTerm * 0.55),
);
} else if (giBillChapter === 1606 && isCorrespondence) {
housingAllowTerm2 = Math.max(
0,
Math.min(
totalHousingAllowance,
tuitionFeesPerTerm * (consecutiveService * 0.6),
),
);
} else if (onlyTuitionFees) {
housingAllowTerm2 = Math.max(
0,
Math.min(totalHousingAllowance, tuitionFeesPerTerm),
);
} else if (oldGiBill || onlyVRE) {
housingAllowTerm2 = totalHousingAllowance;
} else if (
militaryStatus === 'active duty' ||
(militaryStatus === 'spouse' && spouseActiveDuty)
) {
housingAllowTerm2 = rop * kickerBenefit * termLength;
} else if (isFlightOrCorrespondence) {
housingAllowTerm2 = 0;
} else if (
onlineClasses === 'yes' &&
!isUSSchool(institution.facilityCode)
) {
housingAllowTerm2 = 0;
} else if (onlineClasses === 'yes') {
housingAllowTerm2 =
termLength * rop * ((tier * avgBah) / 2 + kickerBenefit);
} else if (hasClassesOutsideUS) {
housingAllowTerm2 = termLength * rop * (tier * avgBah + kickerBenefit);
} else {
housingAllowTerm2 = termLength * rop * (tier * bah + kickerBenefit);
}
// getHousingAllowTerm3
if (
isOJT &&
(militaryStatus === 'active duty' ||
(giBillChapter === 33 &&
militaryStatus === 'spouse' &&
spouseActiveDuty))
) {
housingAllowTerm3 = 0;
} else if (giBillChapter === 35 && isPhilipines(institution.facilityCode)) {
housingAllowTerm3 = totalHousingAllowance / 2;
} else if (giBillChapter === 35 && isOJT) {
housingAllowTerm3 = 0.494 * monthlyRateFinal;
} else if (oldGiBill && isOJT) {
housingAllowTerm3 = (7 / 15) * monthlyRateFinal;
} else if (onlyVRE && isOJT) {
housingAllowTerm3 = monthlyRateFinal;
} else if (isOJT) {
housingAllowTerm3 = 0.6 * ropOjt * (tier * bah + kickerBenefit);
} else if (inputs.calendar === 'semesters') {
housingAllowTerm3 = 0;
} else if (inputs.calendar === 'nontraditional' && numberOfTerms < 3) {
housingAllowTerm3 = 0;
} else if (giBillChapter === 31 && isFlightOrCorrespondence) {
housingAllowTerm3 = 0;
} else if (giBillChapter === 1606 && isFlight) {
housingAllowTerm3 = Math.max(
0,
Math.min(totalHousingAllowance, tuitionFeesPerTerm * 0.55),
);
} else if (giBillChapter === 1606 && isCorrespondence) {
housingAllowTerm3 = Math.max(
0,
Math.min(
totalHousingAllowance,
tuitionFeesPerTerm * (consecutiveService * 0.6),
),
);
} else if (onlyTuitionFees) {
housingAllowTerm3 = Math.max(
0,
Math.min(totalHousingAllowance, tuitionFeesPerTerm),
);
} else if (oldGiBill || onlyVRE) {
housingAllowTerm3 = totalHousingAllowance;
} else if (
militaryStatus === 'active duty' ||
(militaryStatus === 'spouse' && spouseActiveDuty)
) {
housingAllowTerm3 = rop * kickerBenefit * termLength;
} else if (isFlightOrCorrespondence) {
housingAllowTerm3 = 0;
} else if (
onlineClasses === 'yes' &&
!isUSSchool(institution.facilityCode)
) {
housingAllowTerm3 = 0;
} else if (onlineClasses === 'yes') {
housingAllowTerm3 =
termLength * rop * ((tier * avgBah) / 2 + kickerBenefit);
} else if (hasClassesOutsideUS) {
housingAllowTerm3 = termLength * rop * (tier * avgBah + kickerBenefit);
} else {
housingAllowTerm3 = termLength * rop * (tier * bah + kickerBenefit);
}
// Calculate Housing Allowance Total for year - getHousingAllowTotal
if (militaryStatus === 'active duty' && isOJT) {
housingAllowTotal = 0;
} else if (giBillChapter === 35 && isOJT) {
housingAllowTotal = 0.25 * monthlyRateFinal;
} else if (oldGiBill && isOJT) {
housingAllowTotal = (7 / 15) * monthlyRateFinal;
} else if (onlyVRE && isOJT) {
housingAllowTotal = monthlyRateFinal;
} else if (isOJT) {
housingAllowTotal = 0.4 * ropOjt * (tier * bah + kickerBenefit);
} else if (onlyTuitionFees) {
housingAllowTotal = Math.max(
0,
Math.min(monthlyRateFinal * acadYearLength, +inputs.tuitionFees),
);
} else {
housingAllowTotal =
housingAllowTerm1 + housingAllowTerm2 + housingAllowTerm3;
}
// Calculate Book Stipend for Term #1 - getBookStipendTerm1
if (isFlightOrCorrespondence) {
bookStipendTerm1 = 0;
} else if (oldGiBill) {
bookStipendTerm1 = 0;
} else if (giBillChapter === 31) {
bookStipendTerm1 = +inputs.books / numberOfTerms;
} else if (isOJT && giBillChapter === 33) {
bookStipendTerm1 = constant.BSOJTMONTH;
} else {
bookStipendTerm1 = ((ropBook * constant.BSCAP) / numberOfTerms) * tier;
}
// getBookStipendTerm2
if (isFlightOrCorrespondence) {
bookStipendTerm2 = 0;
} else if (isOJT && giBillChapter === 33) {
bookStipendTerm2 = constant.BSOJTMONTH;
} else if (inputs.calendar === 'nontraditional' && numberOfTerms === 1) {
bookStipendTerm2 = 0;
} else if (oldGiBill) {
bookStipendTerm2 = 0;
} else if (giBillChapter === 31) {
bookStipendTerm2 = +inputs.books / numberOfTerms;
} else {
bookStipendTerm2 = ((ropBook * constant.BSCAP) / numberOfTerms) * tier;
}
// getBookStipendTerm3
if (isFlightOrCorrespondence) {
bookStipendTerm3 = 0;
} else if (isOJT && giBillChapter === 33) {
bookStipendTerm3 = constant.BSOJTMONTH;
} else if (inputs.calendar === 'semesters') {
bookStipendTerm3 = 0;
} else if (inputs.calendar === 'nontraditional' && numberOfTerms < 3) {
bookStipendTerm3 = 0;
} else if (oldGiBill) {
bookStipendTerm3 = 0;
} else if (giBillChapter === 31) {
bookStipendTerm3 = inputs.books / numberOfTerms;
} else {
bookStipendTerm3 = ((ropBook * constant.BSCAP) / numberOfTerms) * tier;
}
// Calculate Book Stipend for Year - getBookStipendYear
if (isOJT && giBillChapter === 33) {
bookStipendTotal = constant.BSCAP;
} else {
bookStipendTotal = bookStipendTerm1 + bookStipendTerm2 + bookStipendTerm3;
}
// Calculate Total Payments to You - getTotalPaidToYou
const totalToYou = housingAllowTotal + bookStipendTotal;
// Calculate Total Benefits for Term 1 - getTotalTerm1
if (isOJT) {
totalTerm1 = 0;
} else {
totalTerm1 =
tuitionFeesTerm1 + yrBenTerm1 + housingAllowTerm1 + bookStipendTerm1;
}
// getTotalTerm2
if (inputs.calendar === 'nontraditional' && numberOfTerms === 1) {
totalTerm2 = 0;
} else if (isOJT) {
totalTerm2 = 0;
} else {
totalTerm2 =
tuitionFeesTerm2 + yrBenTerm2 + housingAllowTerm2 + bookStipendTerm2;
}
// getTotalTerm3
if (inputs.calendar === 'semesters') {
totalTerm3 = 0;
} else if (inputs.calendar === 'nontraditional' && numberOfTerms < 3) {
totalTerm3 = 0;
} else if (isOJT) {
totalTerm3 = 0;
} else {
totalTerm3 =
tuitionFeesTerm3 + yrBenTerm3 + housingAllowTerm3 + bookStipendTerm3;
}
// Calculate Text for Total Benefits Row - getTotalText
switch (giBillChapter) {
case 30:
giBillTotalText = 'Total Montgomery GI Bill Benefits';
break;
case 31:
giBillTotalText = 'Total Voc Rehab Benefits';
break;
case 33:
giBillTotalText = 'Total Post-9/11 GI Bill Benefits';
break;
case 35:
giBillTotalText = 'Total DEA GI Bill Benefits';
break;
case 1606:
giBillTotalText = 'Total Select Reserve GI Bill Benefits';
break;
default:
// noop
}
// Calculate Total Benefits for Year - getTotalYear
if (isOJT) {
totalYear = 0;
} else {
totalYear =
tuitionFeesTotal + yrBenTotal + housingAllowTotal + bookStipendTotal;
}
// Calculate Monthly Rate for Display - getMonthlyRateDisplay
if (isOJT) {
monthlyRateDisplay = housingAllowTerm1;
} else {
monthlyRateDisplay = housingAllowTerm1 / termLength;
}
// if FryScholarship and areYouActiveDuty is yes. Monthly Rate should be zero.
monthlyRateDisplay =
eligibility.areYouActiveDuty === 'yes' ? 0 : monthlyRateDisplay;
return {
tier,
onlyVRE,
oldGiBill,
numberOfTerms,
tuitionFeesTerm1,
tuitionFeesTerm2,
tuitionFeesTerm3,
tuitionFeesTotal,
giBillTotalText,
totalTerm1,
totalTerm2,
totalTerm3,
totalYear,
nameOfTerm1,
nameOfTerm2,
nameOfTerm3,
nameOfTerm4,
yellowRibbonElig,
yrBenSchoolTerm1,
yrBenSchoolTerm2,
yrBenSchoolTerm3,
yrBenSchoolTotal,
yrBenVaTerm1,
yrBenVaTerm2,
yrBenVaTerm3,
yrBenVaTotal,
totalScholarshipTa,
totalToSchool,
totalLeftToPay,
housingAllowTerm1,
housingAllowTerm2,
housingAllowTerm3,
housingAllowanceMonthly: monthlyRateDisplay,
housingAllowTotal,
bookStipendTerm1,
bookStipendTerm2,
bookStipendTerm3,
bookStipendTotal,
totalToYou,
isChapter33,
isActiveDuty,
};
},
);
const isThirtySixMonthsPlus = eligibility =>
eligibility.cumulativeService === '1.0';
export const getCalculatedBenefits = createSelector(
getEligibilityDetails,
getInstitution,
getFormInputs,
getDerivedValues,
(eligibility, institution, form, derived) => {
const calculatedBenefits = {};
if ([eligibility, institution, form, derived].some(e => !e || isEmpty(e))) {
return calculatedBenefits;
}
const { militaryStatus } = eligibility;
const institutionType = getInstitutionType(institution);
let giBillChapter;
if (
eligibility.giBillChapter === '33a' ||
eligibility.giBillChapter === '33b'
) {
giBillChapter = 33;
} else {
giBillChapter = +eligibility.giBillChapter;
}
calculatedBenefits.inputs = {
inState: false,
tuition: true,
books: false,
yellowRibbon: false,
scholarships: true,
tuitionAssist: false,
enrolled: true,
enrolledOld: false,
calendar: true,
working: false,
kicker: true,
buyUp: false,
};
calculatedBenefits.outputs = {
giBillPaysToSchool: {
visible: true,
value: formatCurrency(derived.totalToSchool),
},
tuitionAndFeesCharged: {
visible: true,
value: formatCurrency(form.tuitionFees),
},
yourScholarships: {
visible: true,
value: formatCurrency(derived.totalScholarshipTa),
},
outOfPocketTuition: {
visible: true,
value: formatCurrency(derived.totalLeftToPay),
},
housingAllowance: {
visible: true,
value: formatCurrency(derived.housingAllowanceMonthly),
},
bookStipend: {
visible: true,
value: formatCurrency(derived.bookStipendTotal),
},
totalPaidToYou: {
visible: true,
value: formatCurrency(derived.totalToYou),
},
perTerm: {
tuitionFees: {
visible: true,
title: 'Tuition and fees',
modal: 'tuitionAndFeesSchool',
learnMoreAriaLabel: ariaLabels.learnMore.tuitionFees,
terms: [
{
label: derived.nameOfTerm1,
value: formatCurrency(derived.tuitionFeesTerm1),
visible: true,
},
{
label: derived.nameOfTerm2,
value: formatCurrency(derived.tuitionFeesTerm2),
visible: true,
},
{
label: derived.nameOfTerm3,
value: formatCurrency(derived.tuitionFeesTerm3),
visible: true,
},
{
label: 'Total per year',
value: formatCurrency(derived.tuitionFeesTotal),
visible: true,
},
],
},
yellowRibbon: {
visible: true,
title: 'Yellow Ribbon',
terms: [
{
label: `${derived.nameOfTerm1} (paid by school)`,
value: formatCurrency(derived.yrBenSchoolTerm1),
visible: true,
},
{
label: `${derived.nameOfTerm1} (paid by VA)`,
value: formatCurrency(derived.yrBenVaTerm1),
visible: true,
},
{
label: `${derived.nameOfTerm2} (paid by school)`,
value: formatCurrency(derived.yrBenSchoolTerm2),
visible: true,
},
{
label: `${derived.nameOfTerm2} (paid by VA)`,
value: formatCurrency(derived.yrBenVaTerm2),
visible: true,
},
{
label: `${derived.nameOfTerm3} (paid by school)`,
value: formatCurrency(derived.yrBenSchoolTerm3),
visible: true,
},
{
label: `${derived.nameOfTerm3} (paid by VA)`,
value: formatCurrency(derived.yrBenVaTerm3),
visible: true,
},
{
label: 'Total per year',
value: formatCurrency(
derived.yrBenSchoolTotal + derived.yrBenVaTotal,
),
visible: true,
},
],
},
housingAllowance: {
visible: true,
title: 'Housing allowance',
modal: 'housingAllowanceSchool',
learnMoreAriaLabel: ariaLabels.learnMore.housingAllowance,
terms: [
{
label: derived.nameOfTerm1,
value: formatCurrency(derived.housingAllowTerm1),
visible: true,
},
{
label: derived.nameOfTerm2,
value: formatCurrency(derived.housingAllowTerm2),
visible: true,
},
{
label: derived.nameOfTerm3,
value: formatCurrency(derived.housingAllowTerm3),
visible: true,
},
{
label: derived.nameOfTerm4,
value: formatCurrency(derived.housingAllowTotal), // Total if not OJT
visible: true,
},
],
},
},
};
if (giBillChapter === 31 && !derived.onlyVRE) {
calculatedBenefits.inputs = {
...calculatedBenefits.inputs,
enrolled: true,
enrolledOld: false,
yellowRibbon: false,
scholarships: false,
tuitionAssist: false,
};
}
if (giBillChapter === 33) {
calculatedBenefits.inputs = {
...calculatedBenefits.inputs,
giBillBenefit: true,
beneficiaryLocationQuestion: true,
};
}
if (giBillChapter === 35) {
calculatedBenefits.inputs = {
...calculatedBenefits.inputs,
kicker: false,
};
}
if (institutionType === 'flight' || institutionType === 'correspondence') {
calculatedBenefits.inputs = {
...calculatedBenefits.inputs,
enrolled: false,
enrolledOld: false,
kicker: false,
buyUp: false,
};
}
if (institutionType === 'public') {
calculatedBenefits.inputs = {
...calculatedBenefits.inputs,
inState: true,
};
}
if (institution.yr && derived.tier === 1.0) {
calculatedBenefits.inputs = {
...calculatedBenefits.inputs,
yellowRibbon: true,
};
}
if (derived.oldGiBill || derived.onlyVRE) {
calculatedBenefits.inputs = {
...calculatedBenefits.inputs,
yellowRibbon: false,
enrolled: false,
enrolledOld: true,
};
}
if (giBillChapter === 31) {
calculatedBenefits.inputs = {
...calculatedBenefits.inputs,
books: true,
};
}
if (giBillChapter === 30) {
calculatedBenefits.inputs = {
...calculatedBenefits.inputs,
buyUp: true,
};
}
if (
['active duty', 'national guard / reserves'].includes(militaryStatus) &&
giBillChapter === 33
) {
calculatedBenefits.inputs = {
...calculatedBenefits.inputs,
tuitionAssist: true,
};
}
if (
derived.isActiveDuty &&
derived.isChapter33 &&
isThirtySixMonthsPlus(eligibility)
) {
calculatedBenefits.inputs = {
...calculatedBenefits.inputs,
yellowRibbon: false,
};
}
if (!derived.yellowRibbonElig) {
calculatedBenefits.outputs.perTerm.yellowRibbon.visible = false;
}
if (derived.totalScholarshipTa === 0) {
calculatedBenefits.outputs.yourScholarships.visible = false;
}
if (derived.numberOfTerms === 1) {
// Hide all term 2 and 3 calculations
calculatedBenefits.outputs.perTerm.tuitionFees.terms[1].visible = false;
calculatedBenefits.outputs.perTerm.tuitionFees.terms[2].visible = false;
calculatedBenefits.outputs.perTerm.housingAllowance.terms[1].visible = false;
calculatedBenefits.outputs.perTerm.housingAllowance.terms[2].visible = false;
calculatedBenefits.outputs.perTerm.yellowRibbon.terms[2].visible = false;
calculatedBenefits.outputs.perTerm.yellowRibbon.terms[3].visible = false;
calculatedBenefits.outputs.perTerm.yellowRibbon.terms[4].visible = false;
calculatedBenefits.outputs.perTerm.yellowRibbon.terms[5].visible = false;
}
if (derived.numberOfTerms < 3 && institutionType !== 'ojt') {
// Hide all term 3 calculations
calculatedBenefits.outputs.perTerm.tuitionFees.terms[2].visible = false;
calculatedBenefits.outputs.perTerm.housingAllowance.terms[2].visible = false;
calculatedBenefits.outputs.perTerm.yellowRibbon.terms[4].visible = false;
calculatedBenefits.outputs.perTerm.yellowRibbon.terms[5].visible = false;
}
if (institutionType === 'ojt') {
calculatedBenefits.inputs = {
...calculatedBenefits.inputs,
tuition: false,
books: false,
yellowRibbon: false,
scholarships: false,
tuitionAssist: false,
enrolled: false,
enrolledOld: false,
calendar: false,
working: true,
};
calculatedBenefits.outputs.tuitionAndFeesCharged.visible = false;
calculatedBenefits.outputs.giBillPaysToSchool.visible = false;
calculatedBenefits.outputs.yourScholarships.visible = false;
calculatedBenefits.outputs.outOfPocketTuition.visible = false;
calculatedBenefits.outputs.totalPaidToYou.visible = false;
calculatedBenefits.outputs.perTerm.tuitionFees.visible = false;
calculatedBenefits.outputs.perTerm.yellowRibbon.visible = false;
calculatedBenefits.outputs.perTerm.housingAllowance.modal =
'housingAllowanceOJT';
calculatedBenefits.outputs.perTerm.housingAllowance.learnMoreAriaLabel =
'Learn more about how housing allowance is determined';
}
return calculatedBenefits;
},
);