diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e591b311..4359aa775 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.158.0 - 2025-04-30 ### Added @@ -13,8 +13,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- Renamed `Order` to `activities` in the `Account` database schema - Improved the language localization for German (`de`) +### Fixed + +- Fixed an issue with the saving of activities with type `INTEREST`, `ITEM` and `LIABILITY` + ## 2.157.1 - 2025-04-29 ### Added diff --git a/apps/api/src/app/account/account.controller.ts b/apps/api/src/app/account/account.controller.ts index c0f4dac6a..71ff8a044 100644 --- a/apps/api/src/app/account/account.controller.ts +++ b/apps/api/src/app/account/account.controller.ts @@ -57,17 +57,17 @@ export class AccountController { @HasPermission(permissions.deleteAccount) @UseGuards(AuthGuard('jwt'), HasPermissionGuard) public async deleteAccount(@Param('id') id: string): Promise { - const account = await this.accountService.accountWithOrders( + const account = await this.accountService.accountWithActivities( { id_userId: { id, userId: this.request.user.id } }, - { Order: true } + { activities: true } ); - if (!account || account?.Order.length > 0) { + if (!account || account?.activities.length > 0) { throw new HttpException( getReasonPhrase(StatusCodes.FORBIDDEN), StatusCodes.FORBIDDEN diff --git a/apps/api/src/app/account/account.service.ts b/apps/api/src/app/account/account.service.ts index aab4c0766..a10eecac5 100644 --- a/apps/api/src/app/account/account.service.ts +++ b/apps/api/src/app/account/account.service.ts @@ -39,12 +39,12 @@ export class AccountService { return account; } - public async accountWithOrders( + public async accountWithActivities( accountWhereUniqueInput: Prisma.AccountWhereUniqueInput, accountInclude: Prisma.AccountInclude ): Promise< Account & { - Order?: Order[]; + activities?: Order[]; } > { return this.prismaService.account.findUnique({ @@ -62,8 +62,8 @@ export class AccountService { orderBy?: Prisma.AccountOrderByWithRelationInput; }): Promise< (Account & { + activities?: Order[]; balances?: AccountBalance[]; - Order?: Order[]; Platform?: Platform; })[] > { @@ -140,7 +140,7 @@ export class AccountService { public async getAccounts(aUserId: string): Promise { const accounts = await this.accounts({ - include: { Order: true, Platform: true }, + include: { activities: true, Platform: true }, orderBy: { name: 'asc' }, where: { userId: aUserId } }); @@ -148,15 +148,15 @@ export class AccountService { return accounts.map((account) => { let transactionCount = 0; - for (const order of account.Order) { - if (!order.isDraft) { + for (const { isDraft } of account.activities) { + if (!isDraft) { transactionCount += 1; } } const result = { ...account, transactionCount }; - delete result.Order; + delete result.activities; return result; }); diff --git a/apps/api/src/app/order/order.service.ts b/apps/api/src/app/order/order.service.ts index c2b822ac9..d1847635a 100644 --- a/apps/api/src/app/order/order.service.ts +++ b/apps/api/src/app/order/order.service.ts @@ -100,7 +100,7 @@ export class OrderService { userId: string; } ): Promise { - let Account: Prisma.AccountCreateNestedOneWithoutOrderInput; + let Account: Prisma.AccountCreateNestedOneWithoutActivitiesInput; if (data.accountId) { Account = { diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index 87b2bc9df..3aa9696b5 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -139,7 +139,7 @@ export class PortfolioService { } if (filterByDataSource && filterBySymbol) { - where.Order = { + where.activities = { some: { SymbolProfile: { AND: [ @@ -154,7 +154,7 @@ export class PortfolioService { const [accounts, details] = await Promise.all([ this.accountService.accounts({ where, - include: { Order: true, Platform: true }, + include: { activities: true, Platform: true }, orderBy: { name: 'asc' } }), this.getDetails({ @@ -170,8 +170,8 @@ export class PortfolioService { return accounts.map((account) => { let transactionCount = 0; - for (const order of account.Order) { - if (!order.isDraft) { + for (const { isDraft } of account.activities) { + if (!isDraft) { transactionCount += 1; } } @@ -195,7 +195,7 @@ export class PortfolioService { ) }; - delete result.Order; + delete result.activities; return result; }); 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 f6ce2a81d..dce045a4a 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 @@ -238,7 +238,7 @@ export class CreateOrUpdateActivityDialog implements OnDestroy { .get('dataSource') .removeValidators(Validators.required); this.activityForm.get('dataSource').updateValueAndValidity(); - this.activityForm.get('fee').reset(); + this.activityForm.get('fee').setValue(0); this.activityForm.get('name').setValidators(Validators.required); this.activityForm.get('name').updateValueAndValidity(); this.activityForm.get('quantity').setValue(1); @@ -248,11 +248,7 @@ export class CreateOrUpdateActivityDialog implements OnDestroy { this.activityForm.get('searchSymbol').updateValueAndValidity(); this.activityForm.get('updateAccountBalance').disable(); this.activityForm.get('updateAccountBalance').setValue(false); - } else if ( - type === 'FEE' || - type === 'INTEREST' || - type === 'LIABILITY' - ) { + } else if (['FEE', 'INTEREST', 'LIABILITY'].includes(type)) { this.activityForm .get('accountId') .removeValidators(Validators.required); @@ -271,12 +267,8 @@ export class CreateOrUpdateActivityDialog implements OnDestroy { .removeValidators(Validators.required); this.activityForm.get('dataSource').updateValueAndValidity(); - if ( - (type === 'FEE' && this.activityForm.get('fee').value === 0) || - type === 'INTEREST' || - type === 'LIABILITY' - ) { - this.activityForm.get('fee').reset(); + if (['INTEREST', 'LIABILITY'].includes(type)) { + this.activityForm.get('fee').setValue(0); } this.activityForm.get('name').setValidators(Validators.required); @@ -284,7 +276,7 @@ export class CreateOrUpdateActivityDialog implements OnDestroy { if (type === 'FEE') { this.activityForm.get('quantity').setValue(0); - } else if (type === 'INTEREST' || type === 'LIABILITY') { + } else if (['INTEREST', 'LIABILITY'].includes(type)) { this.activityForm.get('quantity').setValue(1); } diff --git a/package-lock.json b/package-lock.json index 54ce11db7..27acd2820 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ghostfolio", - "version": "2.157.1", + "version": "2.158.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ghostfolio", - "version": "2.157.1", + "version": "2.158.0", "hasInstallScript": true, "license": "AGPL-3.0", "dependencies": { diff --git a/package.json b/package.json index 42e173d4c..c64163886 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ghostfolio", - "version": "2.157.1", + "version": "2.158.0", "homepage": "https://ghostfol.io", "license": "AGPL-3.0", "repository": "https://github.com/ghostfolio/ghostfolio", diff --git a/prisma/schema.prisma b/prisma/schema.prisma index b88a5f9f8..c33f7d6cc 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -26,6 +26,7 @@ model Access { } model Account { + activities Order[] balance Float @default(0) balances AccountBalance[] comment String? @@ -39,7 +40,6 @@ model Account { userId String Platform Platform? @relation(fields: [platformId], references: [id]) User User @relation(fields: [userId], onDelete: Cascade, references: [id]) - Order Order[] @@id([id, userId]) @@index([currency])