diff --git a/apps/api/src/app/import/import.service.ts b/apps/api/src/app/import/import.service.ts index 96a8f9333..f4bbd0b78 100644 --- a/apps/api/src/app/import/import.service.ts +++ b/apps/api/src/app/import/import.service.ts @@ -637,12 +637,33 @@ export class ImportService { }); if (assetProfileToCreate) { - // Create the new asset profile and its market data later, once it - // is known which activities are imported - assetProfilesToCreate.push({ - marketDataObjects, - assetProfile: assetProfileToCreate - }); + const assetProfileToCreateIdentifier = + getAssetProfileIdentifier(assetProfileToCreate); + + const duplicateAssetProfileToCreate = assetProfilesToCreate.find( + ({ assetProfile }) => { + return ( + getAssetProfileIdentifier(assetProfile) === + assetProfileToCreateIdentifier + ); + } + ); + + if (duplicateAssetProfileToCreate) { + // The import contains the same asset profile more than once, + // which would fail with a unique constraint violation. Keep the + // first asset profile and merge the market data into it. + duplicateAssetProfileToCreate.marketDataObjects.push( + ...marketDataObjects + ); + } else { + // Create the new asset profile and its market data later, once it + // is known which activities are imported + assetProfilesToCreate.push({ + marketDataObjects, + assetProfile: assetProfileToCreate + }); + } } else { // Insert or update market data await this.marketDataService.updateMany({ @@ -732,10 +753,10 @@ export class ImportService { }) ?? { id: TAG_ID_DRAFT, name: 'DRAFT' }; // Create the new asset profiles of the activities to import only, so that - // no unused asset profile remains, for example if an activity is a - // duplicate. An asset profile which is created before the validation of - // the activities would stay behind, because the import is not rolled back - // on an error. + // no unused asset profile remains, for example if no activity refers to + // the asset profile. An asset profile which is created before the + // validation of the activities would stay behind, because the import is + // not rolled back on an error. if (!isDryRun) { for (const { assetProfile, @@ -744,9 +765,9 @@ export class ImportService { activities: activitiesExtendedWithErrors, assetProfiles: assetProfilesToCreate })) { - await this.symbolProfileService.add(assetProfile); - await this.marketDataService.updateMany({ data: marketDataObjects }); + + await this.symbolProfileService.add(assetProfile); } } diff --git a/apps/api/src/services/data-provider/data-provider.service.ts b/apps/api/src/services/data-provider/data-provider.service.ts index 4b1fdfff1..1b39deb97 100644 --- a/apps/api/src/services/data-provider/data-provider.service.ts +++ b/apps/api/src/services/data-provider/data-provider.service.ts @@ -284,19 +284,19 @@ export class DataProviderService implements OnModuleInit { // A custom asset profile of the import is created after the // validation, thus the data provider cannot resolve it yet if ( - (dataSource === DataSource.MANUAL && - (type === 'BUY' || Boolean(assetProfileInImport))) || + (dataSource === DataSource.MANUAL && type === 'BUY') || + Boolean(assetProfileInImport) || NON_INVESTMENT_ACTIVITY_TYPES.includes(type) ) { assetProfiles[assetProfileIdentifier] = { - currency, - dataSource, - symbol, ...omit(assetProfileInImport ?? {}, [ 'dataSource', 'marketData', 'symbol' ]), + currency, + dataSource, + symbol, name: assetProfileInImport?.name ?? symbol };