Browse Source

Bugfix/incorrect error log output when deleting activities (#7629)

* Fix incorrect error log output when deleting activities

* Update changelog
pull/7636/head
Thomas Kaul 3 days ago
committed by GitHub
parent
commit
e5273cc91a
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 2
      CHANGELOG.md
  2. 366
      apps/api/src/app/activities/activities.service.ts

2
CHANGELOG.md

@ -19,12 +19,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Deprecated the `permissions` attribute of the access in favor of the scopes - Deprecated the `permissions` attribute of the access in favor of the scopes
- Extended the `GET api/v1/access` endpoint by the scopes - Extended the `GET api/v1/access` endpoint by the scopes
- Extended the `GET api/v1/user` endpoint by the scopes - Extended the `GET api/v1/user` endpoint by the scopes
- Improved the performance of deleting activities by loading only the required data
### Fixed ### Fixed
- Fixed the missing currency conversion of the dividends on the analysis page - Fixed the missing currency conversion of the dividends on the analysis page
- Fixed the missing error state in the watchlist - Fixed the missing error state in the watchlist
- Fixed the missing loading indicator in the benchmarks of the markets overview - Fixed the missing loading indicator in the benchmarks of the markets overview
- Fixed the incorrect error log output when deleting activities
## 3.51.0 - 2026-08-14 ## 3.51.0 - 2026-08-14

366
apps/api/src/app/activities/activities.service.ts

@ -393,36 +393,32 @@ export class ActivitiesService {
types?: ActivityType[]; types?: ActivityType[];
userId: string; userId: string;
}): Promise<number> { }): Promise<number> {
const { activities } = await this.getActivities({ const where = this.getWhereClause({
endDate, endDate,
filters, filters,
startDate, startDate,
types, types,
userId, userId,
includeDrafts: true, includeDrafts: true,
userCurrency: undefined,
withExcludedAccountsAndActivities: true withExcludedAccountsAndActivities: true
}); });
const { count } = await this.prismaService.order.deleteMany({ const activities = await this.prismaService.order.findMany({
where: { where,
id: { distinct: ['symbolProfileId'],
in: activities.map(({ id }) => { select: { symbolProfileId: true }
return id;
})
}
}
}); });
const symbolProfiles = const { count } = await this.prismaService.order.deleteMany({ where });
await this.symbolProfileService.getSymbolProfilesByIds(
const [benchmarkAssetProfiles, symbolProfiles] = await Promise.all([
this.benchmarkService.getBenchmarkAssetProfiles(),
this.symbolProfileService.getSymbolProfilesByIds(
activities.map(({ symbolProfileId }) => { activities.map(({ symbolProfileId }) => {
return symbolProfileId; return symbolProfileId;
}) })
); )
]);
const benchmarkAssetProfiles =
await this.benchmarkService.getBenchmarkAssetProfiles();
for (const { for (const {
activitiesCount, activitiesCount,
@ -627,164 +623,19 @@ export class ActivitiesService {
{ date: 'asc' } { date: 'asc' }
]; ];
const andConditions: Prisma.OrderWhereInput[] = [];
const where: Prisma.OrderWhereInput = { userId, AND: andConditions };
if (endDate) {
andConditions.push({ date: { lte: endDate } });
}
if (startDate) {
andConditions.push({ date: { gt: startDate } });
}
const {
ACCOUNT: filtersByAccount = [],
ASSET_CLASS: filtersByAssetClass = [],
DATA_SOURCE: [filterByDataSource] = [],
SEARCH_QUERY: [filterBySearchQuery] = [],
SYMBOL: [filterBySymbol] = [],
TAG: filtersByTag = []
} = groupBy(filters, ({ type }) => {
return type;
});
if (filtersByAccount.length > 0) {
where.accountId = {
in: filtersByAccount.map(({ id }) => {
return id;
})
};
}
const isFilteredByDraftTag = filtersByTag.some(({ id }) => {
return id === TAG_ID_DRAFT;
});
if (includeDrafts === false && !isFilteredByDraftTag) {
andConditions.push(WHERE_ACTIVITY_NOT_DRAFT);
}
if (filtersByAssetClass.length > 0) {
where.SymbolProfile = {
OR: [
{
AND: [
{
OR: filtersByAssetClass.map(({ id }) => {
return { assetClass: AssetClass[id] };
})
},
{
OR: [
{ assetProfileOverrides: { is: null } },
{ assetProfileOverrides: { assetClass: null } }
]
}
]
},
{
assetProfileOverrides: {
OR: filtersByAssetClass.map(({ id }) => {
return { assetClass: AssetClass[id] };
})
}
}
]
};
}
if (filterByDataSource && filterBySymbol) {
if (where.SymbolProfile) {
where.SymbolProfile = {
AND: [
where.SymbolProfile,
{
AND: [
{ dataSource: filterByDataSource.id as DataSource },
{ symbol: filterBySymbol.id }
]
}
]
};
} else {
where.SymbolProfile = {
AND: [
{ dataSource: filterByDataSource.id as DataSource },
{ symbol: filterBySymbol.id }
]
};
}
}
if (filterBySearchQuery) {
const searchQueryWhereInput: Prisma.SymbolProfileWhereInput[] = [
{ id: { mode: 'insensitive', startsWith: filterBySearchQuery.id } },
{ isin: { mode: 'insensitive', startsWith: filterBySearchQuery.id } },
{ name: { mode: 'insensitive', startsWith: filterBySearchQuery.id } },
{ symbol: { mode: 'insensitive', startsWith: filterBySearchQuery.id } }
];
if (where.SymbolProfile) {
where.SymbolProfile = {
AND: [
where.SymbolProfile,
{
OR: searchQueryWhereInput
}
]
};
} else {
where.SymbolProfile = {
OR: searchQueryWhereInput
};
}
}
if (filtersByTag.length > 0) {
andConditions.push({
OR: [
{
tags: {
some: {
OR: filtersByTag.map(({ id }) => {
return { id };
})
}
}
},
{
account: {
tags: {
some: {
OR: filtersByTag.map(({ id }) => {
return { tagId: id };
})
}
}
}
}
]
});
}
if (sortColumn) { if (sortColumn) {
orderBy = [{ [sortColumn]: sortDirection }]; orderBy = [{ [sortColumn]: sortDirection }];
} }
if (types?.length > 0) { const where = this.getWhereClause({
where.type = { in: types }; endDate,
} filters,
includeDrafts,
if (withExcludedAccountsAndActivities === false) { startDate,
where.OR = [{ account: null }, { account: WHERE_ACCOUNT_NOT_EXCLUDED }]; types,
userId,
where.tags = { withExcludedAccountsAndActivities
none: { });
id: TAG_ID_EXCLUDE_FROM_ANALYSIS
}
};
}
const [orders, count] = await Promise.all([ const [orders, count] = await Promise.all([
this.orders({ this.orders({
@ -1113,6 +964,181 @@ export class ActivitiesService {
return activity; return activity;
} }
private getWhereClause({
endDate,
filters,
includeDrafts,
startDate,
types,
userId,
withExcludedAccountsAndActivities
}: {
endDate?: Date;
filters?: Filter[];
includeDrafts: boolean;
startDate?: Date;
types?: ActivityType[];
userId: string;
withExcludedAccountsAndActivities: boolean;
}): Prisma.OrderWhereInput {
const andConditions: Prisma.OrderWhereInput[] = [];
const where: Prisma.OrderWhereInput = { userId, AND: andConditions };
if (endDate) {
andConditions.push({ date: { lte: endDate } });
}
if (startDate) {
andConditions.push({ date: { gt: startDate } });
}
const {
ACCOUNT: filtersByAccount = [],
ASSET_CLASS: filtersByAssetClass = [],
DATA_SOURCE: [filterByDataSource] = [],
SEARCH_QUERY: [filterBySearchQuery] = [],
SYMBOL: [filterBySymbol] = [],
TAG: filtersByTag = []
} = groupBy(filters, ({ type }) => {
return type;
});
if (filtersByAccount.length > 0) {
where.accountId = {
in: filtersByAccount.map(({ id }) => {
return id;
})
};
}
const isFilteredByDraftTag = filtersByTag.some(({ id }) => {
return id === TAG_ID_DRAFT;
});
if (includeDrafts === false && !isFilteredByDraftTag) {
andConditions.push(WHERE_ACTIVITY_NOT_DRAFT);
}
if (filtersByAssetClass.length > 0) {
where.SymbolProfile = {
OR: [
{
AND: [
{
OR: filtersByAssetClass.map(({ id }) => {
return { assetClass: AssetClass[id] };
})
},
{
OR: [
{ assetProfileOverrides: { is: null } },
{ assetProfileOverrides: { assetClass: null } }
]
}
]
},
{
assetProfileOverrides: {
OR: filtersByAssetClass.map(({ id }) => {
return { assetClass: AssetClass[id] };
})
}
}
]
};
}
if (filterByDataSource && filterBySymbol) {
if (where.SymbolProfile) {
where.SymbolProfile = {
AND: [
where.SymbolProfile,
{
AND: [
{ dataSource: filterByDataSource.id as DataSource },
{ symbol: filterBySymbol.id }
]
}
]
};
} else {
where.SymbolProfile = {
AND: [
{ dataSource: filterByDataSource.id as DataSource },
{ symbol: filterBySymbol.id }
]
};
}
}
if (filterBySearchQuery) {
const searchQueryWhereInput: Prisma.SymbolProfileWhereInput[] = [
{ id: { mode: 'insensitive', startsWith: filterBySearchQuery.id } },
{ isin: { mode: 'insensitive', startsWith: filterBySearchQuery.id } },
{ name: { mode: 'insensitive', startsWith: filterBySearchQuery.id } },
{ symbol: { mode: 'insensitive', startsWith: filterBySearchQuery.id } }
];
if (where.SymbolProfile) {
where.SymbolProfile = {
AND: [
where.SymbolProfile,
{
OR: searchQueryWhereInput
}
]
};
} else {
where.SymbolProfile = {
OR: searchQueryWhereInput
};
}
}
if (filtersByTag.length > 0) {
andConditions.push({
OR: [
{
tags: {
some: {
OR: filtersByTag.map(({ id }) => {
return { id };
})
}
}
},
{
account: {
tags: {
some: {
OR: filtersByTag.map(({ id }) => {
return { tagId: id };
})
}
}
}
}
]
});
}
if (types?.length > 0) {
where.type = { in: types };
}
if (withExcludedAccountsAndActivities === false) {
where.OR = [{ account: null }, { account: WHERE_ACCOUNT_NOT_EXCLUDED }];
where.tags = {
none: {
id: TAG_ID_EXCLUDE_FROM_ANALYSIS
}
};
}
return where;
}
private async orders(params: { private async orders(params: {
include?: Prisma.OrderInclude; include?: Prisma.OrderInclude;
skip?: number; skip?: number;

Loading…
Cancel
Save