From 71fba8d2043b2a8e6b3f8b3e9631fd0e8534da48 Mon Sep 17 00:00:00 2001 From: Anirban Biswas <139000437+Rustix69@users.noreply.github.com> Date: Fri, 25 Jul 2025 12:37:27 +0530 Subject: [PATCH 01/14] Feature/set up Storybook story for activity type component (#5234) * Set up Storybook story for activity type component * Update changelog --- CHANGELOG.md | 4 +++ .../activity-type.component.stories.ts | 30 +++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 libs/ui/src/lib/activity-type/activity-type.component.stories.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 7251f99b8..cded684bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +### Added + +- Added a _Storybook_ story for the activity type component + ### Changed - Refactored the toggle component to standalone diff --git a/libs/ui/src/lib/activity-type/activity-type.component.stories.ts b/libs/ui/src/lib/activity-type/activity-type.component.stories.ts new file mode 100644 index 000000000..349cf6a7b --- /dev/null +++ b/libs/ui/src/lib/activity-type/activity-type.component.stories.ts @@ -0,0 +1,30 @@ +import { CommonModule } from '@angular/common'; +import { IonIcon } from '@ionic/angular/standalone'; +import { moduleMetadata } from '@storybook/angular'; +import type { Meta, StoryObj } from '@storybook/angular'; + +import { GfActivityTypeComponent } from './activity-type.component'; + +export default { + title: 'Activity Type', + component: GfActivityTypeComponent, + decorators: [ + moduleMetadata({ + imports: [CommonModule, IonIcon] + }) + ], + argTypes: { + activityType: { + control: 'select', + options: ['BUY', 'DIVIDEND', 'FEE', 'INTEREST', 'LIABILITY', 'SELL'] + } + } +} as Meta; + +type Story = StoryObj; + +export const Default: Story = { + args: { + activityType: 'BUY' + } +}; From eaa6a7d628d6a2446bf2f133cce16de401c9523b Mon Sep 17 00:00:00 2001 From: Nick Verner <59479310+naevern@users.noreply.github.com> Date: Fri, 25 Jul 2025 19:29:38 +0600 Subject: [PATCH 02/14] Feature/improve language localization for PT 20250725 (#5247) * Improve language localization for PT * Update changelog --- CHANGELOG.md | 1 + apps/client/src/locales/messages.pt.xlf | 30 ++++++++++++------------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cded684bb..fb443e793 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Refactored the toggle component to standalone - Improved the language localization for Dutch (`nl`) +- Improved the language localization for Portuguese (`pt`) - Improved the language localization for Turkish (`tr`) - Upgraded the _Stripe_ dependencies - Upgraded `angular` from version `19.2.1` to `20.0.7` diff --git a/apps/client/src/locales/messages.pt.xlf b/apps/client/src/locales/messages.pt.xlf index ecbcbf0dc..bed337ad9 100644 --- a/apps/client/src/locales/messages.pt.xlf +++ b/apps/client/src/locales/messages.pt.xlf @@ -8181,7 +8181,7 @@ Emerging Markets - Emerging Markets + Mercados Emergentes apps/client/src/app/pages/i18n/i18n-page.html 113 @@ -8213,7 +8213,7 @@ No accounts have been set up - No accounts have been set up + Nenhuma conta foi configurada apps/client/src/app/pages/i18n/i18n-page.html 20 @@ -8221,7 +8221,7 @@ Your net worth is managed by 0 accounts - Your net worth is managed by 0 accounts + Seu patrimônio líquido é gerenciado por 0 contas apps/client/src/app/pages/i18n/i18n-page.html 32 @@ -8229,7 +8229,7 @@ Asia-Pacific - Asia-Pacific + Ásia-Pacífico apps/client/src/app/pages/i18n/i18n-page.html 152 @@ -8261,7 +8261,7 @@ Emerging Markets - Emerging Markets + Mercados Emergentes apps/client/src/app/pages/i18n/i18n-page.html 166 @@ -8293,7 +8293,7 @@ Europe - Europe + Europa apps/client/src/app/pages/i18n/i18n-page.html 182 @@ -8325,7 +8325,7 @@ Japan - Japan + Japão apps/client/src/app/pages/i18n/i18n-page.html 196 @@ -8357,7 +8357,7 @@ North America - North America + América do Norte apps/client/src/app/pages/i18n/i18n-page.html 210 @@ -8389,7 +8389,7 @@ Find Ghostfolio on GitHub - Find Ghostfolio on GitHub + Encontre o Ghostfolio no GitHub apps/client/src/app/pages/about/overview/about-overview-page.html 74 @@ -8401,7 +8401,7 @@ Join the Ghostfolio Slack community - Join the Ghostfolio Slack community + Junte-se à comunidade do Ghostfolio Slack apps/client/src/app/pages/about/overview/about-overview-page.html 84 @@ -8409,7 +8409,7 @@ Follow Ghostfolio on X (formerly Twitter) - Follow Ghostfolio on X (formerly Twitter) + Siga o Ghostfolio no X (antigo Twitter) apps/client/src/app/pages/about/overview/about-overview-page.html 93 @@ -8417,7 +8417,7 @@ Send an e-mail - Send an e-mail + Enviar um e-mail apps/client/src/app/pages/about/overview/about-overview-page.html 103 @@ -8425,7 +8425,7 @@ Follow Ghostfolio on LinkedIn - Follow Ghostfolio on LinkedIn + Siga o Ghostfolio no LinkedIn apps/client/src/app/pages/about/overview/about-overview-page.html 122 @@ -8433,7 +8433,7 @@ Ghostfolio is an independent & bootstrapped business - Ghostfolio is an independent & bootstrapped business + Ghostfolio é um negócio independente e autossuficiente apps/client/src/app/pages/about/overview/about-overview-page.html 132 @@ -8441,7 +8441,7 @@ Support Ghostfolio - Support Ghostfolio + Apoie o Ghostfolio apps/client/src/app/pages/about/overview/about-overview-page.html 141 From 58043def08c87a5878cf2bca15f2d0cb426bcc75 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Fri, 25 Jul 2025 19:09:32 +0200 Subject: [PATCH 03/14] Bugfix/fix date format of retirement date in FIRE calculator (#5245) * Fix date format * Update changelog --- CHANGELOG.md | 1 + .../ui/src/lib/fire-calculator/fire-calculator.component.html | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fb443e793..d29746466 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +- Fixed the date format of the retirement date in the _FIRE_ calculator - Fixed an issue with the permissions of the impersonation mode related to the onboarding on the overview tab of the home page - Fixed an issue with the permissions of the impersonation mode related to the manage activities button of the holdings tab on the home page diff --git a/libs/ui/src/lib/fire-calculator/fire-calculator.component.html b/libs/ui/src/lib/fire-calculator/fire-calculator.component.html index 31c7b334d..60d5204e1 100644 --- a/libs/ui/src/lib/fire-calculator/fire-calculator.component.html +++ b/libs/ui/src/lib/fire-calculator/fire-calculator.component.html @@ -31,7 +31,9 @@ Retirement Date
- {{ calculatorForm.get('retirementDate').value | date: 'MMMM YYYY' }} + {{ + calculatorForm.get('retirementDate')?.value | date: 'MMMM yyyy' + }}
Date: Sat, 26 Jul 2025 08:26:19 +0200 Subject: [PATCH 04/14] Bugfix/fix issue with currency detection in Yahoo Finance service (#5250) * Improve currency detection * Extend tests * Update changelog --- CHANGELOG.md | 1 + .../yahoo-finance.service.spec.ts | 20 +++++++++++++++++++ .../yahoo-finance/yahoo-finance.service.ts | 3 ++- 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d29746466..7e2fadb83 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed the date format of the retirement date in the _FIRE_ calculator - Fixed an issue with the permissions of the impersonation mode related to the onboarding on the overview tab of the home page - Fixed an issue with the permissions of the impersonation mode related to the manage activities button of the holdings tab on the home page +- Fixed an issue with the currency detection related to `USD.AX` in the _Yahoo Finance_ service ## 2.184.0 - 2025-07-22 diff --git a/apps/api/src/services/data-provider/data-enhancer/yahoo-finance/yahoo-finance.service.spec.ts b/apps/api/src/services/data-provider/data-enhancer/yahoo-finance/yahoo-finance.service.spec.ts index 8a8ab1f08..c37a9fe3e 100644 --- a/apps/api/src/services/data-provider/data-enhancer/yahoo-finance/yahoo-finance.service.spec.ts +++ b/apps/api/src/services/data-provider/data-enhancer/yahoo-finance/yahoo-finance.service.spec.ts @@ -47,11 +47,21 @@ describe('YahooFinanceDataEnhancerService', () => { 'BTC-USD' ) ).toEqual('BTCUSD'); + expect( + await yahooFinanceDataEnhancerService.convertFromYahooFinanceSymbol( + 'USD.AX' + ) + ).toEqual('USD.AX'); expect( await yahooFinanceDataEnhancerService.convertFromYahooFinanceSymbol( 'EURUSD=X' ) ).toEqual('EURUSD'); + expect( + await yahooFinanceDataEnhancerService.convertFromYahooFinanceSymbol( + 'USDCHF=X' + ) + ).toEqual('USDCHF'); }); it('convertToYahooFinanceSymbol', async () => { @@ -65,6 +75,16 @@ describe('YahooFinanceDataEnhancerService', () => { 'DOGEUSD' ) ).toEqual('DOGE-USD'); + expect( + await yahooFinanceDataEnhancerService.convertToYahooFinanceSymbol( + 'EURUSD' + ) + ).toEqual('EURUSD=X'); + expect( + await yahooFinanceDataEnhancerService.convertToYahooFinanceSymbol( + 'USD.AX' + ) + ).toEqual('USD.AX'); expect( await yahooFinanceDataEnhancerService.convertToYahooFinanceSymbol( 'USDCHF' diff --git a/apps/api/src/services/data-provider/data-enhancer/yahoo-finance/yahoo-finance.service.ts b/apps/api/src/services/data-provider/data-enhancer/yahoo-finance/yahoo-finance.service.ts index 8b76ae86b..54167bc5b 100644 --- a/apps/api/src/services/data-provider/data-enhancer/yahoo-finance/yahoo-finance.service.ts +++ b/apps/api/src/services/data-provider/data-enhancer/yahoo-finance/yahoo-finance.service.ts @@ -63,7 +63,8 @@ export class YahooFinanceDataEnhancerService implements DataEnhancerInterface { if ( isCurrency( aSymbol.substring(0, aSymbol.length - DEFAULT_CURRENCY.length) - ) + ) && + isCurrency(aSymbol.substring(aSymbol.length - DEFAULT_CURRENCY.length)) ) { return `${aSymbol}=X`; } else if ( From a765e578a7c82da6e731182852670907c91e8a1b Mon Sep 17 00:00:00 2001 From: Anirban Biswas <139000437+Rustix69@users.noreply.github.com> Date: Sat, 26 Jul 2025 11:57:30 +0530 Subject: [PATCH 05/14] Feature/move toggle component to @ghostfolio/ui and set up Storybook story (#5248) * Move toggle component to @ghostfolio/ui * Set up Storybook story * Update changelog --- CHANGELOG.md | 1 + .../home-holdings/home-holdings.component.ts | 2 +- .../home-holdings/home-holdings.html | 2 +- .../home-overview/home-overview.component.ts | 2 -- .../components/markets/markets.component.ts | 2 +- .../src/app/components/markets/markets.html | 2 +- .../analysis/analysis-page.component.ts | 3 +- .../portfolio/analysis/analysis-page.html | 4 +-- libs/ui/src/lib/toggle/index.ts | 1 + .../ui/src/lib}/toggle/toggle.component.html | 0 .../ui/src/lib}/toggle/toggle.component.scss | 0 .../lib/toggle/toggle.component.stories.ts | 33 +++++++++++++++++++ .../ui/src/lib}/toggle/toggle.component.ts | 14 ++------ 13 files changed, 45 insertions(+), 21 deletions(-) create mode 100644 libs/ui/src/lib/toggle/index.ts rename {apps/client/src/app/components => libs/ui/src/lib}/toggle/toggle.component.html (100%) rename {apps/client/src/app/components => libs/ui/src/lib}/toggle/toggle.component.scss (100%) create mode 100644 libs/ui/src/lib/toggle/toggle.component.stories.ts rename {apps/client/src/app/components => libs/ui/src/lib}/toggle/toggle.component.ts (66%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e2fadb83..6abb6119b 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 ### Added - Added a _Storybook_ story for the activity type component +- Added a _Storybook_ story for the toggle component ### Changed diff --git a/apps/client/src/app/components/home-holdings/home-holdings.component.ts b/apps/client/src/app/components/home-holdings/home-holdings.component.ts index e4a369d41..33d9139ea 100644 --- a/apps/client/src/app/components/home-holdings/home-holdings.component.ts +++ b/apps/client/src/app/components/home-holdings/home-holdings.component.ts @@ -1,4 +1,3 @@ -import { GfToggleComponent } from '@ghostfolio/client/components/toggle/toggle.component'; import { DataService } from '@ghostfolio/client/services/data.service'; import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service'; import { UserService } from '@ghostfolio/client/services/user/user.service'; @@ -12,6 +11,7 @@ import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { internalRoutes } from '@ghostfolio/common/routes/routes'; import { HoldingType, HoldingsViewMode } from '@ghostfolio/common/types'; import { GfHoldingsTableComponent } from '@ghostfolio/ui/holdings-table'; +import { GfToggleComponent } from '@ghostfolio/ui/toggle'; import { GfTreemapChartComponent } from '@ghostfolio/ui/treemap-chart'; import { CommonModule } from '@angular/common'; diff --git a/apps/client/src/app/components/home-holdings/home-holdings.html b/apps/client/src/app/components/home-holdings/home-holdings.html index 8f9276fa5..87d0a514d 100644 --- a/apps/client/src/app/components/home-holdings/home-holdings.html +++ b/apps/client/src/app/components/home-holdings/home-holdings.html @@ -28,7 +28,7 @@ [defaultValue]="holdingType" [isLoading]="false" [options]="holdingTypeOptions" - (change)="onChangeHoldingType($event.value)" + (valueChange)="onChangeHoldingType($event.value)" /> diff --git a/apps/client/src/app/components/home-overview/home-overview.component.ts b/apps/client/src/app/components/home-overview/home-overview.component.ts index db3e59f59..06fccd650 100644 --- a/apps/client/src/app/components/home-overview/home-overview.component.ts +++ b/apps/client/src/app/components/home-overview/home-overview.component.ts @@ -1,5 +1,4 @@ import { GfPortfolioPerformanceModule } from '@ghostfolio/client/components/portfolio-performance/portfolio-performance.module'; -import { GfToggleComponent } from '@ghostfolio/client/components/toggle/toggle.component'; import { LayoutService } from '@ghostfolio/client/core/layout.service'; import { DataService } from '@ghostfolio/client/services/data.service'; import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service'; @@ -43,7 +42,6 @@ import { takeUntil } from 'rxjs/operators'; templateUrl: './home-overview.html' }) export class GfHomeOverviewComponent implements OnDestroy, OnInit { - public dateRangeOptions = GfToggleComponent.DEFAULT_DATE_RANGE_OPTIONS; public deviceType: string; public errors: AssetProfileIdentifier[]; public hasError: boolean; diff --git a/apps/client/src/app/components/markets/markets.component.ts b/apps/client/src/app/components/markets/markets.component.ts index 153c1ea14..91c28e1c7 100644 --- a/apps/client/src/app/components/markets/markets.component.ts +++ b/apps/client/src/app/components/markets/markets.component.ts @@ -1,5 +1,4 @@ import { GfFearAndGreedIndexModule } from '@ghostfolio/client/components/fear-and-greed-index/fear-and-greed-index.module'; -import { GfToggleComponent } from '@ghostfolio/client/components/toggle/toggle.component'; import { DataService } from '@ghostfolio/client/services/data.service'; import { UserService } from '@ghostfolio/client/services/user/user.service'; import { resetHours } from '@ghostfolio/common/helper'; @@ -13,6 +12,7 @@ import { import { FearAndGreedIndexMode } from '@ghostfolio/common/types'; import { GfBenchmarkComponent } from '@ghostfolio/ui/benchmark'; import { GfLineChartComponent } from '@ghostfolio/ui/line-chart'; +import { GfToggleComponent } from '@ghostfolio/ui/toggle'; import { ChangeDetectionStrategy, diff --git a/apps/client/src/app/components/markets/markets.html b/apps/client/src/app/components/markets/markets.html index 947772d57..90ddbba06 100644 --- a/apps/client/src/app/components/markets/markets.html +++ b/apps/client/src/app/components/markets/markets.html @@ -9,7 +9,7 @@ [defaultValue]="fearAndGreedIndexMode" [isLoading]="false" [options]="fearAndGreedIndexModeOptions" - (change)="onChangeFearAndGreedIndexMode($event.value)" + (valueChange)="onChangeFearAndGreedIndexMode($event.value)" /> } diff --git a/apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts b/apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts index b56a1fe5a..02be40250 100644 --- a/apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts +++ b/apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts @@ -1,6 +1,5 @@ import { GfBenchmarkComparatorModule } from '@ghostfolio/client/components/benchmark-comparator/benchmark-comparator.module'; import { GfInvestmentChartModule } from '@ghostfolio/client/components/investment-chart/investment-chart.module'; -import { GfToggleComponent } from '@ghostfolio/client/components/toggle/toggle.component'; import { DataService } from '@ghostfolio/client/services/data.service'; import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service'; import { UserService } from '@ghostfolio/client/services/user/user.service'; @@ -17,6 +16,7 @@ import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import type { AiPromptMode, GroupBy } from '@ghostfolio/common/types'; import { translate } from '@ghostfolio/ui/i18n'; import { GfPremiumIndicatorComponent } from '@ghostfolio/ui/premium-indicator'; +import { GfToggleComponent } from '@ghostfolio/ui/toggle'; import { GfValueComponent } from '@ghostfolio/ui/value'; import { Clipboard } from '@angular/cdk/clipboard'; @@ -68,7 +68,6 @@ export class GfAnalysisPageComponent implements OnDestroy, OnInit { public benchmarkDataItems: HistoricalDataItem[] = []; public benchmarks: Partial[]; public bottom3: PortfolioPosition[]; - public dateRangeOptions = GfToggleComponent.DEFAULT_DATE_RANGE_OPTIONS; public deviceType: string; public dividendsByGroup: InvestmentItem[]; public dividendTimelineDataLabel = $localize`Dividend`; diff --git a/apps/client/src/app/pages/portfolio/analysis/analysis-page.html b/apps/client/src/app/pages/portfolio/analysis/analysis-page.html index 56c95e40f..477d47b40 100644 --- a/apps/client/src/app/pages/portfolio/analysis/analysis-page.html +++ b/apps/client/src/app/pages/portfolio/analysis/analysis-page.html @@ -375,7 +375,7 @@ [defaultValue]="mode" [isLoading]="false" [options]="modeOptions" - (change)="onChangeGroupBy($event.value)" + (valueChange)="onChangeGroupBy($event.value)" /> @if (streaks) { @@ -432,7 +432,7 @@ [defaultValue]="mode" [isLoading]="false" [options]="modeOptions" - (change)="onChangeGroupBy($event.value)" + (valueChange)="onChangeGroupBy($event.value)" />
diff --git a/libs/ui/src/lib/toggle/index.ts b/libs/ui/src/lib/toggle/index.ts new file mode 100644 index 000000000..251899391 --- /dev/null +++ b/libs/ui/src/lib/toggle/index.ts @@ -0,0 +1 @@ +export * from './toggle.component'; diff --git a/apps/client/src/app/components/toggle/toggle.component.html b/libs/ui/src/lib/toggle/toggle.component.html similarity index 100% rename from apps/client/src/app/components/toggle/toggle.component.html rename to libs/ui/src/lib/toggle/toggle.component.html diff --git a/apps/client/src/app/components/toggle/toggle.component.scss b/libs/ui/src/lib/toggle/toggle.component.scss similarity index 100% rename from apps/client/src/app/components/toggle/toggle.component.scss rename to libs/ui/src/lib/toggle/toggle.component.scss diff --git a/libs/ui/src/lib/toggle/toggle.component.stories.ts b/libs/ui/src/lib/toggle/toggle.component.stories.ts new file mode 100644 index 000000000..36468ea3c --- /dev/null +++ b/libs/ui/src/lib/toggle/toggle.component.stories.ts @@ -0,0 +1,33 @@ +import { CommonModule } from '@angular/common'; +import { ReactiveFormsModule } from '@angular/forms'; +import { MatRadioModule } from '@angular/material/radio'; +import { moduleMetadata } from '@storybook/angular'; +import type { Meta, StoryObj } from '@storybook/angular'; + +import { GfToggleComponent } from './toggle.component'; + +export default { + title: 'Toggle', + component: GfToggleComponent, + decorators: [ + moduleMetadata({ + imports: [CommonModule, MatRadioModule, ReactiveFormsModule] + }) + ] +} as Meta; + +type Story = StoryObj; + +export const Default: Story = { + args: { + defaultValue: '1d', + isLoading: false, + options: [ + { label: 'Today', value: '1d' }, + { label: 'YTD', value: 'ytd' }, + { label: '1Y', value: '1y' }, + { label: '5Y', value: '5y' }, + { label: 'Max', value: 'max' } + ] + } +}; diff --git a/apps/client/src/app/components/toggle/toggle.component.ts b/libs/ui/src/lib/toggle/toggle.component.ts similarity index 66% rename from apps/client/src/app/components/toggle/toggle.component.ts rename to libs/ui/src/lib/toggle/toggle.component.ts index 8f1a13df3..be460f7fa 100644 --- a/apps/client/src/app/components/toggle/toggle.component.ts +++ b/libs/ui/src/lib/toggle/toggle.component.ts @@ -20,19 +20,11 @@ import { MatRadioModule } from '@angular/material/radio'; templateUrl: './toggle.component.html' }) export class GfToggleComponent implements OnChanges { - public static DEFAULT_DATE_RANGE_OPTIONS: ToggleOption[] = [ - { label: $localize`Today`, value: '1d' }, - { label: $localize`YTD`, value: 'ytd' }, - { label: $localize`1Y`, value: '1y' }, - { label: $localize`5Y`, value: '5y' }, - { label: $localize`Max`, value: 'max' } - ]; - @Input() defaultValue: string; @Input() isLoading: boolean; - @Input() options: ToggleOption[]; + @Input() options: ToggleOption[] = []; - @Output() change = new EventEmitter>(); + @Output() valueChange = new EventEmitter>(); public optionFormControl = new FormControl(undefined); @@ -41,6 +33,6 @@ export class GfToggleComponent implements OnChanges { } public onValueChange() { - this.change.emit({ value: this.optionFormControl.value }); + this.valueChange.emit({ value: this.optionFormControl.value }); } } From d30cf43c26d1fa9a647a5ace9e4f5885f162ac5f Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 26 Jul 2025 09:26:52 +0200 Subject: [PATCH 06/14] Feature/harmonize use of hasImpersonationId in header component (#5251) * Harmonize use of hasImpersonationId in header component --- apps/client/src/app/components/header/header.component.html | 2 +- apps/client/src/app/components/header/header.component.ts | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/client/src/app/components/header/header.component.html b/apps/client/src/app/components/header/header.component.html index 3f443dfea..ec62e41fe 100644 --- a/apps/client/src/app/components/header/header.component.html +++ b/apps/client/src/app/components/header/header.component.html @@ -205,7 +205,7 @@ { + this.hasImpersonationId = !!impersonationId; this.impersonationId = impersonationId; }); From c8c5842cec644ee6e9fc12c03151a11e0abc70b3 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 26 Jul 2025 17:29:00 +0200 Subject: [PATCH 07/14] Feature/migrate various requests to its stable API version in Financial Modeling Prep service (#5253) * Migrate to stable API version * Update changelog --- CHANGELOG.md | 1 + .../financial-modeling-prep.service.ts | 68 ++++++++----------- .../src/app/pages/api/api-page.component.ts | 2 +- 3 files changed, 32 insertions(+), 39 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6abb6119b..bca053c0c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- Migrated the get country and sector weightings, dividends, ETF holdings, ETF info, historical price, profile, quote and symbol search functionalities of the _Financial Modeling Prep_ service to its stable API version - Refactored the toggle component to standalone - Improved the language localization for Dutch (`nl`) - Improved the language localization for Portuguese (`pt`) diff --git a/apps/api/src/services/data-provider/financial-modeling-prep/financial-modeling-prep.service.ts b/apps/api/src/services/data-provider/financial-modeling-prep/financial-modeling-prep.service.ts index a9f171f13..2dcb689a7 100644 --- a/apps/api/src/services/data-provider/financial-modeling-prep/financial-modeling-prep.service.ts +++ b/apps/api/src/services/data-provider/financial-modeling-prep/financial-modeling-prep.service.ts @@ -46,7 +46,6 @@ import { @Injectable() export class FinancialModelingPrepService implements DataProviderInterface { private apiKey: string; - private readonly URL = this.getUrl({ version: 3 }); public constructor( private readonly configurationService: ConfigurationService, @@ -81,7 +80,7 @@ export class FinancialModelingPrepService implements DataProviderInterface { ); } else if (this.cryptocurrencyService.isCryptocurrency(symbol)) { const [quote] = await fetch( - `${this.URL}/quote/${symbol}?apikey=${this.apiKey}`, + `${this.getUrl({ version: 'stable' })}/quote?symbol=${symbol}&apikey=${this.apiKey}`, { signal: AbortSignal.timeout(requestTimeout) } @@ -95,7 +94,7 @@ export class FinancialModelingPrepService implements DataProviderInterface { response.name = quote.name; } else { const [assetProfile] = await fetch( - `${this.URL}/profile/${symbol}?apikey=${this.apiKey}`, + `${this.getUrl({ version: 'stable' })}/profile?symbol=${symbol}&apikey=${this.apiKey}`, { signal: AbortSignal.timeout(requestTimeout) } @@ -109,7 +108,7 @@ export class FinancialModelingPrepService implements DataProviderInterface { if (assetSubClass === AssetSubClass.ETF) { const etfCountryWeightings = await fetch( - `${this.URL}/etf-country-weightings/${symbol}?apikey=${this.apiKey}`, + `${this.getUrl({ version: 'stable' })}/etf/country-weightings?symbol=${symbol}&apikey=${this.apiKey}`, { signal: AbortSignal.timeout(requestTimeout) } @@ -133,45 +132,38 @@ export class FinancialModelingPrepService implements DataProviderInterface { } ); - const [etfInformation] = await fetch( - `${this.getUrl({ version: 4 })}/etf-info?symbol=${symbol}&apikey=${this.apiKey}`, + const etfHoldings = await fetch( + `${this.getUrl({ version: 'stable' })}/etf/holdings?symbol=${symbol}&apikey=${this.apiKey}`, { signal: AbortSignal.timeout(requestTimeout) } ).then((res) => res.json()); - if (etfInformation.website) { - response.url = etfInformation.website; - } + const sortedTopHoldings = etfHoldings + .sort((a, b) => { + return b.weightPercentage - a.weightPercentage; + }) + .slice(0, 10); - const [portfolioDate] = await fetch( - `${this.getUrl({ version: 4 })}/etf-holdings/portfolio-date?symbol=${symbol}&apikey=${this.apiKey}`, + response.holdings = sortedTopHoldings.map( + ({ name, weightPercentage }) => { + return { name, weight: weightPercentage / 100 }; + } + ); + + const [etfInformation] = await fetch( + `${this.getUrl({ version: 'stable' })}/etf/info?symbol=${symbol}&apikey=${this.apiKey}`, { signal: AbortSignal.timeout(requestTimeout) } ).then((res) => res.json()); - if (portfolioDate) { - const etfHoldings = await fetch( - `${this.getUrl({ version: 4 })}/etf-holdings?date=${portfolioDate.date}&symbol=${symbol}&apikey=${this.apiKey}`, - { - signal: AbortSignal.timeout(requestTimeout) - } - ).then((res) => res.json()); - - const sortedTopHoldings = etfHoldings - .sort((a, b) => { - return b.pctVal - a.pctVal; - }) - .slice(0, 10); - - response.holdings = sortedTopHoldings.map(({ name, pctVal }) => { - return { name, weight: pctVal / 100 }; - }); + if (etfInformation.website) { + response.url = etfInformation.website; } const etfSectorWeightings = await fetch( - `${this.URL}/etf-sector-weightings/${symbol}?apikey=${this.apiKey}`, + `${this.getUrl({ version: 'stable' })}/etf/sector-weightings?symbol=${symbol}&apikey=${this.apiKey}`, { signal: AbortSignal.timeout(requestTimeout) } @@ -181,7 +173,7 @@ export class FinancialModelingPrepService implements DataProviderInterface { ({ sector, weightPercentage }) => { return { name: sector, - weight: parseFloat(weightPercentage.slice(0, -1)) / 100 + weight: weightPercentage / 100 }; } ); @@ -246,14 +238,14 @@ export class FinancialModelingPrepService implements DataProviderInterface { [date: string]: IDataProviderHistoricalResponse; } = {}; - const { historical = [] } = await fetch( - `${this.URL}/historical-price-full/stock_dividend/${symbol}?apikey=${this.apiKey}`, + const dividends = await fetch( + `${this.getUrl({ version: 'stable' })}/dividends?symbol=${symbol}&apikey=${this.apiKey}`, { signal: AbortSignal.timeout(requestTimeout) } ).then((res) => res.json()); - historical + dividends .filter(({ date }) => { return ( (isSameDay(parseISO(date), from) || @@ -307,21 +299,21 @@ export class FinancialModelingPrepService implements DataProviderInterface { ? addYears(currentFrom, MAX_YEARS_PER_REQUEST) : to; - const { historical = [] } = await fetch( - `${this.URL}/historical-price-full/${symbol}?apikey=${this.apiKey}&from=${format(currentFrom, DATE_FORMAT)}&to=${format(currentTo, DATE_FORMAT)}`, + const historical = await fetch( + `${this.getUrl({ version: 'stable' })}/historical-price-eod/full?symbol=${symbol}&apikey=${this.apiKey}&from=${format(currentFrom, DATE_FORMAT)}&to=${format(currentTo, DATE_FORMAT)}`, { signal: AbortSignal.timeout(requestTimeout) } ).then((res) => res.json()); - for (const { adjClose, date } of historical) { + for (const { close, date } of historical) { if ( (isSameDay(parseDate(date), currentFrom) || isAfter(parseDate(date), currentFrom)) && isBefore(parseDate(date), currentTo) ) { result[symbol][date] = { - marketPrice: adjClose + marketPrice: close }; } } @@ -454,7 +446,7 @@ export class FinancialModelingPrepService implements DataProviderInterface { }); } else { const result = await fetch( - `${this.URL}/search?query=${query}&apikey=${this.apiKey}`, + `${this.getUrl({ version: 'stable' })}/search-symbol?query=${query}&apikey=${this.apiKey}`, { signal: AbortSignal.timeout( this.configurationService.get('REQUEST_TIMEOUT') diff --git a/apps/client/src/app/pages/api/api-page.component.ts b/apps/client/src/app/pages/api/api-page.component.ts index 7b385ec2f..87fc164af 100644 --- a/apps/client/src/app/pages/api/api-page.component.ts +++ b/apps/client/src/app/pages/api/api-page.component.ts @@ -44,7 +44,7 @@ export class GfApiPageComponent implements OnInit { this.historicalData$ = this.fetchHistoricalData({ symbol: 'AAPL' }); this.isinLookupItems$ = this.fetchLookupItems({ query: 'US0378331005' }); this.lookupItems$ = this.fetchLookupItems({ query: 'apple' }); - this.quotes$ = this.fetchQuotes({ symbols: ['AAPL', 'VOO.US'] }); + this.quotes$ = this.fetchQuotes({ symbols: ['AAPL', 'VOO'] }); this.status$ = this.fetchStatus(); } From 3b92558e03904fa3cd0a3b730911ec1404e0d35d Mon Sep 17 00:00:00 2001 From: Attila Cseh <77381875+csehatt741@users.noreply.github.com> Date: Sat, 26 Jul 2025 17:30:39 +0200 Subject: [PATCH 08/14] Feature/extend activities import by custom asset profiles (#5243) * Extend activities import by custom asset profiles * Update changelog --- CHANGELOG.md | 1 + .../src/app/admin/create-asset-profile.dto.ts | 92 ++++++++++++++ apps/api/src/app/export/export.service.ts | 1 - ...eate-asset-profile-with-market-data.dto.ts | 17 +++ apps/api/src/app/import/import-data.dto.ts | 11 +- apps/api/src/app/import/import.controller.ts | 1 + apps/api/src/app/import/import.module.ts | 2 + apps/api/src/app/import/import.service.ts | 72 ++++++++++- .../import-activities-dialog.component.ts | 11 +- .../app/services/import-activities.service.ts | 26 ++-- .../src/lib/interfaces/export.interface.ts | 8 +- libs/common/src/lib/interfaces/index.ts | 2 + .../lib/interfaces/market-data.interface.ts | 4 + test/import/ok/sample.json | 115 +++++++++++++----- 14 files changed, 316 insertions(+), 47 deletions(-) create mode 100644 apps/api/src/app/admin/create-asset-profile.dto.ts create mode 100644 apps/api/src/app/import/create-asset-profile-with-market-data.dto.ts create mode 100644 libs/common/src/lib/interfaces/market-data.interface.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index bca053c0c..a1048c6b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- Extended the import functionality by custom asset profiles - Migrated the get country and sector weightings, dividends, ETF holdings, ETF info, historical price, profile, quote and symbol search functionalities of the _Financial Modeling Prep_ service to its stable API version - Refactored the toggle component to standalone - Improved the language localization for Dutch (`nl`) diff --git a/apps/api/src/app/admin/create-asset-profile.dto.ts b/apps/api/src/app/admin/create-asset-profile.dto.ts new file mode 100644 index 000000000..8041b0f0e --- /dev/null +++ b/apps/api/src/app/admin/create-asset-profile.dto.ts @@ -0,0 +1,92 @@ +import { IsCurrencyCode } from '@ghostfolio/api/validators/is-currency-code'; + +import { AssetClass, AssetSubClass, DataSource, Prisma } from '@prisma/client'; +import { + IsArray, + IsBoolean, + IsEnum, + IsObject, + IsOptional, + IsString, + IsUrl +} from 'class-validator'; + +export class CreateAssetProfileDto { + @IsEnum(AssetClass, { each: true }) + @IsOptional() + assetClass?: AssetClass; + + @IsEnum(AssetSubClass, { each: true }) + @IsOptional() + assetSubClass?: AssetSubClass; + + @IsOptional() + @IsString() + comment?: string; + + @IsArray() + @IsOptional() + countries?: Prisma.InputJsonArray; + + @IsCurrencyCode() + currency: string; + + @IsOptional() + @IsString() + cusip?: string; + + @IsEnum(DataSource) + dataSource: DataSource; + + @IsOptional() + @IsString() + figi?: string; + + @IsOptional() + @IsString() + figiComposite?: string; + + @IsOptional() + @IsString() + figiShareClass?: string; + + @IsArray() + @IsOptional() + holdings?: Prisma.InputJsonArray; + + @IsBoolean() + @IsOptional() + isActive?: boolean; + + @IsOptional() + @IsString() + isin?: string; + + @IsOptional() + @IsString() + name?: string; + + @IsObject() + @IsOptional() + scraperConfiguration?: Prisma.InputJsonObject; + + @IsArray() + @IsOptional() + sectors?: Prisma.InputJsonArray; + + @IsString() + symbol: string; + + @IsObject() + @IsOptional() + symbolMapping?: { + [dataProvider: string]: string; + }; + + @IsOptional() + @IsUrl({ + protocols: ['https'], + require_protocol: true + }) + url?: string; +} diff --git a/apps/api/src/app/export/export.service.ts b/apps/api/src/app/export/export.service.ts index 9c9d20682..54fd0763d 100644 --- a/apps/api/src/app/export/export.service.ts +++ b/apps/api/src/app/export/export.service.ts @@ -195,7 +195,6 @@ export class ExportService { figiComposite, figiShareClass, holdings: holdings as unknown as Prisma.JsonArray, - id, isActive, isin, marketData: marketDataByAssetProfile[id], diff --git a/apps/api/src/app/import/create-asset-profile-with-market-data.dto.ts b/apps/api/src/app/import/create-asset-profile-with-market-data.dto.ts new file mode 100644 index 000000000..fd90ab1af --- /dev/null +++ b/apps/api/src/app/import/create-asset-profile-with-market-data.dto.ts @@ -0,0 +1,17 @@ +import { MarketData } from '@ghostfolio/common/interfaces'; + +import { DataSource } from '@prisma/client'; +import { IsArray, IsEnum, IsOptional } from 'class-validator'; + +import { CreateAssetProfileDto } from '../admin/create-asset-profile.dto'; + +export class CreateAssetProfileWithMarketDataDto extends CreateAssetProfileDto { + @IsEnum([DataSource.MANUAL], { + message: `dataSource must be '${DataSource.MANUAL}'` + }) + dataSource: DataSource; + + @IsArray() + @IsOptional() + marketData?: MarketData[]; +} diff --git a/apps/api/src/app/import/import-data.dto.ts b/apps/api/src/app/import/import-data.dto.ts index 207c8152b..138d16961 100644 --- a/apps/api/src/app/import/import-data.dto.ts +++ b/apps/api/src/app/import/import-data.dto.ts @@ -4,16 +4,23 @@ import { Type } from 'class-transformer'; import { IsArray, IsOptional, ValidateNested } from 'class-validator'; import { CreateAccountWithBalancesDto } from './create-account-with-balances.dto'; +import { CreateAssetProfileWithMarketDataDto } from './create-asset-profile-with-market-data.dto'; export class ImportDataDto { - @IsOptional() @IsArray() + @IsOptional() @Type(() => CreateAccountWithBalancesDto) @ValidateNested({ each: true }) - accounts: CreateAccountWithBalancesDto[]; + accounts?: CreateAccountWithBalancesDto[]; @IsArray() @Type(() => CreateOrderDto) @ValidateNested({ each: true }) activities: CreateOrderDto[]; + + @IsArray() + @IsOptional() + @Type(() => CreateAssetProfileWithMarketDataDto) + @ValidateNested({ each: true }) + assetProfiles?: CreateAssetProfileWithMarketDataDto[]; } diff --git a/apps/api/src/app/import/import.controller.ts b/apps/api/src/app/import/import.controller.ts index 081541fee..8c06bdc6d 100644 --- a/apps/api/src/app/import/import.controller.ts +++ b/apps/api/src/app/import/import.controller.ts @@ -73,6 +73,7 @@ export class ImportController { maxActivitiesToImport, accountsWithBalancesDto: importData.accounts ?? [], activitiesDto: importData.activities, + assetProfilesWithMarketDataDto: importData.assetProfiles ?? [], user: this.request.user }); diff --git a/apps/api/src/app/import/import.module.ts b/apps/api/src/app/import/import.module.ts index 142a939a6..fb6c29fc5 100644 --- a/apps/api/src/app/import/import.module.ts +++ b/apps/api/src/app/import/import.module.ts @@ -9,6 +9,7 @@ import { TransformDataSourceInResponseModule } from '@ghostfolio/api/interceptor 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'; +import { MarketDataModule } from '@ghostfolio/api/services/market-data/market-data.module'; import { PrismaModule } from '@ghostfolio/api/services/prisma/prisma.module'; import { DataGatheringModule } from '@ghostfolio/api/services/queues/data-gathering/data-gathering.module'; import { SymbolProfileModule } from '@ghostfolio/api/services/symbol-profile/symbol-profile.module'; @@ -27,6 +28,7 @@ import { ImportService } from './import.service'; DataGatheringModule, DataProviderModule, ExchangeRateDataModule, + MarketDataModule, OrderModule, PlatformModule, PortfolioModule, diff --git a/apps/api/src/app/import/import.service.ts b/apps/api/src/app/import/import.service.ts index e41dcd819..d23427616 100644 --- a/apps/api/src/app/import/import.service.ts +++ b/apps/api/src/app/import/import.service.ts @@ -10,6 +10,7 @@ import { PlatformService } from '@ghostfolio/api/app/platform/platform.service'; import { PortfolioService } from '@ghostfolio/api/app/portfolio/portfolio.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'; import { DataGatheringService } from '@ghostfolio/api/services/queues/data-gathering/data-gathering.service'; import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile/symbol-profile.service'; import { DATA_GATHERING_QUEUE_PRIORITY_HIGH } from '@ghostfolio/common/config'; @@ -31,6 +32,7 @@ import { endOfToday, isAfter, isSameSecond, parseISO } from 'date-fns'; import { omit, uniqBy } from 'lodash'; import { v4 as uuidv4 } from 'uuid'; +import { CreateAssetProfileDto } from '../admin/create-asset-profile.dto'; import { ImportDataDto } from './import-data.dto'; @Injectable() @@ -40,6 +42,7 @@ export class ImportService { private readonly configurationService: ConfigurationService, private readonly dataGatheringService: DataGatheringService, private readonly dataProviderService: DataProviderService, + private readonly marketDataService: MarketDataService, private readonly orderService: OrderService, private readonly platformService: PlatformService, private readonly portfolioService: PortfolioService, @@ -148,17 +151,20 @@ export class ImportService { public async import({ accountsWithBalancesDto, activitiesDto, + assetProfilesWithMarketDataDto, isDryRun = false, maxActivitiesToImport, user }: { accountsWithBalancesDto: ImportDataDto['accounts']; activitiesDto: ImportDataDto['activities']; + assetProfilesWithMarketDataDto: ImportDataDto['assetProfiles']; isDryRun?: boolean; maxActivitiesToImport: number; user: UserWithSettings; }): Promise { const accountIdMapping: { [oldAccountId: string]: string } = {}; + const assetProfileSymbolMapping: { [oldSymbol: string]: string } = {}; const userCurrency = user.settings.settings.baseCurrency; if (!isDryRun && accountsWithBalancesDto?.length) { @@ -230,6 +236,63 @@ export class ImportService { } } + if (!isDryRun && assetProfilesWithMarketDataDto?.length) { + const existingAssetProfiles = + await this.symbolProfileService.getSymbolProfiles( + assetProfilesWithMarketDataDto.map(({ dataSource, symbol }) => { + return { dataSource, symbol }; + }) + ); + + for (const assetProfileWithMarketData of assetProfilesWithMarketDataDto) { + // Check if there is any existing asset profile + const existingAssetProfile = existingAssetProfiles.find( + ({ dataSource, symbol }) => { + return ( + dataSource === assetProfileWithMarketData.dataSource && + symbol === assetProfileWithMarketData.symbol + ); + } + ); + + // If there is no asset profile or if the asset profile belongs to a different user, then create a new asset profile + if (!existingAssetProfile || existingAssetProfile.userId !== user.id) { + const assetProfile: CreateAssetProfileDto = omit( + assetProfileWithMarketData, + 'marketData' + ); + + // Asset profile belongs to a different user + if (existingAssetProfile) { + const symbol = uuidv4(); + assetProfileSymbolMapping[assetProfile.symbol] = symbol; + assetProfile.symbol = symbol; + } + + // Create a new asset profile + const assetProfileObject: Prisma.SymbolProfileCreateInput = { + ...assetProfile, + user: { connect: { id: user.id } } + }; + + await this.symbolProfileService.add(assetProfileObject); + } + + // Insert or update market data + const marketDataObjects = assetProfileWithMarketData.marketData.map( + (marketData) => { + return { + ...marketData, + dataSource: assetProfileWithMarketData.dataSource, + symbol: assetProfileWithMarketData.symbol + } as Prisma.MarketDataUpdateInput; + } + ); + + await this.marketDataService.updateMany({ data: marketDataObjects }); + } + } + for (const activity of activitiesDto) { if (!activity.dataSource) { if (['FEE', 'INTEREST', 'LIABILITY'].includes(activity.type)) { @@ -240,11 +303,16 @@ export class ImportService { } } - // If a new account is created, then update the accountId in all activities if (!isDryRun) { - if (Object.keys(accountIdMapping).includes(activity.accountId)) { + // If a new account is created, then update the accountId in all activities + if (accountIdMapping[activity.accountId]) { activity.accountId = accountIdMapping[activity.accountId]; } + + // If a new asset profile is created, then update the symbol in all activities + if (assetProfileSymbolMapping[activity.symbol]) { + activity.symbol = assetProfileSymbolMapping[activity.symbol]; + } } } diff --git a/apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts b/apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts index b9f0986ac..660e7265e 100644 --- a/apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts +++ b/apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts @@ -1,4 +1,5 @@ -import { CreateAccountDto } from '@ghostfolio/api/app/account/create-account.dto'; +import { CreateAccountWithBalancesDto } from '@ghostfolio/api/app/import/create-account-with-balances.dto'; +import { CreateAssetProfileWithMarketDataDto } from '@ghostfolio/api/app/import/create-asset-profile-with-market-data.dto'; import { Activity } from '@ghostfolio/api/app/order/interfaces/activities.interface'; import { GfDialogFooterModule } from '@ghostfolio/client/components/dialog-footer/dialog-footer.module'; import { GfDialogHeaderModule } from '@ghostfolio/client/components/dialog-header/dialog-header.module'; @@ -75,9 +76,10 @@ import { ImportActivitiesDialogParams } from './interfaces/interfaces'; templateUrl: 'import-activities-dialog.html' }) export class GfImportActivitiesDialog implements OnDestroy { - public accounts: CreateAccountDto[] = []; + public accounts: CreateAccountWithBalancesDto[] = []; public activities: Activity[] = []; public assetProfileForm: FormGroup; + public assetProfiles: CreateAssetProfileWithMarketDataDto[] = []; public dataSource: MatTableDataSource; public details: any[] = []; public deviceType: string; @@ -166,7 +168,8 @@ export class GfImportActivitiesDialog implements OnDestroy { await this.importActivitiesService.importSelectedActivities({ accounts: this.accounts, - activities: this.selectedActivities + activities: this.selectedActivities, + assetProfiles: this.assetProfiles }); this.snackBar.open( @@ -293,6 +296,7 @@ export class GfImportActivitiesDialog implements OnDestroy { const content = JSON.parse(fileContent); this.accounts = content.accounts; + this.assetProfiles = content.assetProfiles; if (!isArray(content.activities)) { if (isArray(content.orders)) { @@ -323,6 +327,7 @@ export class GfImportActivitiesDialog implements OnDestroy { await this.importActivitiesService.importJson({ accounts: content.accounts, activities: content.activities, + assetProfiles: content.assetProfiles, isDryRun: true }); this.activities = activities; diff --git a/apps/client/src/app/services/import-activities.service.ts b/apps/client/src/app/services/import-activities.service.ts index a4ffa7ec4..033ae7e24 100644 --- a/apps/client/src/app/services/import-activities.service.ts +++ b/apps/client/src/app/services/import-activities.service.ts @@ -1,4 +1,5 @@ -import { CreateAccountDto } from '@ghostfolio/api/app/account/create-account.dto'; +import { CreateAccountWithBalancesDto } from '@ghostfolio/api/app/import/create-account-with-balances.dto'; +import { CreateAssetProfileWithMarketDataDto } from '@ghostfolio/api/app/import/create-asset-profile-with-market-data.dto'; import { CreateOrderDto } from '@ghostfolio/api/app/order/create-order.dto'; import { Activity } from '@ghostfolio/api/app/order/interfaces/activities.interface'; import { parseDate as parseDateHelper } from '@ghostfolio/common/helper'; @@ -73,20 +74,22 @@ export class ImportActivitiesService { public importJson({ accounts, activities, + assetProfiles, isDryRun = false }: { activities: CreateOrderDto[]; - accounts?: CreateAccountDto[]; + accounts?: CreateAccountWithBalancesDto[]; + assetProfiles?: CreateAssetProfileWithMarketDataDto[]; isDryRun?: boolean; }): Promise<{ activities: Activity[]; - accounts?: CreateAccountDto[]; }> { return new Promise((resolve, reject) => { this.postImport( { accounts, - activities + activities, + assetProfiles }, isDryRun ) @@ -106,13 +109,14 @@ export class ImportActivitiesService { public importSelectedActivities({ accounts, - activities + activities, + assetProfiles }: { - accounts: CreateAccountDto[]; + accounts?: CreateAccountWithBalancesDto[]; activities: Activity[]; + assetProfiles?: CreateAssetProfileWithMarketDataDto[]; }): Promise<{ activities: Activity[]; - accounts?: CreateAccountDto[]; }> { const importData: CreateOrderDto[] = []; @@ -120,7 +124,7 @@ export class ImportActivitiesService { importData.push(this.convertToCreateOrderDto(activity)); } - return this.importJson({ accounts, activities: importData }); + return this.importJson({ accounts, assetProfiles, activities: importData }); } private convertToCreateOrderDto({ @@ -383,7 +387,11 @@ export class ImportActivitiesService { } private postImport( - aImportData: { accounts: CreateAccountDto[]; activities: CreateOrderDto[] }, + aImportData: { + accounts?: CreateAccountWithBalancesDto[]; + activities: CreateOrderDto[]; + assetProfiles?: CreateAssetProfileWithMarketDataDto[]; + }, aIsDryRun = false ) { return this.http.post<{ activities: Activity[] }>( diff --git a/libs/common/src/lib/interfaces/export.interface.ts b/libs/common/src/lib/interfaces/export.interface.ts index 905e33b06..16a49b0ef 100644 --- a/libs/common/src/lib/interfaces/export.interface.ts +++ b/libs/common/src/lib/interfaces/export.interface.ts @@ -8,6 +8,7 @@ import { } from '@prisma/client'; import { AccountBalance } from './account-balance.interface'; +import { MarketData } from './market-data.interface'; export interface Export { accounts: (Omit & { @@ -23,8 +24,11 @@ export interface Export { | 'updatedAt' | 'userId' > & { dataSource: DataSource; date: string; symbol: string })[]; - assetProfiles: (Omit & { - marketData: { date: string; marketPrice: number }[]; + assetProfiles: (Omit< + SymbolProfile, + 'createdAt' | 'id' | 'updatedAt' | 'userId' + > & { + marketData: MarketData[]; })[]; meta: { date: string; diff --git a/libs/common/src/lib/interfaces/index.ts b/libs/common/src/lib/interfaces/index.ts index 611a5c963..52ca76b3a 100644 --- a/libs/common/src/lib/interfaces/index.ts +++ b/libs/common/src/lib/interfaces/index.ts @@ -25,6 +25,7 @@ import type { InfoItem } from './info-item.interface'; import type { InvestmentItem } from './investment-item.interface'; import type { LineChartItem } from './line-chart-item.interface'; import type { LookupItem } from './lookup-item.interface'; +import type { MarketData } from './market-data.interface'; import type { PortfolioChart } from './portfolio-chart.interface'; import type { PortfolioDetails } from './portfolio-details.interface'; import type { PortfolioDividends } from './portfolio-dividends.interface'; @@ -111,6 +112,7 @@ export { LineChartItem, LookupItem, LookupResponse, + MarketData, MarketDataDetailsResponse, MarketDataOfMarketsResponse, OAuthResponse, diff --git a/libs/common/src/lib/interfaces/market-data.interface.ts b/libs/common/src/lib/interfaces/market-data.interface.ts new file mode 100644 index 000000000..b7a410cba --- /dev/null +++ b/libs/common/src/lib/interfaces/market-data.interface.ts @@ -0,0 +1,4 @@ +export interface MarketData { + date: string; + marketPrice: number; +} diff --git a/test/import/ok/sample.json b/test/import/ok/sample.json index 01bcc60d9..4ebb323de 100644 --- a/test/import/ok/sample.json +++ b/test/import/ok/sample.json @@ -16,6 +16,7 @@ "value": 1000 } ], + "comment": null, "currency": "USD", "id": "b2d3fe1d-d6a8-41a3-be39-07ef5e9480f0", "isExcluded": false, @@ -23,30 +24,80 @@ "platformId": null } ], + "assetProfiles": [ + { + "assetClass": null, + "assetSubClass": null, + "comment": null, + "countries": [], + "currency": "USD", + "cusip": null, + "dataSource": "MANUAL", + "figi": null, + "figiComposite": null, + "figiShareClass": null, + "holdings": [], + "isActive": true, + "isin": null, + "marketData": [], + "name": "Account Opening Fee", + "scraperConfiguration": null, + "sectors": [], + "symbol": "14a69cb9-1e31-43fa-b320-83703d8ed74b", + "symbolMapping": {}, + "url": null + }, + { + "assetClass": null, + "assetSubClass": null, + "comment": null, + "countries": [], + "currency": "USD", + "cusip": null, + "dataSource": "MANUAL", + "figi": null, + "figiComposite": null, + "figiShareClass": null, + "holdings": [], + "isActive": true, + "isin": null, + "marketData": [], + "name": "Penthouse Apartment", + "scraperConfiguration": null, + "sectors": [], + "symbol": "7e91b7d4-1430-4212-8380-289a06c9bbc1", + "symbolMapping": {}, + "url": null + } + ], + "platforms": [], + "tags": [], "activities": [ { "accountId": "b2d3fe1d-d6a8-41a3-be39-07ef5e9480f0", "comment": null, - "fee": 0, + "fee": 49, "quantity": 0, - "type": "BUY", + "type": "FEE", "unitPrice": 0, "currency": "USD", - "dataSource": "YAHOO", - "date": "2050-06-06T00:00:00.000Z", - "symbol": "US5949181045" + "dataSource": "MANUAL", + "date": "2021-09-01T00:00:00.000Z", + "symbol": "14a69cb9-1e31-43fa-b320-83703d8ed74b", + "tags": [] }, { - "accountId": null, - "comment": null, - "fee": 0, - "quantity": 1, + "accountId": "b2d3fe1d-d6a8-41a3-be39-07ef5e9480f0", + "comment": "My first order 🤓", + "fee": 19, + "quantity": 5, "type": "BUY", - "unitPrice": 500000, + "unitPrice": 298.58, "currency": "USD", - "dataSource": "MANUAL", - "date": "2022-01-01T00:00:00.000Z", - "symbol": "Penthouse Apartment" + "dataSource": "YAHOO", + "date": "2021-09-16T00:00:00.000Z", + "symbol": "MSFT", + "tags": [] }, { "accountId": "b2d3fe1d-d6a8-41a3-be39-07ef5e9480f0", @@ -58,31 +109,39 @@ "currency": "USD", "dataSource": "YAHOO", "date": "2021-11-17T00:00:00.000Z", - "symbol": "MSFT" + "symbol": "MSFT", + "tags": [] }, { - "accountId": "b2d3fe1d-d6a8-41a3-be39-07ef5e9480f0", - "comment": "My first order 🤓", - "fee": 19, - "quantity": 5, + "accountId": null, + "comment": null, + "fee": 0, + "quantity": 1, "type": "BUY", - "unitPrice": 298.58, + "unitPrice": 500000, "currency": "USD", - "dataSource": "YAHOO", - "date": "2021-09-16T00:00:00.000Z", - "symbol": "MSFT" + "dataSource": "MANUAL", + "date": "2022-01-01T00:00:00.000Z", + "symbol": "7e91b7d4-1430-4212-8380-289a06c9bbc1", + "tags": [] }, { "accountId": "b2d3fe1d-d6a8-41a3-be39-07ef5e9480f0", "comment": null, - "fee": 49, + "fee": 0, "quantity": 0, - "type": "FEE", + "type": "BUY", "unitPrice": 0, "currency": "USD", - "dataSource": "MANUAL", - "date": "2021-09-01T00:00:00.000Z", - "symbol": "Account Opening Fee" + "dataSource": "YAHOO", + "date": "2050-06-06T00:00:00.000Z", + "symbol": "MSFT", + "tags": [] + } + ], + "user": { + "settings": { + "currency": "USD" } - ] + } } From 569d750afdbea0a5303dfcf2fb91188338a97f91 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 26 Jul 2025 17:38:32 +0200 Subject: [PATCH 09/14] Feature/update locales (#5249) Co-authored-by: github-actions[bot] --- apps/client/src/locales/messages.ca.xlf | 58 ++++++++----------------- apps/client/src/locales/messages.de.xlf | 58 ++++++++----------------- apps/client/src/locales/messages.es.xlf | 58 ++++++++----------------- apps/client/src/locales/messages.fr.xlf | 58 ++++++++----------------- apps/client/src/locales/messages.it.xlf | 58 ++++++++----------------- apps/client/src/locales/messages.nl.xlf | 58 ++++++++----------------- apps/client/src/locales/messages.pl.xlf | 58 ++++++++----------------- apps/client/src/locales/messages.pt.xlf | 58 ++++++++----------------- apps/client/src/locales/messages.tr.xlf | 58 ++++++++----------------- apps/client/src/locales/messages.uk.xlf | 58 ++++++++----------------- apps/client/src/locales/messages.xlf | 58 ++++++++----------------- apps/client/src/locales/messages.zh.xlf | 58 ++++++++----------------- 12 files changed, 228 insertions(+), 468 deletions(-) diff --git a/apps/client/src/locales/messages.ca.xlf b/apps/client/src/locales/messages.ca.xlf index 0ee70a08f..e1f80d47e 100644 --- a/apps/client/src/locales/messages.ca.xlf +++ b/apps/client/src/locales/messages.ca.xlf @@ -22,7 +22,7 @@ Iniciar sessió apps/client/src/app/components/header/header.component.ts - 257 + 259 libs/common/src/lib/routes/routes.ts @@ -2199,7 +2199,7 @@ Oooh! El testimoni de seguretat és incorrecte. apps/client/src/app/components/header/header.component.ts - 272 + 274 apps/client/src/app/components/user-account-access/user-account-access.component.ts @@ -2913,10 +2913,6 @@ Today Avui - - apps/client/src/app/components/toggle/toggle.component.ts - 24 - libs/ui/src/lib/assistant/assistant.component.ts 348 @@ -2925,10 +2921,6 @@ YTD YTD - - apps/client/src/app/components/toggle/toggle.component.ts - 25 - libs/ui/src/lib/assistant/assistant.component.ts 360 @@ -2937,10 +2929,6 @@ 1Y 1 any - - apps/client/src/app/components/toggle/toggle.component.ts - 26 - libs/ui/src/lib/assistant/assistant.component.ts 370 @@ -2949,10 +2937,6 @@ 5Y 5 anys - - apps/client/src/app/components/toggle/toggle.component.ts - 27 - libs/ui/src/lib/assistant/assistant.component.ts 395 @@ -2961,10 +2945,6 @@ Max Màx - - apps/client/src/app/components/toggle/toggle.component.ts - 28 - libs/ui/src/lib/assistant/assistant.component.ts 401 @@ -3311,7 +3291,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 183 + 186 @@ -3331,7 +3311,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 181 + 184 @@ -3347,7 +3327,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 184 + 187 @@ -4372,7 +4352,7 @@ Activitats d’importació apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 84 + 86 @@ -4380,7 +4360,7 @@ Importar dividends apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 127 + 129 @@ -4388,7 +4368,7 @@ S’estan important dades... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 165 + 167 @@ -4396,7 +4376,7 @@ La importació s’ha completat apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 173 + 176 @@ -4404,7 +4384,7 @@ S’estan validant les dades... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 281 + 284 @@ -4692,7 +4672,7 @@ Dividend apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 74 + 73 libs/ui/src/lib/i18n.ts @@ -4704,11 +4684,11 @@ Inversió apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 79 + 78 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 95 + 94 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts @@ -4720,7 +4700,7 @@ Mensualment apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 89 + 88 @@ -4728,7 +4708,7 @@ Anualment apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 90 + 89 @@ -5809,7 +5789,7 @@ Import total previst libs/ui/src/lib/fire-calculator/fire-calculator.component.html - 57 + 59 @@ -7171,7 +7151,7 @@ AI prompt has been copied to the clipboard apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 198 + 197 @@ -7259,7 +7239,7 @@ Open Duck.ai apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 199 + 198 @@ -7291,7 +7271,7 @@ Performance apps/client/src/app/components/home-overview/home-overview.component.ts - 57 + 55 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts diff --git a/apps/client/src/locales/messages.de.xlf b/apps/client/src/locales/messages.de.xlf index d8dd963fc..b2f396c01 100644 --- a/apps/client/src/locales/messages.de.xlf +++ b/apps/client/src/locales/messages.de.xlf @@ -1026,7 +1026,7 @@ Einloggen apps/client/src/app/components/header/header.component.ts - 257 + 259 libs/common/src/lib/routes/routes.ts @@ -1042,7 +1042,7 @@ Ups! Falsches Sicherheits-Token. apps/client/src/app/components/header/header.component.ts - 272 + 274 apps/client/src/app/components/user-account-access/user-account-access.component.ts @@ -1412,10 +1412,6 @@ Today Heute - - apps/client/src/app/components/toggle/toggle.component.ts - 24 - libs/ui/src/lib/assistant/assistant.component.ts 348 @@ -1424,10 +1420,6 @@ YTD YTD - - apps/client/src/app/components/toggle/toggle.component.ts - 25 - libs/ui/src/lib/assistant/assistant.component.ts 360 @@ -1436,10 +1428,6 @@ 1Y 1J - - apps/client/src/app/components/toggle/toggle.component.ts - 26 - libs/ui/src/lib/assistant/assistant.component.ts 370 @@ -1448,10 +1436,6 @@ 5Y 5J - - apps/client/src/app/components/toggle/toggle.component.ts - 27 - libs/ui/src/lib/assistant/assistant.component.ts 395 @@ -1460,10 +1444,6 @@ Max Max - - apps/client/src/app/components/toggle/toggle.component.ts - 28 - libs/ui/src/lib/assistant/assistant.component.ts 401 @@ -1482,7 +1462,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 184 + 187 @@ -2346,7 +2326,7 @@ Daten importieren... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 165 + 167 @@ -2354,7 +2334,7 @@ Der Import wurde abgeschlossen apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 173 + 176 @@ -2486,7 +2466,7 @@ Aktivitäten importieren apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 84 + 86 @@ -2606,7 +2586,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 183 + 186 @@ -2618,7 +2598,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 181 + 184 @@ -2746,7 +2726,7 @@ Projizierter Gesamtbetrag libs/ui/src/lib/fire-calculator/fire-calculator.component.html - 57 + 59 @@ -2754,7 +2734,7 @@ Monatlich apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 89 + 88 @@ -3282,7 +3262,7 @@ Dividenden apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 74 + 73 libs/ui/src/lib/i18n.ts @@ -3310,7 +3290,7 @@ Daten validieren... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 281 + 284 @@ -3378,7 +3358,7 @@ Jährlich apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 90 + 89 @@ -3386,7 +3366,7 @@ Dividenden importieren apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 127 + 129 @@ -5908,11 +5888,11 @@ Investition apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 79 + 78 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 95 + 94 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts @@ -7195,7 +7175,7 @@ KI-Anweisung wurde in die Zwischenablage kopiert apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 198 + 197 @@ -7283,7 +7263,7 @@ Öffne Duck.ai apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 199 + 198 @@ -7315,7 +7295,7 @@ Performance apps/client/src/app/components/home-overview/home-overview.component.ts - 57 + 55 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts diff --git a/apps/client/src/locales/messages.es.xlf b/apps/client/src/locales/messages.es.xlf index 086e45b0c..0ba10426a 100644 --- a/apps/client/src/locales/messages.es.xlf +++ b/apps/client/src/locales/messages.es.xlf @@ -1011,7 +1011,7 @@ Iniciar sesión apps/client/src/app/components/header/header.component.ts - 257 + 259 libs/common/src/lib/routes/routes.ts @@ -1027,7 +1027,7 @@ Vaya! Token de seguridad incorrecto. apps/client/src/app/components/header/header.component.ts - 272 + 274 apps/client/src/app/components/user-account-access/user-account-access.component.ts @@ -1397,10 +1397,6 @@ Today Hoy - - apps/client/src/app/components/toggle/toggle.component.ts - 24 - libs/ui/src/lib/assistant/assistant.component.ts 348 @@ -1409,10 +1405,6 @@ YTD Desde principio de año - - apps/client/src/app/components/toggle/toggle.component.ts - 25 - libs/ui/src/lib/assistant/assistant.component.ts 360 @@ -1421,10 +1413,6 @@ 1Y 1 año - - apps/client/src/app/components/toggle/toggle.component.ts - 26 - libs/ui/src/lib/assistant/assistant.component.ts 370 @@ -1433,10 +1421,6 @@ 5Y 5 años - - apps/client/src/app/components/toggle/toggle.component.ts - 27 - libs/ui/src/lib/assistant/assistant.component.ts 395 @@ -1445,10 +1429,6 @@ Max Máximo - - apps/client/src/app/components/toggle/toggle.component.ts - 28 - libs/ui/src/lib/assistant/assistant.component.ts 401 @@ -1467,7 +1447,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 184 + 187 @@ -2331,7 +2311,7 @@ Importando datos... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 165 + 167 @@ -2339,7 +2319,7 @@ La importación se ha completado apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 173 + 176 @@ -2471,7 +2451,7 @@ Importar operaciones apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 84 + 86 @@ -2587,7 +2567,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 181 + 184 @@ -2603,7 +2583,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 183 + 186 @@ -2731,7 +2711,7 @@ Importe total previsto libs/ui/src/lib/fire-calculator/fire-calculator.component.html - 57 + 59 @@ -2767,7 +2747,7 @@ Mensual apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 89 + 88 @@ -3259,7 +3239,7 @@ Dividendo apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 74 + 73 libs/ui/src/lib/i18n.ts @@ -3295,7 +3275,7 @@ Validando datos... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 281 + 284 @@ -3363,7 +3343,7 @@ Anual apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 90 + 89 @@ -3371,7 +3351,7 @@ Importar Dividendos apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 127 + 129 @@ -5885,11 +5865,11 @@ Inversión apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 79 + 78 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 95 + 94 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts @@ -7172,7 +7152,7 @@ El aviso de IA ha sido copiado al portapapeles apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 198 + 197 @@ -7260,7 +7240,7 @@ Abrir Duck.ai apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 199 + 198 @@ -7292,7 +7272,7 @@ Performance apps/client/src/app/components/home-overview/home-overview.component.ts - 57 + 55 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts diff --git a/apps/client/src/locales/messages.fr.xlf b/apps/client/src/locales/messages.fr.xlf index 4137eb9b1..f13b9246a 100644 --- a/apps/client/src/locales/messages.fr.xlf +++ b/apps/client/src/locales/messages.fr.xlf @@ -1322,7 +1322,7 @@ Se connecter apps/client/src/app/components/header/header.component.ts - 257 + 259 libs/common/src/lib/routes/routes.ts @@ -1338,7 +1338,7 @@ Oups! Jeton de Sécurité Incorrect. apps/client/src/app/components/header/header.component.ts - 272 + 274 apps/client/src/app/components/user-account-access/user-account-access.component.ts @@ -1712,10 +1712,6 @@ Today Aujourd’hui - - apps/client/src/app/components/toggle/toggle.component.ts - 24 - libs/ui/src/lib/assistant/assistant.component.ts 348 @@ -1724,10 +1720,6 @@ YTD CDA - - apps/client/src/app/components/toggle/toggle.component.ts - 25 - libs/ui/src/lib/assistant/assistant.component.ts 360 @@ -1736,10 +1728,6 @@ 1Y 1A - - apps/client/src/app/components/toggle/toggle.component.ts - 26 - libs/ui/src/lib/assistant/assistant.component.ts 370 @@ -1748,10 +1736,6 @@ 5Y 5A - - apps/client/src/app/components/toggle/toggle.component.ts - 27 - libs/ui/src/lib/assistant/assistant.component.ts 395 @@ -1760,10 +1744,6 @@ Max Max - - apps/client/src/app/components/toggle/toggle.component.ts - 28 - libs/ui/src/lib/assistant/assistant.component.ts 401 @@ -1790,7 +1770,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 183 + 186 @@ -1802,7 +1782,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 181 + 184 @@ -1818,7 +1798,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 184 + 187 @@ -2502,7 +2482,7 @@ Import des données... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 165 + 167 @@ -2510,7 +2490,7 @@ L’import est terminé apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 173 + 176 @@ -2518,7 +2498,7 @@ Validation des données... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 281 + 284 @@ -2702,7 +2682,7 @@ Dividende apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 74 + 73 libs/ui/src/lib/i18n.ts @@ -2722,7 +2702,7 @@ Mensuel apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 89 + 88 @@ -2986,7 +2966,7 @@ Importer Activités apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 84 + 86 @@ -3066,7 +3046,7 @@ Montant Total Prévu libs/ui/src/lib/fire-calculator/fire-calculator.component.html - 57 + 59 @@ -3362,7 +3342,7 @@ Annuel apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 90 + 89 @@ -3370,7 +3350,7 @@ Importer Dividendes apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 127 + 129 @@ -5884,11 +5864,11 @@ Investissement apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 79 + 78 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 95 + 94 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts @@ -7171,7 +7151,7 @@ Le prompt IA a été copié dans le presse-papiers apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 198 + 197 @@ -7259,7 +7239,7 @@ Ouvrir Duck.ai apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 199 + 198 @@ -7291,7 +7271,7 @@ Performance apps/client/src/app/components/home-overview/home-overview.component.ts - 57 + 55 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts diff --git a/apps/client/src/locales/messages.it.xlf b/apps/client/src/locales/messages.it.xlf index 18d523377..07bc27401 100644 --- a/apps/client/src/locales/messages.it.xlf +++ b/apps/client/src/locales/messages.it.xlf @@ -1011,7 +1011,7 @@ Accedi apps/client/src/app/components/header/header.component.ts - 257 + 259 libs/common/src/lib/routes/routes.ts @@ -1027,7 +1027,7 @@ Ops! Token di sicurezza errato. apps/client/src/app/components/header/header.component.ts - 272 + 274 apps/client/src/app/components/user-account-access/user-account-access.component.ts @@ -1397,10 +1397,6 @@ Today Oggi - - apps/client/src/app/components/toggle/toggle.component.ts - 24 - libs/ui/src/lib/assistant/assistant.component.ts 348 @@ -1409,10 +1405,6 @@ YTD anno corrente - - apps/client/src/app/components/toggle/toggle.component.ts - 25 - libs/ui/src/lib/assistant/assistant.component.ts 360 @@ -1421,10 +1413,6 @@ 1Y 1 anno - - apps/client/src/app/components/toggle/toggle.component.ts - 26 - libs/ui/src/lib/assistant/assistant.component.ts 370 @@ -1433,10 +1421,6 @@ 5Y 5 anni - - apps/client/src/app/components/toggle/toggle.component.ts - 27 - libs/ui/src/lib/assistant/assistant.component.ts 395 @@ -1445,10 +1429,6 @@ Max Massimo - - apps/client/src/app/components/toggle/toggle.component.ts - 28 - libs/ui/src/lib/assistant/assistant.component.ts 401 @@ -1467,7 +1447,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 184 + 187 @@ -2331,7 +2311,7 @@ Importazione dei dati... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 165 + 167 @@ -2339,7 +2319,7 @@ L’importazione è stata completata apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 173 + 176 @@ -2471,7 +2451,7 @@ Importa le attività apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 84 + 86 @@ -2587,7 +2567,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 181 + 184 @@ -2603,7 +2583,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 183 + 186 @@ -2731,7 +2711,7 @@ Importo totale previsto libs/ui/src/lib/fire-calculator/fire-calculator.component.html - 57 + 59 @@ -2767,7 +2747,7 @@ Mensile apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 89 + 88 @@ -3259,7 +3239,7 @@ Dividendi apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 74 + 73 libs/ui/src/lib/i18n.ts @@ -3295,7 +3275,7 @@ Convalida dei dati... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 281 + 284 @@ -3363,7 +3343,7 @@ Annuale apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 90 + 89 @@ -3371,7 +3351,7 @@ Importa i dividendi apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 127 + 129 @@ -5885,11 +5865,11 @@ Investimento apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 79 + 78 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 95 + 94 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts @@ -7172,7 +7152,7 @@ L’AI prompt è stato copiato negli appunti apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 198 + 197 @@ -7260,7 +7240,7 @@ Apri Duck.ai apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 199 + 198 @@ -7292,7 +7272,7 @@ Prestazione apps/client/src/app/components/home-overview/home-overview.component.ts - 57 + 55 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts diff --git a/apps/client/src/locales/messages.nl.xlf b/apps/client/src/locales/messages.nl.xlf index ca5e850b3..44259c0fd 100644 --- a/apps/client/src/locales/messages.nl.xlf +++ b/apps/client/src/locales/messages.nl.xlf @@ -1010,7 +1010,7 @@ Aanmelden apps/client/src/app/components/header/header.component.ts - 257 + 259 libs/common/src/lib/routes/routes.ts @@ -1026,7 +1026,7 @@ Oeps! Onjuiste beveiligingstoken. apps/client/src/app/components/header/header.component.ts - 272 + 274 apps/client/src/app/components/user-account-access/user-account-access.component.ts @@ -1396,10 +1396,6 @@ Today Vandaag - - apps/client/src/app/components/toggle/toggle.component.ts - 24 - libs/ui/src/lib/assistant/assistant.component.ts 348 @@ -1408,10 +1404,6 @@ YTD YTD - - apps/client/src/app/components/toggle/toggle.component.ts - 25 - libs/ui/src/lib/assistant/assistant.component.ts 360 @@ -1420,10 +1412,6 @@ 1Y 1J - - apps/client/src/app/components/toggle/toggle.component.ts - 26 - libs/ui/src/lib/assistant/assistant.component.ts 370 @@ -1432,10 +1420,6 @@ 5Y 5J - - apps/client/src/app/components/toggle/toggle.component.ts - 27 - libs/ui/src/lib/assistant/assistant.component.ts 395 @@ -1444,10 +1428,6 @@ Max Max - - apps/client/src/app/components/toggle/toggle.component.ts - 28 - libs/ui/src/lib/assistant/assistant.component.ts 401 @@ -1466,7 +1446,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 184 + 187 @@ -2330,7 +2310,7 @@ Gegevens importeren... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 165 + 167 @@ -2338,7 +2318,7 @@ Importeren is voltooid apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 173 + 176 @@ -2470,7 +2450,7 @@ Activiteiten importeren apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 84 + 86 @@ -2586,7 +2566,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 181 + 184 @@ -2602,7 +2582,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 183 + 186 @@ -2730,7 +2710,7 @@ Verwacht totaalbedrag libs/ui/src/lib/fire-calculator/fire-calculator.component.html - 57 + 59 @@ -2766,7 +2746,7 @@ Maandelijks apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 89 + 88 @@ -3258,7 +3238,7 @@ Dividend apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 74 + 73 libs/ui/src/lib/i18n.ts @@ -3294,7 +3274,7 @@ Gegevens valideren... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 281 + 284 @@ -3362,7 +3342,7 @@ Jaarlijks apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 90 + 89 @@ -3370,7 +3350,7 @@ Importeer dividenden apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 127 + 129 @@ -5884,11 +5864,11 @@ Investering apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 79 + 78 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 95 + 94 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts @@ -7171,7 +7151,7 @@ AI-prompt is naar het klembord gekopieerd apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 198 + 197 @@ -7259,7 +7239,7 @@ Open Duck.ai apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 199 + 198 @@ -7291,7 +7271,7 @@ Prestatie apps/client/src/app/components/home-overview/home-overview.component.ts - 57 + 55 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts diff --git a/apps/client/src/locales/messages.pl.xlf b/apps/client/src/locales/messages.pl.xlf index 64e5ad94e..651b15e25 100644 --- a/apps/client/src/locales/messages.pl.xlf +++ b/apps/client/src/locales/messages.pl.xlf @@ -1995,7 +1995,7 @@ Zaloguj się apps/client/src/app/components/header/header.component.ts - 257 + 259 libs/common/src/lib/routes/routes.ts @@ -2011,7 +2011,7 @@ Ups! Nieprawidłowy token bezpieczeństwa. apps/client/src/app/components/header/header.component.ts - 272 + 274 apps/client/src/app/components/user-account-access/user-account-access.component.ts @@ -2673,10 +2673,6 @@ Today Dziś - - apps/client/src/app/components/toggle/toggle.component.ts - 24 - libs/ui/src/lib/assistant/assistant.component.ts 348 @@ -2685,10 +2681,6 @@ YTD Liczony od początku roku (year-to-date) - - apps/client/src/app/components/toggle/toggle.component.ts - 25 - libs/ui/src/lib/assistant/assistant.component.ts 360 @@ -2697,10 +2689,6 @@ 1Y 1 rok - - apps/client/src/app/components/toggle/toggle.component.ts - 26 - libs/ui/src/lib/assistant/assistant.component.ts 370 @@ -2709,10 +2697,6 @@ 5Y 5 lat - - apps/client/src/app/components/toggle/toggle.component.ts - 27 - libs/ui/src/lib/assistant/assistant.component.ts 395 @@ -2721,10 +2705,6 @@ Max Maksimum - - apps/client/src/app/components/toggle/toggle.component.ts - 28 - libs/ui/src/lib/assistant/assistant.component.ts 401 @@ -3015,7 +2995,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 183 + 186 @@ -3027,7 +3007,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 181 + 184 @@ -3043,7 +3023,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 184 + 187 @@ -3999,7 +3979,7 @@ Importuj Aktywności apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 84 + 86 @@ -4007,7 +3987,7 @@ Impotruj Dywidendy apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 127 + 129 @@ -4015,7 +3995,7 @@ Importowanie danych... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 165 + 167 @@ -4023,7 +4003,7 @@ Importowanie zakończone apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 173 + 176 @@ -4031,7 +4011,7 @@ Weryfikacja danych... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 281 + 284 @@ -4303,7 +4283,7 @@ Dywidenda apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 74 + 73 libs/ui/src/lib/i18n.ts @@ -4323,7 +4303,7 @@ Miesięcznie apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 89 + 88 @@ -4331,7 +4311,7 @@ Rocznie apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 90 + 89 @@ -5244,7 +5224,7 @@ Przewidywana Łączna Kwota libs/ui/src/lib/fire-calculator/fire-calculator.component.html - 57 + 59 @@ -5884,11 +5864,11 @@ Inwestycje apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 79 + 78 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 95 + 94 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts @@ -7171,7 +7151,7 @@ Prompt AI został skopiowany do schowka apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 198 + 197 @@ -7259,7 +7239,7 @@ Otwórz Duck.ai apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 199 + 198 @@ -7291,7 +7271,7 @@ Wydajność apps/client/src/app/components/home-overview/home-overview.component.ts - 57 + 55 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts diff --git a/apps/client/src/locales/messages.pt.xlf b/apps/client/src/locales/messages.pt.xlf index bed337ad9..a0af13730 100644 --- a/apps/client/src/locales/messages.pt.xlf +++ b/apps/client/src/locales/messages.pt.xlf @@ -1194,7 +1194,7 @@ Iniciar sessão apps/client/src/app/components/header/header.component.ts - 257 + 259 libs/common/src/lib/routes/routes.ts @@ -1210,7 +1210,7 @@ Oops! Token de Segurança Incorreto. apps/client/src/app/components/header/header.component.ts - 272 + 274 apps/client/src/app/components/user-account-access/user-account-access.component.ts @@ -1696,10 +1696,6 @@ Today Hoje - - apps/client/src/app/components/toggle/toggle.component.ts - 24 - libs/ui/src/lib/assistant/assistant.component.ts 348 @@ -1708,10 +1704,6 @@ YTD AATD - - apps/client/src/app/components/toggle/toggle.component.ts - 25 - libs/ui/src/lib/assistant/assistant.component.ts 360 @@ -1720,10 +1712,6 @@ 1Y 1A - - apps/client/src/app/components/toggle/toggle.component.ts - 26 - libs/ui/src/lib/assistant/assistant.component.ts 370 @@ -1732,10 +1720,6 @@ 5Y 5A - - apps/client/src/app/components/toggle/toggle.component.ts - 27 - libs/ui/src/lib/assistant/assistant.component.ts 395 @@ -1744,10 +1728,6 @@ Max Máx - - apps/client/src/app/components/toggle/toggle.component.ts - 28 - libs/ui/src/lib/assistant/assistant.component.ts 401 @@ -1774,7 +1754,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 183 + 186 @@ -1786,7 +1766,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 181 + 184 @@ -1802,7 +1782,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 184 + 187 @@ -2442,7 +2422,7 @@ A importar dados... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 165 + 167 @@ -2450,7 +2430,7 @@ A importação foi concluída apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 173 + 176 @@ -2618,7 +2598,7 @@ Mensalmente apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 89 + 88 @@ -2866,7 +2846,7 @@ Importar Atividades apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 84 + 86 @@ -2946,7 +2926,7 @@ Montante Total Projetado libs/ui/src/lib/fire-calculator/fire-calculator.component.html - 57 + 59 @@ -3290,7 +3270,7 @@ A validar dados... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 281 + 284 @@ -3314,7 +3294,7 @@ Dividendos apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 74 + 73 libs/ui/src/lib/i18n.ts @@ -3362,7 +3342,7 @@ Anualmente apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 90 + 89 @@ -3370,7 +3350,7 @@ Importar Dividendos apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 127 + 129 @@ -5884,11 +5864,11 @@ Investimento apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 79 + 78 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 95 + 94 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts @@ -7171,7 +7151,7 @@ AI prompt has been copied to the clipboard apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 198 + 197 @@ -7259,7 +7239,7 @@ Open Duck.ai apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 199 + 198 @@ -7291,7 +7271,7 @@ Performance apps/client/src/app/components/home-overview/home-overview.component.ts - 57 + 55 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts diff --git a/apps/client/src/locales/messages.tr.xlf b/apps/client/src/locales/messages.tr.xlf index 29867abcd..84b990640 100644 --- a/apps/client/src/locales/messages.tr.xlf +++ b/apps/client/src/locales/messages.tr.xlf @@ -1843,7 +1843,7 @@ Giriş apps/client/src/app/components/header/header.component.ts - 257 + 259 libs/common/src/lib/routes/routes.ts @@ -1859,7 +1859,7 @@ Hay Allah! Güvenlik anahtarı yanlış. apps/client/src/app/components/header/header.component.ts - 272 + 274 apps/client/src/app/components/user-account-access/user-account-access.component.ts @@ -2513,10 +2513,6 @@ Today Bugün - - apps/client/src/app/components/toggle/toggle.component.ts - 24 - libs/ui/src/lib/assistant/assistant.component.ts 348 @@ -2525,10 +2521,6 @@ YTD YTD - - apps/client/src/app/components/toggle/toggle.component.ts - 25 - libs/ui/src/lib/assistant/assistant.component.ts 360 @@ -2537,10 +2529,6 @@ 1Y 1Y - - apps/client/src/app/components/toggle/toggle.component.ts - 26 - libs/ui/src/lib/assistant/assistant.component.ts 370 @@ -2549,10 +2537,6 @@ 5Y 5Y - - apps/client/src/app/components/toggle/toggle.component.ts - 27 - libs/ui/src/lib/assistant/assistant.component.ts 395 @@ -2561,10 +2545,6 @@ Max Maks. - - apps/client/src/app/components/toggle/toggle.component.ts - 28 - libs/ui/src/lib/assistant/assistant.component.ts 401 @@ -2591,7 +2571,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 183 + 186 @@ -2603,7 +2583,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 181 + 184 @@ -2619,7 +2599,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 184 + 187 @@ -3479,7 +3459,7 @@ İşlemleri İçe Aktar apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 84 + 86 @@ -3487,7 +3467,7 @@ Temettüleri İçe Aktar apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 127 + 129 @@ -3495,7 +3475,7 @@ Veri içe aktarılıyor... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 165 + 167 @@ -3503,7 +3483,7 @@ İçe aktarma tamamlandı apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 173 + 176 @@ -3511,7 +3491,7 @@ Veri doğrulanıyor... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 281 + 284 @@ -3791,7 +3771,7 @@ Temettü apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 74 + 73 libs/ui/src/lib/i18n.ts @@ -3811,7 +3791,7 @@ Aylık apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 89 + 88 @@ -3819,7 +3799,7 @@ Yıllık apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 90 + 89 @@ -4960,7 +4940,7 @@ Hesaplanan Toplam Tutar libs/ui/src/lib/fire-calculator/fire-calculator.component.html - 57 + 59 @@ -5884,11 +5864,11 @@ Yatırım apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 79 + 78 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 95 + 94 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts @@ -7171,7 +7151,7 @@ Yapay zeka istemi panoya kopyalandı apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 198 + 197 @@ -7259,7 +7239,7 @@ Duck.ai’yi aç apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 199 + 198 @@ -7291,7 +7271,7 @@ Performans apps/client/src/app/components/home-overview/home-overview.component.ts - 57 + 55 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts diff --git a/apps/client/src/locales/messages.uk.xlf b/apps/client/src/locales/messages.uk.xlf index 68b809f88..31de6c802 100644 --- a/apps/client/src/locales/messages.uk.xlf +++ b/apps/client/src/locales/messages.uk.xlf @@ -22,7 +22,7 @@ Увійти apps/client/src/app/components/header/header.component.ts - 257 + 259 libs/common/src/lib/routes/routes.ts @@ -2295,7 +2295,7 @@ Упс! Неправильний Секретний Токен. apps/client/src/app/components/header/header.component.ts - 272 + 274 apps/client/src/app/components/user-account-access/user-account-access.component.ts @@ -3057,10 +3057,6 @@ Today Сьогодні - - apps/client/src/app/components/toggle/toggle.component.ts - 24 - libs/ui/src/lib/assistant/assistant.component.ts 348 @@ -3069,10 +3065,6 @@ YTD З початку року - - apps/client/src/app/components/toggle/toggle.component.ts - 25 - libs/ui/src/lib/assistant/assistant.component.ts 360 @@ -3081,10 +3073,6 @@ 1Y 1 рік - - apps/client/src/app/components/toggle/toggle.component.ts - 26 - libs/ui/src/lib/assistant/assistant.component.ts 370 @@ -3093,10 +3081,6 @@ 5Y 5 років - - apps/client/src/app/components/toggle/toggle.component.ts - 27 - libs/ui/src/lib/assistant/assistant.component.ts 395 @@ -3105,10 +3089,6 @@ Max Максимум - - apps/client/src/app/components/toggle/toggle.component.ts - 28 - libs/ui/src/lib/assistant/assistant.component.ts 401 @@ -3203,7 +3183,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 184 + 187 @@ -3527,7 +3507,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 183 + 186 @@ -3547,7 +3527,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 181 + 184 @@ -4600,7 +4580,7 @@ Імпортувати активності apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 84 + 86 @@ -4608,7 +4588,7 @@ Імпорт дивідендів apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 127 + 129 @@ -4616,7 +4596,7 @@ Імпортуються дані... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 165 + 167 @@ -4624,7 +4604,7 @@ Імпорт завершено apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 173 + 176 @@ -4632,7 +4612,7 @@ Перевірка даних... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 281 + 284 @@ -4936,7 +4916,7 @@ Дивіденди apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 74 + 73 libs/ui/src/lib/i18n.ts @@ -4948,11 +4928,11 @@ Інвестиції apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 79 + 78 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 95 + 94 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts @@ -4964,7 +4944,7 @@ Щомісячно apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 89 + 88 @@ -4972,7 +4952,7 @@ Щорічно apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 90 + 89 @@ -6431,7 +6411,7 @@ Прогнозована загальна сума libs/ui/src/lib/fire-calculator/fire-calculator.component.html - 57 + 59 @@ -7179,7 +7159,7 @@ Запит AI скопійовано в буфер обміну apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 198 + 197 @@ -7259,7 +7239,7 @@ Open Duck.ai apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 199 + 198 @@ -7291,7 +7271,7 @@ Performance apps/client/src/app/components/home-overview/home-overview.component.ts - 57 + 55 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts diff --git a/apps/client/src/locales/messages.xlf b/apps/client/src/locales/messages.xlf index 5958052ff..9ec300d4c 100644 --- a/apps/client/src/locales/messages.xlf +++ b/apps/client/src/locales/messages.xlf @@ -1885,7 +1885,7 @@ Sign in apps/client/src/app/components/header/header.component.ts - 257 + 259 libs/common/src/lib/routes/routes.ts @@ -1900,7 +1900,7 @@ Oops! Incorrect Security Token. apps/client/src/app/components/header/header.component.ts - 272 + 274 apps/client/src/app/components/user-account-access/user-account-access.component.ts @@ -2502,10 +2502,6 @@ Today - - apps/client/src/app/components/toggle/toggle.component.ts - 24 - libs/ui/src/lib/assistant/assistant.component.ts 348 @@ -2513,10 +2509,6 @@ YTD - - apps/client/src/app/components/toggle/toggle.component.ts - 25 - libs/ui/src/lib/assistant/assistant.component.ts 360 @@ -2524,10 +2516,6 @@ 1Y - - apps/client/src/app/components/toggle/toggle.component.ts - 26 - libs/ui/src/lib/assistant/assistant.component.ts 370 @@ -2535,10 +2523,6 @@ 5Y - - apps/client/src/app/components/toggle/toggle.component.ts - 27 - libs/ui/src/lib/assistant/assistant.component.ts 395 @@ -2546,10 +2530,6 @@ Max - - apps/client/src/app/components/toggle/toggle.component.ts - 28 - libs/ui/src/lib/assistant/assistant.component.ts 401 @@ -2807,7 +2787,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 183 + 186 @@ -2818,7 +2798,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 181 + 184 @@ -2833,7 +2813,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 184 + 187 @@ -3682,35 +3662,35 @@ Import Activities apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 84 + 86 Import Dividends apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 127 + 129 Importing data... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 165 + 167 Import has been completed apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 173 + 176 Validating data... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 281 + 284 @@ -3953,7 +3933,7 @@ Dividend apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 74 + 73 libs/ui/src/lib/i18n.ts @@ -3971,14 +3951,14 @@ Monthly apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 89 + 88 Yearly apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 90 + 89 @@ -4838,7 +4818,7 @@ Projected Total Amount libs/ui/src/lib/fire-calculator/fire-calculator.component.html - 57 + 59 @@ -5374,11 +5354,11 @@ Investment apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 79 + 78 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 95 + 94 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts @@ -6485,7 +6465,7 @@ AI prompt has been copied to the clipboard apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 198 + 197 @@ -6562,7 +6542,7 @@ Open Duck.ai apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 199 + 198 @@ -6590,7 +6570,7 @@ Performance apps/client/src/app/components/home-overview/home-overview.component.ts - 57 + 55 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts diff --git a/apps/client/src/locales/messages.zh.xlf b/apps/client/src/locales/messages.zh.xlf index 83205275d..1c7301eb2 100644 --- a/apps/client/src/locales/messages.zh.xlf +++ b/apps/client/src/locales/messages.zh.xlf @@ -2004,7 +2004,7 @@ 登入 apps/client/src/app/components/header/header.component.ts - 257 + 259 libs/common/src/lib/routes/routes.ts @@ -2020,7 +2020,7 @@ 哎呀!安全令牌不正确。 apps/client/src/app/components/header/header.component.ts - 272 + 274 apps/client/src/app/components/user-account-access/user-account-access.component.ts @@ -2682,10 +2682,6 @@ Today 今天 - - apps/client/src/app/components/toggle/toggle.component.ts - 24 - libs/ui/src/lib/assistant/assistant.component.ts 348 @@ -2694,10 +2690,6 @@ YTD 年初至今 - - apps/client/src/app/components/toggle/toggle.component.ts - 25 - libs/ui/src/lib/assistant/assistant.component.ts 360 @@ -2706,10 +2698,6 @@ 1Y 1年 - - apps/client/src/app/components/toggle/toggle.component.ts - 26 - libs/ui/src/lib/assistant/assistant.component.ts 370 @@ -2718,10 +2706,6 @@ 5Y 5年 - - apps/client/src/app/components/toggle/toggle.component.ts - 27 - libs/ui/src/lib/assistant/assistant.component.ts 395 @@ -2730,10 +2714,6 @@ Max 最大限度 - - apps/client/src/app/components/toggle/toggle.component.ts - 28 - libs/ui/src/lib/assistant/assistant.component.ts 401 @@ -3024,7 +3004,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 183 + 186 @@ -3036,7 +3016,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 181 + 184 @@ -3052,7 +3032,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 184 + 187 @@ -4008,7 +3988,7 @@ 导入活动记录 apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 84 + 86 @@ -4016,7 +3996,7 @@ 导入股息 apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 127 + 129 @@ -4024,7 +4004,7 @@ 正在导入数据... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 165 + 167 @@ -4032,7 +4012,7 @@ 导入已完成 apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 173 + 176 @@ -4040,7 +4020,7 @@ 验证数据... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 281 + 284 @@ -4312,7 +4292,7 @@ 股息 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 74 + 73 libs/ui/src/lib/i18n.ts @@ -4332,7 +4312,7 @@ 每月 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 89 + 88 @@ -4340,7 +4320,7 @@ 每年 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 90 + 89 @@ -5301,7 +5281,7 @@ 预计总额 libs/ui/src/lib/fire-calculator/fire-calculator.component.html - 57 + 59 @@ -5909,11 +5889,11 @@ 投资 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 79 + 78 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 95 + 94 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts @@ -7172,7 +7152,7 @@ AI 提示已复制到剪贴板 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 198 + 197 @@ -7260,7 +7240,7 @@ 打开 Duck.ai apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 199 + 198 @@ -7292,7 +7272,7 @@ 表现 apps/client/src/app/components/home-overview/home-overview.component.ts - 57 + 55 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts From 784665d5baed75747419d616fdb25aa110893ad7 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 26 Jul 2025 17:41:09 +0200 Subject: [PATCH 10/14] Release 2.185.0 (#5254) --- CHANGELOG.md | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a1048c6b2..ec236ed90 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## Unreleased +## 2.185.0 - 2025-07-26 ### Added diff --git a/package-lock.json b/package-lock.json index 2183cfaef..de5631a10 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ghostfolio", - "version": "2.184.0", + "version": "2.185.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ghostfolio", - "version": "2.184.0", + "version": "2.185.0", "hasInstallScript": true, "license": "AGPL-3.0", "dependencies": { diff --git a/package.json b/package.json index 86ff201e0..c9fc0f07d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ghostfolio", - "version": "2.184.0", + "version": "2.185.0", "homepage": "https://ghostfol.io", "license": "AGPL-3.0", "repository": "https://github.com/ghostfolio/ghostfolio", From e001997ff894ced861867e6a84bd22ad10e85f14 Mon Sep 17 00:00:00 2001 From: Attila Cseh <77381875+csehatt741@users.noreply.github.com> Date: Sat, 26 Jul 2025 21:01:49 +0200 Subject: [PATCH 11/14] Bugfix/activities unexpectedly listed in holdings (#5182) * Fix activities of type FEE, INTEREST and LIABILITY unexpectedly listed in holdings * Update changelog --- CHANGELOG.md | 6 ++++ .../calculator/portfolio-calculator.ts | 23 ++++++++++--- .../roai/portfolio-calculator-fee.spec.ts | 32 +------------------ .../transaction-point-symbol.interface.ts | 1 + libs/common/src/lib/config.ts | 8 ++++- 5 files changed, 34 insertions(+), 36 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ec236ed90..083fd2d88 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +### Fixed + +- Excluded the holdings originated of `FEE`, `INTEREST` and `LIABILITY` activities from the closed holdings on the portfolio holdings page + ## 2.185.0 - 2025-07-26 ### Added diff --git a/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts b/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts index 185c1cd80..78323a332 100644 --- a/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts +++ b/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts @@ -13,6 +13,7 @@ import { IDataGatheringItem } from '@ghostfolio/api/services/interfaces/interfac import { PortfolioSnapshotService } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service'; import { getIntervalFromDateRange } from '@ghostfolio/common/calculation-helper'; import { + INVESTMENT_ACTIVITY_TYPES, PORTFOLIO_SNAPSHOT_PROCESS_JOB_NAME, PORTFOLIO_SNAPSHOT_PROCESS_JOB_OPTIONS, PORTFOLIO_SNAPSHOT_COMPUTATION_QUEUE_PRIORITY_HIGH, @@ -287,10 +288,12 @@ export abstract class PortfolioCalculator { firstIndex--; } - const positions: TimelinePosition[] = []; + const errors: ResponseError['errors'] = []; let hasAnySymbolMetricsErrors = false; - const errors: ResponseError['errors'] = []; + const positions: (TimelinePosition & { + includeInHoldings: boolean; + })[] = []; const accumulatedValuesByDate: { [date: string]: { @@ -409,6 +412,7 @@ export abstract class PortfolioCalculator { grossPerformanceWithCurrencyEffect: !hasErrors ? (grossPerformanceWithCurrencyEffect ?? null) : null, + includeInHoldings: item.includeInHoldings, investment: totalInvestment, investmentWithCurrencyEffect: totalInvestmentWithCurrencyEffect, marketPrice: @@ -605,14 +609,23 @@ export abstract class PortfolioCalculator { const overall = this.calculateOverallPerformance(positions); + const positionsIncludedInHoldings = positions + .filter(({ includeInHoldings }) => { + return includeInHoldings; + }) + // eslint-disable-next-line @typescript-eslint/no-unused-vars + .map(({ includeInHoldings, ...rest }) => { + return rest; + }); + return { ...overall, errors, historicalData, - positions, totalInterestWithCurrencyEffect, totalLiabilitiesWithCurrencyEffect, - hasErrors: hasAnySymbolMetricsErrors || overall.hasErrors + hasErrors: hasAnySymbolMetricsErrors || overall.hasErrors, + positions: positionsIncludedInHoldings }; } @@ -935,6 +948,7 @@ export abstract class PortfolioCalculator { dividend: new Big(0), fee: oldAccumulatedSymbol.fee.plus(fee), firstBuyDate: oldAccumulatedSymbol.firstBuyDate, + includeInHoldings: oldAccumulatedSymbol.includeInHoldings, quantity: newQuantity, tags: oldAccumulatedSymbol.tags.concat(tags), transactionCount: oldAccumulatedSymbol.transactionCount + 1 @@ -950,6 +964,7 @@ export abstract class PortfolioCalculator { averagePrice: unitPrice, dividend: new Big(0), firstBuyDate: date, + includeInHoldings: INVESTMENT_ACTIVITY_TYPES.includes(type), investment: unitPrice.mul(quantity).mul(factor), quantity: quantity.mul(factor), transactionCount: 1 diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-fee.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-fee.spec.ts index 31c6afe66..aaf2c4302 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-fee.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-fee.spec.ts @@ -116,37 +116,7 @@ describe('PortfolioCalculator', () => { currentValueInBaseCurrency: new Big('0'), errors: [], hasErrors: true, - positions: [ - { - averagePrice: new Big('0'), - currency: 'USD', - dataSource: 'MANUAL', - dividend: new Big('0'), - dividendInBaseCurrency: new Big('0'), - fee: new Big('49'), - feeInBaseCurrency: new Big('49'), - firstBuyDate: '2021-09-01', - grossPerformance: null, - grossPerformancePercentage: null, - grossPerformancePercentageWithCurrencyEffect: null, - grossPerformanceWithCurrencyEffect: null, - investment: new Big('0'), - investmentWithCurrencyEffect: new Big('0'), - marketPrice: null, - marketPriceInBaseCurrency: 0, - netPerformance: null, - netPerformancePercentage: null, - netPerformancePercentageWithCurrencyEffectMap: null, - netPerformanceWithCurrencyEffectMap: null, - quantity: new Big('0'), - symbol: '2c463fb3-af07-486e-adb0-8301b3d72141', - tags: [], - timeWeightedInvestment: new Big('0'), - timeWeightedInvestmentWithCurrencyEffect: new Big('0'), - transactionCount: 1, - valueInBaseCurrency: new Big('0') - } - ], + positions: [], totalFeesWithCurrencyEffect: new Big('49'), totalInterestWithCurrencyEffect: new Big('0'), totalInvestment: new Big('0'), diff --git a/apps/api/src/app/portfolio/interfaces/transaction-point-symbol.interface.ts b/apps/api/src/app/portfolio/interfaces/transaction-point-symbol.interface.ts index 0d648322f..f4ceadf3b 100644 --- a/apps/api/src/app/portfolio/interfaces/transaction-point-symbol.interface.ts +++ b/apps/api/src/app/portfolio/interfaces/transaction-point-symbol.interface.ts @@ -8,6 +8,7 @@ export interface TransactionPointSymbol { dividend: Big; fee: Big; firstBuyDate: string; + includeInHoldings: boolean; investment: Big; quantity: Big; skipErrors: boolean; diff --git a/libs/common/src/lib/config.ts b/libs/common/src/lib/config.ts index 5aee7e0e6..467716575 100644 --- a/libs/common/src/lib/config.ts +++ b/libs/common/src/lib/config.ts @@ -1,4 +1,4 @@ -import { AssetClass, AssetSubClass, DataSource } from '@prisma/client'; +import { AssetClass, AssetSubClass, DataSource, Type } from '@prisma/client'; import { JobOptions, JobStatus } from 'bull'; import ms from 'ms'; @@ -118,6 +118,12 @@ export const GATHER_HISTORICAL_MARKET_DATA_PROCESS_JOB_OPTIONS: JobOptions = { removeOnComplete: true }; +export const INVESTMENT_ACTIVITY_TYPES = [ + Type.BUY, + Type.DIVIDEND, + Type.SELL +] as Type[]; + export const PORTFOLIO_SNAPSHOT_PROCESS_JOB_NAME = 'PORTFOLIO'; export const PORTFOLIO_SNAPSHOT_PROCESS_JOB_OPTIONS: JobOptions = { removeOnComplete: true From f26648842f416953f59dc6f458a4b6f9dbafe6ab Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sun, 27 Jul 2025 09:34:15 +0200 Subject: [PATCH 12/14] Feature/extend personal finance tools 20250727 (#5259) * Add CleverBilling * Add DeFi Portfolio Tracker by Zerion * Add Digrin * Add Monsy * Add Walletguide * Update Maybe Finance --- libs/common/src/lib/personal-finance-tools.ts | 111 +++++++++++++----- libs/ui/src/lib/i18n.ts | 1 + 2 files changed, 81 insertions(+), 31 deletions(-) diff --git a/libs/common/src/lib/personal-finance-tools.ts b/libs/common/src/lib/personal-finance-tools.ts index dd9a821b6..51d847300 100644 --- a/libs/common/src/lib/personal-finance-tools.ts +++ b/libs/common/src/lib/personal-finance-tools.ts @@ -101,6 +101,33 @@ export const personalFinanceTools: Product[] = [ regions: ['Global'], slogan: 'Take control of your financial future' }, + { + hasFreePlan: true, + hasSelfHostingAbility: false, + key: 'capitally', + name: 'Capitally', + origin: 'Poland', + pricingPerYear: '€50', + slogan: 'Optimize your investments performance' + }, + { + founded: 2022, + isArchived: true, + key: 'capmon', + name: 'CapMon.org', + origin: 'Germany', + note: 'CapMon.org was discontinued in 2023', + slogan: 'Next Generation Assets Tracking' + }, + { + founded: 2024, + hasFreePlan: true, + isOpenSource: true, + key: 'cleverbilling', + languages: ['Español'], + name: 'CleverBilling', + slogan: 'Toma el control total de tus finanzas.' + }, { founded: 2017, hasFreePlan: true, @@ -122,35 +149,6 @@ export const personalFinanceTools: Product[] = [ pricingPerYear: '$120', slogan: 'The leading Crypto Portfolio Tracker & Tax Calculator' }, - { - founded: 2022, - hasFreePlan: true, - hasSelfHostingAbility: false, - key: 'degiro-portfolio-tracker-by-capitalyse', - languages: ['English'], - name: 'DEGIRO Portfolio Tracker by Capitalyse', - origin: 'Netherlands', - pricingPerYear: '€24', - slogan: 'Democratizing Data Analytics' - }, - { - hasFreePlan: true, - hasSelfHostingAbility: false, - key: 'capitally', - name: 'Capitally', - origin: 'Poland', - pricingPerYear: '€50', - slogan: 'Optimize your investments performance' - }, - { - founded: 2022, - isArchived: true, - key: 'capmon', - name: 'CapMon.org', - origin: 'Germany', - note: 'CapMon.org was discontinued in 2023', - slogan: 'Next Generation Assets Tracking' - }, { founded: 2019, key: 'compound-planning', @@ -183,6 +181,28 @@ export const personalFinanceTools: Product[] = [ name: 'De.Fi', slogan: 'DeFi Portfolio Tracker' }, + { + founded: 2016, + hasFreePlan: true, + hasSelfHostingAbility: false, + key: 'defi-portfolio-tracker-by-zerion', + languages: ['English'], + name: 'DeFi Portfolio Tracker by Zerion', + origin: 'United States', + pricingPerYear: '$99', + slogan: 'DeFi Portfolio Tracker for All Chains' + }, + { + founded: 2022, + hasFreePlan: true, + hasSelfHostingAbility: false, + key: 'degiro-portfolio-tracker-by-capitalyse', + languages: ['English'], + name: 'DEGIRO Portfolio Tracker by Capitalyse', + origin: 'Netherlands', + pricingPerYear: '€24', + slogan: 'Democratizing Data Analytics' + }, { founded: 2017, hasFreePlan: true, @@ -194,6 +214,15 @@ export const personalFinanceTools: Product[] = [ pricingPerYear: '$150', slogan: 'The app to track all your investments. Make smart moves only.' }, + { + hasFreePlan: true, + hasSelfHostingAbility: false, + key: 'digrin', + languages: ['English'], + name: 'Digrin', + pricingPerYear: '$49.90', + slogan: 'Dividend Portfolio Tracker' + }, { founded: 2019, hasFreePlan: true, @@ -464,12 +493,11 @@ export const personalFinanceTools: Product[] = [ }, { founded: 2021, - hasSelfHostingAbility: false, isArchived: true, key: 'maybe-finance', languages: ['English'], name: 'Maybe Finance', - note: 'Maybe Finance was discontinued in 2023', + note: 'Maybe Finance was discontinued in 2023, relaunched in 2024, and discontinued again in 2025', origin: 'United States', pricingPerYear: '$145', regions: ['United States'], @@ -532,6 +560,17 @@ export const personalFinanceTools: Product[] = [ pricingPerYear: '$60', slogan: 'Gain financial control and keep your data private.' }, + { + founded: 2025, + hasFreePlan: true, + hasSelfHostingAbility: false, + key: 'monsy', + languages: ['English'], + name: 'Monsy', + origin: 'Indonesia', + pricingPerYear: '$20', + slogan: 'Smart, simple, stress-free money tracking.' + }, { hasFreePlan: true, hasSelfHostingAbility: false, @@ -858,6 +897,16 @@ export const personalFinanceTools: Product[] = [ pricingPerYear: '$348', slogan: 'Virtual Family Office for Smart Wealth Management' }, + { + founded: 2020, + hasFreePlan: false, + hasSelfHostingAbility: false, + key: 'walletguide', + name: 'Walletguide', + origin: 'Germany', + pricingPerYear: '€90', + slogan: 'Personal finance reimagined with AI' + }, { hasSelfHostingAbility: false, key: 'wallmine', diff --git a/libs/ui/src/lib/i18n.ts b/libs/ui/src/lib/i18n.ts index 749509f82..f02da40e1 100644 --- a/libs/ui/src/lib/i18n.ts +++ b/libs/ui/src/lib/i18n.ts @@ -84,6 +84,7 @@ const locales = { France: $localize`France`, Germany: $localize`Germany`, India: $localize`India`, + Indonesia: $localize`Indonesia`, Italy: $localize`Italy`, Japan: $localize`Japan`, Netherlands: $localize`Netherlands`, From be745362ee82f5fa1c9a4b8efdf9ecce0c6a3c37 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sun, 27 Jul 2025 09:34:47 +0200 Subject: [PATCH 13/14] Feature/update operational cost descriptions (#5257) * Update operational cost descriptions --- README.md | 2 +- .../src/app/pages/faq/overview/faq-overview-page.html | 5 +++-- apps/client/src/app/pages/faq/saas/saas-page.html | 6 +++--- apps/client/src/app/pages/pricing/pricing-page.html | 5 +++-- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index f2e9de4f1..02f17fe49 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ ## Ghostfolio Premium -Our official **[Ghostfolio Premium](https://ghostfol.io/en/pricing)** cloud offering is the easiest way to get started. Due to the time it saves, this will be the best option for most people. Revenue is used to cover the costs of the hosting infrastructure and to fund ongoing development. +Our official **[Ghostfolio Premium](https://ghostfol.io/en/pricing)** cloud offering is the easiest way to get started. Due to the time it saves, this will be the best option for most people. Revenue is used to cover operational costs for the hosting infrastructure and professional data providers, and to fund ongoing development. If you prefer to run Ghostfolio on your own infrastructure, please find further instructions in the [Self-hosting](#self-hosting) section. diff --git a/apps/client/src/app/pages/faq/overview/faq-overview-page.html b/apps/client/src/app/pages/faq/overview/faq-overview-page.html index bc7f6ba37..24caf8d97 100644 --- a/apps/client/src/app/pages/faq/overview/faq-overview-page.html +++ b/apps/client/src/app/pages/faq/overview/faq-overview-page.html @@ -133,8 +133,9 @@ class="d-inline-block ml-1" [enableLink]="false" /> - subscription to finance the hosting infrastructure, a positive rating - in the + subscription to finance the operational costs for the hosting + infrastructure and professional data providers, a positive rating in + the Google Play Store is a fully managed Ghostfolio cloud offering for ambitious investors. - Revenue is used to cover the costs of the hosting infrastructure and - to fund ongoing development. It is the Open Source code base with some - extras like the + Revenue is used to cover operational costs for the hosting + infrastructure and professional data providers, and to fund ongoing + development. It is the Open Source code base with some extras like the markets overview and a professional data provider. diff --git a/apps/client/src/app/pages/pricing/pricing-page.html b/apps/client/src/app/pages/pricing/pricing-page.html index c13766b75..ea68b74eb 100644 --- a/apps/client/src/app/pages/pricing/pricing-page.html +++ b/apps/client/src/app/pages/pricing/pricing-page.html @@ -6,8 +6,9 @@

Our official Ghostfolio Premium cloud offering is the easiest way to get started. Due to the time it saves, this will be the best option - for most people. Revenue is used to cover the costs of the hosting - infrastructure and to fund ongoing development. + for most people. Revenue is used to cover operational costs for the + hosting infrastructure and professional data providers, and to fund + ongoing development.

If you prefer to run Ghostfolio on your own infrastructure, please From 4b03d5a9265d249f92a5ccc84a83b966b638640a Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sun, 27 Jul 2025 09:45:20 +0200 Subject: [PATCH 14/14] Feature/restructure portfolio report response (#5260) * Restructure response of portfolio report endpoint * Update changelog --- CHANGELOG.md | 4 ++++ apps/api/src/app/portfolio/portfolio.controller.ts | 6 +++--- apps/api/src/app/portfolio/portfolio.service.ts | 13 +++++++++---- .../pages/portfolio/x-ray/x-ray-page.component.ts | 6 +++--- .../responses/portfolio-report.interface.ts | 10 ++++++---- 5 files changed, 25 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 083fd2d88..acd55e571 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +### Changed + +- Restructured the response of the portfolio report endpoint (_X-ray_) + ### Fixed - Excluded the holdings originated of `FEE`, `INTEREST` and `LIABILITY` activities from the closed holdings on the portfolio holdings page diff --git a/apps/api/src/app/portfolio/portfolio.controller.ts b/apps/api/src/app/portfolio/portfolio.controller.ts index 2c71a4668..17cf41702 100644 --- a/apps/api/src/app/portfolio/portfolio.controller.ts +++ b/apps/api/src/app/portfolio/portfolio.controller.ts @@ -655,11 +655,11 @@ export class PortfolioController { this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION') && this.request.user.subscription.type === 'Basic' ) { - for (const rule in report.rules) { - report.rules[rule] = null; + for (const rule in report['x-ray'].rules) { + report['x-ray'].rules[rule] = null; } - report.statistics = { + report['x-ray'].statistics = { rulesActiveCount: 0, rulesFulfilledCount: 0 }; diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index 88d6e7d60..c5b9c2148 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -1156,7 +1156,7 @@ export class PortfolioService { }) ).toNumber(); - const rules: PortfolioReportResponse['rules'] = { + const rules: PortfolioReportResponse['x-ray']['rules'] = { accountClusterRisk: summary.activityCount > 0 ? await this.rulesService.evaluate( @@ -1311,7 +1311,12 @@ export class PortfolioService { : undefined }; - return { rules, statistics: this.getReportStatistics(rules) }; + return { + 'x-ray': { + rules, + statistics: this.getReportStatistics(rules) + } + }; } public async updateTags({ @@ -1731,8 +1736,8 @@ export class PortfolioService { } private getReportStatistics( - evaluatedRules: PortfolioReportResponse['rules'] - ): PortfolioReportResponse['statistics'] { + evaluatedRules: PortfolioReportResponse['x-ray']['rules'] + ): PortfolioReportResponse['x-ray']['statistics'] { const rulesActiveCount = Object.values(evaluatedRules) .flat() .filter((rule) => { diff --git a/apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.ts b/apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.ts index 5aabfc749..cad7d41e9 100644 --- a/apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.ts +++ b/apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.ts @@ -47,7 +47,7 @@ export class GfXRayPageComponent { public inactiveRules: PortfolioReportRule[]; public isLoading = false; public regionalMarketClusterRiskRules: PortfolioReportRule[]; - public statistics: PortfolioReportResponse['statistics']; + public statistics: PortfolioReportResponse['x-ray']['statistics']; public user: User; private unsubscribeSubject = new Subject(); @@ -115,7 +115,7 @@ export class GfXRayPageComponent { this.dataService .fetchPortfolioReport() .pipe(takeUntil(this.unsubscribeSubject)) - .subscribe(({ rules, statistics }) => { + .subscribe(({ 'x-ray': { rules, statistics } }) => { this.inactiveRules = this.mergeInactiveRules(rules); this.statistics = statistics; @@ -161,7 +161,7 @@ export class GfXRayPageComponent { } private mergeInactiveRules( - rules: PortfolioReportResponse['rules'] + rules: PortfolioReportResponse['x-ray']['rules'] ): PortfolioReportRule[] { let inactiveRules: PortfolioReportRule[] = []; diff --git a/libs/common/src/lib/interfaces/responses/portfolio-report.interface.ts b/libs/common/src/lib/interfaces/responses/portfolio-report.interface.ts index 35ff033eb..7ede7a5ed 100644 --- a/libs/common/src/lib/interfaces/responses/portfolio-report.interface.ts +++ b/libs/common/src/lib/interfaces/responses/portfolio-report.interface.ts @@ -1,9 +1,11 @@ import { PortfolioReportRule } from '../portfolio-report-rule.interface'; export interface PortfolioReportResponse { - rules: { [group: string]: PortfolioReportRule[] }; - statistics: { - rulesActiveCount: number; - rulesFulfilledCount: number; + 'x-ray': { + rules: { [group: string]: PortfolioReportRule[] }; + statistics: { + rulesActiveCount: number; + rulesFulfilledCount: number; + }; }; }