From 7e7d7df82b7ee1cdbff66260c45e80463a816833 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 15 Aug 2026 09:45:09 +0200 Subject: [PATCH] Add business logic and tests for stock splits --- .../src/app/activities/activities.service.ts | 12 ++++------ .../asset-profiles.service.spec.ts | 17 ++++++------- .../asset-profiles/asset-profiles.service.ts | 24 +++++++++---------- 3 files changed, 22 insertions(+), 31 deletions(-) diff --git a/apps/api/src/app/activities/activities.service.ts b/apps/api/src/app/activities/activities.service.ts index bfe35aeb0..c655e26a4 100644 --- a/apps/api/src/app/activities/activities.service.ts +++ b/apps/api/src/app/activities/activities.service.ts @@ -984,17 +984,13 @@ export class ActivitiesService { * Returns the id of every user who has an activity for the given asset * profile, including draft activities and activities of excluded accounts */ - public async getUserIdsByAssetProfile({ - dataSource, - symbol - }: AssetProfileIdentifier): Promise { + public async getUserIdsBySymbolProfileId( + symbolProfileId: string + ): Promise { const activitiesByUser = await this.prismaService.order.groupBy({ by: ['userId'], where: { - SymbolProfile: { - dataSource, - symbol - } + symbolProfileId } }); diff --git a/apps/api/src/app/endpoints/asset-profiles/asset-profiles.service.spec.ts b/apps/api/src/app/endpoints/asset-profiles/asset-profiles.service.spec.ts index 14ee54229..909c96e8b 100644 --- a/apps/api/src/app/endpoints/asset-profiles/asset-profiles.service.spec.ts +++ b/apps/api/src/app/endpoints/asset-profiles/asset-profiles.service.spec.ts @@ -15,7 +15,7 @@ describe('AssetProfilesService', () => { let emit: jest.Mock; let finished: jest.Mock; let gatherSymbol: jest.Mock; - let getUserIdsByAssetProfile: jest.Mock; + let getUserIdsBySymbolProfileId: jest.Mock; let upsert: jest.Mock; beforeEach(() => { @@ -23,11 +23,11 @@ describe('AssetProfilesService', () => { emit = jest.fn(); finished = jest.fn().mockResolvedValue(undefined); gatherSymbol = jest.fn().mockResolvedValue([{ finished }]); - getUserIdsByAssetProfile = jest.fn().mockResolvedValue([]); + getUserIdsBySymbolProfileId = jest.fn().mockResolvedValue([]); upsert = jest.fn(); assetProfilesService = new AssetProfilesService( - { getUserIdsByAssetProfile } as unknown as ActivitiesService, + { getUserIdsBySymbolProfileId } as unknown as ActivitiesService, { deleteById, upsert @@ -73,7 +73,7 @@ describe('AssetProfilesService', () => { it('invalidates portfolio snapshots for users holding the asset', async () => { upsert.mockResolvedValue({} as AssetProfileSplit); - getUserIdsByAssetProfile.mockResolvedValue(['user-1', 'user-2']); + getUserIdsBySymbolProfileId.mockResolvedValue(['user-1', 'user-2']); await assetProfilesService.createSplit({ dataSource: DataSource.YAHOO, @@ -85,10 +85,7 @@ describe('AssetProfilesService', () => { }); await flushPendingPromises(); - expect(getUserIdsByAssetProfile).toHaveBeenCalledWith({ - dataSource: DataSource.YAHOO, - symbol: 'AAPL' - }); + expect(getUserIdsBySymbolProfileId).toHaveBeenCalledWith('profile-id'); expect(emit.mock.calls.map(([, event]) => event.getUserId())).toEqual([ 'user-1', 'user-2' @@ -105,7 +102,7 @@ describe('AssetProfilesService', () => { }) ); upsert.mockResolvedValue({} as AssetProfileSplit); - getUserIdsByAssetProfile.mockResolvedValue(['user-1']); + getUserIdsBySymbolProfileId.mockResolvedValue(['user-1']); await assetProfilesService.createSplit({ dataSource: DataSource.YAHOO, @@ -148,7 +145,7 @@ describe('AssetProfilesService', () => { it('deletes an existing split using its profile scope', async () => { deleteById.mockResolvedValue(true); - getUserIdsByAssetProfile.mockResolvedValue(['user-1']); + getUserIdsBySymbolProfileId.mockResolvedValue(['user-1']); await expect( assetProfilesService.deleteSplit({ diff --git a/apps/api/src/app/endpoints/asset-profiles/asset-profiles.service.ts b/apps/api/src/app/endpoints/asset-profiles/asset-profiles.service.ts index 9f52f2b37..e34feb649 100644 --- a/apps/api/src/app/endpoints/asset-profiles/asset-profiles.service.ts +++ b/apps/api/src/app/endpoints/asset-profiles/asset-profiles.service.ts @@ -67,7 +67,8 @@ export class AssetProfilesService { await this.gatherSymbolAndEmitPortfolioChangedEvents({ dataSource, - symbol + symbol, + symbolProfileId }); return assetProfileSplit; @@ -93,7 +94,8 @@ export class AssetProfilesService { await this.gatherSymbolAndEmitPortfolioChangedEvents({ dataSource, - symbol + symbol, + symbolProfileId }); } @@ -438,14 +440,9 @@ export class AssetProfilesService { return assetProfile; } - private async emitPortfolioChangedEvents({ - dataSource, - symbol - }: AssetProfileIdentifier) { - const userIds = await this.activitiesService.getUserIdsByAssetProfile({ - dataSource, - symbol - }); + private async emitPortfolioChangedEvents(symbolProfileId: string) { + const userIds = + await this.activitiesService.getUserIdsBySymbolProfileId(symbolProfileId); for (const userId of userIds) { this.eventEmitter.emit( @@ -463,8 +460,9 @@ export class AssetProfilesService { */ private async gatherSymbolAndEmitPortfolioChangedEvents({ dataSource, - symbol - }: AssetProfileIdentifier) { + symbol, + symbolProfileId + }: { symbolProfileId: string } & AssetProfileIdentifier) { const jobs = await this.dataGatheringService.gatherSymbol({ dataSource, symbol @@ -475,7 +473,7 @@ export class AssetProfilesService { return job.finished(); }) ).then(() => { - return this.emitPortfolioChangedEvents({ dataSource, symbol }); + return this.emitPortfolioChangedEvents(symbolProfileId); }); }