diff --git a/CHANGELOG.md b/CHANGELOG.md index 124d03113..a7f58838f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Deprecated `activities` in the endpoint `GET api/v1/portfolio/holding/:dataSource/:symbol` +- Refactored the dividend import ## 2.228.0 - 2026-01-03 diff --git a/apps/api/src/app/import/import.controller.ts b/apps/api/src/app/import/import.controller.ts index 2681444df..81481fd65 100644 --- a/apps/api/src/app/import/import.controller.ts +++ b/apps/api/src/app/import/import.controller.ts @@ -103,6 +103,7 @@ export class ImportController { const activities = await this.importService.getDividends({ dataSource, symbol, + userCurrency: this.request.user.settings.settings.baseCurrency, userId: this.request.user.id }); diff --git a/apps/api/src/app/import/import.module.ts b/apps/api/src/app/import/import.module.ts index 88990af2e..a4a13f941 100644 --- a/apps/api/src/app/import/import.module.ts +++ b/apps/api/src/app/import/import.module.ts @@ -6,6 +6,7 @@ import { PortfolioModule } from '@ghostfolio/api/app/portfolio/portfolio.module' import { RedisCacheModule } from '@ghostfolio/api/app/redis-cache/redis-cache.module'; import { TransformDataSourceInRequestModule } from '@ghostfolio/api/interceptors/transform-data-source-in-request/transform-data-source-in-request.module'; import { TransformDataSourceInResponseModule } from '@ghostfolio/api/interceptors/transform-data-source-in-response/transform-data-source-in-response.module'; +import { ApiModule } from '@ghostfolio/api/services/api/api.module'; import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.module'; import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data-provider.module'; import { ExchangeRateDataModule } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.module'; @@ -24,6 +25,7 @@ import { ImportService } from './import.service'; controllers: [ImportController], imports: [ AccountModule, + ApiModule, CacheModule, ConfigurationModule, DataGatheringModule, diff --git a/apps/api/src/app/import/import.service.ts b/apps/api/src/app/import/import.service.ts index 2deef1c44..3f8bd2cde 100644 --- a/apps/api/src/app/import/import.service.ts +++ b/apps/api/src/app/import/import.service.ts @@ -2,6 +2,7 @@ import { AccountService } from '@ghostfolio/api/app/account/account.service'; import { OrderService } from '@ghostfolio/api/app/order/order.service'; import { PlatformService } from '@ghostfolio/api/app/platform/platform.service'; import { PortfolioService } from '@ghostfolio/api/app/portfolio/portfolio.service'; +import { ApiService } from '@ghostfolio/api/services/api/api.service'; import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service'; import { MarketDataService } from '@ghostfolio/api/services/market-data/market-data.service'; @@ -25,7 +26,7 @@ import { } from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { - AccountWithPlatform, + AccountWithValue, OrderWithAccount, UserWithSettings } from '@ghostfolio/common/types'; @@ -43,6 +44,7 @@ import { ImportDataDto } from './import-data.dto'; export class ImportService { public constructor( private readonly accountService: AccountService, + private readonly apiService: ApiService, private readonly configurationService: ConfigurationService, private readonly dataGatheringService: DataGatheringService, private readonly dataProviderService: DataProviderService, @@ -57,8 +59,12 @@ export class ImportService { public async getDividends({ dataSource, symbol, + userCurrency, userId - }: AssetProfileIdentifier & { userId: string }): Promise { + }: AssetProfileIdentifier & { + userCurrency: string; + userId: string; + }): Promise { try { const holding = await this.portfolioService.getHolding({ dataSource, @@ -71,36 +77,45 @@ export class ImportService { return []; } - const { activities, firstBuyDate, historicalData } = holding; + const filters = this.apiService.buildFiltersFromQueryParams({ + filterByDataSource: dataSource, + filterBySymbol: symbol + }); - const [[assetProfile], dividends] = await Promise.all([ - this.symbolProfileService.getSymbolProfiles([ - { - dataSource, - symbol - } - ]), - await this.dataProviderService.getDividends({ - dataSource, - symbol, - from: parseDate(firstBuyDate), - granularity: 'day', - to: new Date() - }) - ]); + const { firstBuyDate, historicalData } = holding; - const accounts = activities - .filter(({ account }) => { - return !!account; - }) - .map(({ account }) => { - return account; - }); + const [{ accounts }, { activities }, [assetProfile], dividends] = + await Promise.all([ + this.portfolioService.getAccountsWithAggregations({ + filters, + userId, + withExcludedAccounts: true + }), + this.orderService.getOrders({ + filters, + userCurrency, + userId, + startDate: parseDate(firstBuyDate) + }), + this.symbolProfileService.getSymbolProfiles([ + { + dataSource, + symbol + } + ]), + await this.dataProviderService.getDividends({ + dataSource, + symbol, + from: parseDate(firstBuyDate), + granularity: 'day', + to: new Date() + }) + ]); const account = this.isUniqueAccount(accounts) ? accounts[0] : undefined; return await Promise.all( - Object.entries(dividends).map(async ([dateString, { marketPrice }]) => { + Object.entries(dividends).map(([dateString, { marketPrice }]) => { const quantity = historicalData.find((historicalDataItem) => { return historicalDataItem.date === dateString; @@ -695,11 +710,11 @@ export class ImportService { ); } - private isUniqueAccount(accounts: AccountWithPlatform[]) { + private isUniqueAccount(accounts: AccountWithValue[]) { const uniqueAccountIds = new Set(); - for (const account of accounts) { - uniqueAccountIds.add(account.id); + for (const { id } of accounts) { + uniqueAccountIds.add(id); } return uniqueAccountIds.size === 1;