Skip to content

Commit 9eb6796

Browse files
authored
feat: get year avg cash flow (#59)
1 parent cca2553 commit 9eb6796

File tree

4 files changed

+115
-1
lines changed

4 files changed

+115
-1
lines changed

src/ledger/ledger-collection.ts

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@ export interface ILedgerCollection {
4444
*/
4545
hasMinimumSavings(properties: IRentalPropertyEntity[], date: Date, minMonthsRequired?: number): boolean;
4646

47+
/**
48+
* used to get the average cash flow for the year.
49+
* @param date
50+
*/
51+
getCashFlowYearAverage(date?: Date): number;
52+
4753
getSummaryMonth(date: Date): ILedgerSummary;
4854

4955
getSummaryAnnual(year?: number): ILedgerSummary;
@@ -161,12 +167,42 @@ export class LedgerCollection implements ILedgerCollection {
161167
return this.getBalance(date) >= this.getMinimumSavings(properties, date, minMonthsRequired);
162168
}
163169

170+
getAverageByType(collection: LedgerItem[], type: LedgerItemType): number {
171+
return this.getSummaryByType(collection, type) / collection.filter((x) => x.typeMatches(type)).length;
172+
}
173+
174+
/**
175+
* used to get the average cash flow for the year.
176+
* @param date
177+
*/
178+
getCashFlowYearAverage(date?: Date): number {
179+
if (this.isEmpty()) {
180+
return 0;
181+
}
182+
183+
if (!date) {
184+
date = this.collection.last().created;
185+
}
186+
187+
const boundary = this.filter((li) => li.dateMatchesYear(date.getUTCFullYear()));
188+
189+
if (boundary.length === 0) {
190+
return 0;
191+
}
192+
193+
return this.getAverageByType(boundary, LedgerItemType.CashFlow);
194+
}
195+
164196
getCashFlowMonth(date?: Date): number {
165197
if (this.isEmpty()) {
166198
return 0;
167199
}
168200

169-
const boundary = this.filter((li) => li.dateMatchesYearAndMonth(date ?? this.collection.last().created));
201+
if (!date) {
202+
date = this.collection.last().created;
203+
}
204+
205+
const boundary = this.filter((li) => li.dateMatchesYearAndMonth(date));
170206

171207
if (boundary.length === 0) {
172208
return 0;

tests/accounts/user.spec.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ describe('User unit tests', () => {
1717
getAvailableSavings: jest.fn(),
1818
filter: jest.fn(),
1919
add: jest.fn(),
20+
getCashFlowYearAverage: jest.fn(),
2021
getBalance: jest.fn(),
2122
getCashFlowMonth: jest.fn(),
2223
getMinimumSavings: jest.fn(),

tests/ledger/ledger-collection.spec.ts

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,82 @@ describe('LedgerCollection unit tests', () => {
236236
});
237237
});
238238
});
239+
describe('and getCashFlowYearAverage', () => {
240+
describe('and no date', () => {
241+
test('should return 0', () => {
242+
expect(instance.getCashFlowYearAverage(null)).toEqual(0);
243+
});
244+
});
245+
describe('and no ledgerItem', () => {
246+
test('should return empty data', () => {
247+
expect(instance.getCashFlowYearAverage(dateUtc)).toEqual(0);
248+
});
249+
});
250+
describe('and ledgerItems', () => {
251+
describe('with matches', () => {
252+
let createdDate: Date;
253+
let cashFlow: LedgerItem;
254+
let cashFlowTwo: LedgerItem;
255+
256+
beforeEach(() => {
257+
createdDate = new Date(Date.UTC(dateUtc.getUTCFullYear() + 1, dateUtc.getUTCMonth(), 1));
258+
259+
cashFlow = new LedgerItem();
260+
cashFlow.created = createdDate;
261+
cashFlow.amount = 1;
262+
cashFlow.type = LedgerItemType.CashFlow;
263+
264+
cashFlowTwo = new LedgerItem();
265+
cashFlowTwo.created = createdDate;
266+
cashFlowTwo.amount = 3;
267+
cashFlowTwo.type = LedgerItemType.CashFlow;
268+
269+
const cashFlowOut = new LedgerItem();
270+
cashFlowOut.created = new Date(Date.UTC(dateUtc.getUTCFullYear(), dateUtc.getUTCMonth(), 1));
271+
cashFlowOut.created.setUTCMonth(cashFlowOut.created.getUTCMonth() + 2);
272+
cashFlowOut.amount = 111111;
273+
cashFlowOut.type = LedgerItemType.CashFlow;
274+
275+
const equity = new LedgerItem();
276+
equity.created = createdDate;
277+
equity.amount = 2;
278+
equity.type = LedgerItemType.Equity;
279+
280+
const purchase = new LedgerItem();
281+
purchase.created = createdDate;
282+
purchase.amount = -3;
283+
purchase.type = LedgerItemType.Purchase;
284+
285+
const salary = new LedgerItem();
286+
salary.created = createdDate;
287+
salary.amount = 4;
288+
salary.type = LedgerItemType.Salary;
289+
290+
instance.add([cashFlow, cashFlowTwo, cashFlowOut, equity, purchase, salary]);
291+
});
292+
293+
describe('with date', () => {
294+
test('should return average result', () => {
295+
expect(instance.getCashFlowYearAverage()).toEqual((cashFlow.amount + cashFlowTwo.amount) / 2);
296+
});
297+
});
298+
});
299+
300+
test('and no matching dates', () => {
301+
const createdDate = new Date(Date.UTC(dateUtc.getUTCFullYear() + 1, dateUtc.getUTCMonth(), 1));
302+
303+
const cashFlowOut = new LedgerItem();
304+
cashFlowOut.created = new Date(Date.UTC(dateUtc.getUTCFullYear(), dateUtc.getUTCMonth(), 1));
305+
cashFlowOut.created.setUTCMonth(cashFlowOut.created.getUTCMonth() + 2);
306+
cashFlowOut.amount = 111111;
307+
cashFlowOut.type = LedgerItemType.CashFlow;
308+
309+
instance.add([cashFlowOut]);
310+
311+
expect(instance.getCashFlowYearAverage(createdDate)).toEqual(0);
312+
});
313+
});
314+
});
239315
describe('and getSummariesAnnual', () => {
240316
describe('and no date', () => {
241317
test('should throw error', () => {

tests/time/looper.spec.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ describe('looper unit tests', () => {
5959
user = {
6060
ledgerCollection: {
6161
add: jest.fn(),
62+
getCashFlowYearAverage: jest.fn(),
6263
getBalance: jest.fn(),
6364
getMinimumSavings: jest.fn(),
6465
clone: jest.fn().mockReturnThis(),

0 commit comments

Comments
 (0)