From 04a70a46cdc616d26b39a5715c3535aebfe3b4cf Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Thu, 28 Aug 2025 21:12:22 +0200 Subject: [PATCH 1/4] Change tags to tagIds in import and export --- apps/api/src/app/export/export.service.ts | 2 +- apps/api/src/app/import/import.service.ts | 11 ++++++----- apps/api/src/app/order/create-order.dto.ts | 2 +- apps/api/src/app/order/order.controller.ts | 2 +- ...reate-or-update-activity-dialog.component.ts | 2 +- .../app/services/import-activities.service.ts | 8 +++----- .../src/lib/interfaces/export.interface.ts | 11 +++++++++-- test/import/ok/500-activities.json | 2 +- test/import/ok/btceur.json | 4 ++-- test/import/ok/btcusd.json | 4 ++-- test/import/ok/derived-currency.json | 2 +- test/import/ok/sample.json | 17 +++++++++++------ test/import/ok/vti-buy-long-history.json | 2 +- 13 files changed, 40 insertions(+), 29 deletions(-) diff --git a/apps/api/src/app/export/export.service.ts b/apps/api/src/app/export/export.service.ts index 7d78bdf22..b018020ba 100644 --- a/apps/api/src/app/export/export.service.ts +++ b/apps/api/src/app/export/export.service.ts @@ -237,7 +237,7 @@ export class ExportService { dataSource: SymbolProfile.dataSource, date: date.toISOString(), symbol: SymbolProfile.symbol, - tags: currentTags.map(({ id: tagId }) => { + tagId: currentTags.map(({ id: tagId }) => { return tagId; }) }; diff --git a/apps/api/src/app/import/import.service.ts b/apps/api/src/app/import/import.service.ts index a96200261..1dc26a6ab 100644 --- a/apps/api/src/app/import/import.service.ts +++ b/apps/api/src/app/import/import.service.ts @@ -365,7 +365,7 @@ export class ImportService { } // If a new tag is created, then update the tag ID in all activities - activity.tags = (activity.tags ?? []).map((tagId) => { + activity.tagIds = (activity.tagIds ?? []).map((tagId) => { return tagIdMapping[tagId] ?? tagId; }); } @@ -630,7 +630,7 @@ export class ImportService { fee, quantity, symbol, - tags, + tagIds, type, unitPrice }) => { @@ -663,6 +663,7 @@ export class ImportService { error, fee, quantity, + tagIds, type, unitPrice, SymbolProfile: { @@ -679,8 +680,7 @@ export class ImportService { isActive: true, sectors: undefined, updatedAt: undefined - }, - tagIds: tags + } }; } ); @@ -745,7 +745,8 @@ export class ImportService { } } - if (!assetProfiles[getAssetProfileIdentifier({ dataSource, symbol })]) { + if (assetProfiles[getAssetProfileIdentifier({ dataSource, symbol })]) { + } else { const assetProfile = { currency, ...( diff --git a/apps/api/src/app/order/create-order.dto.ts b/apps/api/src/app/order/create-order.dto.ts index af87fd93e..ec5c3e2b2 100644 --- a/apps/api/src/app/order/create-order.dto.ts +++ b/apps/api/src/app/order/create-order.dto.ts @@ -64,7 +64,7 @@ export class CreateOrderDto { @IsArray() @IsOptional() - tags?: string[]; + tagIds?: string[]; @IsEnum(Type, { each: true }) type: Type; diff --git a/apps/api/src/app/order/order.controller.ts b/apps/api/src/app/order/order.controller.ts index ffed8ac2e..52f80903c 100644 --- a/apps/api/src/app/order/order.controller.ts +++ b/apps/api/src/app/order/order.controller.ts @@ -217,7 +217,7 @@ export class OrderController { } } }, - tags: data.tags?.map((id) => { + tags: data.tagIds?.map((id) => { return { id }; }), user: { connect: { id: this.request.user.id } }, diff --git a/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.component.ts b/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.component.ts index fde4f20fa..6b40fa802 100644 --- a/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.component.ts +++ b/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.component.ts @@ -523,7 +523,7 @@ export class GfCreateOrUpdateActivityDialog implements OnDestroy { ? undefined : this.activityForm.get('searchSymbol')?.value?.symbol) ?? this.activityForm.get('name')?.value, - tags: this.activityForm.get('tags').value?.map(({ id }) => { + tagIds: this.activityForm.get('tags').value?.map(({ id }) => { return id; }), type: this.activityForm.get('type').value, diff --git a/apps/client/src/app/services/import-activities.service.ts b/apps/client/src/app/services/import-activities.service.ts index 27a34652b..0e8979b9e 100644 --- a/apps/client/src/app/services/import-activities.service.ts +++ b/apps/client/src/app/services/import-activities.service.ts @@ -146,7 +146,7 @@ export class ImportActivitiesService { fee, quantity, SymbolProfile, - tags, + tagIds, type, unitPrice, updateAccountBalance @@ -156,16 +156,14 @@ export class ImportActivitiesService { comment, fee, quantity, + tagIds, type, unitPrice, updateAccountBalance, currency: currency ?? SymbolProfile.currency, dataSource: SymbolProfile.dataSource, date: date.toString(), - symbol: SymbolProfile.symbol, - tags: tags?.map(({ id }) => { - return id; - }) + symbol: SymbolProfile.symbol }; } diff --git a/libs/common/src/lib/interfaces/export.interface.ts b/libs/common/src/lib/interfaces/export.interface.ts index 16a49b0ef..43b10d9f8 100644 --- a/libs/common/src/lib/interfaces/export.interface.ts +++ b/libs/common/src/lib/interfaces/export.interface.ts @@ -1,7 +1,8 @@ +import { Activity } from '@ghostfolio/api/app/order/interfaces/activities.interface'; + import { Account, DataSource, - Order, Platform, SymbolProfile, Tag @@ -15,14 +16,20 @@ export interface Export { balances: AccountBalance[]; })[]; activities: (Omit< - Order, + Activity, | 'accountUserId' | 'createdAt' | 'date' + | 'feeInAssetProfileCurrency' + | 'feeInBaseCurrency' | 'isDraft' | 'symbolProfileId' + | 'tags' + | 'unitPriceInAssetProfileCurrency' | 'updatedAt' | 'userId' + | 'value' + | 'valueInBaseCurrency' > & { dataSource: DataSource; date: string; symbol: string })[]; assetProfiles: (Omit< SymbolProfile, diff --git a/test/import/ok/500-activities.json b/test/import/ok/500-activities.json index b691a6f9f..07c7541b7 100644 --- a/test/import/ok/500-activities.json +++ b/test/import/ok/500-activities.json @@ -14,7 +14,7 @@ } ], "platforms": [], - "tags": [], + "tagIds": [], "activities": [ { "accountId": "b2d3fe1d-d6a8-41a3-be39-07ef5e9480f0", diff --git a/test/import/ok/btceur.json b/test/import/ok/btceur.json index b370682f9..b6e54e9ef 100644 --- a/test/import/ok/btceur.json +++ b/test/import/ok/btceur.json @@ -5,7 +5,7 @@ }, "accounts": [], "platforms": [], - "tags": [], + "tagIds": [], "activities": [ { "accountId": null, @@ -18,7 +18,7 @@ "dataSource": "YAHOO", "date": "2021-12-12T00:00:00.000Z", "symbol": "BTCUSD", - "tags": [] + "tagIds": [] } ], "user": { diff --git a/test/import/ok/btcusd.json b/test/import/ok/btcusd.json index fc2e1f66e..3634cf83d 100644 --- a/test/import/ok/btcusd.json +++ b/test/import/ok/btcusd.json @@ -5,7 +5,7 @@ }, "accounts": [], "platforms": [], - "tags": [], + "tagIds": [], "activities": [ { "accountId": null, @@ -18,7 +18,7 @@ "dataSource": "YAHOO", "date": "2021-12-12T00:00:00.000Z", "symbol": "BTCUSD", - "tags": [] + "tagIds": [] } ], "user": { diff --git a/test/import/ok/derived-currency.json b/test/import/ok/derived-currency.json index e740c1ae3..5e0c7dcc5 100644 --- a/test/import/ok/derived-currency.json +++ b/test/import/ok/derived-currency.json @@ -14,7 +14,7 @@ } ], "platforms": [], - "tags": [], + "tagIds": [], "activities": [ { "accountId": "b2d3fe1d-d6a8-41a3-be39-07ef5e9480f0", diff --git a/test/import/ok/sample.json b/test/import/ok/sample.json index 21277129f..0760534f4 100644 --- a/test/import/ok/sample.json +++ b/test/import/ok/sample.json @@ -77,7 +77,12 @@ "url": "https://interactivebrokers.com" } ], - "tags": [], + "tagIds": [ + { + "id": "7314654b-46a7-48a4-b6b9-4895b45ea107", + "name": "CORE" + } + ], "activities": [ { "accountId": "b2d3fe1d-d6a8-41a3-be39-07ef5e9480f0", @@ -90,7 +95,7 @@ "dataSource": "MANUAL", "date": "2021-09-01T00:00:00.000Z", "symbol": "14a69cb9-1e31-43fa-b320-83703d8ed74b", - "tags": [] + "tagIds": [] }, { "accountId": "b2d3fe1d-d6a8-41a3-be39-07ef5e9480f0", @@ -103,7 +108,7 @@ "dataSource": "YAHOO", "date": "2021-09-16T00:00:00.000Z", "symbol": "MSFT", - "tags": [] + "tagIds": ["7314654b-46a7-48a4-b6b9-4895b45ea107"] }, { "accountId": "b2d3fe1d-d6a8-41a3-be39-07ef5e9480f0", @@ -116,7 +121,7 @@ "dataSource": "YAHOO", "date": "2021-11-17T00:00:00.000Z", "symbol": "MSFT", - "tags": [] + "tagIds": ["7314654b-46a7-48a4-b6b9-4895b45ea107"] }, { "accountId": null, @@ -129,7 +134,7 @@ "dataSource": "MANUAL", "date": "2022-01-01T00:00:00.000Z", "symbol": "7e91b7d4-1430-4212-8380-289a06c9bbc1", - "tags": [] + "tagIds": [] }, { "accountId": "b2d3fe1d-d6a8-41a3-be39-07ef5e9480f0", @@ -142,7 +147,7 @@ "dataSource": "YAHOO", "date": "2050-06-06T00:00:00.000Z", "symbol": "MSFT", - "tags": [] + "tagIds": ["7314654b-46a7-48a4-b6b9-4895b45ea107"] } ], "user": { diff --git a/test/import/ok/vti-buy-long-history.json b/test/import/ok/vti-buy-long-history.json index c8cd25e60..9fe6a6b21 100644 --- a/test/import/ok/vti-buy-long-history.json +++ b/test/import/ok/vti-buy-long-history.json @@ -5,7 +5,7 @@ }, "accounts": [], "platforms": [], - "tags": [], + "tagIds": [], "activities": [ { "fee": 0, From fb749ae419bc209416ebd675835f9a7aa3084448 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Thu, 28 Aug 2025 21:14:51 +0200 Subject: [PATCH 2/4] Extend activities import documentation by tags --- README.md | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 82d5710d1..420610438 100644 --- a/README.md +++ b/README.md @@ -221,18 +221,19 @@ Deprecated: `GET http://localhost:3333/api/v1/auth/anonymous/ Date: Thu, 28 Aug 2025 21:15:05 +0200 Subject: [PATCH 3/4] Update changelog --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 399d2a07c..5828579d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,8 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +### Added + +- Extended the activities import documentation by the tags + ### Changed +- Changed `tags` to `tagIds` in the activities import and export - Refactored the _ZEN_ page to standalone ## 2.194.0 - 2025-08-27 From 565a8c2a83323b2901ebd04e04fe7bcd9d9ece29 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Fri, 29 Aug 2025 09:45:03 +0200 Subject: [PATCH 4/4] Fix tests --- .../calculator/roai/portfolio-calculator-btceur.spec.ts | 4 ---- .../calculator/roai/portfolio-calculator-btcusd.spec.ts | 4 ---- .../portfolio-calculator-novn-buy-and-sell-partially.spec.ts | 4 ---- .../roai/portfolio-calculator-novn-buy-and-sell.spec.ts | 4 ---- 4 files changed, 16 deletions(-) diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btceur.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btceur.spec.ts index ad64cb383..3594b4427 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btceur.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btceur.spec.ts @@ -18,7 +18,6 @@ import { PortfolioSnapshotServiceMock } from '@ghostfolio/api/services/queues/po import { parseDate } from '@ghostfolio/common/helper'; import { PerformanceCalculationType } from '@ghostfolio/common/types/performance-calculation-type.type'; -import { Tag } from '@prisma/client'; import { Big } from 'big.js'; import { join } from 'path'; @@ -109,9 +108,6 @@ describe('PortfolioCalculator', () => { name: 'Bitcoin', symbol: activity.symbol }, - tags: activity.tags?.map((id) => { - return { id } as Tag; - }), unitPriceInAssetProfileCurrency: 44558.42 })); diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd.spec.ts index d17fd028a..d1d9fbd93 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd.spec.ts @@ -18,7 +18,6 @@ import { PortfolioSnapshotServiceMock } from '@ghostfolio/api/services/queues/po import { parseDate } from '@ghostfolio/common/helper'; import { PerformanceCalculationType } from '@ghostfolio/common/types/performance-calculation-type.type'; -import { Tag } from '@prisma/client'; import { Big } from 'big.js'; import { join } from 'path'; @@ -109,9 +108,6 @@ describe('PortfolioCalculator', () => { name: 'Bitcoin', symbol: activity.symbol }, - tags: activity.tags?.map((id) => { - return { id } as Tag; - }), unitPriceInAssetProfileCurrency: 44558.42 })); diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell-partially.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell-partially.spec.ts index 18455477e..96bbbc757 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell-partially.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell-partially.spec.ts @@ -18,7 +18,6 @@ import { PortfolioSnapshotServiceMock } from '@ghostfolio/api/services/queues/po import { parseDate } from '@ghostfolio/common/helper'; import { PerformanceCalculationType } from '@ghostfolio/common/types/performance-calculation-type.type'; -import { Tag } from '@prisma/client'; import { Big } from 'big.js'; import { join } from 'path'; @@ -112,9 +111,6 @@ describe('PortfolioCalculator', () => { name: 'Novartis AG', symbol: activity.symbol }, - tags: activity.tags?.map((id) => { - return { id } as Tag; - }), unitPriceInAssetProfileCurrency: activity.unitPrice })); diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell.spec.ts index e20400cb7..c19f6917e 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell.spec.ts @@ -18,7 +18,6 @@ import { PortfolioSnapshotServiceMock } from '@ghostfolio/api/services/queues/po import { parseDate } from '@ghostfolio/common/helper'; import { PerformanceCalculationType } from '@ghostfolio/common/types/performance-calculation-type.type'; -import { Tag } from '@prisma/client'; import { Big } from 'big.js'; import { join } from 'path'; @@ -112,9 +111,6 @@ describe('PortfolioCalculator', () => { name: 'Novartis AG', symbol: activity.symbol }, - tags: activity.tags?.map((id) => { - return { id } as Tag; - }), unitPriceInAssetProfileCurrency: activity.unitPrice }));