From a6124891e76b31c07ea10e5a8b3175ce2aaa0628 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Wed, 26 Aug 2026 15:48:22 +0200 Subject: [PATCH] Fix creation of asset profiles with symbol in wrong letter case by using original symbol --- .../app/activities/activities.controller.ts | 22 ++++++++++++++----- .../endpoints/watchlist/watchlist.service.ts | 22 ++++++++++++++----- .../data-provider/data-provider.service.ts | 4 ++-- .../data-gathering/data-gathering.service.ts | 10 ++++++--- 4 files changed, 42 insertions(+), 16 deletions(-) diff --git a/apps/api/src/app/activities/activities.controller.ts b/apps/api/src/app/activities/activities.controller.ts index caf4103b9..3ea0f8a99 100644 --- a/apps/api/src/app/activities/activities.controller.ts +++ b/apps/api/src/app/activities/activities.controller.ts @@ -12,6 +12,7 @@ import { getIntervalFromDateRange } from '@ghostfolio/common/calculation-helper' import { DATA_GATHERING_QUEUE_PRIORITY_HIGH } from '@ghostfolio/common/config'; import { CreateOrderDto, UpdateOrderDto } from '@ghostfolio/common/dtos'; import { SubscriptionType } from '@ghostfolio/common/enums'; +import { getAssetProfileIdentifier } from '@ghostfolio/common/helper'; import { ActivitiesResponse, ActivityResponse @@ -32,7 +33,7 @@ import { Query, UseInterceptors } from '@nestjs/common'; -import { Order } from '@prisma/client'; +import { Order, SymbolProfile } from '@prisma/client'; import { parseISO } from 'date-fns'; import { StatusCodes, getReasonPhrase } from 'http-status-codes'; @@ -224,8 +225,12 @@ export class ActivitiesController { ? userSubscription : authenticatedUserSubscription; + let assetProfiles: { + [assetProfileIdentifier: string]: Partial; + }; + try { - await this.dataProviderService.validateActivities({ + assetProfiles = await this.dataProviderService.validateActivities({ subscription, activitiesDto: [ { @@ -251,6 +256,11 @@ export class ActivitiesController { const customCurrency = data.customCurrency; const dataSource = data.dataSource; + const symbol = + assetProfiles[ + getAssetProfileIdentifier({ dataSource, symbol: data.symbol }) + ]?.symbol ?? data.symbol; + if (customCurrency) { data.currency = customCurrency; @@ -268,12 +278,12 @@ export class ActivitiesController { create: { currency, dataSource, - symbol: data.symbol + symbol }, where: { dataSource_symbol: { dataSource, - symbol: data.symbol + symbol } } } @@ -291,8 +301,8 @@ export class ActivitiesController { dataGatheringItems: [ { dataSource, - date: activity.date, - symbol: data.symbol + symbol, + date: activity.date } ], priority: DATA_GATHERING_QUEUE_PRIORITY_HIGH diff --git a/apps/api/src/app/endpoints/watchlist/watchlist.service.ts b/apps/api/src/app/endpoints/watchlist/watchlist.service.ts index 88702da00..d6ee7f13f 100644 --- a/apps/api/src/app/endpoints/watchlist/watchlist.service.ts +++ b/apps/api/src/app/endpoints/watchlist/watchlist.service.ts @@ -26,10 +26,12 @@ export class WatchlistService { public async createWatchlistItem({ dataSource, - symbol, + symbol: aSymbol, userId }: { userId: string } & AssetProfileIdentifier): Promise { - const symbolProfile = await this.prismaService.symbolProfile.findUnique({ + let symbol = aSymbol; + + let symbolProfile = await this.prismaService.symbolProfile.findUnique({ where: { dataSource_symbol: { dataSource, symbol } } @@ -49,9 +51,19 @@ export class WatchlistService { ); } - await this.symbolProfileService.add( - assetProfile as Prisma.SymbolProfileCreateInput - ); + symbol = assetProfile.symbol; + + symbolProfile = await this.prismaService.symbolProfile.findUnique({ + where: { + dataSource_symbol: { dataSource, symbol } + } + }); + + if (!symbolProfile) { + await this.symbolProfileService.add( + assetProfile as Prisma.SymbolProfileCreateInput + ); + } } await this.dataGatheringService.gatherSymbol({ diff --git a/apps/api/src/services/data-provider/data-provider.service.ts b/apps/api/src/services/data-provider/data-provider.service.ts index 0d0924f80..15ec0b150 100644 --- a/apps/api/src/services/data-provider/data-provider.service.ts +++ b/apps/api/src/services/data-provider/data-provider.service.ts @@ -130,8 +130,8 @@ export class DataProviderService implements OnModuleInit { }) ] = { ...assetProfile, - symbol, - name: formatAssetProfileName(assetProfile) + name: formatAssetProfileName(assetProfile), + symbol: assetProfile.symbol ?? symbol }; } }) diff --git a/apps/api/src/services/queues/data-gathering/data-gathering.service.ts b/apps/api/src/services/queues/data-gathering/data-gathering.service.ts index 4cbe6969a..691d3a0e1 100644 --- a/apps/api/src/services/queues/data-gathering/data-gathering.service.ts +++ b/apps/api/src/services/queues/data-gathering/data-gathering.service.ts @@ -95,8 +95,13 @@ export class DataGatheringService { assetProfileIdentifiers ); - for (const assetProfile of Object.values(assetProfiles)) { - const { symbol } = assetProfile; + for (const { dataSource, symbol } of assetProfileIdentifiers) { + const assetProfile = + assetProfiles[getAssetProfileIdentifier({ dataSource, symbol })]; + + if (!assetProfile) { + continue; + } const symbolProfile = symbolProfiles.find( ({ symbol: symbolProfileSymbol }) => { @@ -137,7 +142,6 @@ export class DataGatheringService { countries, currency, cusip, - dataSource, figi, figiComposite, figiShareClass,