Skip to content

Commit 592bd6a

Browse files
committed
feat: currency formatter
1 parent 5a82dcd commit 592bd6a

17 files changed

+80
-30
lines changed

README.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,7 @@ Once a feature's PR is merged, the pipeline will run checks and publish.
8989

9090
## Missing features
9191

92-
1. currency formatting
93-
2. easier setup
94-
3. apartments (passive investor)
92+
1. apartments (passive investor)
9593

9694
## Future
9795

src/calculations/get-monthly-mortgage.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { differenceInMonths } from 'date-fns';
2+
import currency from '../formatters/currency';
23

34
/**
45
* formula for M = P [ i(1 + i)^n ] / [ (1 + i)^n – 1].
@@ -20,7 +21,8 @@ export function getMonthlyMortgage(
2021
const i = loanRatePercent / 100 / 12;
2122
const n = loanTermInYears * 12;
2223

23-
return (p * i * Math.pow(1 + i, n)) / (Math.pow(1 + i, n) - 1);
24+
const mort = (p * i * Math.pow(1 + i, n)) / (Math.pow(1 + i, n) - 1);
25+
return currency(mort);
2426
}
2527

2628
/**
@@ -29,7 +31,7 @@ export function getMonthlyMortgage(
2931
* @param cashDownPercent
3032
*/
3133
export function getCashDown(purchasePrice: number, cashDownPercent: number) {
32-
return (purchasePrice * cashDownPercent) / 100;
34+
return currency((purchasePrice * cashDownPercent) / 100);
3335
}
3436

3537
export function getSellPriceEstimate(
@@ -45,5 +47,5 @@ export function getSellPriceEstimate(
4547
result = result + (result * sellPriceAppreciationPercent) / 100;
4648
}
4749

48-
return result;
50+
return currency(result);
4951
}

src/calculations/get-monthly-principal-interest-tax-interest.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { getMonthlyMortgage } from './get-monthly-mortgage';
2+
import currency from '../formatters/currency';
23

34
/**
45
* This gets you PITI!
@@ -28,5 +29,5 @@ export function getMonthlyPrincipalInterestTaxInterest(
2829
loanRatePercent,
2930
loanTermInYears
3031
);
31-
return monthlyMortgage + annualTaxes / 12 + annualInsurance / 12;
32+
return currency(monthlyMortgage + annualTaxes / 12 + annualInsurance / 12);
3233
}

src/formatters/currency.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
export default function (value: number /*?*/): number {
2+
if (!value || value === 0) {
3+
return 0;
4+
}
5+
6+
const c = value
7+
.toString()
8+
.split('.')
9+
.map((v, i) => (i % 2 !== 0 ? v.substr(0, 2) : v));
10+
return parseFloat(c.join('.'));
11+
}

src/formatters/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './currency';

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
export * from './account';
22
export * from './caching';
33
export * from './calculations';
4+
export * from './formatters';
45
export * from './generators';
56
export * from './investments';
67
export * from './ledger';

src/ledger/ledger-collection.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import itiriri, { IterableQuery } from 'itiriri';
33
import { ILedgerSummary } from './i-ledger-summary';
44
import { LedgerItemType } from './ledger-item-type';
55
import { IRentalSavings, RentalSingleFamily } from '../properties';
6+
import currency from '../formatters/currency';
67

