- |
+ |
Name
|
@@ -102,7 +114,12 @@
- |
+ |
Asset Profiles
|
diff --git a/apps/client/src/app/components/admin-settings/admin-settings.component.ts b/apps/client/src/app/components/admin-settings/admin-settings.component.ts
index 219fd2847..b8cd3409d 100644
--- a/apps/client/src/app/components/admin-settings/admin-settings.component.ts
+++ b/apps/client/src/app/components/admin-settings/admin-settings.component.ts
@@ -23,17 +23,20 @@ import {
ChangeDetectorRef,
Component,
OnDestroy,
- OnInit
+ OnInit,
+ ViewChild
} from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from '@angular/material/card';
import { MatMenuModule } from '@angular/material/menu';
import { MatProgressBarModule } from '@angular/material/progress-bar';
+import { MatSort, MatSortModule } from '@angular/material/sort';
import { MatTableDataSource, MatTableModule } from '@angular/material/table';
import { RouterModule } from '@angular/router';
import { IonIcon } from '@ionic/angular/standalone';
import { addIcons } from 'ionicons';
import { ellipsisHorizontal, trashOutline } from 'ionicons/icons';
+import { get } from 'lodash';
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
import { catchError, filter, of, Subject, takeUntil } from 'rxjs';
@@ -52,6 +55,7 @@ import { catchError, filter, of, Subject, takeUntil } from 'rxjs';
MatCardModule,
MatMenuModule,
MatProgressBarModule,
+ MatSortModule,
MatTableModule,
NgxSkeletonLoaderModule,
RouterModule
@@ -61,6 +65,8 @@ import { catchError, filter, of, Subject, takeUntil } from 'rxjs';
templateUrl: './admin-settings.component.html'
})
export class GfAdminSettingsComponent implements OnDestroy, OnInit {
+ @ViewChild(MatSort) sort: MatSort;
+
public dataSource = new MatTableDataSource();
public defaultDateFormat: string;
public displayedColumns = [
@@ -166,6 +172,8 @@ export class GfAdminSettingsComponent implements OnDestroy, OnInit {
});
this.dataSource = new MatTableDataSource(filteredProviders);
+ this.dataSource.sort = this.sort;
+ this.dataSource.sortingDataAccessor = get;
const ghostfolioApiKey = settings[
PROPERTY_API_KEY_GHOSTFOLIO
From 249cf0cdd9ee4000327b9981650a91511497a75a Mon Sep 17 00:00:00 2001
From: Kenrick Tandrian <60643640+KenTandrian@users.noreply.github.com>
Date: Sun, 8 Mar 2026 00:02:42 +0700
Subject: [PATCH 4/6] Bugfix/projected total amount in FIRE calculator (#6490)
* Fix projected total amount
* Update changelog
---
CHANGELOG.md | 4 ++++
.../fire-calculator.component.ts | 23 +++++++++++--------
2 files changed, 18 insertions(+), 9 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9a837052a..c002057ee 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -19,6 +19,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Reused the value component in the tag management of the admin control panel
- Upgraded `jsonpath` from version `1.1.1` to `1.2.1`
+### Fixed
+
+- Fixed an issue in the _FIRE_ calculator to correctly calculate the projected total amount
+
## 2.247.0 - 2026-03-04
### Changed
diff --git a/libs/ui/src/lib/fire-calculator/fire-calculator.component.ts b/libs/ui/src/lib/fire-calculator/fire-calculator.component.ts
index 8b472fc47..7a62564c6 100644
--- a/libs/ui/src/lib/fire-calculator/fire-calculator.component.ts
+++ b/libs/ui/src/lib/fire-calculator/fire-calculator.component.ts
@@ -16,8 +16,8 @@ import {
Input,
OnChanges,
OnDestroy,
- ViewChild,
- output
+ output,
+ viewChild
} from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import {
@@ -55,7 +55,7 @@ import {
startOfMonth,
sub
} from 'date-fns';
-import { isNil, isNumber } from 'lodash';
+import { isNumber } from 'lodash';
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
import { debounceTime } from 'rxjs';
@@ -90,8 +90,6 @@ export class GfFireCalculatorComponent implements OnChanges, OnDestroy {
@Input() retirementDate: Date;
@Input() savingsRate = 0;
- @ViewChild('chartCanvas') chartCanvas: ElementRef;
-
public calculatorForm = this.formBuilder.group({
annualInterestRate: new FormControl(null),
paymentPerPeriod: new FormControl(null),
@@ -99,23 +97,30 @@ export class GfFireCalculatorComponent implements OnChanges, OnDestroy {
projectedTotalAmount: new FormControl(null),
retirementDate: new FormControl(null)
});
+
public chart: Chart<'bar'>;
public isLoading = true;
public minDate = addDays(new Date(), 1);
public periodsToRetire = 0;
protected readonly annualInterestRateChanged = output();
+
protected readonly calculationCompleted =
output();
+
protected readonly projectedTotalAmountChanged = output();
protected readonly retirementDateChanged = output();
protected readonly savingsRateChanged = output();
private readonly CONTRIBUTION_PERIOD = 12;
+
private readonly DEFAULT_RETIREMENT_DATE = startOfMonth(
addYears(new Date(), 10)
);
+ private readonly chartCanvas =
+ viewChild.required>('chartCanvas');
+
public constructor(
private changeDetectorRef: ChangeDetectorRef,
private fireCalculatorService: FireCalculatorService,
@@ -272,7 +277,7 @@ export class GfFireCalculatorComponent implements OnChanges, OnDestroy {
const chartData = this.getChartData();
- if (this.chartCanvas) {
+ if (this.chartCanvas()) {
if (this.chart) {
this.chart.data.labels = chartData.labels;
@@ -282,7 +287,7 @@ export class GfFireCalculatorComponent implements OnChanges, OnDestroy {
this.chart.update();
} else {
- this.chart = new Chart<'bar'>(this.chartCanvas.nativeElement, {
+ this.chart = new Chart<'bar'>(this.chartCanvas().nativeElement, {
data: chartData,
options: {
plugins: {
@@ -303,7 +308,7 @@ export class GfFireCalculatorComponent implements OnChanges, OnDestroy {
}).format(totalAmount)}`;
},
label: (context) => {
- let label = context.dataset.label || '';
+ let label = context.dataset.label ?? '';
if (label) {
label += ': ';
@@ -473,7 +478,7 @@ export class GfFireCalculatorComponent implements OnChanges, OnDestroy {
'projectedTotalAmount'
)?.value;
- if (!isNil(projectedTotalAmount)) {
+ if (projectedTotalAmount) {
return projectedTotalAmount;
}
From 4a832f12ca46482d73892bb3684979f26efa7837 Mon Sep 17 00:00:00 2001
From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com>
Date: Sat, 7 Mar 2026 18:19:25 +0100
Subject: [PATCH 5/6] Task/deprecate order endpoints in favor of activities
endpoints (#6446)
* Deprecate order endpoints in favor of activities endpoints
* Update changelog
---
CHANGELOG.md | 1 +
.../activities.controller.ts} | 55 ++++++++------
.../activities.module.ts} | 12 +--
.../activities.service.ts} | 73 ++++++++++---------
apps/api/src/app/admin/admin.module.ts | 4 +-
apps/api/src/app/admin/admin.service.ts | 8 +-
apps/api/src/app/app.module.ts | 4 +-
apps/api/src/app/endpoints/ai/ai.module.ts | 4 +-
.../endpoints/benchmarks/benchmarks.module.ts | 4 +-
.../app/endpoints/public/public.controller.ts | 6 +-
.../src/app/endpoints/public/public.module.ts | 4 +-
apps/api/src/app/export/export.module.ts | 4 +-
apps/api/src/app/export/export.service.ts | 6 +-
apps/api/src/app/import/import.module.ts | 4 +-
apps/api/src/app/import/import.service.ts | 10 +--
.../roai/portfolio-calculator-cash.spec.ts | 17 ++---
.../portfolio/current-rate.service.spec.ts | 2 +-
.../src/app/portfolio/current-rate.service.ts | 13 ++--
.../src/app/portfolio/portfolio.controller.ts | 6 +-
.../api/src/app/portfolio/portfolio.module.ts | 4 +-
.../src/app/portfolio/portfolio.service.ts | 21 ++++--
apps/api/src/app/user/user.module.ts | 4 +-
apps/api/src/app/user/user.service.ts | 6 +-
.../events/asset-profile-changed.listener.ts | 8 +-
apps/api/src/events/events.module.ts | 4 +-
.../portfolio-snapshot.module.ts | 4 +-
.../portfolio-snapshot.processor.ts | 6 +-
.../holding-detail-dialog.component.ts | 2 +-
.../activities/activities-page.component.ts | 4 +-
libs/ui/src/lib/services/data.service.ts | 40 +++++-----
30 files changed, 180 insertions(+), 160 deletions(-)
rename apps/api/src/app/{order/order.controller.ts => activities/activities.controller.ts} (87%)
rename apps/api/src/app/{order/order.module.ts => activities/activities.module.ts} (86%)
rename apps/api/src/app/{order/order.service.ts => activities/activities.service.ts} (93%)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c002057ee..1279ef62f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Included asset profile data in the holdings of the public page
- Reused the value component in the platform management of the admin control panel
- Reused the value component in the tag management of the admin control panel
+- Deprecated the `api/v1/order` endpoints in favor of the `api/v1/activities` endpoints
- Upgraded `jsonpath` from version `1.1.1` to `1.2.1`
### Fixed
diff --git a/apps/api/src/app/order/order.controller.ts b/apps/api/src/app/activities/activities.controller.ts
similarity index 87%
rename from apps/api/src/app/order/order.controller.ts
rename to apps/api/src/app/activities/activities.controller.ts
index c7021809e..da7aed21d 100644
--- a/apps/api/src/app/order/order.controller.ts
+++ b/apps/api/src/app/activities/activities.controller.ts
@@ -37,20 +37,24 @@ import {
} from '@nestjs/common';
import { REQUEST } from '@nestjs/core';
import { AuthGuard } from '@nestjs/passport';
-import { Order as OrderModel, Prisma } from '@prisma/client';
+import { Order, Prisma } from '@prisma/client';
import { parseISO } from 'date-fns';
import { StatusCodes, getReasonPhrase } from 'http-status-codes';
-import { OrderService } from './order.service';
+import { ActivitiesService } from './activities.service';
-@Controller('order')
-export class OrderController {
+@Controller([
+ 'activities',
+ /** @deprecated */
+ 'order'
+])
+export class ActivitiesController {
public constructor(
+ private readonly activitiesService: ActivitiesService,
private readonly apiService: ApiService,
private readonly dataProviderService: DataProviderService,
private readonly dataGatheringService: DataGatheringService,
private readonly impersonationService: ImpersonationService,
- private readonly orderService: OrderService,
@Inject(REQUEST) private readonly request: RequestWithUser
) {}
@@ -58,7 +62,7 @@ export class OrderController {
@HasPermission(permissions.deleteOrder)
@UseGuards(AuthGuard('jwt'), HasPermissionGuard)
@UseInterceptors(TransformDataSourceInRequestInterceptor)
- public async deleteOrders(
+ public async deleteActivities(
@Query('accounts') filterByAccounts?: string,
@Query('assetClasses') filterByAssetClasses?: string,
@Query('dataSource') filterByDataSource?: string,
@@ -73,7 +77,7 @@ export class OrderController {
filterByTags
});
- return this.orderService.deleteOrders({
+ return this.activitiesService.deleteActivities({
filters,
userId: this.request.user.id
});
@@ -82,20 +86,20 @@ export class OrderController {
@Delete(':id')
@HasPermission(permissions.deleteOrder)
@UseGuards(AuthGuard('jwt'), HasPermissionGuard)
- public async deleteOrder(@Param('id') id: string): Promise {
- const order = await this.orderService.order({
+ public async deleteActivity(@Param('id') id: string): Promise {
+ const activity = await this.activitiesService.order({
id,
userId: this.request.user.id
});
- if (!order) {
+ if (!activity) {
throw new HttpException(
getReasonPhrase(StatusCodes.FORBIDDEN),
StatusCodes.FORBIDDEN
);
}
- return this.orderService.deleteOrder({
+ return this.activitiesService.deleteActivity({
id
});
}
@@ -105,7 +109,7 @@ export class OrderController {
@UseInterceptors(RedactValuesInResponseInterceptor)
@UseInterceptors(TransformDataSourceInRequestInterceptor)
@UseInterceptors(TransformDataSourceInResponseInterceptor)
- public async getAllOrders(
+ public async getAllActivities(
@Headers(HEADER_KEY_IMPERSONATION.toLowerCase()) impersonationId: string,
@Query('accounts') filterByAccounts?: string,
@Query('assetClasses') filterByAssetClasses?: string,
@@ -137,7 +141,7 @@ export class OrderController {
await this.impersonationService.validateImpersonationId(impersonationId);
const userCurrency = this.request.user.settings.settings.baseCurrency;
- const { activities, count } = await this.orderService.getOrders({
+ const { activities, count } = await this.activitiesService.getActivities({
endDate,
filters,
sortColumn,
@@ -158,7 +162,7 @@ export class OrderController {
@UseGuards(AuthGuard('jwt'), HasPermissionGuard)
@UseInterceptors(RedactValuesInResponseInterceptor)
@UseInterceptors(TransformDataSourceInResponseInterceptor)
- public async getOrderById(
+ public async getActivityById(
@Headers(HEADER_KEY_IMPERSONATION.toLowerCase()) impersonationId: string,
@Param('id') id: string
): Promise {
@@ -166,7 +170,7 @@ export class OrderController {
await this.impersonationService.validateImpersonationId(impersonationId);
const userCurrency = this.request.user.settings.settings.baseCurrency;
- const { activities } = await this.orderService.getOrders({
+ const { activities } = await this.activitiesService.getActivities({
userCurrency,
includeDrafts: true,
userId: impersonationUserId || this.request.user.id,
@@ -191,7 +195,7 @@ export class OrderController {
@Post()
@UseGuards(AuthGuard('jwt'), HasPermissionGuard)
@UseInterceptors(TransformDataSourceInRequestInterceptor)
- public async createOrder(@Body() data: CreateOrderDto): Promise {
+ public async createActivity(@Body() data: CreateOrderDto): Promise {
try {
await this.dataProviderService.validateActivities({
activitiesDto: [
@@ -227,7 +231,7 @@ export class OrderController {
delete data.dataSource;
- const order = await this.orderService.createOrder({
+ const activity = await this.activitiesService.createActivity({
...data,
date: parseISO(data.date),
SymbolProfile: {
@@ -252,14 +256,14 @@ export class OrderController {
userId: this.request.user.id
});
- if (dataSource && !order.isDraft) {
+ if (dataSource && !activity.isDraft) {
// Gather symbol data in the background, if data source is set
// (not MANUAL) and not draft
this.dataGatheringService.gatherSymbols({
dataGatheringItems: [
{
dataSource,
- date: order.date,
+ date: activity.date,
symbol: data.symbol
}
],
@@ -267,19 +271,22 @@ export class OrderController {
});
}
- return order;
+ return activity;
}
@HasPermission(permissions.updateOrder)
@Put(':id')
@UseGuards(AuthGuard('jwt'), HasPermissionGuard)
@UseInterceptors(TransformDataSourceInRequestInterceptor)
- public async update(@Param('id') id: string, @Body() data: UpdateOrderDto) {
- const originalOrder = await this.orderService.order({
+ public async updateActivity(
+ @Param('id') id: string,
+ @Body() data: UpdateOrderDto
+ ) {
+ const originalActivity = await this.activitiesService.order({
id
});
- if (!originalOrder || originalOrder.userId !== this.request.user.id) {
+ if (!originalActivity || originalActivity.userId !== this.request.user.id) {
throw new HttpException(
getReasonPhrase(StatusCodes.FORBIDDEN),
StatusCodes.FORBIDDEN
@@ -302,7 +309,7 @@ export class OrderController {
delete data.dataSource;
- return this.orderService.updateOrder({
+ return this.activitiesService.updateActivity({
data: {
...data,
date,
diff --git a/apps/api/src/app/order/order.module.ts b/apps/api/src/app/activities/activities.module.ts
similarity index 86%
rename from apps/api/src/app/order/order.module.ts
rename to apps/api/src/app/activities/activities.module.ts
index 9bc837aa6..7476ad66a 100644
--- a/apps/api/src/app/order/order.module.ts
+++ b/apps/api/src/app/activities/activities.module.ts
@@ -15,12 +15,12 @@ import { SymbolProfileModule } from '@ghostfolio/api/services/symbol-profile/sym
import { Module } from '@nestjs/common';
-import { OrderController } from './order.controller';
-import { OrderService } from './order.service';
+import { ActivitiesController } from './activities.controller';
+import { ActivitiesService } from './activities.service';
@Module({
- controllers: [OrderController],
- exports: [OrderService],
+ controllers: [ActivitiesController],
+ exports: [ActivitiesService],
imports: [
ApiModule,
CacheModule,
@@ -35,6 +35,6 @@ import { OrderService } from './order.service';
TransformDataSourceInRequestModule,
TransformDataSourceInResponseModule
],
- providers: [AccountBalanceService, AccountService, OrderService]
+ providers: [AccountBalanceService, AccountService, ActivitiesService]
})
-export class OrderModule {}
+export class ActivitiesModule {}
diff --git a/apps/api/src/app/order/order.service.ts b/apps/api/src/app/activities/activities.service.ts
similarity index 93%
rename from apps/api/src/app/order/order.service.ts
rename to apps/api/src/app/activities/activities.service.ts
index 9a4f1e46b..89b9468f8 100644
--- a/apps/api/src/app/order/order.service.ts
+++ b/apps/api/src/app/activities/activities.service.ts
@@ -44,7 +44,7 @@ import { groupBy, uniqBy } from 'lodash';
import { randomUUID } from 'node:crypto';
@Injectable()
-export class OrderService {
+export class ActivitiesService {
public constructor(
private readonly accountBalanceService: AccountBalanceService,
private readonly accountService: AccountService,
@@ -62,7 +62,7 @@ export class OrderService {
tags,
userId
}: { tags: Tag[]; userId: string } & AssetProfileIdentifier) {
- const orders = await this.prismaService.order.findMany({
+ const activities = await this.prismaService.order.findMany({
where: {
userId,
SymbolProfile: {
@@ -73,7 +73,7 @@ export class OrderService {
});
await Promise.all(
- orders.map(({ id }) =>
+ activities.map(({ id }) =>
this.prismaService.order.update({
data: {
tags: {
@@ -96,7 +96,7 @@ export class OrderService {
);
}
- public async createOrder(
+ public async createActivity(
data: Prisma.OrderCreateInput & {
accountId?: string;
assetClass?: AssetClass;
@@ -201,7 +201,7 @@ export class OrderService {
? false
: isAfter(data.date as Date, endOfToday());
- const order = await this.prismaService.order.create({
+ const activity = await this.prismaService.order.create({
data: {
...orderData,
account,
@@ -235,56 +235,56 @@ export class OrderService {
this.eventEmitter.emit(
AssetProfileChangedEvent.getName(),
new AssetProfileChangedEvent({
- currency: order.SymbolProfile.currency,
- dataSource: order.SymbolProfile.dataSource,
- symbol: order.SymbolProfile.symbol
+ currency: activity.SymbolProfile.currency,
+ dataSource: activity.SymbolProfile.dataSource,
+ symbol: activity.SymbolProfile.symbol
})
);
this.eventEmitter.emit(
PortfolioChangedEvent.getName(),
new PortfolioChangedEvent({
- userId: order.userId
+ userId: activity.userId
})
);
- return order;
+ return activity;
}
- public async deleteOrder(
+ public async deleteActivity(
where: Prisma.OrderWhereUniqueInput
): Promise {
- const order = await this.prismaService.order.delete({
+ const activity = await this.prismaService.order.delete({
where
});
const [symbolProfile] =
await this.symbolProfileService.getSymbolProfilesByIds([
- order.symbolProfileId
+ activity.symbolProfileId
]);
if (symbolProfile.activitiesCount === 0) {
- await this.symbolProfileService.deleteById(order.symbolProfileId);
+ await this.symbolProfileService.deleteById(activity.symbolProfileId);
}
this.eventEmitter.emit(
PortfolioChangedEvent.getName(),
new PortfolioChangedEvent({
- userId: order.userId
+ userId: activity.userId
})
);
- return order;
+ return activity;
}
- public async deleteOrders({
+ public async deleteActivities({
filters,
userId
}: {
filters?: Filter[];
userId: string;
}): Promise {
- const { activities } = await this.getOrders({
+ const { activities } = await this.getActivities({
filters,
userId,
includeDrafts: true,
@@ -324,7 +324,7 @@ export class OrderService {
}
/**
- * Generates synthetic orders for cash holdings based on account balance history.
+ * Generates synthetic activities for cash holdings based on account balance history.
* Treat currencies as assets with a fixed unit price of 1.0 (in their own currency) to allow
* performance tracking based on exchange rate fluctuations.
*
@@ -334,7 +334,7 @@ export class OrderService {
* @param userId - The ID of the user.
* @returns A response containing the list of synthetic cash activities.
*/
- public async getCashOrders({
+ public async getCashActivities({
cashDetails,
filters = [],
userCurrency,
@@ -448,7 +448,10 @@ export class OrderService {
};
}
- public async getLatestOrder({ dataSource, symbol }: AssetProfileIdentifier) {
+ public async getLatestActivity({
+ dataSource,
+ symbol
+ }: AssetProfileIdentifier) {
return this.prismaService.order.findFirst({
orderBy: {
date: 'desc'
@@ -459,7 +462,7 @@ export class OrderService {
});
}
- public async getOrders({
+ public async getActivities({
endDate,
filters,
includeDrafts = false,
@@ -742,17 +745,17 @@ export class OrderService {
}
/**
- * Retrieves all orders required for the portfolio calculator, including both standard asset orders
- * and optional synthetic orders representing cash activities.
+ * Retrieves all activities required for the portfolio calculator, including both standard asset activities
+ * and optional synthetic activities representing cash activities.
*/
@LogPerformance
- public async getOrdersForPortfolioCalculator({
+ public async getActivitiesForPortfolioCalculator({
filters,
userCurrency,
userId,
withCash = false
}: {
- /** Optional filters to apply to the orders. */
+ /** Optional filters to apply to the activities. */
filters?: Filter[];
/** The base currency of the user. */
userCurrency: string;
@@ -761,7 +764,7 @@ export class OrderService {
/** Whether to include cash activities in the result. */
withCash?: boolean;
}) {
- const orders = await this.getOrders({
+ const activities = await this.getActivities({
filters,
userCurrency,
userId,
@@ -775,18 +778,18 @@ export class OrderService {
currency: userCurrency
});
- const cashOrders = await this.getCashOrders({
+ const cashActivities = await this.getCashActivities({
cashDetails,
filters,
userCurrency,
userId
});
- orders.activities.push(...cashOrders.activities);
- orders.count += cashOrders.count;
+ activities.activities.push(...cashActivities.activities);
+ activities.count += cashActivities.count;
}
- return orders;
+ return activities;
}
public async getStatisticsByCurrency(
@@ -817,7 +820,7 @@ export class OrderService {
});
}
- public async updateOrder({
+ public async updateActivity({
data,
where
}: {
@@ -882,7 +885,7 @@ export class OrderService {
data: { tags: { set: [] } }
});
- const order = await this.prismaService.order.update({
+ const activity = await this.prismaService.order.update({
where,
data: {
...data,
@@ -896,11 +899,11 @@ export class OrderService {
this.eventEmitter.emit(
PortfolioChangedEvent.getName(),
new PortfolioChangedEvent({
- userId: order.userId
+ userId: activity.userId
})
);
- return order;
+ return activity;
}
private async orders(params: {
diff --git a/apps/api/src/app/admin/admin.module.ts b/apps/api/src/app/admin/admin.module.ts
index 598b68f17..960a36629 100644
--- a/apps/api/src/app/admin/admin.module.ts
+++ b/apps/api/src/app/admin/admin.module.ts
@@ -1,4 +1,4 @@
-import { OrderModule } from '@ghostfolio/api/app/order/order.module';
+import { ActivitiesModule } from '@ghostfolio/api/app/activities/activities.module';
import { TransformDataSourceInRequestModule } from '@ghostfolio/api/interceptors/transform-data-source-in-request/transform-data-source-in-request.module';
import { ApiModule } from '@ghostfolio/api/services/api/api.module';
import { BenchmarkModule } from '@ghostfolio/api/services/benchmark/benchmark.module';
@@ -20,6 +20,7 @@ import { QueueModule } from './queue/queue.module';
@Module({
imports: [
+ ActivitiesModule,
ApiModule,
BenchmarkModule,
ConfigurationModule,
@@ -28,7 +29,6 @@ import { QueueModule } from './queue/queue.module';
DemoModule,
ExchangeRateDataModule,
MarketDataModule,
- OrderModule,
PrismaModule,
PropertyModule,
QueueModule,
diff --git a/apps/api/src/app/admin/admin.service.ts b/apps/api/src/app/admin/admin.service.ts
index 1f8745cd1..d2bf6e411 100644
--- a/apps/api/src/app/admin/admin.service.ts
+++ b/apps/api/src/app/admin/admin.service.ts
@@ -1,4 +1,4 @@
-import { OrderService } from '@ghostfolio/api/app/order/order.service';
+import { ActivitiesService } from '@ghostfolio/api/app/activities/activities.service';
import { environment } from '@ghostfolio/api/environments/environment';
import { BenchmarkService } from '@ghostfolio/api/services/benchmark/benchmark.service';
import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service';
@@ -55,12 +55,12 @@ import { groupBy } from 'lodash';
@Injectable()
export class AdminService {
public constructor(
+ private readonly activitiesService: ActivitiesService,
private readonly benchmarkService: BenchmarkService,
private readonly configurationService: ConfigurationService,
private readonly dataProviderService: DataProviderService,
private readonly exchangeRateDataService: ExchangeRateDataService,
private readonly marketDataService: MarketDataService,
- private readonly orderService: OrderService,
private readonly prismaService: PrismaService,
private readonly propertyService: PropertyService,
private readonly symbolProfileService: SymbolProfileService
@@ -475,7 +475,7 @@ export class AdminService {
if (isCurrencyAssetProfile) {
currency = getCurrencyFromSymbol(symbol);
({ activitiesCount, dateOfFirstActivity } =
- await this.orderService.getStatisticsByCurrency(currency));
+ await this.activitiesService.getStatisticsByCurrency(currency));
}
const [[assetProfile], marketData] = await Promise.all([
@@ -798,7 +798,7 @@ export class AdminService {
if (isCurrency(getCurrencyFromSymbol(symbol))) {
currency = getCurrencyFromSymbol(symbol);
({ activitiesCount, dateOfFirstActivity } =
- await this.orderService.getStatisticsByCurrency(currency));
+ await this.activitiesService.getStatisticsByCurrency(currency));
}
const lastMarketPrice = lastMarketPriceMap.get(
diff --git a/apps/api/src/app/app.module.ts b/apps/api/src/app/app.module.ts
index 89f52e1ea..4b790d0db 100644
--- a/apps/api/src/app/app.module.ts
+++ b/apps/api/src/app/app.module.ts
@@ -25,6 +25,7 @@ import { join } from 'node:path';
import { AccessModule } from './access/access.module';
import { AccountModule } from './account/account.module';
+import { ActivitiesModule } from './activities/activities.module';
import { AdminModule } from './admin/admin.module';
import { AppController } from './app.controller';
import { AssetModule } from './asset/asset.module';
@@ -48,7 +49,6 @@ import { HealthModule } from './health/health.module';
import { ImportModule } from './import/import.module';
import { InfoModule } from './info/info.module';
import { LogoModule } from './logo/logo.module';
-import { OrderModule } from './order/order.module';
import { PlatformModule } from './platform/platform.module';
import { PortfolioModule } from './portfolio/portfolio.module';
import { RedisCacheModule } from './redis-cache/redis-cache.module';
@@ -62,6 +62,7 @@ import { UserModule } from './user/user.module';
AdminModule,
AccessModule,
AccountModule,
+ ActivitiesModule,
AiModule,
ApiKeysModule,
AssetModule,
@@ -94,7 +95,6 @@ import { UserModule } from './user/user.module';
InfoModule,
LogoModule,
MarketDataModule,
- OrderModule,
PlatformModule,
PlatformsModule,
PortfolioModule,
diff --git a/apps/api/src/app/endpoints/ai/ai.module.ts b/apps/api/src/app/endpoints/ai/ai.module.ts
index 8a441fde7..eab4ecf8b 100644
--- a/apps/api/src/app/endpoints/ai/ai.module.ts
+++ b/apps/api/src/app/endpoints/ai/ai.module.ts
@@ -1,6 +1,6 @@
import { AccountBalanceService } from '@ghostfolio/api/app/account-balance/account-balance.service';
import { AccountService } from '@ghostfolio/api/app/account/account.service';
-import { OrderModule } from '@ghostfolio/api/app/order/order.module';
+import { ActivitiesModule } from '@ghostfolio/api/app/activities/activities.module';
import { PortfolioCalculatorFactory } from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory';
import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.service';
import { PortfolioService } from '@ghostfolio/api/app/portfolio/portfolio.service';
@@ -29,6 +29,7 @@ import { AiService } from './ai.service';
@Module({
controllers: [AiController],
imports: [
+ ActivitiesModule,
ApiModule,
BenchmarkModule,
ConfigurationModule,
@@ -37,7 +38,6 @@ import { AiService } from './ai.service';
I18nModule,
ImpersonationModule,
MarketDataModule,
- OrderModule,
PortfolioSnapshotQueueModule,
PrismaModule,
PropertyModule,
diff --git a/apps/api/src/app/endpoints/benchmarks/benchmarks.module.ts b/apps/api/src/app/endpoints/benchmarks/benchmarks.module.ts
index 8bdf79035..2bcd6177d 100644
--- a/apps/api/src/app/endpoints/benchmarks/benchmarks.module.ts
+++ b/apps/api/src/app/endpoints/benchmarks/benchmarks.module.ts
@@ -1,6 +1,6 @@
import { AccountBalanceService } from '@ghostfolio/api/app/account-balance/account-balance.service';
import { AccountService } from '@ghostfolio/api/app/account/account.service';
-import { OrderModule } from '@ghostfolio/api/app/order/order.module';
+import { ActivitiesModule } from '@ghostfolio/api/app/activities/activities.module';
import { PortfolioCalculatorFactory } from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory';
import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.service';
import { PortfolioService } from '@ghostfolio/api/app/portfolio/portfolio.service';
@@ -32,6 +32,7 @@ import { BenchmarksService } from './benchmarks.service';
@Module({
controllers: [BenchmarksController],
imports: [
+ ActivitiesModule,
ApiModule,
ConfigurationModule,
DataProviderModule,
@@ -39,7 +40,6 @@ import { BenchmarksService } from './benchmarks.service';
I18nModule,
ImpersonationModule,
MarketDataModule,
- OrderModule,
PortfolioSnapshotQueueModule,
PrismaModule,
PropertyModule,
diff --git a/apps/api/src/app/endpoints/public/public.controller.ts b/apps/api/src/app/endpoints/public/public.controller.ts
index a1b2b7864..b97640cab 100644
--- a/apps/api/src/app/endpoints/public/public.controller.ts
+++ b/apps/api/src/app/endpoints/public/public.controller.ts
@@ -1,5 +1,5 @@
import { AccessService } from '@ghostfolio/api/app/access/access.service';
-import { OrderService } from '@ghostfolio/api/app/order/order.service';
+import { ActivitiesService } from '@ghostfolio/api/app/activities/activities.service';
import { PortfolioService } from '@ghostfolio/api/app/portfolio/portfolio.service';
import { UserService } from '@ghostfolio/api/app/user/user.service';
import { RedactValuesInResponseInterceptor } from '@ghostfolio/api/interceptors/redact-values-in-response/redact-values-in-response.interceptor';
@@ -28,9 +28,9 @@ import { StatusCodes, getReasonPhrase } from 'http-status-codes';
export class PublicController {
public constructor(
private readonly accessService: AccessService,
+ private readonly activitiesService: ActivitiesService,
private readonly configurationService: ConfigurationService,
private readonly exchangeRateDataService: ExchangeRateDataService,
- private readonly orderService: OrderService,
private readonly portfolioService: PortfolioService,
@Inject(REQUEST) private readonly request: RequestWithUser,
private readonly userService: UserService
@@ -81,7 +81,7 @@ export class PublicController {
})
]);
- const { activities } = await this.orderService.getOrders({
+ const { activities } = await this.activitiesService.getActivities({
sortColumn: 'date',
sortDirection: 'desc',
take: 10,
diff --git a/apps/api/src/app/endpoints/public/public.module.ts b/apps/api/src/app/endpoints/public/public.module.ts
index 19e281dde..e8395228f 100644
--- a/apps/api/src/app/endpoints/public/public.module.ts
+++ b/apps/api/src/app/endpoints/public/public.module.ts
@@ -1,7 +1,7 @@
import { AccessModule } from '@ghostfolio/api/app/access/access.module';
import { AccountBalanceService } from '@ghostfolio/api/app/account-balance/account-balance.service';
import { AccountService } from '@ghostfolio/api/app/account/account.service';
-import { OrderModule } from '@ghostfolio/api/app/order/order.module';
+import { ActivitiesModule } from '@ghostfolio/api/app/activities/activities.module';
import { PortfolioCalculatorFactory } from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory';
import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.service';
import { PortfolioService } from '@ghostfolio/api/app/portfolio/portfolio.service';
@@ -27,13 +27,13 @@ import { PublicController } from './public.controller';
controllers: [PublicController],
imports: [
AccessModule,
+ ActivitiesModule,
BenchmarkModule,
DataProviderModule,
ExchangeRateDataModule,
I18nModule,
ImpersonationModule,
MarketDataModule,
- OrderModule,
PortfolioSnapshotQueueModule,
PrismaModule,
RedisCacheModule,
diff --git a/apps/api/src/app/export/export.module.ts b/apps/api/src/app/export/export.module.ts
index 4f40cc417..6158fe043 100644
--- a/apps/api/src/app/export/export.module.ts
+++ b/apps/api/src/app/export/export.module.ts
@@ -1,5 +1,5 @@
import { AccountModule } from '@ghostfolio/api/app/account/account.module';
-import { OrderModule } from '@ghostfolio/api/app/order/order.module';
+import { ActivitiesModule } from '@ghostfolio/api/app/activities/activities.module';
import { TransformDataSourceInRequestModule } from '@ghostfolio/api/interceptors/transform-data-source-in-request/transform-data-source-in-request.module';
import { ApiModule } from '@ghostfolio/api/services/api/api.module';
import { MarketDataModule } from '@ghostfolio/api/services/market-data/market-data.module';
@@ -14,9 +14,9 @@ import { ExportService } from './export.service';
controllers: [ExportController],
imports: [
AccountModule,
+ ActivitiesModule,
ApiModule,
MarketDataModule,
- OrderModule,
TagModule,
TransformDataSourceInRequestModule
],
diff --git a/apps/api/src/app/export/export.service.ts b/apps/api/src/app/export/export.service.ts
index 55f8d7dc9..4f2fb3309 100644
--- a/apps/api/src/app/export/export.service.ts
+++ b/apps/api/src/app/export/export.service.ts
@@ -1,5 +1,5 @@
import { AccountService } from '@ghostfolio/api/app/account/account.service';
-import { OrderService } from '@ghostfolio/api/app/order/order.service';
+import { ActivitiesService } from '@ghostfolio/api/app/activities/activities.service';
import { environment } from '@ghostfolio/api/environments/environment';
import { MarketDataService } from '@ghostfolio/api/services/market-data/market-data.service';
import { TagService } from '@ghostfolio/api/services/tag/tag.service';
@@ -17,8 +17,8 @@ import { groupBy, uniqBy } from 'lodash';
export class ExportService {
public constructor(
private readonly accountService: AccountService,
+ private readonly activitiesService: ActivitiesService,
private readonly marketDataService: MarketDataService,
- private readonly orderService: OrderService,
private readonly tagService: TagService
) {}
@@ -38,7 +38,7 @@ export class ExportService {
});
const platformsMap: { [platformId: string]: Platform } = {};
- let { activities } = await this.orderService.getOrders({
+ let { activities } = await this.activitiesService.getActivities({
filters,
userId,
includeDrafts: true,
diff --git a/apps/api/src/app/import/import.module.ts b/apps/api/src/app/import/import.module.ts
index a4a13f941..ca9b5667b 100644
--- a/apps/api/src/app/import/import.module.ts
+++ b/apps/api/src/app/import/import.module.ts
@@ -1,6 +1,6 @@
import { AccountModule } from '@ghostfolio/api/app/account/account.module';
+import { ActivitiesModule } from '@ghostfolio/api/app/activities/activities.module';
import { CacheModule } from '@ghostfolio/api/app/cache/cache.module';
-import { OrderModule } from '@ghostfolio/api/app/order/order.module';
import { PlatformModule } from '@ghostfolio/api/app/platform/platform.module';
import { PortfolioModule } from '@ghostfolio/api/app/portfolio/portfolio.module';
import { RedisCacheModule } from '@ghostfolio/api/app/redis-cache/redis-cache.module';
@@ -25,6 +25,7 @@ import { ImportService } from './import.service';
controllers: [ImportController],
imports: [
AccountModule,
+ ActivitiesModule,
ApiModule,
CacheModule,
ConfigurationModule,
@@ -32,7 +33,6 @@ import { ImportService } from './import.service';
DataProviderModule,
ExchangeRateDataModule,
MarketDataModule,
- OrderModule,
PlatformModule,
PortfolioModule,
PrismaModule,
diff --git a/apps/api/src/app/import/import.service.ts b/apps/api/src/app/import/import.service.ts
index 497b8a7e9..b82f763a0 100644
--- a/apps/api/src/app/import/import.service.ts
+++ b/apps/api/src/app/import/import.service.ts
@@ -1,5 +1,5 @@
import { AccountService } from '@ghostfolio/api/app/account/account.service';
-import { OrderService } from '@ghostfolio/api/app/order/order.service';
+import { ActivitiesService } from '@ghostfolio/api/app/activities/activities.service';
import { PlatformService } from '@ghostfolio/api/app/platform/platform.service';
import { PortfolioService } from '@ghostfolio/api/app/portfolio/portfolio.service';
import { ApiService } from '@ghostfolio/api/services/api/api.service';
@@ -44,12 +44,12 @@ import { ImportDataDto } from './import-data.dto';
export class ImportService {
public constructor(
private readonly accountService: AccountService,
+ private readonly activitiesService: ActivitiesService,
private readonly apiService: ApiService,
private readonly dataGatheringService: DataGatheringService,
private readonly dataProviderService: DataProviderService,
private readonly exchangeRateDataService: ExchangeRateDataService,
private readonly marketDataService: MarketDataService,
- private readonly orderService: OrderService,
private readonly platformService: PlatformService,
private readonly portfolioService: PortfolioService,
private readonly symbolProfileService: SymbolProfileService,
@@ -91,7 +91,7 @@ export class ImportService {
userId,
withExcludedAccounts: true
}),
- this.orderService.getOrders({
+ this.activitiesService.getActivities({
filters,
userCurrency,
userId,
@@ -548,7 +548,7 @@ export class ImportService {
continue;
}
- order = await this.orderService.createOrder({
+ order = await this.activitiesService.createActivity({
comment,
currency,
date,
@@ -645,7 +645,7 @@ export class ImportService {
userId: string;
}): Promise[]> {
const { activities: existingActivities } =
- await this.orderService.getOrders({
+ await this.activitiesService.getActivities({
userCurrency,
userId,
includeDrafts: true,
diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-cash.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-cash.spec.ts
index a53ebcf05..217a67c49 100644
--- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-cash.spec.ts
+++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-cash.spec.ts
@@ -1,6 +1,6 @@
import { AccountBalanceService } from '@ghostfolio/api/app/account-balance/account-balance.service';
import { AccountService } from '@ghostfolio/api/app/account/account.service';
-import { OrderService } from '@ghostfolio/api/app/order/order.service';
+import { ActivitiesService } from '@ghostfolio/api/app/activities/activities.service';
import { userDummyData } from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator-test-utils';
import { PortfolioCalculatorFactory } from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory';
import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.service';
@@ -62,11 +62,11 @@ jest.mock('@ghostfolio/api/app/redis-cache/redis-cache.service', () => {
describe('PortfolioCalculator', () => {
let accountBalanceService: AccountBalanceService;
let accountService: AccountService;
+ let activitiesService: ActivitiesService;
let configurationService: ConfigurationService;
let currentRateService: CurrentRateService;
let dataProviderService: DataProviderService;
let exchangeRateDataService: ExchangeRateDataService;
- let orderService: OrderService;
let portfolioCalculatorFactory: PortfolioCalculatorFactory;
let portfolioSnapshotService: PortfolioSnapshotService;
let redisCacheService: RedisCacheService;
@@ -106,13 +106,13 @@ describe('PortfolioCalculator', () => {
);
currentRateService = new CurrentRateService(
- dataProviderService,
null,
+ dataProviderService,
null,
null
);
- orderService = new OrderService(
+ activitiesService = new ActivitiesService(
accountBalanceService,
accountService,
null,
@@ -183,18 +183,17 @@ describe('PortfolioCalculator', () => {
.spyOn(dataProviderService, 'getDataSourceForExchangeRates')
.mockReturnValue(DataSource.YAHOO);
- jest.spyOn(orderService, 'getOrders').mockResolvedValue({
+ jest.spyOn(activitiesService, 'getActivities').mockResolvedValue({
activities: [],
count: 0
});
- const { activities } = await orderService.getOrdersForPortfolioCalculator(
- {
+ const { activities } =
+ await activitiesService.getActivitiesForPortfolioCalculator({
userCurrency: 'CHF',
userId: userDummyData.id,
withCash: true
- }
- );
+ });
jest.spyOn(currentRateService, 'getValues').mockResolvedValue({
dataProviderInfos: [],
diff --git a/apps/api/src/app/portfolio/current-rate.service.spec.ts b/apps/api/src/app/portfolio/current-rate.service.spec.ts
index d8b7482e7..5f2358679 100644
--- a/apps/api/src/app/portfolio/current-rate.service.spec.ts
+++ b/apps/api/src/app/portfolio/current-rate.service.spec.ts
@@ -114,9 +114,9 @@ describe('CurrentRateService', () => {
marketDataService = new MarketDataService(null);
currentRateService = new CurrentRateService(
+ null,
dataProviderService,
marketDataService,
- null,
null
);
});
diff --git a/apps/api/src/app/portfolio/current-rate.service.ts b/apps/api/src/app/portfolio/current-rate.service.ts
index 5d39a54bb..b454b01cd 100644
--- a/apps/api/src/app/portfolio/current-rate.service.ts
+++ b/apps/api/src/app/portfolio/current-rate.service.ts
@@ -1,4 +1,4 @@
-import { OrderService } from '@ghostfolio/api/app/order/order.service';
+import { ActivitiesService } from '@ghostfolio/api/app/activities/activities.service';
import { LogPerformance } from '@ghostfolio/api/interceptors/performance-logging/performance-logging.interceptor';
import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service';
import { MarketDataService } from '@ghostfolio/api/services/market-data/market-data.service';
@@ -24,9 +24,9 @@ export class CurrentRateService {
private static readonly MARKET_DATA_PAGE_SIZE = 50000;
public constructor(
+ private readonly activitiesService: ActivitiesService,
private readonly dataProviderService: DataProviderService,
private readonly marketDataService: MarketDataService,
- private readonly orderService: OrderService,
@Inject(REQUEST) private readonly request: RequestWithUser
) {}
@@ -129,10 +129,11 @@ export class CurrentRateService {
if (!value) {
// Fallback to unit price of latest activity
- const latestActivity = await this.orderService.getLatestOrder({
- dataSource,
- symbol
- });
+ const latestActivity =
+ await this.activitiesService.getLatestActivity({
+ dataSource,
+ symbol
+ });
value = {
dataSource,
diff --git a/apps/api/src/app/portfolio/portfolio.controller.ts b/apps/api/src/app/portfolio/portfolio.controller.ts
index 67b5229c1..80d7f9acc 100644
--- a/apps/api/src/app/portfolio/portfolio.controller.ts
+++ b/apps/api/src/app/portfolio/portfolio.controller.ts
@@ -1,4 +1,4 @@
-import { OrderService } from '@ghostfolio/api/app/order/order.service';
+import { ActivitiesService } from '@ghostfolio/api/app/activities/activities.service';
import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorator';
import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard';
import {
@@ -63,10 +63,10 @@ import { UpdateHoldingTagsDto } from './update-holding-tags.dto';
@Controller('portfolio')
export class PortfolioController {
public constructor(
+ private readonly activitiesService: ActivitiesService,
private readonly apiService: ApiService,
private readonly configurationService: ConfigurationService,
private readonly impersonationService: ImpersonationService,
- private readonly orderService: OrderService,
private readonly portfolioService: PortfolioService,
@Inject(REQUEST) private readonly request: RequestWithUser
) {}
@@ -322,7 +322,7 @@ export class PortfolioController {
const { endDate, startDate } = getIntervalFromDateRange(dateRange);
- const { activities } = await this.orderService.getOrders({
+ const { activities } = await this.activitiesService.getActivities({
endDate,
filters,
startDate,
diff --git a/apps/api/src/app/portfolio/portfolio.module.ts b/apps/api/src/app/portfolio/portfolio.module.ts
index 6dd5811a3..65a9b71aa 100644
--- a/apps/api/src/app/portfolio/portfolio.module.ts
+++ b/apps/api/src/app/portfolio/portfolio.module.ts
@@ -1,7 +1,7 @@
import { AccessModule } from '@ghostfolio/api/app/access/access.module';
import { AccountBalanceService } from '@ghostfolio/api/app/account-balance/account-balance.service';
import { AccountService } from '@ghostfolio/api/app/account/account.service';
-import { OrderModule } from '@ghostfolio/api/app/order/order.module';
+import { ActivitiesModule } from '@ghostfolio/api/app/activities/activities.module';
import { RedisCacheModule } from '@ghostfolio/api/app/redis-cache/redis-cache.module';
import { UserModule } from '@ghostfolio/api/app/user/user.module';
import { PerformanceLoggingModule } from '@ghostfolio/api/interceptors/performance-logging/performance-logging.module';
@@ -34,6 +34,7 @@ import { RulesService } from './rules.service';
exports: [PortfolioService],
imports: [
AccessModule,
+ ActivitiesModule,
ApiModule,
BenchmarkModule,
ConfigurationModule,
@@ -43,7 +44,6 @@ import { RulesService } from './rules.service';
I18nModule,
ImpersonationModule,
MarketDataModule,
- OrderModule,
PerformanceLoggingModule,
PortfolioSnapshotQueueModule,
PrismaModule,
diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts
index 1bfad8395..ed72260ca 100644
--- a/apps/api/src/app/portfolio/portfolio.service.ts
+++ b/apps/api/src/app/portfolio/portfolio.service.ts
@@ -1,7 +1,7 @@
import { AccountBalanceService } from '@ghostfolio/api/app/account-balance/account-balance.service';
import { AccountService } from '@ghostfolio/api/app/account/account.service';
import { CashDetails } from '@ghostfolio/api/app/account/interfaces/cash-details.interface';
-import { OrderService } from '@ghostfolio/api/app/order/order.service';
+import { ActivitiesService } from '@ghostfolio/api/app/activities/activities.service';
import { UserService } from '@ghostfolio/api/app/user/user.service';
import { getFactor } from '@ghostfolio/api/helper/portfolio.helper';
import { AccountClusterRiskCurrentInvestment } from '@ghostfolio/api/models/rules/account-cluster-risk/current-investment';
@@ -105,13 +105,13 @@ export class PortfolioService {
public constructor(
private readonly accountBalanceService: AccountBalanceService,
private readonly accountService: AccountService,
+ private readonly activitiesService: ActivitiesService,
private readonly benchmarkService: BenchmarkService,
private readonly calculatorFactory: PortfolioCalculatorFactory,
private readonly dataProviderService: DataProviderService,
private readonly exchangeRateDataService: ExchangeRateDataService,
private readonly i18nService: I18nService,
private readonly impersonationService: ImpersonationService,
- private readonly orderService: OrderService,
@Inject(REQUEST) private readonly request: RequestWithUser,
private readonly rulesService: RulesService,
private readonly symbolProfileService: SymbolProfileService,
@@ -406,7 +406,7 @@ export class PortfolioService {
const { endDate, startDate } = getIntervalFromDateRange(dateRange);
const { activities } =
- await this.orderService.getOrdersForPortfolioCalculator({
+ await this.activitiesService.getActivitiesForPortfolioCalculator({
filters,
userCurrency,
userId
@@ -490,7 +490,7 @@ export class PortfolioService {
);
const { activities } =
- await this.orderService.getOrdersForPortfolioCalculator({
+ await this.activitiesService.getActivitiesForPortfolioCalculator({
filters,
userCurrency,
userId
@@ -779,7 +779,7 @@ export class PortfolioService {
const userCurrency = this.getUserCurrency(user);
const { activities } =
- await this.orderService.getOrdersForPortfolioCalculator({
+ await this.activitiesService.getActivitiesForPortfolioCalculator({
userCurrency,
userId
});
@@ -1009,7 +1009,7 @@ export class PortfolioService {
userId,
userCurrency
}),
- this.orderService.getOrdersForPortfolioCalculator({
+ this.activitiesService.getActivitiesForPortfolioCalculator({
filters,
userCurrency,
userId
@@ -1370,7 +1370,12 @@ export class PortfolioService {
}) {
userId = await this.getUserId(impersonationId, userId);
- await this.orderService.assignTags({ dataSource, symbol, tags, userId });
+ await this.activitiesService.assignTags({
+ dataSource,
+ symbol,
+ tags,
+ userId
+ });
}
private getAggregatedMarkets(holdings: Record): {
@@ -1872,7 +1877,7 @@ export class PortfolioService {
userId = await this.getUserId(impersonationId, userId);
const user = await this.userService.user({ id: userId });
- const { activities } = await this.orderService.getOrders({
+ const { activities } = await this.activitiesService.getActivities({
userCurrency,
userId,
withExcludedAccountsAndActivities: true
diff --git a/apps/api/src/app/user/user.module.ts b/apps/api/src/app/user/user.module.ts
index 7ca68d275..3f4e898fc 100644
--- a/apps/api/src/app/user/user.module.ts
+++ b/apps/api/src/app/user/user.module.ts
@@ -1,4 +1,4 @@
-import { OrderModule } from '@ghostfolio/api/app/order/order.module';
+import { ActivitiesModule } from '@ghostfolio/api/app/activities/activities.module';
import { SubscriptionModule } from '@ghostfolio/api/app/subscription/subscription.module';
import { RedactValuesInResponseModule } from '@ghostfolio/api/interceptors/redact-values-in-response/redact-values-in-response.module';
import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.module';
@@ -18,6 +18,7 @@ import { UserService } from './user.service';
controllers: [UserController],
exports: [UserService],
imports: [
+ ActivitiesModule,
ConfigurationModule,
I18nModule,
ImpersonationModule,
@@ -25,7 +26,6 @@ import { UserService } from './user.service';
secret: process.env.JWT_SECRET_KEY,
signOptions: { expiresIn: '30 days' }
}),
- OrderModule,
PrismaModule,
PropertyModule,
RedactValuesInResponseModule,
diff --git a/apps/api/src/app/user/user.service.ts b/apps/api/src/app/user/user.service.ts
index 97ab8a59f..5a339c090 100644
--- a/apps/api/src/app/user/user.service.ts
+++ b/apps/api/src/app/user/user.service.ts
@@ -1,4 +1,4 @@
-import { OrderService } from '@ghostfolio/api/app/order/order.service';
+import { ActivitiesService } from '@ghostfolio/api/app/activities/activities.service';
import { SubscriptionService } from '@ghostfolio/api/app/subscription/subscription.service';
import { environment } from '@ghostfolio/api/environments/environment';
import { PortfolioChangedEvent } from '@ghostfolio/api/events/portfolio-changed.event';
@@ -55,10 +55,10 @@ import { createHmac } from 'node:crypto';
@Injectable()
export class UserService {
public constructor(
+ private readonly activitiesService: ActivitiesService,
private readonly configurationService: ConfigurationService,
private readonly eventEmitter: EventEmitter2,
private readonly i18nService: I18nService,
- private readonly orderService: OrderService,
private readonly prismaService: PrismaService,
private readonly propertyService: PropertyService,
private readonly subscriptionService: SubscriptionService,
@@ -643,7 +643,7 @@ export class UserService {
} catch {}
try {
- await this.orderService.deleteOrders({
+ await this.activitiesService.deleteActivities({
userId: where.id
});
} catch {}
diff --git a/apps/api/src/events/asset-profile-changed.listener.ts b/apps/api/src/events/asset-profile-changed.listener.ts
index ad80ee4a5..1ecadec67 100644
--- a/apps/api/src/events/asset-profile-changed.listener.ts
+++ b/apps/api/src/events/asset-profile-changed.listener.ts
@@ -1,4 +1,4 @@
-import { OrderService } from '@ghostfolio/api/app/order/order.service';
+import { ActivitiesService } from '@ghostfolio/api/app/activities/activities.service';
import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service';
import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service';
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service';
@@ -13,11 +13,11 @@ import { AssetProfileChangedEvent } from './asset-profile-changed.event';
@Injectable()
export class AssetProfileChangedListener {
public constructor(
+ private readonly activitiesService: ActivitiesService,
private readonly configurationService: ConfigurationService,
private readonly dataGatheringService: DataGatheringService,
private readonly dataProviderService: DataProviderService,
- private readonly exchangeRateDataService: ExchangeRateDataService,
- private readonly orderService: OrderService
+ private readonly exchangeRateDataService: ExchangeRateDataService
) {}
@OnEvent(AssetProfileChangedEvent.getName())
@@ -48,7 +48,7 @@ export class AssetProfileChangedListener {
}
const { dateOfFirstActivity } =
- await this.orderService.getStatisticsByCurrency(event.data.currency);
+ await this.activitiesService.getStatisticsByCurrency(event.data.currency);
if (dateOfFirstActivity) {
await this.dataGatheringService.gatherSymbol({
diff --git a/apps/api/src/events/events.module.ts b/apps/api/src/events/events.module.ts
index ece67ebe0..772766945 100644
--- a/apps/api/src/events/events.module.ts
+++ b/apps/api/src/events/events.module.ts
@@ -1,4 +1,4 @@
-import { OrderModule } from '@ghostfolio/api/app/order/order.module';
+import { ActivitiesModule } from '@ghostfolio/api/app/activities/activities.module';
import { RedisCacheModule } from '@ghostfolio/api/app/redis-cache/redis-cache.module';
import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.module';
import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data-provider.module';
@@ -12,11 +12,11 @@ import { PortfolioChangedListener } from './portfolio-changed.listener';
@Module({
imports: [
+ ActivitiesModule,
ConfigurationModule,
DataGatheringModule,
DataProviderModule,
ExchangeRateDataModule,
- OrderModule,
RedisCacheModule
],
providers: [AssetProfileChangedListener, PortfolioChangedListener]
diff --git a/apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.module.ts b/apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.module.ts
index 958636334..553765768 100644
--- a/apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.module.ts
+++ b/apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.module.ts
@@ -1,5 +1,5 @@
import { AccountBalanceModule } from '@ghostfolio/api/app/account-balance/account-balance.module';
-import { OrderModule } from '@ghostfolio/api/app/order/order.module';
+import { ActivitiesModule } from '@ghostfolio/api/app/activities/activities.module';
import { PortfolioCalculatorFactory } from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory';
import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.service';
import { RedisCacheModule } from '@ghostfolio/api/app/redis-cache/redis-cache.module';
@@ -22,6 +22,7 @@ import { PortfolioSnapshotProcessor } from './portfolio-snapshot.processor';
exports: [BullModule, PortfolioSnapshotService],
imports: [
AccountBalanceModule,
+ ActivitiesModule,
BullModule.registerQueue({
name: PORTFOLIO_SNAPSHOT_COMPUTATION_QUEUE,
settings: {
@@ -36,7 +37,6 @@ import { PortfolioSnapshotProcessor } from './portfolio-snapshot.processor';
DataProviderModule,
ExchangeRateDataModule,
MarketDataModule,
- OrderModule,
RedisCacheModule
],
providers: [
diff --git a/apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.processor.ts b/apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.processor.ts
index 58a0a8f8a..f3aa6e77e 100644
--- a/apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.processor.ts
+++ b/apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.processor.ts
@@ -1,5 +1,5 @@
import { AccountBalanceService } from '@ghostfolio/api/app/account-balance/account-balance.service';
-import { OrderService } from '@ghostfolio/api/app/order/order.service';
+import { ActivitiesService } from '@ghostfolio/api/app/activities/activities.service';
import { PortfolioCalculatorFactory } from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory';
import { PortfolioSnapshotValue } from '@ghostfolio/api/app/portfolio/interfaces/snapshot-value.interface';
import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.service';
@@ -23,9 +23,9 @@ import { PortfolioSnapshotQueueJob } from './interfaces/portfolio-snapshot-queue
export class PortfolioSnapshotProcessor {
public constructor(
private readonly accountBalanceService: AccountBalanceService,
+ private readonly activitiesService: ActivitiesService,
private readonly calculatorFactory: PortfolioCalculatorFactory,
private readonly configurationService: ConfigurationService,
- private readonly orderService: OrderService,
private readonly redisCacheService: RedisCacheService
) {}
@@ -47,7 +47,7 @@ export class PortfolioSnapshotProcessor {
);
const { activities } =
- await this.orderService.getOrdersForPortfolioCalculator({
+ await this.activitiesService.getActivitiesForPortfolioCalculator({
filters: job.data.filters,
userCurrency: job.data.userCurrency,
userId: job.data.userId,
diff --git a/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts b/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts
index 427386796..4d89cfbe1 100644
--- a/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts
+++ b/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts
@@ -581,7 +581,7 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit {
};
this.dataService
- .postOrder(activity)
+ .postActivity(activity)
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe(() => {
this.router.navigate(
diff --git a/apps/client/src/app/pages/portfolio/activities/activities-page.component.ts b/apps/client/src/app/pages/portfolio/activities/activities-page.component.ts
index cf7a41215..ca3f5b30d 100644
--- a/apps/client/src/app/pages/portfolio/activities/activities-page.component.ts
+++ b/apps/client/src/app/pages/portfolio/activities/activities-page.component.ts
@@ -334,7 +334,7 @@ export class GfActivitiesPageComponent implements OnDestroy, OnInit {
.subscribe((activity: UpdateOrderDto) => {
if (activity) {
this.dataService
- .putOrder(activity)
+ .putActivity(activity)
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe({
next: () => {
@@ -385,7 +385,7 @@ export class GfActivitiesPageComponent implements OnDestroy, OnInit {
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe((transaction: CreateOrderDto | null) => {
if (transaction) {
- this.dataService.postOrder(transaction).subscribe({
+ this.dataService.postActivity(transaction).subscribe({
next: () => {
this.userService
.get(true)
diff --git a/libs/ui/src/lib/services/data.service.ts b/libs/ui/src/lib/services/data.service.ts
index 37443cd20..62e7b6b4a 100644
--- a/libs/ui/src/lib/services/data.service.ts
+++ b/libs/ui/src/lib/services/data.service.ts
@@ -241,7 +241,7 @@ export class DataService {
params = params.append('take', take);
}
- return this.http.get('/api/v1/order', { params }).pipe(
+ return this.http.get('/api/v1/activities', { params }).pipe(
map(({ activities, count }) => {
for (const activity of activities) {
activity.createdAt = parseISO(activity.createdAt);
@@ -253,14 +253,18 @@ export class DataService {
}
public fetchActivity(aActivityId: string) {
- return this.http.get(`/api/v1/order/${aActivityId}`).pipe(
- map((activity) => {
- activity.createdAt = parseISO(activity.createdAt as unknown as string);
- activity.date = parseISO(activity.date as unknown as string);
+ return this.http
+ .get(`/api/v1/activities/${aActivityId}`)
+ .pipe(
+ map((activity) => {
+ activity.createdAt = parseISO(
+ activity.createdAt as unknown as string
+ );
+ activity.date = parseISO(activity.date as unknown as string);
- return activity;
- })
- );
+ return activity;
+ })
+ );
}
public fetchDividends({
@@ -317,11 +321,11 @@ export class DataService {
public deleteActivities({ filters }) {
const params = this.buildFiltersAsQueryParams({ filters });
- return this.http.delete('/api/v1/order', { params });
+ return this.http.delete('/api/v1/activities', { params });
}
public deleteActivity(aId: string) {
- return this.http.delete(`/api/v1/order/${aId}`);
+ return this.http.delete(`/api/v1/activities/${aId}`);
}
public deleteBenchmark({ dataSource, symbol }: AssetProfileIdentifier) {
@@ -761,6 +765,10 @@ export class DataService {
);
}
+ public postActivity(aOrder: CreateOrderDto) {
+ return this.http.post('/api/v1/activities', aOrder);
+ }
+
public postApiKey() {
return this.http.post('/api/v1/api-keys', {});
}
@@ -783,10 +791,6 @@ export class DataService {
return this.http.post(url, marketData);
}
- public postOrder(aOrder: CreateOrderDto) {
- return this.http.post('/api/v1/order', aOrder);
- }
-
public postTag(aTag: CreateTagDto) {
return this.http.post(`/api/v1/tags`, aTag);
}
@@ -807,6 +811,10 @@ export class DataService {
return this.http.put(`/api/v1/account/${aAccount.id}`, aAccount);
}
+ public putActivity(aOrder: UpdateOrderDto) {
+ return this.http.put(`/api/v1/activities/${aOrder.id}`, aOrder);
+ }
+
public putAdminSetting(key: string, aData: UpdatePropertyDto) {
return this.http.put(`/api/v1/admin/settings/${key}`, aData);
}
@@ -822,10 +830,6 @@ export class DataService {
);
}
- public putOrder(aOrder: UpdateOrderDto) {
- return this.http.put(`/api/v1/order/${aOrder.id}`, aOrder);
- }
-
public putTag(aTag: UpdateTagDto) {
return this.http.put(`/api/v1/tags/${aTag.id}`, aTag);
}
From 1057f4308485803eb44bf29b4218d596153f7c5b Mon Sep 17 00:00:00 2001
From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com>
Date: Sat, 7 Mar 2026 18:22:55 +0100
Subject: [PATCH 6/6] Release 2.248.0 (#6493)
---
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 1279ef62f..4d8cdd873 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.248.0 - 2026-03-07
### Added
diff --git a/package-lock.json b/package-lock.json
index 0ea9bbdce..ed34faf03 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "ghostfolio",
- "version": "2.247.0",
+ "version": "2.248.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "ghostfolio",
- "version": "2.247.0",
+ "version": "2.248.0",
"hasInstallScript": true,
"license": "AGPL-3.0",
"dependencies": {
diff --git a/package.json b/package.json
index 47c9e9ade..b501bf7a4 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "ghostfolio",
- "version": "2.247.0",
+ "version": "2.248.0",
"homepage": "https://ghostfol.io",
"license": "AGPL-3.0",
"repository": "https://github.com/ghostfolio/ghostfolio",
| |