diff --git a/apps/server/src/app/__tests__/balance-sync.integration.spec.ts b/apps/server/src/app/__tests__/balance-sync.integration.spec.ts index 1acbbb1c..0b868ebf 100644 --- a/apps/server/src/app/__tests__/balance-sync.integration.spec.ts +++ b/apps/server/src/app/__tests__/balance-sync.integration.spec.ts @@ -1,5 +1,5 @@ -import { InvestmentTransactionCategory, type User } from '@prisma/client' -import { PrismaClient } from '@prisma/client' +import type { User } from '@prisma/client' +import { PrismaClient, InvestmentTransactionCategory } from '@prisma/client' import { createLogger, transports } from 'winston' import { DateTime } from 'luxon' import { diff --git a/apps/server/src/app/__tests__/connection.integration.spec.ts b/apps/server/src/app/__tests__/connection.integration.spec.ts index fe3710bc..ac0e0df1 100644 --- a/apps/server/src/app/__tests__/connection.integration.spec.ts +++ b/apps/server/src/app/__tests__/connection.integration.spec.ts @@ -1,18 +1,22 @@ import type { AxiosInstance } from 'axios' -import type { SharedType } from '@maybe-finance/shared' -import type { Prisma, AccountConnection, User } from '@prisma/client' +import { + type Prisma, + type AccountConnection, + type User, + AccountConnectionType, + AccountSyncStatus, +} from '@prisma/client' import { startServer, stopServer } from './utils/server' import { getAxiosClient } from './utils/axios' import prisma from '../lib/prisma' import { InMemoryQueue } from '@maybe-finance/server/shared' -import { default as _teller } from '../lib/teller' import nock from 'nock' import { resetUser } from './utils/user' jest.mock('../lib/teller.ts') // For TypeScript support -const teller = jest.mocked(_teller) +//const teller = jest.mocked(_teller) const authId = '__TEST_USER_ID__' let axios: AxiosInstance @@ -46,13 +50,13 @@ beforeEach(async () => { connectionData = { data: { name: 'Chase Test', - type: 'teller' as SharedType.AccountConnectionType, + type: AccountConnectionType.teller, tellerEnrollmentId: 'test-teller-item-workers', tellerInstitutionId: 'chase_test', tellerAccessToken: 'U2FsdGVkX1+WMq9lfTS9Zkbgrn41+XT1hvSK5ain/udRPujzjVCAx/lyPG7EumVZA+nVKXPauGwI+d7GZgtqTA9R3iCZNusU6LFPnmFOCE4=', // need correct encoding here userId: user.id, - syncStatus: 'PENDING', + syncStatus: AccountSyncStatus.PENDING, }, } diff --git a/apps/server/src/app/__tests__/insights.integration.spec.ts b/apps/server/src/app/__tests__/insights.integration.spec.ts index 89694f6f..16a4ce96 100644 --- a/apps/server/src/app/__tests__/insights.integration.spec.ts +++ b/apps/server/src/app/__tests__/insights.integration.spec.ts @@ -1,5 +1,5 @@ -import { InvestmentTransactionCategory, type User } from '@prisma/client' -import { Prisma, PrismaClient } from '@prisma/client' +import type { User } from '@prisma/client' +import { Prisma, PrismaClient, InvestmentTransactionCategory } from '@prisma/client' import { createLogger, transports } from 'winston' import { DateTime } from 'luxon' import type { diff --git a/apps/workers/src/app/__tests__/queue.integration.spec.ts b/apps/workers/src/app/__tests__/queue.integration.spec.ts index 4074fd12..4d0b1f21 100644 --- a/apps/workers/src/app/__tests__/queue.integration.spec.ts +++ b/apps/workers/src/app/__tests__/queue.integration.spec.ts @@ -7,6 +7,7 @@ import type { AccountConnection, User } from '@prisma/client' import prisma from '../lib/prisma' import { default as _teller } from '../lib/teller' import { resetUser } from './helpers/user.test-helper' +import { Interval } from 'luxon' // Import the workers process import '../../main' @@ -131,13 +132,24 @@ describe('Message queue tests', () => { expect(item.accounts).toHaveLength(1) const [account] = item.accounts - const transactionBalance = mockTransactions.reduce( - (acc, t) => acc + t.amount, - mockAccounts[0].balance.available + + const intervalDates = Interval.fromDateTimes( + TellerGenerator.lowerBound, + TellerGenerator.now + ) + .splitBy({ day: 1 }) + .map((date: Interval) => date.start.toISODate()) + + const startingBalance = Number(mockAccounts[0].balance.available) + + const balances = TellerGenerator.calculateDailyBalances( + startingBalance, + mockTransactions, + intervalDates ) expect(account.transactions).toHaveLength(10) - expect(account.balances.map((b) => b.balance)).toEqual(transactionBalance) + expect(account.balances.map((b) => b.balance)).toEqual(balances) expect(account.holdings).toHaveLength(0) expect(account.valuations).toHaveLength(0) expect(account.investmentTransactions).toHaveLength(0) diff --git a/prisma/seed.ts b/prisma/seed.ts index bcdaa68f..a8716316 100644 --- a/prisma/seed.ts +++ b/prisma/seed.ts @@ -15,7 +15,7 @@ async function main() { name: 'Capital One', providers: [ { - provider: 'TELLER', + provider: Provider.TELLER, providerId: 'capital_one', logoUrl: 'https://teller.io/images/banks/capital_one.jpg', rank: 1, @@ -27,7 +27,7 @@ async function main() { name: 'Wells Fargo', providers: [ { - provider: 'TELLER', + provider: Provider.TELLER, providerId: 'wells_fargo', logoUrl: 'https://teller.io/images/banks/wells_fargo.jpg', }, diff --git a/tools/generators/tellerGenerator.ts b/tools/generators/tellerGenerator.ts index c3f414b1..f0d621ac 100644 --- a/tools/generators/tellerGenerator.ts +++ b/tools/generators/tellerGenerator.ts @@ -263,9 +263,9 @@ export function generateConnection(): GenerateConnectionsResponse { } } -const now = DateTime.fromISO('2022-01-03', { zone: 'utc' }) +export const now = DateTime.fromISO('2022-01-03', { zone: 'utc' }) -const lowerBound = DateTime.fromISO('2021-12-01', { zone: 'utc' }) +export const lowerBound = DateTime.fromISO('2021-12-01', { zone: 'utc' }) export const testDates = { now, @@ -278,3 +278,19 @@ export const testDates = { }, } as Prisma.AccountBalanceWhereInput, } + +export function calculateDailyBalances(startingBalance, transactions, dateInterval) { + transactions.sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime()) + + const balanceChanges = {} + + transactions.forEach((transaction) => { + const date = new Date(transaction.date).toISOString().split('T')[0] + balanceChanges[date] = (balanceChanges[date] || 0) + Number(transaction.amount) + }) + return dateInterval.map((date) => { + return Object.keys(balanceChanges) + .filter((d) => d <= date) + .reduce((acc, d) => acc + balanceChanges[d], startingBalance) + }) +}