78
export interface ILedgerCollection {
89
getBalance(date: Date): number;
@@ -132,7 +133,9 @@ export class LedgerCollection implements ILedgerCollection {
132133

133134
const salary = this.getSummaryByType(boundary, LedgerItemType.Salary);
134135
result.cashFlow = this.getSummaryByType(boundary, LedgerItemType.CashFlow);
135-
result.averageCashFlow = boundary.filter((x) => x.type === LedgerItemType.CashFlow).average((x) => x.amount) || 0;
136+
result.averageCashFlow = currency(
137+
boundary.filter((x) => x.type === LedgerItemType.CashFlow).average((x) => x.amount) || 0
138+
);
136139
result.equity = this.getSummaryByType(boundary, LedgerItemType.Equity);
137140
result.purchases = this.getSummaryByType(boundary, LedgerItemType.Purchase);
138141
result.balance = result.cashFlow + salary + result.equity - result.purchases || 0;
@@ -159,8 +162,8 @@ export class LedgerCollection implements ILedgerCollection {
159162
balance: summaries.sum((x) => x.balance || 0),
160163
equity: summaries.sum((x) => x.equity || 0),
161164
cashFlow: summaries.sum((x) => x.cashFlow || 0),
162-
averageCashFlow: summaries.average((x) => x.cashFlow || 0),
163-
purchases: summaries.average((x) => x.purchases || 0),
165+
averageCashFlow: currency(summaries.average((x) => x.cashFlow || 0)),
166+
purchases: summaries.sum((x) => x.purchases || 0),
164167
};
165168
}
166169

src/properties/rental-single-family.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { PurchaseRuleTypes } from '../rules/purchase-rule-types';
1010
import { canInvestByUser } from '../calculations/can-invest-by-user';
1111
import { IUserInvestorCheck } from '../account/i-user-investor-check';
1212
import { getCashDown, getSellPriceEstimate } from '../calculations/get-monthly-mortgage';
13-
import cloneDateUtc from '../utils/data-clone-date';
13+
import { cloneDateUtc } from '../utils/data-clone-date';
1414
import areSameDate from '../utils/data-are-same-date';
1515
import compareDates from '../utils/data-compare-date';
1616

@@ -125,7 +125,7 @@ export class RentalSingleFamily implements IEntityExistence, IRentalSavings, IRe
125125
return undefined;
126126
}
127127

128-
return new Date(value.getUTCFullYear(), value.getUTCMonth(), 1);
128+
return cloneDateUtc(value);
129129
}
130130

131131
private _purchaseDate: Date | undefined;

src/time/movement.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { IUser } from '../account/user';
77
import { LedgerItemType } from '../ledger/ledger-item-type';
88
import { LedgerItem } from '../ledger/ledger-item';
99
import propertySort from '../properties/property-sort';
10-
import cloneDateUtc from '../utils/data-clone-date';
10+
import { cloneDateUtc } from '../utils/data-clone-date';
1111

1212
export interface ILoopOptions {
1313
/**

src/time/simulate.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { RentalSingleFamily } from '../properties';
1212
import { LedgerCollection, LedgerItem, LedgerItemType } from '../ledger';
1313
import { ValueCache } from '../caching/value-cache';
1414
import { loop } from './movement';
15-
import cloneDateUtc from '../utils/data-clone-date';
15+
import { cloneDateUtc } from '../utils/data-clone-date';
1616

1717
export interface ISimulateOptions extends IPropertyEntityOptions {
1818
/**
@@ -67,12 +67,13 @@ export interface ISimulateOptions extends IPropertyEntityOptions {
6767
*/
6868
export function simulate(options: ISimulateOptions): ITimeline {
6969
const formattedUtcDate = cloneDateUtc(options.startDate ?? new Date());
70-
const valueCache = new ValueCache(cloneDateUtc(formattedUtcDate), [], options.maxRentalOpportunitiesSingleFamily);
70+
const valueCache = new ValueCache(cloneDateUtc(formattedUtcDate), [], 2);
7171

7272
const propertyGeneratorSingleFamily = Object.assign(
7373
new RentalGenerator<RentalSingleFamily>(valueCache, generateSingleFamily),
7474
options
7575
);
76+
propertyGeneratorSingleFamily.maxRentalOpportunities = options.maxRentalOpportunitiesSingleFamily;
7677

7778
const totalSavings = new LedgerItem();
7879
totalSavings.amount = options.amountInSavings;

0 commit comments

Comments
 (0)