From 064f89c263ffb79240bc843a4f5b2d9875cc0ed4 Mon Sep 17 00:00:00 2001 From: alexeh Date: Mon, 4 Nov 2024 06:41:32 +0100 Subject: [PATCH] first prototype revenue-profit.calculators.ts --- .../conservation-cost.calculator.ts | 8 ++ .../revenue-profit.calculators.ts | 115 +++++++++++++++++- 2 files changed, 122 insertions(+), 1 deletion(-) diff --git a/api/src/modules/calculations/conservation-cost.calculator.ts b/api/src/modules/calculations/conservation-cost.calculator.ts index aabfde16..041f3231 100644 --- a/api/src/modules/calculations/conservation-cost.calculator.ts +++ b/api/src/modules/calculations/conservation-cost.calculator.ts @@ -6,6 +6,7 @@ import { BaseSize } from '@shared/entities/base-size.entity'; import { SequestrationRatesCalculator } from '@api/modules/calculations/sequestration-rate.calculator'; import { RESTORATION_ACTIVITY_SUBTYPE } from '@shared/entities/projects.entity'; import { ACTIVITY } from '@shared/entities/activity.enum'; +import { RevenueProfitCalculator } from '@api/modules/calculations/revenue-profit.calculators'; export class ConservationCostCalculator extends CostCalculator { project: ConservationProject; @@ -29,6 +30,7 @@ export class ConservationCostCalculator extends CostCalculator { baseIncrease: BaseIncrease; baseSize: BaseSize; sequestrationCreditsCalculator: SequestrationRatesCalculator; + revenueProfitCalculator: RevenueProfitCalculator; constructor( project: ConservationProject, baseIncrease: BaseIncrease, @@ -63,6 +65,12 @@ export class ConservationCostCalculator extends CostCalculator { ACTIVITY.CONSERVATION, RESTORATION_ACTIVITY_SUBTYPE.PLANTING, ); + this.revenueProfitCalculator = new RevenueProfitCalculator( + this.project, + this.conservationProjectLength, + this.defaultProjectLength, + this.sequestrationCreditsCalculator, + ); } private initializeCostPlan(): { [year: number]: number } { diff --git a/api/src/modules/calculations/revenue-profit.calculators.ts b/api/src/modules/calculations/revenue-profit.calculators.ts index c261dee6..78ec1609 100644 --- a/api/src/modules/calculations/revenue-profit.calculators.ts +++ b/api/src/modules/calculations/revenue-profit.calculators.ts @@ -1 +1,114 @@ -export class RevenueProfitCalculator {} +import { ConservationProject } from '@api/modules/custom-projects/conservation.project'; +import { SequestrationRatesCalculator } from '@api/modules/calculations/sequestration-rate.calculator'; + +export class RevenueProfitCalculator { + private project: ConservationProject; + private sequestrationCreditsCalculator: SequestrationRatesCalculator; + private projectLength: number; + private defaultProjectLength: number; + + constructor( + project: ConservationProject, + projectLength: number, + defaultProjectLength: number, + sequestrationCreditsCalculator: SequestrationRatesCalculator, + ) { + this.project = project; + this.sequestrationCreditsCalculator = sequestrationCreditsCalculator; + this.projectLength = projectLength; + this.defaultProjectLength = defaultProjectLength; + } + + public calculateEstimatedRevenue(): { [year: number]: number } { + const estimatedRevenuePlan: { [year: number]: number } = {}; + + for (let year = -4; year <= this.defaultProjectLength; year++) { + if (year !== 0) { + estimatedRevenuePlan[year] = 0; + } + } + + const estimatedCreditsIssued = + this.sequestrationCreditsCalculator.calculateEstimatedCreditsIssued(); + + for (const year in estimatedRevenuePlan) { + const yearNum = Number(year); + if (yearNum <= this.projectLength) { + if (yearNum < -1) { + estimatedRevenuePlan[yearNum] = 0; + } else { + estimatedRevenuePlan[yearNum] = + estimatedCreditsIssued[yearNum] * + this.project.carbonPrice * + Math.pow(1 + this.project.carbonPriceIncrease, yearNum); + } + } else { + estimatedRevenuePlan[yearNum] = 0; + } + } + + return estimatedRevenuePlan; + } + + public calculateAnnualNetCashFlow( + capexTotalCostPlan: { [year: number]: number }, + opexTotalCostPlan: { [year: number]: number }, + ): { [year: number]: number } { + const estimatedRevenue = this.calculateEstimatedRevenue(); + const costPlans = { + capexTotal: { ...capexTotalCostPlan }, + opexTotal: { ...opexTotalCostPlan }, + }; + + for (const key in costPlans) { + for (const year in costPlans[key]) { + costPlans[key][year] = -costPlans[key][year]; + } + } + + const totalCostPlan: { [year: number]: number } = {}; + for (const year of new Set([ + ...Object.keys(costPlans.capexTotal), + ...Object.keys(costPlans.opexTotal), + ])) { + const yearNum = Number(year); + totalCostPlan[yearNum] = + (costPlans.capexTotal[yearNum] || 0) + + (costPlans.opexTotal[yearNum] || 0); + } + + const annualNetCashFlow: { [year: number]: number } = {}; + for (let year = -4; year <= this.projectLength; year++) { + if (year !== 0) { + annualNetCashFlow[year] = + estimatedRevenue[year] + (totalCostPlan[year] || 0); + } + } + + return annualNetCashFlow; + } + + public calculateAnnualNetIncome(opexTotalCostPlan: { + [year: number]: number; + }): { [year: number]: number } { + const costPlans = { + opexTotal: { ...opexTotalCostPlan }, + }; + + for (const year in costPlans.opexTotal) { + costPlans.opexTotal[year] = -costPlans.opexTotal[year]; + } + + const estimatedRevenue = this.calculateEstimatedRevenue(); + + const annualNetIncome: { [year: number]: number } = {}; + for (let year = -4; year <= this.projectLength; year++) { + if (year !== 0) { + annualNetIncome[year] = + estimatedRevenue[year] + (costPlans.opexTotal[year] || 0); + } + } + + return annualNetIncome; + } +}