|
|
|
@ -21,7 +21,8 @@ import {
|
|
|
|
|
import { UniqueAsset } from '@ghostfolio/common/interfaces';
|
|
|
|
|
import {
|
|
|
|
|
AccountWithPlatform,
|
|
|
|
|
OrderWithAccount
|
|
|
|
|
OrderWithAccount,
|
|
|
|
|
UserWithSettings
|
|
|
|
|
} from '@ghostfolio/common/types';
|
|
|
|
|
import { Injectable } from '@nestjs/common';
|
|
|
|
|
import { DataSource, Prisma, SymbolProfile } from '@prisma/client';
|
|
|
|
@ -138,17 +139,16 @@ export class ImportService {
|
|
|
|
|
activitiesDto,
|
|
|
|
|
isDryRun = false,
|
|
|
|
|
maxActivitiesToImport,
|
|
|
|
|
userCurrency,
|
|
|
|
|
userId
|
|
|
|
|
user
|
|
|
|
|
}: {
|
|
|
|
|
accountsDto: Partial<CreateAccountDto>[];
|
|
|
|
|
activitiesDto: Partial<CreateOrderDto>[];
|
|
|
|
|
isDryRun?: boolean;
|
|
|
|
|
maxActivitiesToImport: number;
|
|
|
|
|
userCurrency: string;
|
|
|
|
|
userId: string;
|
|
|
|
|
user: UserWithSettings;
|
|
|
|
|
}): Promise<Activity[]> {
|
|
|
|
|
const accountIdMapping: { [oldAccountId: string]: string } = {};
|
|
|
|
|
const userCurrency = user.Settings.settings.baseCurrency;
|
|
|
|
|
|
|
|
|
|
if (!isDryRun && accountsDto?.length) {
|
|
|
|
|
const [existingAccounts, existingPlatforms] = await Promise.all([
|
|
|
|
@ -171,7 +171,7 @@ export class ImportService {
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// If there is no account or if the account belongs to a different user then create a new account
|
|
|
|
|
if (!accountWithSameId || accountWithSameId.userId !== userId) {
|
|
|
|
|
if (!accountWithSameId || accountWithSameId.userId !== user.id) {
|
|
|
|
|
let oldAccountId: string;
|
|
|
|
|
const platformId = account.platformId;
|
|
|
|
|
|
|
|
|
@ -184,7 +184,7 @@ export class ImportService {
|
|
|
|
|
|
|
|
|
|
let accountObject: Prisma.AccountCreateInput = {
|
|
|
|
|
...account,
|
|
|
|
|
User: { connect: { id: userId } }
|
|
|
|
|
User: { connect: { id: user.id } }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (
|
|
|
|
@ -200,7 +200,7 @@ export class ImportService {
|
|
|
|
|
|
|
|
|
|
const newAccount = await this.accountService.createAccount(
|
|
|
|
|
accountObject,
|
|
|
|
|
userId
|
|
|
|
|
user.id
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Store the new to old account ID mappings for updating activities
|
|
|
|
@ -231,16 +231,17 @@ export class ImportService {
|
|
|
|
|
|
|
|
|
|
const assetProfiles = await this.validateActivities({
|
|
|
|
|
activitiesDto,
|
|
|
|
|
maxActivitiesToImport
|
|
|
|
|
maxActivitiesToImport,
|
|
|
|
|
user
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const activitiesExtendedWithErrors = await this.extendActivitiesWithErrors({
|
|
|
|
|
activitiesDto,
|
|
|
|
|
userCurrency,
|
|
|
|
|
userId
|
|
|
|
|
userId: user.id
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const accounts = (await this.accountService.getAccounts(userId)).map(
|
|
|
|
|
const accounts = (await this.accountService.getAccounts(user.id)).map(
|
|
|
|
|
({ id, name }) => {
|
|
|
|
|
return { id, name };
|
|
|
|
|
}
|
|
|
|
@ -345,7 +346,6 @@ export class ImportService {
|
|
|
|
|
quantity,
|
|
|
|
|
type,
|
|
|
|
|
unitPrice,
|
|
|
|
|
userId,
|
|
|
|
|
accountId: validatedAccount?.id,
|
|
|
|
|
accountUserId: undefined,
|
|
|
|
|
createdAt: new Date(),
|
|
|
|
@ -374,7 +374,8 @@ export class ImportService {
|
|
|
|
|
},
|
|
|
|
|
Account: validatedAccount,
|
|
|
|
|
symbolProfileId: undefined,
|
|
|
|
|
updatedAt: new Date()
|
|
|
|
|
updatedAt: new Date(),
|
|
|
|
|
userId: user.id
|
|
|
|
|
};
|
|
|
|
|
} else {
|
|
|
|
|
if (error) {
|
|
|
|
@ -388,7 +389,6 @@ export class ImportService {
|
|
|
|
|
quantity,
|
|
|
|
|
type,
|
|
|
|
|
unitPrice,
|
|
|
|
|
userId,
|
|
|
|
|
accountId: validatedAccount?.id,
|
|
|
|
|
SymbolProfile: {
|
|
|
|
|
connectOrCreate: {
|
|
|
|
@ -406,7 +406,8 @@ export class ImportService {
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
updateAccountBalance: false,
|
|
|
|
|
User: { connect: { id: userId } }
|
|
|
|
|
User: { connect: { id: user.id } },
|
|
|
|
|
userId: user.id
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -553,10 +554,12 @@ export class ImportService {
|
|
|
|
|
|
|
|
|
|
private async validateActivities({
|
|
|
|
|
activitiesDto,
|
|
|
|
|
maxActivitiesToImport
|
|
|
|
|
maxActivitiesToImport,
|
|
|
|
|
user
|
|
|
|
|
}: {
|
|
|
|
|
activitiesDto: Partial<CreateOrderDto>[];
|
|
|
|
|
maxActivitiesToImport: number;
|
|
|
|
|
user: UserWithSettings;
|
|
|
|
|
}) {
|
|
|
|
|
if (activitiesDto?.length > maxActivitiesToImport) {
|
|
|
|
|
throw new Error(`Too many activities (${maxActivitiesToImport} at most)`);
|
|
|
|
@ -583,6 +586,21 @@ export class ImportService {
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (
|
|
|
|
|
this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION') &&
|
|
|
|
|
user.subscription.type === 'Basic'
|
|
|
|
|
) {
|
|
|
|
|
const dataProvider = this.dataProviderService.getDataProvider(
|
|
|
|
|
DataSource[dataSource]
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (dataProvider.getDataProviderInfo().isPremium) {
|
|
|
|
|
throw new Error(
|
|
|
|
|
`activities.${index}.dataSource ("${dataSource}") is not valid`
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const assetProfile = {
|
|
|
|
|
currency,
|
|
|
|
|
...(
|
|
|
|
|