Browse Source

Merge remote-tracking branch 'origin/main' into feature/extend-watchlist-endpoint

pull/4634/head
KenTandrian 4 months ago
parent
commit
6c719811de
  1. 7
      CHANGELOG.md
  2. 6
      apps/api/src/app/account/account.controller.ts
  3. 14
      apps/api/src/app/account/account.service.ts
  4. 2
      apps/api/src/app/order/order.service.ts
  5. 10
      apps/api/src/app/portfolio/portfolio.service.ts
  6. 18
      apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.component.ts
  7. 4
      package-lock.json
  8. 2
      package.json
  9. 2
      prisma/schema.prisma

7
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/), 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). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## Unreleased ## 2.158.0 - 2025-04-30
### Added ### Added
@ -13,8 +13,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed ### Changed
- Renamed `Order` to `activities` in the `Account` database schema
- Improved the language localization for German (`de`) - 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 ## 2.157.1 - 2025-04-29
### Added ### Added

6
apps/api/src/app/account/account.controller.ts

@ -57,17 +57,17 @@ export class AccountController {
@HasPermission(permissions.deleteAccount) @HasPermission(permissions.deleteAccount)
@UseGuards(AuthGuard('jwt'), HasPermissionGuard) @UseGuards(AuthGuard('jwt'), HasPermissionGuard)
public async deleteAccount(@Param('id') id: string): Promise<AccountModel> { public async deleteAccount(@Param('id') id: string): Promise<AccountModel> {
const account = await this.accountService.accountWithOrders( const account = await this.accountService.accountWithActivities(
{ {
id_userId: { id_userId: {
id, id,
userId: this.request.user.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( throw new HttpException(
getReasonPhrase(StatusCodes.FORBIDDEN), getReasonPhrase(StatusCodes.FORBIDDEN),
StatusCodes.FORBIDDEN StatusCodes.FORBIDDEN

14
apps/api/src/app/account/account.service.ts

@ -39,12 +39,12 @@ export class AccountService {
return account; return account;
} }
public async accountWithOrders( public async accountWithActivities(
accountWhereUniqueInput: Prisma.AccountWhereUniqueInput, accountWhereUniqueInput: Prisma.AccountWhereUniqueInput,
accountInclude: Prisma.AccountInclude accountInclude: Prisma.AccountInclude
): Promise< ): Promise<
Account & { Account & {
Order?: Order[]; activities?: Order[];
} }
> { > {
return this.prismaService.account.findUnique({ return this.prismaService.account.findUnique({
@ -62,8 +62,8 @@ export class AccountService {
orderBy?: Prisma.AccountOrderByWithRelationInput; orderBy?: Prisma.AccountOrderByWithRelationInput;
}): Promise< }): Promise<
(Account & { (Account & {
activities?: Order[];
balances?: AccountBalance[]; balances?: AccountBalance[];
Order?: Order[];
Platform?: Platform; Platform?: Platform;
})[] })[]
> { > {
@ -140,7 +140,7 @@ export class AccountService {
public async getAccounts(aUserId: string): Promise<Account[]> { public async getAccounts(aUserId: string): Promise<Account[]> {
const accounts = await this.accounts({ const accounts = await this.accounts({
include: { Order: true, Platform: true }, include: { activities: true, Platform: true },
orderBy: { name: 'asc' }, orderBy: { name: 'asc' },
where: { userId: aUserId } where: { userId: aUserId }
}); });
@ -148,15 +148,15 @@ export class AccountService {
return accounts.map((account) => { return accounts.map((account) => {
let transactionCount = 0; let transactionCount = 0;
for (const order of account.Order) { for (const { isDraft } of account.activities) {
if (!order.isDraft) { if (!isDraft) {
transactionCount += 1; transactionCount += 1;
} }
} }
const result = { ...account, transactionCount }; const result = { ...account, transactionCount };
delete result.Order; delete result.activities;
return result; return result;
}); });

2
apps/api/src/app/order/order.service.ts

@ -100,7 +100,7 @@ export class OrderService {
userId: string; userId: string;
} }
): Promise<Order> { ): Promise<Order> {
let Account: Prisma.AccountCreateNestedOneWithoutOrderInput; let Account: Prisma.AccountCreateNestedOneWithoutActivitiesInput;
if (data.accountId) { if (data.accountId) {
Account = { Account = {

10
apps/api/src/app/portfolio/portfolio.service.ts

@ -139,7 +139,7 @@ export class PortfolioService {
} }
if (filterByDataSource && filterBySymbol) { if (filterByDataSource && filterBySymbol) {
where.Order = { where.activities = {
some: { some: {
SymbolProfile: { SymbolProfile: {
AND: [ AND: [
@ -154,7 +154,7 @@ export class PortfolioService {
const [accounts, details] = await Promise.all([ const [accounts, details] = await Promise.all([
this.accountService.accounts({ this.accountService.accounts({
where, where,
include: { Order: true, Platform: true }, include: { activities: true, Platform: true },
orderBy: { name: 'asc' } orderBy: { name: 'asc' }
}), }),
this.getDetails({ this.getDetails({
@ -170,8 +170,8 @@ export class PortfolioService {
return accounts.map((account) => { return accounts.map((account) => {
let transactionCount = 0; let transactionCount = 0;
for (const order of account.Order) { for (const { isDraft } of account.activities) {
if (!order.isDraft) { if (!isDraft) {
transactionCount += 1; transactionCount += 1;
} }
} }
@ -195,7 +195,7 @@ export class PortfolioService {
) )
}; };
delete result.Order; delete result.activities;
return result; return result;
}); });

18
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') .get('dataSource')
.removeValidators(Validators.required); .removeValidators(Validators.required);
this.activityForm.get('dataSource').updateValueAndValidity(); 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').setValidators(Validators.required);
this.activityForm.get('name').updateValueAndValidity(); this.activityForm.get('name').updateValueAndValidity();
this.activityForm.get('quantity').setValue(1); this.activityForm.get('quantity').setValue(1);
@ -248,11 +248,7 @@ export class CreateOrUpdateActivityDialog implements OnDestroy {
this.activityForm.get('searchSymbol').updateValueAndValidity(); this.activityForm.get('searchSymbol').updateValueAndValidity();
this.activityForm.get('updateAccountBalance').disable(); this.activityForm.get('updateAccountBalance').disable();
this.activityForm.get('updateAccountBalance').setValue(false); this.activityForm.get('updateAccountBalance').setValue(false);
} else if ( } else if (['FEE', 'INTEREST', 'LIABILITY'].includes(type)) {
type === 'FEE' ||
type === 'INTEREST' ||
type === 'LIABILITY'
) {
this.activityForm this.activityForm
.get('accountId') .get('accountId')
.removeValidators(Validators.required); .removeValidators(Validators.required);
@ -271,12 +267,8 @@ export class CreateOrUpdateActivityDialog implements OnDestroy {
.removeValidators(Validators.required); .removeValidators(Validators.required);
this.activityForm.get('dataSource').updateValueAndValidity(); this.activityForm.get('dataSource').updateValueAndValidity();
if ( if (['INTEREST', 'LIABILITY'].includes(type)) {
(type === 'FEE' && this.activityForm.get('fee').value === 0) || this.activityForm.get('fee').setValue(0);
type === 'INTEREST' ||
type === 'LIABILITY'
) {
this.activityForm.get('fee').reset();
} }
this.activityForm.get('name').setValidators(Validators.required); this.activityForm.get('name').setValidators(Validators.required);
@ -284,7 +276,7 @@ export class CreateOrUpdateActivityDialog implements OnDestroy {
if (type === 'FEE') { if (type === 'FEE') {
this.activityForm.get('quantity').setValue(0); this.activityForm.get('quantity').setValue(0);
} else if (type === 'INTEREST' || type === 'LIABILITY') { } else if (['INTEREST', 'LIABILITY'].includes(type)) {
this.activityForm.get('quantity').setValue(1); this.activityForm.get('quantity').setValue(1);
} }

4
package-lock.json

@ -1,12 +1,12 @@
{ {
"name": "ghostfolio", "name": "ghostfolio",
"version": "2.157.1", "version": "2.158.0",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "ghostfolio", "name": "ghostfolio",
"version": "2.157.1", "version": "2.158.0",
"hasInstallScript": true, "hasInstallScript": true,
"license": "AGPL-3.0", "license": "AGPL-3.0",
"dependencies": { "dependencies": {

2
package.json

@ -1,6 +1,6 @@
{ {
"name": "ghostfolio", "name": "ghostfolio",
"version": "2.157.1", "version": "2.158.0",
"homepage": "https://ghostfol.io", "homepage": "https://ghostfol.io",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"repository": "https://github.com/ghostfolio/ghostfolio", "repository": "https://github.com/ghostfolio/ghostfolio",

2
prisma/schema.prisma

@ -26,6 +26,7 @@ model Access {
} }
model Account { model Account {
activities Order[]
balance Float @default(0) balance Float @default(0)
balances AccountBalance[] balances AccountBalance[]
comment String? comment String?
@ -39,7 +40,6 @@ model Account {
userId String userId String
Platform Platform? @relation(fields: [platformId], references: [id]) Platform Platform? @relation(fields: [platformId], references: [id])
User User @relation(fields: [userId], onDelete: Cascade, references: [id]) User User @relation(fields: [userId], onDelete: Cascade, references: [id])
Order Order[]
@@id([id, userId]) @@id([id, userId])
@@index([currency]) @@index([currency])

Loading…
Cancel
Save