Skip to content

Commit

Permalink
feat: Update Household and MarketPurchase classes (#44)
Browse files Browse the repository at this point in the history
* chore: SocialRentAdjustment type

* feat: MarketPurchase

* feat: Household
  • Loading branch information
DafyddLlyr authored Aug 6, 2024
1 parent 64c7b9b commit 4d73932
Show file tree
Hide file tree
Showing 5 changed files with 239 additions and 315 deletions.
49 changes: 25 additions & 24 deletions app/models/Household.test.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,34 @@
import { DEFAULT_FORECAST_PARAMETERS } from "./ForecastParameters";
import { Household } from "./Household";
import { Property } from "./Property";
import { SocialRentAdjustments } from "./tenure/SocialRent";

let property: Property;
let household: Household;
const socialRentAdjustments = [
{ id: 1, inflation: 3.3, total: 4.3, year: "2001-02" },
{ id: 2, inflation: 1.7, total: 2.2, year: "2002-03" },
{ id: 3, inflation: 1.7, total: 2.2, year: "2003-04" },
{ id: 4, inflation: 2.8, total: 3.3, year: "2004-05" },
{ id: 5, inflation: 3.1, total: 3.6, year: "2005-06" },
{ id: 6, inflation: 2.7, total: 3.2, year: "2006-07" },
{ id: 7, inflation: 3.6, total: 4.1, year: "2007-08" },
{ id: 8, inflation: 3.9, total: 4.4, year: "2008-09" },
{ id: 9, inflation: 5.0, total: 5.5, year: "2009-10" },
{ id: 10, inflation: -1.4, total: -0.9, year: "2010-11" },
{ id: 11, inflation: 4.6, total: 5.1, year: "2011-12" },
{ id: 12, inflation: 5.6, total: 6.1, year: "2012-13" },
{ id: 13, inflation: 2.6, total: 3.1, year: "2013-14" },
{ id: 14, inflation: 3.2, total: 3.7, year: "2014-15" },
{ id: 15, inflation: 1.2, total: 2.2, year: "2015-16" },
{ id: 16, inflation: NaN, total: -1.0, year: "2016-17" },
{ id: 17, inflation: NaN, total: -1.0, year: "2017-18" },
{ id: 18, inflation: NaN, total: -1.0, year: "2018-19" },
{ id: 19, inflation: NaN, total: -1.0, year: "2019-20" },
{ id: 20, inflation: 1.7, total: 2.7, year: "2020-21" },
{ id: 21, inflation: 0.5, total: 1.5, year: "2021-22" },
{ id: 22, inflation: 3.1, total: 4.1, year: "2022-23" },
{ id: 23, inflation: 10.1, total: 11.1, year: "2023-24" },
const socialRentAdjustments: SocialRentAdjustments = [
{ inflation: 3.3, total: 4.3, year: "2001-02" },
{ inflation: 1.7, total: 2.2, year: "2002-03" },
{ inflation: 1.7, total: 2.2, year: "2003-04" },
{ inflation: 2.8, total: 3.3, year: "2004-05" },
{ inflation: 3.1, total: 3.6, year: "2005-06" },
{ inflation: 2.7, total: 3.2, year: "2006-07" },
{ inflation: 3.6, total: 4.1, year: "2007-08" },
{ inflation: 3.9, total: 4.4, year: "2008-09" },
{ inflation: 5.0, total: 5.5, year: "2009-10" },
{ inflation: -1.4, total: -0.9, year: "2010-11" },
{ inflation: 4.6, total: 5.1, year: "2011-12" },
{ inflation: 5.6, total: 6.1, year: "2012-13" },
{ inflation: 2.6, total: 3.1, year: "2013-14" },
{ inflation: 3.2, total: 3.7, year: "2014-15" },
{ inflation: 1.2, total: 2.2, year: "2015-16" },
{ inflation: NaN, total: -1.0, year: "2016-17" },
{ inflation: NaN, total: -1.0, year: "2017-18" },
{ inflation: NaN, total: -1.0, year: "2018-19" },
{ inflation: NaN, total: -1.0, year: "2019-20" },
{ inflation: 1.7, total: 2.7, year: "2020-21" },
{ inflation: 0.5, total: 1.5, year: "2021-22" },
{ inflation: 3.1, total: 4.1, year: "2022-23" },
{ inflation: 10.1, total: 11.1, year: "2023-24" },
];

beforeEach(() => {
Expand Down
194 changes: 79 additions & 115 deletions app/models/Household.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,160 +4,117 @@ import { FairholdLandPurchase } from "./tenure/FairholdLandPurchase";
import { FairholdLandRent } from "./tenure/FairholdLandRent";
import { Fairhold } from "./Fairhold";
import { Property } from "./Property";
import { SocialRent, socialRentAdjustmentTypes } from "./tenure/SocialRent";
import { SocialRent, SocialRentAdjustments } from "./tenure/SocialRent";
import { ForecastParameters } from "./ForecastParameters";

const HOUSE_MULTIPLIER = 2.4;

type ConstructorParams = Pick<
Household,
"incomePerPersonYearly" | "gasBillYearly" | "property" | "forecastParameters"
> & {
averageRentYearly: number;
socialRentAverageEarning: number;
socialRentAdjustments: SocialRentAdjustments;
housePriceIndex: number;
};

type Lifetime = {
affordabilityThresholdIncome: number;
incomeYearly: number;
}[];

export class Household {
incomePerPersonYearly; // income per person
gasBillYearly; // gas bill monthly
property; // property object
forecastParameters; // forecast parameters
incomeYearly!: number; // income per household
tenure: {
marketPurchase?: MarketPurchase;
marketRent?: MarketRent;
socialRent?: SocialRent;
fairholdLandPurchase?: FairholdLandPurchase;
fairholdLandRent?: FairholdLandRent;
}; // grouped tenure field

lifetime?: {
affordabilityThresholdIncome: number;
incomeYearly: number;
}[];

constructor({
incomePerPersonYearly,
averageRentYearly,
socialRentAverageEarning,
socialRentAdjustments,
housePriceIndex,
gasBillYearly,
property,
forecastParameters,
}: {
incomePerPersonYearly: number;
averageRentYearly: number;
socialRentAverageEarning: number;
socialRentAdjustments: socialRentAdjustmentTypes;
housePriceIndex: number;
gasBillYearly: number;
property: Property;
forecastParameters: ForecastParameters;
}) {
this.incomePerPersonYearly = incomePerPersonYearly;
this.gasBillYearly = gasBillYearly;
this.property = property;
this.forecastParameters = forecastParameters;
this.tenure = {}; // Initialize the tenure object
this.calculateHouseholdIncome();
this.calculateTenures(
averageRentYearly,
socialRentAverageEarning,
socialRentAdjustments,
housePriceIndex
);
this.calculateLifetime(
public incomePerPersonYearly: number;
public gasBillYearly: number;
public property: Property;
public forecastParameters: ForecastParameters;
public incomeYearly: number;
public tenure: {
marketPurchase: MarketPurchase;
marketRent: MarketRent;
socialRent: SocialRent;
fairholdLandPurchase: FairholdLandPurchase;
fairholdLandRent: FairholdLandRent;
};
public lifetime: Lifetime;

constructor(params: ConstructorParams) {
this.incomePerPersonYearly = params.incomePerPersonYearly;
this.gasBillYearly = params.gasBillYearly;
this.property = params.property;
this.forecastParameters = params.forecastParameters;
this.incomeYearly = HOUSE_MULTIPLIER * params.incomePerPersonYearly;
this.tenure = this.calculateTenures(params);
this.lifetime = this.calculateLifetime(
this.incomeYearly,
forecastParameters.incomeGrowthPerYear,
forecastParameters.affordabilityThresholdIncomePercentage,
forecastParameters.yearsForecast
params.forecastParameters
);
}

calculateHouseholdIncome(houseMultiplier: number = 2.4) {
this.incomeYearly = houseMultiplier * this.incomePerPersonYearly; // calculate the income for house hold
}

calculateTenures(
averageRentYearly: number,
socialRentAverageEarning: number,
socialRentAdjustments: socialRentAdjustmentTypes,
housePriceIndex: number
) {
if (this.incomeYearly == undefined) throw new Error("income is undefined");
if (this.property.newBuildPrice == undefined)
throw new Error("newBuildPrice is undefined");
if (this.property.depreciatedBuildPrice == undefined)
throw new Error("depreciatedBuildPrice is undefined");
if (this.property.landPrice == undefined)
throw new Error("landPrice is undefined");

// calculate tenure market purchase
this.tenure.marketPurchase = new MarketPurchase({
private calculateTenures({
averageRentYearly,
socialRentAverageEarning,
socialRentAdjustments,
housePriceIndex,
}: ConstructorParams) {
const marketPurchase = new MarketPurchase({
incomeYearly: this.incomeYearly,
averagePrice: this.property.averageMarketPrice,
newBuildPrice: this.property.newBuildPrice,
depreciatedBuildPrice: this.property.depreciatedBuildPrice,
landPrice: this.property.landPrice,
//affordabilityThresholdIncomePercentage:this.forecastParameters.affordabilityThresholdIncomePercentage,
propertyPriceGrowthPerYear:
this.forecastParameters.propertyPriceGrowthPerYear,
constructionPriceGrowthPerYear:
this.forecastParameters.constructionPriceGrowthPerYear,
yearsForecast: this.forecastParameters.yearsForecast,
maintenanceCostPercentage:
this.forecastParameters.maintenanceCostPercentage,
//incomeGrowthPerYear: this.forecastParameters.incomeGrowthPerYear,
});

//calculate tenure market rent
this.tenure.marketRent = new MarketRent({
const marketRent = new MarketRent({
averageRentYearly: averageRentYearly,
averagePrice: this.property.averageMarketPrice,
newBuildPrice: this.property.newBuildPrice,
depreciatedBuildPrice: this.property.depreciatedBuildPrice,
landPrice: this.property.landPrice,
incomeYearly: this.incomeYearly,
//affordabilityThresholdIncomePercentage:this.forecastParameters.affordabilityThresholdIncomePercentage,
propertyPriceGrowthPerYear:
this.forecastParameters.propertyPriceGrowthPerYear,
constructionPriceGrowthPerYear:
this.forecastParameters.constructionPriceGrowthPerYear,
yearsForecast: this.forecastParameters.yearsForecast,
maintenanceCostPercentage:
this.forecastParameters.maintenanceCostPercentage,
//incomeGrowthPerYear: this.forecastParameters.incomeGrowthPerYear,
rentGrowthPerYear: this.forecastParameters.rentGrowthPerYear,
});

//calculate tenure social rent
this.tenure.socialRent = new SocialRent({
socialRentAverageEarning: socialRentAverageEarning,
socialRentAdjustments: socialRentAdjustments,
housePriceIndex: housePriceIndex,
const socialRent = new SocialRent({
socialRentAverageEarning,
socialRentAdjustments,
housePriceIndex,
landToTotalRatio: this.property.landToTotalRatio,
numberOfBedrooms: this.property.numberOfBedrooms,
});

if (this.tenure.marketPurchase.affordability == undefined)
throw new Error("tenureMarketPurchase.affordability is undefined");

this.tenure.fairholdLandPurchase = new FairholdLandPurchase({
//averagePrice: this.property.averagePrice, // average price of the property
const fairholdLandPurchase = new FairholdLandPurchase({
newBuildPrice: this.property.newBuildPrice,
depreciatedBuildPrice: this.property.depreciatedBuildPrice,
//landPrice: this.property.landPrice,
//incomeYearly: this.incomeYearly, // income Yearly
//affordabilityThresholdIncomePercentage:this.forecastParameters.affordabilityThresholdIncomePercentage,
//propertyPriceGrowthPerYear:this.forecastParameters.propertyPriceGrowthPerYear,
constructionPriceGrowthPerYear:
this.forecastParameters.constructionPriceGrowthPerYear,
yearsForecast: this.forecastParameters.yearsForecast,
maintenanceCostPercentage:
this.forecastParameters.maintenanceCostPercentage,
incomeGrowthPerYear: this.forecastParameters.incomeGrowthPerYear,
affordability: this.tenure.marketPurchase.affordability,
affordability: marketPurchase.affordability,
fairhold: new Fairhold({
affordability: this.tenure.marketPurchase.affordability,
affordability: marketPurchase.affordability,
landPriceOrRent: this.property.landPrice,
}),
});

if (this.tenure.marketRent.affordability == undefined)
throw new Error("tenureMarketRent.affordability is undefined");

this.tenure.fairholdLandRent = new FairholdLandRent({
const fairholdLandRent = new FairholdLandRent({
averageRentYearly: averageRentYearly,
averagePrice: this.property.averageMarketPrice, // average price of the property
newBuildPrice: this.property.newBuildPrice,
Expand All @@ -177,43 +134,50 @@ export class Household {
rentGrowthPerYear: this.forecastParameters.rentGrowthPerYear, // rent growth per year

fairhold: new Fairhold({
affordability: this.tenure.marketRent.affordability,
affordability: marketRent.affordability,
landPriceOrRent: averageRentYearly,
}), // fairhold object
});

return {
marketPurchase,
marketRent,
socialRent,
fairholdLandPurchase,
fairholdLandRent,
};
}

calculateLifetime(
private calculateLifetime(
incomeYearly: number,
incomeGrowthPerYear: number,
affordabilityThresholdIncomePercentage: number,
yearsForecast: number
{
incomeGrowthPerYear,
affordabilityThresholdIncomePercentage,
yearsForecast,
}: ForecastParameters
) {
let incomeYearlyIterative = incomeYearly; // set the current income
let incomeYearlyIterative = incomeYearly;
let affordabilityThresholdIncomeIterative =
incomeYearlyIterative * affordabilityThresholdIncomePercentage; // affordable income
incomeYearlyIterative * affordabilityThresholdIncomePercentage;

interface lifetimeTypes {
affordabilityThresholdIncome: number;
incomeYearly: number;
}
let lifetime: lifetimeTypes[] = [
const lifetime: Lifetime = [
{
incomeYearly: incomeYearlyIterative,
affordabilityThresholdIncome: affordabilityThresholdIncomeIterative,
},
];

for (let i = 0; i < yearsForecast - 1; i++) {
incomeYearlyIterative = incomeYearlyIterative * (1 + incomeGrowthPerYear); // calculate the current income
incomeYearlyIterative = incomeYearlyIterative * (1 + incomeGrowthPerYear);
affordabilityThresholdIncomeIterative =
incomeYearlyIterative * affordabilityThresholdIncomePercentage; // affordable income
incomeYearlyIterative * affordabilityThresholdIncomePercentage;

lifetime.push({
incomeYearly: incomeYearlyIterative,
affordabilityThresholdIncome: affordabilityThresholdIncomeIterative,
});
}
this.lifetime = lifetime;

return lifetime;
}
}
Loading

0 comments on commit 4d73932

Please sign in to comment.